基础知识(重点理解设备树)
块设备:
块设备(Block Device)是指在操作系统中以固定大小的块为单位进行数据读写的设备。 每个块的大小通常为512字节或更大,用于存储和传输数据。 块设备可以是硬盘、固态硬盘(SSD)、光盘、闪存等存储设备。
树形结构:
目录/文件这种结构,用树形结构去访问一个块设备的关键是块设备和文件系统;
Linux用super_block来将两者联系在一起;
inode和dentry:
系统使用 struct inode
结构来标识块设备内部的一个文件夹或者文件,struct inode
结构中最重要的成员是 ->i_ino
这个记录了 inode 在块设备中的偏移。
系统为了辅助 struct inode
的使用还设计了一个 struct dentry
结构,通常情况下一个 struct dentry
对应一个 struct inode
,也有少数情况下多个 struct dentry
对应一个 struct inode
(如硬链接)。struct dentry
中 cache 了更多的文件信息,类如文件名、层次结构,成员 ->d_parent
指向同一块设备内的父节点 struct dentry
,成员 ->d_subdirs
链接了所有的子节点 struct dentry
。
对于一个super_block,通过s_root找到自己的根节点,然后dentry之间构成了一个树形结构,由孩子指向父亲;
同时还有两个链表结构用于父子间的指向;
多设备的层次化(重点理解mount树)
Linux 使用父子树的形式来构造,父设备树中的一个文件夹 struct dentry
可以充当子设备树的挂载点 mountpoint
比之前多了一个struct mount结构;
如果是多个块设备的挂载,相互之间形成了树形结构:
如果 dentry
成为了挂载点 mountpoint
,会给其标识成 DCACHE_MOUNTED
。我们在查找路径的时候同样会判断 dentry
的 DCACHE_MOUNTED
标志,一旦置位就变成了 mountpoint
,挂载点文件夹下原有的内容就不能访问了,转而访问子设备树根节点下的内容。
规则1、一个设备可以被挂载多次:
规则2、一个挂载点可以挂载多个设备:
解释:这里第一次挂载成功之后,挂载点(蓝色)的dentry会被标记为DCACHE_MOUNTED,那么第二次挂载再次输入这个目录的路径之后,这里就不能被访问了,转而访问第一次挂载的块设备的根节点的dentry,所以我们看到的第二次的挂载点就是途中黄色的dentry了。
path
因为 Linux 提供的灵活的挂载规则,所以我们如果要标识一个路径 struct path
的话需要两个元素:vfsmount
和 dentry
。
path的定义路径:https://elixir.bootlin.com/linux/v6.13.6/source/include/linux/path.h
判断两个路径相等用的是path_equal,要同时比较mnt和dentry:
chroot
多名空间的层次化(mnt_namespace)
mount
创建文件会创建对应的path;
删除文件会删除对应的path;
所以mount的时候回去找这个目录的path,mount成功后会将struct mount 挂载到struct path上;
chroot
task_struct中有一个fs成员:https://elixir.bootlin.com/linux/v6.13.5/source/include/linux/sched.h#L785
然后查看fs_struct定义:
关注chroot中的set_fs_root:
https://elixir.bootlin.com/linux/v6.13.5/source/fs/fs_struct.c#L15
就是设置fs->root为path;