|
该函数在将这些来自用户内存空间(user space)的参数拷贝到内核空间后,便调用 do_mount() 函数开始真正的安装文档系统的工作。同样,为了便于叙述和讲清楚主流程,接下来的说明将不严格按照具体的函数调用细节来进行。
do_mount() 函数会首先调用 path_lookup() 函数来得到安装点的相关信息,如同创建目录过程中叙述的那样,该安装点的信息最终记录在 struct nameidata 类型的一个变量当中,为叙述方便,记该变量为nd。在本例中当 path_lookup() 函数返回时,nd 中记录的信息如下:nd.entry = new_entry; nd.mnt = mnt; 这里的变量如图 3 和 4 中所示。
然后,do_mount() 函数会根据调用参数 flags 来决定调用以下四个函数之一:do_remount()、 do_loopback()、do_move_mount()、do_add_mount()。
在 我们当前的例子中,系统会调用 do_add_mount() 函数来向 VFS 树中安装点 "/dev " 安装一个实际的文档系统。在 do_add_mount() 中,主要完成了两件重要事情:一是获得一个新的安装区域块,二是将该新的安装区域块加入了安装系统链表。他们分别是调用 do_kern_mount() 函数和 graft_tree() 函数来完成的。这里的描述可能有点抽象,诸如安装区域块、安装系统链表等,但是不用着急,因为他们都是笔者自己定义出来的概念,等一下到后面会有专门的图 表解释,到时便会清楚。
do_kern_mount() 函数要做的事情,便是建立一新的安装区域块,具体的内容在前面的章节 VFS 目录树的建立中已叙述过,这里不再赘述。
graft_tree() 函数要做的事情便是将 do_kern_mount() 函数返回的一 struct vfsmount 类型的变量加入到安装系统链表中,同时 graft_tree() 还要将新分配的 struct vfsmount 类型的变量加入到一个hash表中,其目的我们将会在以后看到。
这样,当 do_kern_mount() 函数返回时,在图 4 的基础上,新的数据结构间的关系将如图 5 所示。其中,红圈区域里面的数据结构便是被称做安装区域块的东西,其中不妨称 e2_mnt 为安装区域块的指针,蓝色箭头曲线即构成了所谓的安装系统链表。
在 把这些函数调用后形成的数据结构关系理清楚之后,让我们回到本章节开始提到的问题,即将 ext2 文档系统安装到了 "/dev " 上之后,对该目录上的操作如何转化为对 ext2 文档系统相应的操作。从图 5上看到,对 sys_mount() 函数的调用并没有直接改变 "/dev " 目录所对应的 inode (即图中的 new_inode变量)结构中的 i_op 和 i_fop 指针,而且 "/dev " 所对应的 dentry(即图中的 new_dentry 变量)结构仍然在 VFS 的目录树中,并没有被从其中隐藏起来,相应地,来自 hda2 上的 ext2 文档系统的根目录所对应的 e2_entry 也不是如当初笔者所想象地那样将 VFS 目录树中的 new_dentry 取而代之,那么这之间的转化到底是如何实现的呢?
请读者注意下面的这段代码:
|
这 段代码在 link_path_walk() 函数中被调用,而 link_path_walk() 最终又会被 path_lookup() 函数调用,假如读者阅读过 Linux 关于文档系统部分的代码,应该知道 path_lookup() 函数在整个 Linux 繁琐的文档系统代码中属于一个重要的基础性的函数。简单说来,这个函数用于解析文档路径名,这里的文档路径名和我们平时在应用程式中所涉及到的概念相同, 比如在 Linux 的应用程式中 open 或 read 一个文档 /home/windfly.cs 时,这里的 /home/windfly.cs 就是文档路径名,path_lookup() 函数的责任就是对文档路径名中进行搜索,直到找到目标文档所属目录所对应的 dentry 或目标直接就是个目录,笔者不想在有限的篇幅里周详解释这个函数,读者只要记住 path_lookup() 会返回一个目标目录即可。
上 面的代码很地不起眼,以至于初次阅读文档系统的代码时经常会忽略掉他,但是前文所提到从 VFS 的操作到实际文档系统操作的转化却是由他完成的,对 VFS 中实现的文档系统的安装可谓功不可没。现在让我们仔细剖析一下该段代码: d_mountpoint(dentry) 的作用很简单,他只是返回 dentry 中 d_mounted 成员变量的值。这里的dentry 仍然还是 VFS 目录树上的东西。假如 VFS 目录树上某个目录被安装过一次,那么该值为 1。对VFS 中的一个目录可进行多次安装,后面会有例子说明这种情况。在我们的例子中,"/dev" 所对应的new_dentry 中 d_mounted=1,所以 while 循环中第一个条件满足。下面再来看__follow_down(&nd->mnt, &dentry)代
图 5:安装 ext2 类型根文档系统到 "/dev " 目录上 
码 做了什么?到此我们应该记住,这里 nd 中的 dentry 成员就是图 5 中的 new_dentry,nd 中的 mnt成员就是图 5 中的 mnt,所以我们现在能够把 __follow_down(&nd->mnt, &dentry) 改写成__follow_down(&mnt, &new_dentry),接下来我们将 __follow_down() 函数的代码改写(只是去处掉一些不太相关的代码,并且为了便于说明,在部分代码行前加上了序号)如下:




