分类: LINUX
2010-11-24 18:10:15
“安装”一个文件系统涉及“被安装设备”和“安装点”两个部分,安装的过程就是把“安装点”和“被安装设备”关联起来,这是通过一个“安装连接件”结构 vfsmount来完成的。
vfsmount 将“安装点”dentry 和“被安装设备”的根目录节点 dentry 关联起来。
每安装一次文件系统,会导致:
1、 创建一个 vfsmount
2、 为“被安装设备”创建一个 super_block,并由具体的文件系统来设置这个 super_block。(我们在“注册文件系统”一节将再来分析这一步)
3、 为被安装设备的根目录节点创建 dentry
4、 为被安装设备的根目录节点创建 inode, 并由 super_operations->read_inode() 来设置此 inode
5、 将 super_block 与“被安装设备“根目录节点 dentry 关联起来
6、 将 vfsmount 与“被安装设备”的根目录节点 dentry 关联起来
在内核将根设备安装到“根安装点”上后,内存中有如下结构关系:
现在假设我们在 /mnt/win 下安装了 /dev/sda1, /dev/sda1 下有 dir1,然后又在 dir1 下安装了 /dev/sda2,那么内存中就有了如下的结构关系
前面说了,在安装一个文件系统的时候,需要为“被安装设备”创建一个 super_block,并设置它。
如果从源码追寻这个创建和设置 super_block 的过程,就引出了“注册文件系统”的概念。
实际上,在安装一个文件系统之前,还需要有一个注册文件系统的步骤,否则内核就因为不认识该文件系统而无法完成安装。
通过register_filesystem() ,将一个“文件系统类型”结构 file_system_type注册到内核中一个全局的链表file_systems 上。
这个结构中最关键的就是 read_super() 这个函数指针,它就是用于创建并设置 super_block 的目的的。
因为安装一个文件系统的关键一步就是要为“被安装设备”创建和设置一个 super_block,而不同的具体的文件系统的 super_block 有自己特定的信息,因此要求具体的文件系统首先向内核注册,并提供 read_super() 的实现。
下面来研究文件系统中的一个非常关键的操作:根据路径名寻找目标节点的 dentry。
例如要打开 /mnt/win/dir1/abc 这个文件,就是根据这个路径,找到目标节点 ‘abc’ 对应的 dentry ,进而得到 inode 的过程。
寻找过程大致如下:
1、 首先找到根文件系统的根目录节点 dentry 和 inode
2、 由这个 inode 提供的操作接口 i_op->lookup(),找到下一层节点 ‘mnt’ 的 dentry 和 inode
3、 由 ‘mnt’ 的 inode 找到 ‘win’ 的 dentry 和 inode
4、 由于 ‘win’ 是个“安装点”,因此需要找到“被安装设备”/dev/sda1 根目录节点的 dentry 和 inode,只要找到 vfsmount B,就可以完成这个任务。
5、 然后由 /dev/sda1 根目录节点的 inode 负责找到下一层节点 ‘dir1’ 的 dentry 和 inode
6、 由于 dir1 是个“安装点”,因此需要借助 vfsmount C 找到 /dev/sda2 的根目录节点 dentry 和 inode
7、 最后由这个 inode 负责找到 ‘abc’ 的 dentry 和 inode
可以看到,整个寻找过程是一个递归的过程。
完成寻找后,内存中结构如下,其中红色线条是寻找目标节点的路径
现在有两个问题:
1、在寻找过程的第一步,如何得到“根文件系统”的根目录节点的 dentry?
答案是这个 dentry 是被保存在进程的 task_struct 中的。后面分析进程与文件系统关系的时候再说这个。
2、如何寻找 vfsmount B 和 C?
这是接下来要分析的。