代码行[1]中的 lookup_mnt() 函数用于查找一个 VFS 目录树下某一目录最近一次被 mount 时的安装区域块的指针,在本例中最终会返回图 5 中的 e2_mnt。至于查找的原理,这里粗略地描述一下。记得当我们在安装 ext2 文档系统到 "/dev" 时,在后期会调用 graft_tree() 函数,在这个函数里会把图 5 中的安装区域块指针 e2_mnt 挂到一 hash 表(Linux 2.4.20源代码中称之为 mount_hashtable)中的某一项,而该项的键值就是由被安装点所对应的 dentry(本例中为 new_dentry)和 mount(本例中为 mnt)所一起产生,所以自然地,当我们知道 VFS 树中某一 dentry 被安装过(该 dentry 变成为一安装点),而要去查找其最近一次被安装的安装区域块指针时,同样由该安装点所对应的 dentry 和 mount 来产生一键值,以此值去索引 mount_hashtable,自然可找到该安装点对应的安装区域块指针形成的链表的头指针,然后遍历该链表,当发现某一安装区域块指针,记为 p,满足以下条件时:
|
P 便为该安装点所对应的安装区域块指针。当找到该指针后,便将 nd 中的 mnt 成员换成该安装区域块指针,同时将 nd 中的 dentry 成员换成安装区域块中的 dentry 指针。在我们的例子中,e2_mnt->mnt_root成员指向 e2_dentry,也就是 ext2 文档系统的 "/" 目录。这样,当 path_lookup() 函数搜索到 "/dev"时,nd 中的 dentry 成员为 e2_dentry,而不再是原来的 new_dentry,同时 mnt 成员被换成 e2_mnt,转化便在不知不觉中完成了。
现在考 虑一下对某一安装点多次安装的情况,同样作为例子,我们假设在 "/dev" 上安装完一个 ext2文档系统后,再在其上安装一个 ntfs 文档系统。在安装之前,同样会对安装点所在的路径调用path_lookup() 函数进行搜索,但是这次由于在 "/dev" 目录上已安装过了 ext2 文档系统,所以搜索到最后,由 nd 返回的信息是:nd.dentry = e2_dentry, nd.mnt = e2_mnt。由此可见,在第二次安装时,安装点已由 dentry 变成了 e2_dentry。接下来,同样地,系统会再分配一个安装区域块,假设该安装区域块的指针为 ntfs_mnt,区域块中的 dentry 为 ntfs_dentry。ntfs_mnt 的父指针指向了e2_mnt,mnfs_mnt 中的 mnt_root 指向了代表 ntfs 文档系统根目录的 ntfs_dentry。然后,系统通过 e2_dentry和 e2_mnt 来生成一个新的 hash 键值,利用该值作为索引,将 ntfs_mnt 加入到 mount_hashtable 中,同时将 e2_dentry 中的成员 d_mounted 值设定为 1。这样,安装过程便告结束。
读者可能已知道,对同一安装点上的最近一次安装会隐藏起前面的若干次安装,下面我们通过上述的例子解释一下该过程:
在 先后将 ext2 和 ntfs 文档系统安装到 "/dev" 目录之后,我们再调用 path_lookup() 函数来对"/dev" 进行搜索,函数首先找到 VFS 目录树下的安装点 "/dev" 所对应的 dentry 和 mnt,此时他发现dentry 成员中的 d_mounted 为 1,于是他知道已有文档系统安装到了该 dentry 上,于是他通过 dentry 和 mnt 来生成一个 hash 值,通过该值来对 mount_hashtable 进行搜索,根据安装过程,他应该能找到 e2_mnt 指针并返回之,同时原先的 dentry 也已被替换成 e2_dentry。回头再看一下前面已提到的下列代码: while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry)); 当第一次循环结束后, nd->mnt 已是 e2_mnt,而 dentry 则变成 e2_dentry。此时由于 e2_dentry 中的成员 d_mounted 值为 1,所以 while 循环的第一个条件满足,要继续调用 __follow_down() 函数,这个函数前面已剖析过,当他返回后 nd->mnt 变成了 ntfs_mnt,dentry 则变成了 ntfs_dentry。由于此时 ntfs_dentry 没有被安装过其他文档,所以他的成员 d_mounted 应该为 0,循环结束。对 "/dev" 发起的 path_lookup() 函数最终返回了 ntfs 文档系统根目录所对应的 dentry。这就是为什么 "/dev" 本身和安装在其上的 ext2 都被隐藏的原因。假如此时对 "/dev" 目录进行一个 ls 命令,将返回安装上去的 ntfs 文档系统根目录下任何的文档和目录。
7. 安装根文档系统
有了前面章节 5 的基础,理解 Linux 下根文档系统的安装并不困难,因为不管怎么样,安装一个文档系统到 VFS 中某一安装点的过程原理毕竟都是相同的。
这个过程大致是:首先要确定待安装的 ext2 文档系统的来源,其次是确定 ext2 文档系统在 VFS中的安装点,然后便是具体的安装过程。
关于第一问题,Linux 2.4.20 的内核另有一大堆的代码去解决,限于篇幅,笔者不想在这里去具体说明这个过程,大概记住他是要解决到哪里去找要安装的文档系统的就能够了,这里我们不妨就认为要安装的根文档系统就来自于主硬盘的第一分区 hda1.
关 于第二个问题,Linux 2.4.20 的内核把来自于 hda1 上 ext2 文档系统安装到了 VFS 目录树中的"/root" 目录上。其实,把 ext2 文档系统安装到 VFS 目录树下的哪个安装点并不重要(VFS 的根目录除外),只要是这个安装点在 VFS 树中是存在的,并且内核对他没有另外的用途。假如读者喜欢,尽能够自己在 VFS 中创建一个 "/Windows" 目录,然后将 ext2 文档系统安装上去作为将来用户进程的根目录,没有什么不能够的。问题的关键是要将进程的根目录和当前工作目录设定好,因为毕竟只用用户进程才去关心现实的 文档系统,要知道笔者的这篇稿子可是要存到硬盘上去的。
在 Linux 下,设定一个进程的当前工作目录是通过系统调用 sys_chdir() 进行的。初始化期间,Linux 在将 hda1 上的 ext2 文档系统安装到了 "/root" 上后,通过调用 sys_chdir("/root") 将当前进程,也就是 init_task 进程的当前工作目录(pwd)设定为 ext2 文档系统的根目录。记住此时 init_task进程的根目录仍然是图 3 中的 dentry,也就是 VFS 树的根目录,这显然是不行的,因为以后 Linux 世界中的任何进程都由这个 init_task 进程派生出来,无一例外地要继承该进程的根目录,假如是这样,意味着用户进程从根目录搜索某一目录时,实际上是从 VFS 的根目录开始的,而事实上却是从 ext2 的根文档开始搜索的。这个矛盾的解决是靠了在调用完 mount_root() 函数后,系统调用的下面两个函数:
文章整理:西部数码--专业提供域名注册、虚拟主机服务
http://www.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!



