Chinaunix首页 | 论坛 | 博客
  • 博客访问: 752157
  • 博文数量: 79
  • 博客积分: 2671
  • 博客等级: 少校
  • 技术积分: 1247
  • 用 户 组: 普通用户
  • 注册时间: 2010-04-02 15:26
个人简介

宅男

文章分类

全部博文(79)

文章存档

2017年(11)

2016年(12)

2015年(6)

2012年(10)

2011年(33)

2010年(7)

分类: LINUX

2011-05-06 19:26:16

在上次的给定路径名到目标节点中都是以纯代码的形式讲解,本次将以代码集合图表的方式分析上次忽略的细节。

在这之前,先设想这样的几个实例:

(1)要查找的目标是一个链接。

(2)在路径名中存在子系统的情况。(比如在/mnt目录上挂载了一个文件系统,现在要查找/mnt/test文件夹)

在上一章我们选择性忽略了err = do_lookup(nd, &this, &next) 函数,因为这个函数比较复杂。

  1. static int do_lookup(struct nameidata *nd, struct qstr *name,
  2.              struct path *path)
  3.     {
  4.         struct vfsmount *mnt = nd->mnt;
  5.     //首先先根据其父目录以及文件名在杂凑表中查找。(即内存中)
  6.         struct dentry *dentry = __d_lookup(nd->dentry, name);
  7.         if (!dentry)
  8.     //如果没有找到,就表示在内存中不存在当前目录的dentry数据结构。就需要到设备中读出信息来重新在内存中建立该数据结构,这个就涉及到具体的文件系统了。
  9.             goto need_lookup;
  10.         if (dentry->d_op && dentry->d_op->d_revalidate)
  11.             goto need_revalidate;
  12.     done:
  13.         path->mnt = mnt;
  14.         path->dentry = dentry;
  15.         __follow_mount(path);
  16.         return 0;
  17.     need_lookup:
  18.     //real_lookup在磁盘中查找信息,然后在内存中建立数据结构,挂入杂凑表
  19.         dentry = real_lookup(nd->dentry, name, nd);
  20.         if (IS_ERR(dentry))
  21.             goto fail;
  22.         goto done;
  23.     need_revalidate:
  24.         if (dentry->d_op->d_revalidate(dentry, nd))
  25.     //通过d_revalidate来检验找到的dentry数据结构,如果验证失败就要从杂凑表中脱链
  26.             goto done;
  27.         if (d_invalidate(dentry))
  28.             goto done;
  29.         dput(dentry);
  30.         goto need_lookup;
  31.     fail:
  32.         return PTR_ERR(dentry);
  33.     }

关于上面的函数,首先在内存中根据父目录项以及文件名查找,如果没有找到就代表该目录项不在内存中,就需要调用具体文件系统的钩子函数从设备中读出相应的目录项,在内存中重建,然后挂入杂凑表中。在上面的函数中,有一个极其重要的函数__follow_mount(path)

  1. static int __follow_mount(struct path *path)
  2.     {
  3.         int res = 0;
  4.         while (d_mountpoint(path->dentry)) {
  5.         struct vfsmount *mounted = lookup_mnt(path->mnt, path->dentry);
  6.             if (!mounted)
  7.                 break;
  8.             dput(path->dentry);
  9.             if (res)
  10.                 mntput(path->mnt);
  11.             path->mnt = mounted;
  12.             path->dentry = dget(mounted->mnt_root);
  13.             res = 1;
  14.         }
  15.         return res;
  16.     }

这个函数是首先通过d_mountpoint函数来检查在该dentry设备上有没有安装设备。

dentry数据结构中有一个成员变量为d_mounted,用于指示在该目录项上有没有安装设备。d_mountpoint函数仅仅检查了该标志位。内核中一个全局变量mount_hashtable。这是一个hash表,用于链接所有的vfsmount结构,即在安装过程中产生的“连接部件”。我们可以认为vfsmount用于建立一个目录项dentry与一个另外一个文件系统的根目录之间的关系。


图一:vfsmount结构体在安装过程中的作用

事实在dentry结构中并没有相应的指针指向vfsmount结构,而是通过父目录项以及文件名构成的hash值存储在mount_hashtable中。

如果在某一个dentry中安装了设备会怎么样。很简单,用安装文件系统的根目录项替换当前目录项,然后继续查找。这样查找就从安装文件系统中继续下去,而原来的dentry的子目录项等等就变得不可见了。

图二:安装设备之后,原dentry的子目录项变得不可见

上述是在执行命令:mount -t yaffs   /dev/mtdblock2 /mnt前后的对比(在操作系统的根文件系统下存在/mnt/test/code文件,而在yaffs文件系统下存在/test/code文件),在没有执行该命令之前,我们通过路径名/mnt/test/code查找到的目录项是属于操作系统的根文件系统的,而在/mnt上安装了yaffs文件系统之后,情况就变了。通过路径名查找到是yaffs文件系统上的文件/mnt/test/code

另外在path_walk(2.6.16源码中为__link_path_walk函数)函数中存在这样的代码,在上一章中只是粗略的带过.

  1. if (inode->i_op->follow_link) {
  2.                 err = do_follow_link(&next, nd);
  3.                 if (err)
  4.                     goto return_err;
  5.                 err = -ENOENT;
  6.                 inode = nd->dentry->d_inode;
  7.                 if (!inode)
  8.                     break;
  9.                 err = -ENOTDIR;
  10.                 if (!inode->i_op)
  11.                     break;
  12.             }

如果inode操作结构体支持follow_link的话(比如FAT文件系统不支持软连接),那么就调用do_follow_link

do_follow_link->__do_follow_link:

//首先调用follow_link来获得链接文件的路径名

  1. cookie = dentry->d_inode->i_op->follow_link(dentry, nd);
  2.         error = PTR_ERR(cookie);
  3.         if (!IS_ERR(cookie)) {
  4.             char *s = nd_get_link(nd);
  5.             error = 0;
  6.             if (s)
  7.                 error = __vfs_follow_link(nd, s);
  8.             if (dentry->d_inode->i_op->put_link)
  9.                 dentry->d_inode->i_op->put_link(dentry, nd, cookie);
  10.         }

首先需要调用各个文件系统具体的follow_link函数来获得链接导致指向何处。一般软连接没有具体的数据,而仅仅保持的是链接对象的路径名。要解析一个链接。首先需要获得链接指向对象的路径名。然后通过前面我们提到的path_walk来查找,即上面的__vfs_follow_link,那么为什么需要从VFS层来重新查找呢?因为链接的对象可能在另外一个设备上(即跨设备),需要从VFS层面来查找。另外为了防止链接陷入死循环(比如两个软连接相互指向)。在查找过程中需要对链接的深度做一定的限制。

阅读(2026) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~