Chinaunix首页 | 论坛 | 博客
  • 博客访问: 434257
  • 博文数量: 99
  • 博客积分: 65
  • 博客等级: 民兵
  • 技术积分: 1012
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-20 16:30
个人简介

linux kernel 工程师

文章分类

全部博文(99)

文章存档

2018年(5)

2017年(12)

2016年(27)

2015年(10)

2014年(43)

2012年(2)

我的朋友

分类: LINUX

2016-12-25 21:39:35

link_path_walk里面有一个for循环,每个循环截取一个路径分量,直到最后一个分量。
比如“/mnt/tmp1", "/"是根路径,在path_init函数里面已经确定;下面两个分量是mnt和tmp1.
第1次执行for循环,截取出来的路径分量是"mnt",由于它不是路径的最后一个分量,所以不需要跳转到last_component或者last_with_slashes处执行。在红色字体的continue处回到for循环开始,开始截取下一个路径分量。
第2次执行for循环,截取出来的路径分量是"tmp1",由于它是路径的最后一个分量,所以需要goto到last_component处。


点击(此处)折叠或打开

  1. /*
  2.  * Name resolution.
  3.  * This is the basic name resolution function, turning a pathname into
  4.  * the final dentry. We expect 'base' to be positive and a directory.
  5.  *
  6.  * Returns 0 and nd will have valid dentry and mnt on success.
  7.  * Returns error and drops reference to input namei data on failure.
  8.  */
  9. static int link_path_walk(const char *name, struct nameidata *nd)
  10. {
  11.     struct path next;
  12.     struct inode *inode;
  13.     int err;
  14.     unsigned int lookup_flags = nd->flags;
  15.     
  16.     while (*name=='/')
  17.         name++;
  18.     if (!*name)
  19.         goto return_reval;

  20.     inode = nd->path.dentry->d_inode;
  21.     if (nd->depth)
  22.         lookup_flags = LOOKUP_FOLLOW | (nd->flags & LOOKUP_CONTINUE);

  23.     /* At this point we know we have a real path component. */
  24.     for(;;) {    /* 在这个循环里,每次循环截取一个路径分量  */
  25.         unsigned long hash;
  26.         struct qstr this;
  27.         unsigned int c;

  28.         nd->flags |= LOOKUP_CONTINUE;
  29.         err = exec_permission(inode);
  30.          if (err)
  31.             break;
  32.         /* struct qstr this; 这个变量,就是为了记录路径分量的字符串,字符串长度,路径分量hash值 */

  33.         /* 路径分量的截取,begin */
  34.         this.name = name;
  35.         c = *(const unsigned char *)name;

  36.         hash = init_name_hash();
  37.         do {
  38.             name++;
  39.             hash = partial_name_hash(c, hash);
  40.             c = *(const unsigned char *)name;
  41.         } while (c && (c != '/'));
  42.         this.len = name - (const char *) this.name;
  43.         this.hash = end_name_hash(hash);
  44.         /* 路径分量的截取, end */

  45.         /* remove trailing slashes? */
  46.         if (!c)
  47.             goto last_component;
  48.         while (*++name == '/');
  49.         if (!*name)
  50.             goto last_with_slashes;

/* 路径中间分量的处理,begin*/

          /* 对于路径分量中出现的"."和".."的特殊处理,
            如果是"."则不更新nd->path

            如果是"..",则调用follow_dotdot,更新nd->path为父目录的dentry和vfsmount,返回父目录要着重考虑跨越mountponit            的情况
          */

  1.         /*
  2.          * "." and ".." are special - ".." especially so because it has
  3.          * to be able to know about the current root directory and
  4.          * parent relationships.
  5.          */
  6.         if (this.name[0] == '.') switch (this.len) {
  7.             default:
  8.                 break;
  9.             case 2:    
  10.                 if (this.name[1] != '.')
  11.                     break;
  12.                 follow_dotdot(nd);
  13.                 inode = nd->path.dentry->d_inode;
  14.                 /* fallthrough */
  15.             case 1:
  16.                 continue;
  17.         }
  18.         /* This does the actual lookups.. */
  19.         /* 根据路径名称查找dentry的过程:先在内存hash表里查找,如果查找不到,再进行文件系统的查找 */
  20.         err = do_lookup(nd, &this, &next);
  21.         if (err)
  22.             break;

  23.         err = -ENOENT;
  24.         inode = next.dentry->d_inode;
  25.         if (!inode)
  26.             goto out_dput;
  27.         /* 路径的中间分量,需要对符号链接进行跟踪 */
  28.         if (inode->i_op->follow_link) {
  29.             err = do_follow_link(&next, nd);
  30.             if (err)
  31.                 goto return_err;
  32.             err = -ENOENT;
  33.             inode = nd->path.dentry->d_inode;
  34.             if (!inode)
  35.                 break;
  36.         } else
  37.             path_to_nameidata(&next, nd);
  38.         err = -ENOTDIR;
  39.         if (!inode->i_op->lookup)
  40.             break;
  41.         continue/* 对于一个路径中间分量,处到此就结束,回到for循环开始,继续下一个路径分量 */
  42.         /* here ends the main loop */
  43. /* 路径中间分量的处理,end */

/* 路径最后分量的处理,begin
    路径最后分量与路径中间分量处理的不同点在于
    1. 如果lookup_flags & LOOKUP_PARENT,则不需要对最后一个分量进行查找。
    这样的情形比如要删除一个"/mnt/tmp1/abc"这个目录,那么我们需要的是先找到"/mnt/tmp1"这个目录,因为删除"/mnt/tmp1"的child 目录,很多操作都要在"/mnt/tmp1"的目录数据结构上操作,没有必要直接找到"/mnt/tmp1/abc"这个目录。 有了"/mnt/tmp1"这个目录的数据结构后,再查找目录下的"abc"目录,完成dentry的删除操作
如下面的调用关系:
    do_rmdir
          user_path_parent
                do_path_lookup(dfd, s, LOOKUP_PARENT, nd)
     
     nd->last = this, 所以nd->last变量记录了最后一个分量的信息。并且nd.last_type能够指示:    
          如果最后一个分量是".", nd.last_type=LAST_DOT
          如果最后一个分量是"..", nd.last_type=LAST_DOTDOT
          如果最后一个分量是正常字符, nd.last_type=LAST_NORM
    2. 对于路径的中间分量,如果是符号链接,一定要跟踪过去。但对于路径的最后分量,却要判断通过follow_on_final
来判断,如果是目录的话才会跟踪过去。
    3. 对于路径的中间分量,如果inode->i_op->lookup==NULL, 因为中间节点需要是目录,如果lookup函数为空,意味着无法进一步查找了。所以要返回失败。
        但是对于路径的最后分量,inode->i_op->lookup==NUL,只有LOOKUP_DIRECTORY标志设置时(比如执行"cd /mnt/tmp1/"这样的命令),才会返回失败。

*/
/*
如果最后一个分量后面带一个"/", 比如要查找"/mnt/tmp1/",而不是查找“/mnt/tmp",那么就要在lookup_flags上加上LOOKUP_FOLLOW | LOOKUP_DIRECTORY两个标志。
LOOKUP_DIRECTORY,表示要查找的对象时一个目录。
*/

last_with_slashes:

  1.         lookup_flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
  2. last_component:
  3.         /* Clear LOOKUP_CONTINUE iff it was previously unset */
  4.         nd->flags &= lookup_flags | ~LOOKUP_CONTINUE;
  5.         if (lookup_flags & LOOKUP_PARENT)
  6.             goto lookup_parent;

        /* 对于最后分量的处理,同样要对"."和".."的特殊处理,
            如果是"."则不更新nd->path

            如果是"..",则调用follow_dotdot,更新nd->path为父目录的dentry和vfsmount,返回父目录要着重考虑跨越mountponit的情况 */

  1.         if (this.name[0] == '.') switch (this.len) {
  2.             default:
  3.                 break;
  4.             case 2:    
  5.                 if (this.name[1] != '.')
  6.                     break;
  7.                 follow_dotdot(nd);
  8.                 inode = nd->path.dentry->d_inode;
  9.                 /* fallthrough */
  10.             case 1:
  11.                 goto return_reval;
  12.         }
  13.         err = do_lookup(nd, &this, &next);
  14.         if (err)
  15.             break;
  16.         inode = next.dentry->d_inode;
  17.         if (follow_on_final(inode, lookup_flags)) {
  18.             err = do_follow_link(&next, nd);
  19.             if (err)
  20.                 goto return_err;
  21.             inode = nd->path.dentry->d_inode;
  22.         } else
  23.             path_to_nameidata(&next, nd);
  24.         err = -ENOENT;
  25.         if (!inode)
  26.             break;
  27.         if (lookup_flags & LOOKUP_DIRECTORY) {
  28.             err = -ENOTDIR;
  29.             /* 如果查找对象是一个目录,则inode必须有lookup函数,否则就返回错误信息 */
  30.             if (!inode->i_op->lookup)
  31.                 break;
  32.         }
  33.         goto return_base;
  34. lookup_parent:
  35.         nd->last = this;
  36.         nd->last_type = LAST_NORM;
  37.         if (this.name[0] != '.')
  38.             goto return_base;
  39.         if (this.len == 1)
  40.             nd->last_type = LAST_DOT;
  41.         else if (this.len == 2 && this.name[1] == '.')
  42.             nd->last_type = LAST_DOTDOT;
  43.         else
  44.             goto return_base;
  45. /* 路径最后分量的处理,end
  46. return_reval:
  47.         /*
  48.          * We bypassed the ordinary revalidation routines.
  49.          * We may need to check the cached dentry for staleness.
  50.          */
  51.         if (nd->path.dentry && nd->path.dentry->d_sb &&
  52.          (nd->path.dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT)) {
  53.             err = -ESTALE;
  54.             /* Note: we do not d_invalidate() */
  55.             if (!nd->path.dentry->d_op->d_revalidate(
  56.                     nd->path.dentry, nd))
  57.                 break;
  58.         }
  59. return_base:
  60.         return 0;
  61. out_dput:
  62.         path_put_conditional(&next, nd);
  63.         break;
  64.     } /* for循环的结束 */
  65.     path_put(&nd->path);
  66. return_err:
  67.     return err;
  68. }

阅读(1546) | 评论(0) | 转发(0) |
0

上一篇:d_alloc

下一篇:sys_mount

给主人留下些什么吧!~~