我发现在大多数情况下,i_data只是i_mapping的解引用数据,如下所示,为什么在一个inode结构中设置两个相同的值?
crash> struct inode ffffffc073c1f360 -o
struct inode {
...
[ffffffc073c1f4a8] struct file_lock *i_flock;
**[ffffffc073c1f4b0] struct address_space i_data;**
[ffffffc073c1f558] struct list_head i_devices;
...
crash> struct inode ffffffc073c1f360
struct inode {
...
i_op = 0xffffffc0007ad1c0 <ext4_file_inode_operations>,
i_sb = 0xffffffc002010000,
**i_mapping = 0xffffffc073c1f4b0,**
i_security = 0xffffffc07230d050,
...
地址空间总是处理页面缓存。当访问页面缓存中的页面时,如果该页面的所有者是文件,则
address_space
对象将嵌入到 VFS inode 对象的 i_data
字段中。 inode 的 i_mapping 字段始终指向包含 inode 数据的页面所有者的 address_space
对象。 address_space
对象的host字段指向嵌入描述符的inode对象。
例如如果页面属于存储在 ext4 文件系统中的常规文件,则 VFS inode 的
i_data
指向该文件的 inode,inode 的 i_mapping 字段指向同一 inode 的 i_data
,以及 address_space
对象的 host 字段指向同一个 inode。
然而事情并不总是那么简单。假设一个页面包含从块设备文件读取的数据,该文件包含块设备的“原始”数据,
address_space
嵌入在bdev中文件的“主”inode中,bdev是与块设备关联的特殊文件系统(参考通过 bd_inode)。因此块设备文件的inode的i_mapping字段指向
address_space
对象嵌入在主inode中;相应地,address_space
对象的host字段指向主inode。这样,包含从块设备读取的数据的所有页面都具有相同的 address_space
对象,即使它们是通过引用不同的块设备文件来访问的。
因此,当页面属于常规文件或属于块设备特殊文件时,两者之间存在细微差别。
来自 http://lkml.iu.edu/hypermail/linux/kernel/0105.2/1363.html:
i_data 是“此 inode 读取/写入的页面”
i_mapping 是“我应该向谁索要页面?”
IOW,单个文件系统之外的所有内容都应该使用后者。 当(且仅当)inode 拥有数据时它们是相同的。 CODA(或任何 将数据缓存在本地文件系统上)将使 i_mapping 指向以下的 i_data 它缓存到的索引节点。对于块设备,如果/当它们进入页面缓存时也是如此 - 我们应该将 pagecache 与 struct block_device 关联起来,因为我们可以有 许多 inode 具有相同的主要:次要。 IOW,->i_mapping 应该指向 所有人都去同一个地方。
来自 https://marc.info/?l=linux-fsdevel&m=99470104708354&w=2:
它由环绕现有文件系统的文件系统使用。据我所知尾声是 树中唯一真正使用它的。
所有 VFS 函数始终使用 inode->i_mapping->a_ops。科达复制了 底层 inode 到它自己的 inode 的 i_mapping。这样我们就可以使用 与容器文件相同的地址空间并避免映射相同的文件 内存中不同位置的页面。
i_mapping 是真正的页面缓存。 i_data 是address_space 所在的位置,并与inode 一起分配和释放,并且通常是i_mapping 指向的位置。但是文件系统可以将一个 inode 的 i_data 留空,并将 i_mapping 指向另一个 inode 的 i_data,以避免多个页面缓存。