分类: LINUX
2008-04-24 22:31:51
◆
为了更好地理解 VFS,下面我们用一个实际例子来看看 Linux 是如何在 VFS 的根目录下建立一个新的目录 "/dev" 的。
要在 VFS 中建立一个新的目录,首先我们得对该目录进行搜索,搜索的目的是找到将要建立的目录其父目录的相关信息,因为"皮之不存,毛将焉附"。比如要建立目录 /home/ricard,那么首先必须沿目录路径进行逐层搜索,本例中先从根目录找起,然后在根目录下找到目录 home,然后再往下,便是要新建的目录名 ricard,那么前面讲得要先对目录搜索,在该例中便是要找到 ricard 这个新目录的父目录,也就是 home 目录所对应的信息。
当然,如果搜索的过程中发现错误,比如要建目录的父目录并不存在,或者当前进程并无相应的权限等等,这种情况系统必然会调用相关过程进行处理,对于此种情况,本文略过不提。
Linux 下用系统调用 sys_mkdir 来在 VFS 目录树中增加新的节点。同时为配合路径搜索,引入了下面一个数据结构:
struct nameidata { struct dentry *dentry; struct vfsmount *mnt; struct qstr last; unsigned int flags; int last_type; }; |
这个数据结构在路径搜索的过程中用来记录相关信息,起着类似"路标"的作用。其中前两项中的 dentry记录的是要建目录的父目录的信息,mnt 成员接下来会解释到。后三项记录的是所查找路径的最后一个节点(即待建目录或文件)的信息。 现在为建立目录 "/dev" 而调用 sys_mkdir("/dev", 0700),其中参数 0700 我们不去管它,它只是限定将要建立的目录的某种模式。sys_mkdir 函数首先调用 path_lookup("/dev", LOOKUP_PARENT, &nd);来对路径进行查找,其中 nd 为 struct nameidata nd 声明的变量。在接下来的叙述中,因为函数调用关系的繁琐,为了突出过程主线,将不再严格按照函数的调用关系来进行描述。
path_lookup 发现 "/dev" 是以 "/" 开头,所以它从当前进程的根目录开始往下查找,具体代码如下:
nd->mnt = mntget(current->fs->rootmnt); nd->dentry = dget(current->fs->root); |
记得在 init_mount_tree() 函数的后半段曾经将新建立的 VFS 根目录相关信息记录在了 init_task 进程的进程数据块中,那么在这个场景里,nd->mnt 便指向了图 3 中 mnt 变量,nd->dentry 便指向了图 3 中的 dentry 变量。
然后调用函数 path_walk 接着往下查找,找到最后通过变量 nd 返回的信息是 nd.last.name="dev",nd.last.len=3,nd.last_type=LAST_NORM,至于 nd 中 mnt 和 dentry 成员,在这个场景里还是前面设置的值,并无变化。这样一圈下来,只是用 nd 记录下相关信息,实际的目录建立工作并没有真正展开,但是前面所做的工作却为接下来建立新的节点收集了必要的信息。
好,到此为止真正建立新目录节点的工作将会展开,这是由函数 lookup_create 来完成的,调用这个函数时会传入两个参数:lookup_create(&nd, 1);其中参数 nd 便是前面提到的变量,参数1表明要建立一个新目录。
这里的大体过程是:新分配了一个 struct dentry 结构的内存空间,用于记录 dev 目录所对应的信息,该dentry 结构将会挂接到其父目录中,也就是图 3 中 "/" 目录对应的 dentry 结构中,由链表实现这一关系。接下来会再分配一个 struct inode 结构。Inode 中的 i_sb 和 dentry 中的 d_sb 分别都指向图 3 中的 sb,这样看来,在同一文件系统下建立新的目录时并不需要重新分配一个超级块结构,因为毕竟它们都属于同一文件系统,因此一个文件系统只对应一个超级块。
这样,当调用 sys_mkdir 成功地在 VFS 的目录树中新建立一个目录 "/dev" 之后,在图 3 的基础上,新的数据结构之间的关系便如图 4 所示。图 4 中颜色较深的两个矩形块 new_inode 和 new_entry 便是在sys_mkdir() 函数中新分配的内存结构,至于图中的 mnt,sb,dentry,inode 等结构,仍为图 3 中相应的数据结构,其相互之间的链接关系不变(图中为避免过多的链接曲线,忽略了一些链接关系,如 mnt 和 sb,dentry之间的链接,读者可在图 3 的基础上参看图 4)。
需要强调一点的是,既然 rootfs 文件系统被 mount 到了 VFS 树上,那么它在 sys_mkdir 的过程中必然会参与进来,事实上在整个过程中,rootfs 文件系统中的 ramfs_mkdir、ramfs_lookup 等函数都曾被调用过。