我正在监视文件操作事件(VFS)。
我的 BTRFS 文件系统有问题,BTRFS 使用子卷,btrfs 中的所有最高层次结构目录都具有相同的 inode (256/512)。
简短的故事:
当我收到文件操作事件时,我收到路径,然后将其解析为 inode。
通过解决我的意思是:给定一个路径,我得到它的 dentry(user_path() 调用),从 dentry 我拉: dEntry->d_inode->i_ino
问题是我在同一设备上的不同目录收到相同的 inode。
我猜想,BTRFS 有某种抽象层,它创建一个“虚拟”inode 编号(相同的 inode 是虚拟的)——同一设备 ID 上不可能有两个相同的 inode。
设备 ID 问题的证明:
我从内核收到设备 ID 29:
代码:设备 ID 解析:对于给定路径 (/home) -> 使用 user_path 获取 dentry,然后 dEntry->d_inode->i_sb->s_dev 或者我运行命令:
"grep btrfs /proc/self/mountinfo | less"
输出:
/proc/self/mountinfo return inode 29 also: 34 18 0:29 /home /home rw,noatime,nodiratime shared:19 - btrfs /dev/md127 rw,nospace_cache,subvolid=257,subvol=/home
我从用户空间收到设备 ID 33:
root@nas-B9-43-AA:/# stat /home
File: `/home'
Size: 90 Blocks: 0 IO Block: 4096 directory
Device: 21h/33d Inode: 256 Links: 1
root@nas-B9-43-AA:/# mountpoint -d /home
0:33
所以我得到 29 和 33 作为设备 ID。
让我们将设备 id 29 称为“实际 id”,33 是“虚拟 id”。
有没有办法从内核代码中获取实际 id?
我正在寻找 dEntry->d_inode->i_sb->s_dev 的替代品。获取与我们从用户模式收到的相同的 id。
我使用的是 Debian 7
答案1
这个问题基于一些常见的误解,即 UNIX 文件系统类似于 MS-DOS 文件系统,因此每个块设备只能有一个文件系统实例(意味着文件系统实例只能跨越单个块设备),并且只有一个根目录每个文件系统实例。
相反,Btrs 和 ZFS 都可以跨越多个块设备,并且每个实例中可以有多个文件系统根目录。
UNIX 文件系统语义所要求的只是设备 ID ( st_dev
) 和 i 节点号 ( st_ino
) 唯一标识整个系统中的 inode。它们不要求设备 ID 仅对应于一个块设备或任何一个块设备。因此,设备 IDstat
报告是唯一有效的“实际”设备 ID,即使它不是块设备的设备 ID。
事情稍微复杂一点,更多细节在这篇博文中。
答案2
而不是去dentry - inode - superblock - device id。
我使用 dentry 上的 getattr(..) 获取设备 ID。
我的解决方案取自主题中的 Suse 补丁(经过大量谷歌挖掘后)。