从文件名找到文件信息(namei)

来源:互联网 发布:淘宝仓库 编辑:程序博客网 时间:2024/06/16 11:58

从文件名找到文件信息(namei)

本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。 
msn: yfydz_no1@hotmail.com 
来源:http://yfydz.cublog.cn 

Java代码  收藏代码
  1. 1. 前言  
  2.   
  3. inode是类Unix系统的文件系统的基本索引方法,每个文件都对应一个inode,再通过inode找到文件中的实际数据,因此根据文件路径名找到具体的inode节点就是一个很重要的处理步骤。系统会缓存用过的每个文件或目录对应的dentry结构, 从该结构可以指向相应的inode, 每次打开文件, 都会最终对应到文件的inode,中间查找过程称为namei。  
  4.   
  5. 本文介绍Linux下的路径到文件指针的转换过程,内核版本为2.6.19.2。  
  6.   
  7. 虚拟文件系统的转换源代码在fs/namei.c中,具体和文件系统相关的部分在fs/*/namei.c文件中。 
  8.  
  9. 2. 引子 
  10.  
  11. 由于这种转换是一个中间过程,在具体分析namei处理前,先看看系统的调用顺序是如何进入转换的: 
  12. 当用户空间程序用open系统调用打开一个文件时,内核对应的处理是sys_open: 
  13. /* fs/open.c */  
  14. asmlinkage long sys_open(const char __user *filename, int flags, int mode)  
  15. {  
  16.  long ret;  
  17.  if (force_o_largefile())  
  18.   flags |= O_LARGEFILE;  
  19.  ret = do_sys_open(AT_FDCWD, filename, flags, mode);  
  20.  /* avoid REGPARM breakage on x86: */  
  21.  prevent_tail_call(ret);  
  22.  return ret;  
  23. }  
  24. 真正的打开函数是do_sys_open:  
  25. /* fs/open.c */  
  26. // dfd为AT_FDCWD  
  27. long do_sys_open(int dfd, const char __user *filename, int flags, int mode)  
  28. {  
  29. // 通过该函数将用户空间的文件名传递到内核  
  30. // tmp是一个cache类的动态内存空间,用于保存文件路径名  
  31. //  
  32.  char *tmp = getname(filename);  
  33.  int fd = PTR_ERR(tmp);  
  34.  if (!IS_ERR(tmp)) {  
  35. // 获取一个未使用的文件描述符, 和inode无关  
  36.   fd = get_unused_fd();  
  37.   if (fd >= 0) {  
  38. // 打开文件,将文件名转换为文件结构  
  39.    struct file *f = do_filp_open(dfd, tmp, flags, mode);  
  40.    if (IS_ERR(f)) {  
  41.     put_unused_fd(fd);  
  42.     fd = PTR_ERR(f);  
  43.    } else {  
  44.     fsnotify_open(f->f_dentry);  
  45.     fd_install(fd, f);  
  46.    }  
  47.   }  
  48.   putname(tmp);  
  49.  }  
  50.  return fd;  
  51. }  
  52.   
  53. // 文件打开  
  54. static struct file *do_filp_open(int dfd, const char *filename, int flags,  
  55.      int mode)  
  56. {  
  57.  int namei_flags, error;  
  58. // 注意这是结构而不是指针  
  59.  struct nameidata nd;  
  60.  namei_flags = flags;  
  61.  if ((namei_flags+1) & O_ACCMODE)  
  62.   namei_flags++;  
  63. // 根据文件名得到nameidata, nd作为namei空间保存结果  
  64.  error = open_namei(dfd, filename, namei_flags, mode, &nd);  
  65.  if (!error)  
  66. // 成功, nameidata再转换为file指针  
  67.   return nameidata_to_filp(&nd, flags);  
  68.  return ERR_PTR(error);  
  69. }  
  70.   
  71. 因此重点函数是open_namei函数, 实现了从文件名到inode的转换, 也是namei的处理入口.  
  72.   
  73. 在分析open_namei前, 再分析一下getname, 这用到了kmem_cache来处理的:  
  74. // 文件名转换, 从用户空间拷贝到内核空间  
  75. /* fs/namei.c */  
  76. char * getname(const char __user * filename)  
  77. {  
  78.  char *tmp, *result;  
  79.  result = ERR_PTR(-ENOMEM);  
  80. /* include/linux/fs.h */  
  81. // __getname和__putname的定义,实际就是内核cache的分配和释放  
  82. // #define __getname() kmem_cache_alloc(names_cachep, SLAB_KERNEL)  
  83. // #define __putname(name) kmem_cache_free(names_cachep, (void *)(name))  
  84. // 这里实际是分配names的cache, 该cache定义为  
  85. //  names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0,  
  86. //   SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);  
  87.  tmp = __getname();  
  88.  if (tmp)  {  
  89. // cache分配成功  
  90. // 进入实际操作函数  
  91.   int retval = do_getname(filename, tmp);  
  92. // 要返回结果指向cache  
  93.   result = tmp;  
  94.   if (retval < 0) {  
  95. // 操作失败,释放cache,返回错误  
  96.    __putname(tmp);  
  97.    result = ERR_PTR(retval);  
  98.   }  
  99.  }  
  100. // 编译内核时如果没有设置CONFIG_AUDITSYSCALL, 则audit_getname为空  
  101. // 审计系统调用结果  
  102.  audit_getname(result);  
  103.  return result;  
  104. }  
  105.   
  106. static int do_getname(const char __user *filename, char *page)  
  107. {  
  108.  int retval;  
  109.  unsigned long len = PATH_MAX;  
  110.  if (!segment_eq(get_fs(), KERNEL_DS)) {  
  111.   if ((unsigned long) filename >= TASK_SIZE)  
  112.    return -EFAULT;  
  113.   if (TASK_SIZE - (unsigned long) filename < PATH_MAX)  
  114.    len = TASK_SIZE - (unsigned long) filename;  
  115.  }  
  116. // 将用户空间提供的文件名拷贝到cache中  
  117.  retval = strncpy_from_user(page, filename, len);  
  118.  if (retval > 0) {  
  119.   if (retval < len)  
  120.    return 0;  
  121.   return -ENAMETOOLONG;  
  122.  } else if (!retval)  
  123.   retval = -ENOENT;  
  124.  return retval;  
  125. }  
  126.    
  127. 3. namei相关数据结构  
  128. /* include/linux/namei.h */  
  129. struct nameidata {  
  130. // 路径点  
  131.  struct dentry *dentry;  
  132. // 虚拟系统挂接点  
  133.  struct vfsmount *mnt;  
  134. // 路径名中的最后的文件名或目录名  
  135.  struct qstr last;  
  136.  unsigned int flags;  
  137.  int  last_type;  
  138. // 目录深度  
  139.  unsigned depth;  
  140.  char *saved_names[MAX_NESTED_LINKS + 1]; // 9  
  141.  /* Intent data */  
  142. // 相关数据  
  143.  union {  
  144. // 包含打开的文件的指针  
  145.   struct open_intent open;  
  146.  } intent;  
  147. };  
  148.   
  149. struct open_intent {  
  150. // 标志  
  151.  int flags;  
  152. // 创建模式  
  153.  int create_mode;  
  154. // 文件指针  
  155.  struct file *file;  
  156. };  
  157.   
  158. // 路径结构, 属于中间处理结构, 将文件系统挂接点和dentry捆绑在一起而已  
  159. struct path {  
  160.  struct vfsmount *mnt;  
  161.  struct dentry *dentry;  
  162. };  
  163.   
  164. /* include/linux/dcache.h */  
  165. // 文件目录项, 在系统cache中  
  166. struct dentry {  
  167.  atomic_t d_count;  
  168.  unsigned int d_flags;  /* protected by d_lock */  
  169.  spinlock_t d_lock;  /* per dentry lock */  
  170.  struct inode *d_inode;  /* Where the name belongs to - NULL is 
  171.       * negative */  
  172.  /* 
  173.   * The next three fields are touched by __d_lookup.  Place them here 
  174.   * so they all fit in a cache line. 
  175.   */  
  176.  struct hlist_node d_hash; /* lookup hash list */  
  177.  struct dentry *d_parent; /* parent directory */  
  178.  struct qstr d_name;  
  179.  struct list_head d_lru;  /* LRU list */  
  180.  /* 
  181.   * d_child and d_rcu can share memory 
  182.   */  
  183.  union {  
  184.   struct list_head d_child; /* child of parent list */  
  185.    struct rcu_head d_rcu;  
  186.  } d_u;  
  187.  struct list_head d_subdirs; /* our children */  
  188.  struct list_head d_alias; /* inode alias list */  
  189.  unsigned long d_time;  /* used by d_revalidate */  
  190.  struct dentry_operations *d_op;  
  191.  struct super_block *d_sb; /* The root of the dentry tree */  
  192.  void *d_fsdata;   /* fs-specific data */  
  193. #ifdef CONFIG_PROFILING  
  194.  struct dcookie_struct *d_cookie; /* cookie, if any */  
  195. #endif  
  196.  int d_mounted;  
  197.  unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */  
  198. };  
  199.   
  200. /* include/linux/fs.h */  
  201. // 文件结构  
  202. struct file {  
  203.  /* 
  204.   * fu_list becomes invalid after file_free is called and queued via 
  205.   * fu_rcuhead for RCU freeing 
  206.   */  
  207.  union {  
  208.   struct list_head fu_list;  
  209.   struct rcu_head  fu_rcuhead;  
  210.  } f_u;  
  211. // 文件的dentry  
  212.  struct dentry  *f_dentry;  
  213. // 虚拟文件系统挂接点  
  214.  struct vfsmount         *f_vfsmnt;  
  215. // 文件操作  
  216.  const struct file_operations *f_op;  
  217.  atomic_t  f_count;  
  218.  unsigned int   f_flags;  
  219.  mode_t   f_mode;  
  220.  loff_t   f_pos;  
  221.  struct fown_struct f_owner;  
  222.  unsigned int  f_uid, f_gid;  
  223.  struct file_ra_state f_ra;  
  224.  unsigned long  f_version;  
  225. #ifdef CONFIG_SECURITY  
  226.  void   *f_security;  
  227. #endif  
  228.  /* needed for tty driver, and maybe others */  
  229.  void   *private_data;  
  230. #ifdef CONFIG_EPOLL  
  231.  /* Used by fs/eventpoll.c to link all the hooks to this file */  
  232.  struct list_head f_ep_links;  
  233.  spinlock_t  f_ep_lock;  
  234. #endif /* #ifdef CONFIG_EPOLL */  
  235.  struct address_space *f_mapping;  
  236. };  
  237.    
  238. 4. namei操作  
  239.   
  240. 4.1 open_namei  
  241.   
  242. /* fs/namei.c */  
  243. /* 
  244.  * open_namei() 
  245.  * 
  246.  * namei for open - this is in fact almost the whole open-routine. 
  247.  * 
  248.  * Note that the low bits of "flag" aren't the same as in the open 
  249.  * system call - they are 00 - no permissions needed 
  250.  *     01 - read permission needed 
  251.  *     10 - write permission needed 
  252.  *     11 - read/write permissions needed 
  253.  * which is a lot more logical, and also allows the "no perm" needed 
  254.  * for symlinks (where the permissions are checked later). 
  255.  * SMP-safe 
  256.  */  
  257. int open_namei(int dfd, const char *pathname, int flag,  
  258.   int mode, struct nameidata *nd)  
  259. {  
  260.  int acc_mode, error;  
  261.  struct path path;  
  262.  struct dentry *dir;  
  263.  int count = 0;  
  264. // #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])  
  265. // 审计模式  
  266.  acc_mode = ACC_MODE(flag);  
  267.  /* O_TRUNC implies we need access checks for write permissions */  
  268. // 截断标志, 基本上需要写权限, 除非要截断的长度实际大于文件本身长度  
  269.  if (flag & O_TRUNC)  
  270.   acc_mode |= MAY_WRITE;  
  271.  /* Allow the LSM permission hook to distinguish append 
  272.     access from general write access. */  
  273. // 添加标志, 也是需要写权限  
  274.  if (flag & O_APPEND)  
  275.   acc_mode |= MAY_APPEND;  
  276.  /* 
  277.   * The simplest case - just a plain lookup. 
  278.   */  
  279. // 不需要创建文件  
  280.  if (!(flag & O_CREAT)) {  
  281. // 直接找pathname的dentry和挂接点, 结果填在nd中  
  282.   error = path_lookup_open(dfd, pathname, lookup_flags(flag),  
  283.       nd, flag);  
  284.   if (error)  
  285.    return error;  
  286.   goto ok;  
  287.  }  
  288.  /* 
  289.   * Create - we need to know the parent. 
  290.   */  
  291. // 创建文件的dentry和挂接点, 数据填到nd中  
  292.  error = path_lookup_create(dfd,pathname,LOOKUP_PARENT,nd,flag,mode);  
  293.  if (error)  
  294.   return error;  
  295.  /* 
  296.   * We have the parent and last component. First of all, check 
  297.   * that we are not asked to creat(2) an obvious directory - that 
  298.   * will not do. 
  299.   */  
  300.  error = -EISDIR;  
  301. // 检查nameidata结构中的last参数是否合法  
  302.  if (nd->last_type != LAST_NORM || nd->last.name[nd->last.len])  
  303.   goto exit;  
  304. // 文件项dentry  
  305.  dir = nd->dentry;  
  306. // 去掉查询父目录标志  
  307.  nd->flags &= ~LOOKUP_PARENT;  
  308.  mutex_lock(&dir->d_inode->i_mutex);  
  309. // 填充path参数, 又根据nd的信息搜索一次当前的缓存的dentry  
  310. // 不过dir与path.dentry难道不相同么?  
  311.  path.dentry = lookup_hash(nd);  
  312.  path.mnt = nd->mnt;  
  313. do_last:  
  314. // 检查path.entry是否合法  
  315.  error = PTR_ERR(path.dentry);  
  316.  if (IS_ERR(path.dentry)) {  
  317.   mutex_unlock(&dir->d_inode->i_mutex);  
  318.   goto exit;  
  319.  }  
  320. // 检查nd->intent.open.file是否合法, 这是最终要返回的文件指针  
  321.  if (IS_ERR(nd->intent.open.file)) {  
  322.   mutex_unlock(&dir->d_inode->i_mutex);  
  323.   error = PTR_ERR(nd->intent.open.file);  
  324.   goto exit_dput;  
  325.  }  
  326.  /* Negative dentry, just create the file */  
  327.  if (!path.dentry->d_inode) {  
  328. // 创建新文件的inode, 然后返回  
  329.   error = open_namei_create(nd, &path, flag, mode);  
  330.   if (error)  
  331.    goto exit;  
  332.   return 0;  
  333.  }  
  334. // 现在是打开已经存在的文件  
  335.  /* 
  336.   * It already exists. 
  337.   */  
  338.  mutex_unlock(&dir->d_inode->i_mutex);  
  339.  audit_inode_update(path.dentry->d_inode);  
  340.  error = -EEXIST;  
  341. // O_EXCL标志是只必须打开的是不存在的文件, 文件已存在时错误  
  342.  if (flag & O_EXCL)  
  343.   goto exit_dput;  
  344.  if (__follow_mount(&path)) {  
  345.   error = -ELOOP;  
  346.   if (flag & O_NOFOLLOW)  
  347.    goto exit_dput;  
  348.  }  
  349.  error = -ENOENT;  
  350.  if (!path.dentry->d_inode)  
  351.   goto exit_dput;  
  352. // 如果dentry的具体FS的实现中定义了follow_link操作, 转  
  353. // 不过大多数FS的实现中都没有定义该函数  
  354.  if (path.dentry->d_inode->i_op && path.dentry->d_inode->i_op->follow_link)  
  355.   goto do_link;  
  356. // 从路径中的dentry和mnt信息赋值到nameidata  
  357.  path_to_nameidata(&path, nd);  
  358.  error = -EISDIR;  
  359. // 如果是一个目录, 返回错误  
  360.  if (path.dentry->d_inode && S_ISDIR(path.dentry->d_inode->i_mode))  
  361.   goto exit;  
  362. ok:  
  363. // 对nd中的dentry及其inode进行打开前的错误检查  
  364.  error = may_open(nd, acc_mode, flag);  
  365.  if (error)  
  366.   goto exit;  
  367.  return 0;  
  368. // 下面是错误处理, 释放掉已分配的资源, 返回错误  
  369. exit_dput:  
  370.  dput_path(&path, nd);  
  371. exit:  
  372.  if (!IS_ERR(nd->intent.open.file))  
  373.   release_open_intent(nd);  
  374.  path_release(nd);  
  375.  return error;  
  376. // 处理符号连接, 找到实际文件的inode,然后重新循环, 要注意回环情况的错误处理  
  377. do_link:  
  378.  error = -ELOOP;  
  379.  if (flag & O_NOFOLLOW)  
  380.   goto exit_dput;  
  381.  /* 
  382.   * This is subtle. Instead of calling do_follow_link() we do the 
  383.   * thing by hands. The reason is that this way we have zero link_count 
  384.   * and path_walk() (called from ->follow_link) honoring LOOKUP_PARENT. 
  385.   * After that we have the parent and last component, i.e. 
  386.   * we are in the same situation as after the first path_walk(). 
  387.   * Well, almost - if the last component is normal we get its copy 
  388.   * stored in nd->last.name and we will have to putname() it when we 
  389.   * are done. Procfs-like symlinks just set LAST_BIND. 
  390.   */  
  391. // 设置查找LOOKUP_PARENT标志  
  392.  nd->flags |= LOOKUP_PARENT;  
  393.  error = security_inode_follow_link(path.dentry, nd);  
  394.  if (error)  
  395.   goto exit_dput;  
  396. // 处理符号链接  
  397.  error = __do_follow_link(&path, nd);  
  398.  if (error) {  
  399.   /* Does someone understand code flow here? Or it is only 
  400.    * me so stupid? Anathema to whoever designed this non-sense 
  401.    * with "intent.open". 
  402.    */  
  403.   release_open_intent(nd);  
  404.   return error;  
  405.  }  
  406.  nd->flags &= ~LOOKUP_PARENT;  
  407. // 检查最后一段文件或目录名的属性情况  
  408.  if (nd->last_type == LAST_BIND)  
  409.   goto ok;  
  410.  error = -EISDIR;  
  411.  if (nd->last_type != LAST_NORM)  
  412.   goto exit;  
  413.  if (nd->last.name[nd->last.len]) {  
  414.   __putname(nd->last.name);  
  415.   goto exit;  
  416.  }  
  417.  error = -ELOOP;  
  418. // 出现回环标志: 循环超过32次  
  419.  if (count++==32) {  
  420.   __putname(nd->last.name);  
  421.   goto exit;  
  422.  }  
  423.  dir = nd->dentry;  
  424.  mutex_lock(&dir->d_inode->i_mutex);  
  425. // 更新路径的挂接点和dentry  
  426.  path.dentry = lookup_hash(nd);  
  427.  path.mnt = nd->mnt;  
  428.  __putname(nd->last.name);  
  429.  goto do_last;  
  430. }  
  431.   
  432. 4.2  path_lookup_open和path_lookup_create  
  433.   
  434. 这两个函数找到路径名对应的挂接点和dentry结构, 赋值到nameidata结构中, create时如果文件不存在, 建立新文件:  
  435. /** 
  436.  * path_lookup_open - lookup a file path with open intent 
  437.  * @dfd: the directory to use as base, or AT_FDCWD 
  438.  * @name: pointer to file name 
  439.  * @lookup_flags: lookup intent flags 
  440.  * @nd: pointer to nameidata 
  441.  * @open_flags: open intent flags 
  442.  */  
  443. int path_lookup_open(int dfd, const char *name, unsigned int lookup_flags,  
  444.   struct nameidata *nd, int open_flags)  
  445. {  
  446.  return __path_lookup_intent_open(dfd, name, lookup_flags, nd,  
  447.    open_flags, 0);  
  448. }  
  449.   
  450. /** 
  451.  * path_lookup_create - lookup a file path with open + create intent 
  452.  * @dfd: the directory to use as base, or AT_FDCWD 
  453.  * @name: pointer to file name 
  454.  * @lookup_flags: lookup intent flags 
  455.  * @nd: pointer to nameidata 
  456.  * @open_flags: open intent flags 
  457.  * @create_mode: create intent flags 
  458.  */  
  459. static int path_lookup_create(int dfd, const char *name,  
  460.          unsigned int lookup_flags, struct nameidata *nd,  
  461.          int open_flags, int create_mode)  
  462. {  
  463.  return __path_lookup_intent_open(dfd, name, lookup_flags|LOOKUP_CREATE,  
  464.    nd, open_flags, create_mode);  
  465. }  
  466.   
  467. 这两个函数都是调用__path_lookup_intent_open, 只是参数不同,create中加入了LOOKUP_CREATE标志和create_mode:  
  468.   
  469. static int __path_lookup_intent_open(int dfd, const char *name,  
  470.   unsigned int lookup_flags, struct nameidata *nd,  
  471.   int open_flags, int create_mode)  
  472. {  
  473. // 找一个空闲的文件指针  
  474.  struct file *filp = get_empty_filp();  
  475.  int err;  
  476. // 找不到返回错误, 文件表溢出了  
  477.  if (filp == NULL)  
  478.   return -ENFILE;  
  479. // 在nameidate中填充打开的文件参数, 这是最终会返回的文件指针  
  480.  nd->intent.open.file = filp;  
  481.  nd->intent.open.flags = open_flags;  
  482.  nd->intent.open.create_mode = create_mode;  
  483. // 进行具体的路径查找, name是路径名  
  484.  err = do_path_lookup(dfd, name, lookup_flags|LOOKUP_OPEN, nd);  
  485. // 先检查nd->intent.open.file而不是err  
  486.  if (IS_ERR(nd->intent.open.file)) {  
  487. // 打开的文件指针错误  
  488.   if (err == 0) {  
  489. // do_path_lookup已经成功了, 释放path, err重新设置为错误值  
  490.    err = PTR_ERR(nd->intent.open.file);  
  491.    path_release(nd);  
  492.   }  
  493.  } else if (err != 0)  
  494.   release_open_intent(nd);  
  495.  return err;  
  496. }  
  497.   
  498. // 路径查找  
  499. /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */  
  500. static int fastcall do_path_lookup(int dfd, const char *name,  
  501.     unsigned int flags, struct nameidata *nd)  
  502. {  
  503.  int retval = 0;  
  504.  int fput_needed;  
  505.  struct file *file;  
  506. // 文件系统指针从进程中获取  
  507.  struct fs_struct *fs = current->fs;  
  508. // 缺省情况last_type为绝对路径, 以"/"开头的格式  
  509.  nd->last_type = LAST_ROOT; /* if there are only slashes... */  
  510.  nd->flags = flags;  
  511.  nd->depth = 0;  
  512. // 下面只是用于增加某些变量的使用计数值, get是增加,put是减少  
  513.  if (*name=='/') {  
  514. // 绝对路径格式  
  515.   read_lock(&fs->lock);  
  516.   if (fs->altroot && !(nd->flags & LOOKUP_NOALT)) {  
  517. // 检查是否更改了root, 即用chroot  
  518. // 增加altrootmnt的使用计数, 其为一vfsmount结构指针  
  519.    nd->mnt = mntget(fs->altrootmnt);  
  520.    nd->dentry = dget(fs->altroot);  
  521.    read_unlock(&fs->lock);  
  522.    if (__emul_lookup_dentry(name,nd))  
  523.     goto out; /* found in altroot */  
  524.    read_lock(&fs->lock);  
  525.   }  
  526. // 增加rootmnt的使用计数然后赋值到nd中  
  527.   nd->mnt = mntget(fs->rootmnt);  
  528. // 增加根的dentry的使用计数然后赋值到nd中  
  529.   nd->dentry = dget(fs->root);  
  530.   read_unlock(&fs->lock);  
  531.  } else if (dfd == AT_FDCWD) {  
  532. // 从sys_open调用来的话会到这里, 表示从当前工作目录的路径开始的相对路径  
  533.   read_lock(&fs->lock);  
  534. // 增加pwdmnt使用计数然后赋值到nd中  
  535.   nd->mnt = mntget(fs->pwdmnt);  
  536. // 增加pwd使用计数然后赋值到nd中  
  537.   nd->dentry = dget(fs->pwd);  
  538.   read_unlock(&fs->lock);  
  539.  } else {  
  540.   struct dentry *dentry;  
  541. // 轻量级的路径查找, fd不是共享的话不会增加引用计数  
  542.   file = fget_light(dfd, &fput_needed);  
  543.   retval = -EBADF;  
  544.   if (!file)  
  545.    goto out_fail;  
  546.   dentry = file->f_dentry;  
  547.   retval = -ENOTDIR;  
  548.   if (!S_ISDIR(dentry->d_inode->i_mode))  
  549.    goto fput_fail;  
  550. // 检查文件的执行权限  
  551.   retval = file_permission(file, MAY_EXEC);  
  552.   if (retval)  
  553.    goto fput_fail;  
  554. // 增加f_vfsmnt的使用计数  
  555.   nd->mnt = mntget(file->f_vfsmnt);  
  556.   nd->dentry = dget(dentry);  
  557. // 轻量级释放  
  558.   fput_light(file, fput_needed);  
  559.  }  
  560. // 清空总链接数  
  561.  current->total_link_count = 0;  
  562. // 变量路径表查询, 核心函数  
  563.  retval = link_path_walk(name, nd);  
  564. out:  
  565.  if (likely(retval == 0)) {  
  566. // 在大部分情况下都会执行到这,能正确打开路径  
  567.   if (unlikely(!audit_dummy_context() && nd && nd->dentry &&  
  568.     nd->dentry->d_inode))  
  569.   audit_inode(name, nd->dentry->d_inode);  
  570.  }  
  571. out_fail:  
  572.  return retval;  
  573. fput_fail:  
  574.  fput_light(file, fput_needed);  
  575.  goto out_fail;  
  576. }  
  577.   
  578. do_path_lookup调用的核心函数是link_path_walk:  
  579.   
  580. /* 
  581.  * Wrapper to retry pathname resolution whenever the underlying 
  582.  * file system returns an ESTALE. 
  583.  * 
  584.  * Retry the whole path once, forcing real lookup requests 
  585.  * instead of relying on the dcache. 
  586.  */  
  587. int fastcall link_path_walk(const char *name, struct nameidata *nd)  
  588. {  
  589. // 先备份一下  
  590.  struct nameidata save = *nd;  
  591.  int result;  
  592.  /* make sure the stuff we saved doesn't go away */  
  593.  dget(save.dentry);  
  594.  mntget(save.mnt);  
  595.  result = __link_path_walk(name, nd);  
  596.  if (result == -ESTALE) {  
  597. // ESTALE是失效的文件句柄错误  
  598. // 用备份的nameidate重新恢复, 设置LOOKUP_REVAL标志后重新查询  
  599.   *nd = save;  
  600.   dget(nd->dentry);  
  601.   mntget(nd->mnt);  
  602.   nd->flags |= LOOKUP_REVAL;  
  603.   result = __link_path_walk(name, nd);  
  604.  }  
  605.  dput(save.dentry);  
  606.  mntput(save.mnt);  
  607.  return result;  
  608. }  
  609.   
  610. 真正的名称解析函数__link_path_walk:  
  611. /* 
  612.  * Name resolution. 
  613.  * This is the basic name resolution function, turning a pathname into 
  614.  * the final dentry. We expect 'base' to be positive and a directory. 
  615.  * 
  616.  * Returns 0 and nd will have valid dentry and mnt on success. 
  617.  * Returns error and drops reference to input namei data on failure. 
  618.  */  
  619. static fastcall int __link_path_walk(const char * name, struct nameidata *nd)  
  620. {  
  621.  struct path next;  
  622.  struct inode *inode;  
  623.  int err;  
  624.  unsigned int lookup_flags = nd->flags;  
  625. // 去掉起始多余的"/", 同时也说明系统可以允许你输入多个"/"而不报错  
  626.  while (*name=='/')  
  627.   name++;  
  628. // 空路径  
  629.  if (!*name)  
  630.   goto return_reval;  
  631. // 路径对应的inode  
  632.  inode = nd->dentry->d_inode;  
  633.  if (nd->depth)  
  634.   lookup_flags = LOOKUP_FOLLOW | (nd->flags & LOOKUP_CONTINUE);  
  635.  /* At this point we know we have a real path component. */  
  636.  for(;;) {  
  637. // 循环处理,每个循环提取文件路径的一个目录名, '/'分隔  
  638.   unsigned long hash;  
  639.   struct qstr this;  
  640.   unsigned int c;  
  641.   nd->flags |= LOOKUP_CONTINUE;  
  642. // 检查文件权限, 包括读写执行权限, 用户/组/其他权限, 返回0为合法  
  643.   err = exec_permission_lite(inode, nd);  
  644.   if (err == -EAGAIN)  
  645. // EAGAIN表示该inode正在被操作, 检查其执行权限  
  646. // 而对于普通文件检查结果将是错误  
  647.    err = vfs_permission(nd, MAY_EXEC);  
  648. // 出错中断循环  
  649.    if (err)  
  650.    break;  
  651. // 填充quickstring结构  
  652.   this.name = name;  
  653. // name的第一个字符的数值  
  654.   c = *(const unsigned char *)name;  
  655. // 计算文件名的hash, 不包括'/'  
  656.   hash = init_name_hash();  
  657.   do {  
  658.    name++;  
  659.    hash = partial_name_hash(c, hash);  
  660.    c = *(const unsigned char *)name;  
  661.   } while (c && (c != '/'));  
  662. // 目录(如果有的话)的名称长度  
  663.   this.len = name - (const char *) this.name;  
  664. // hash  
  665.   this.hash = end_name_hash(hash);  
  666.   /* remove trailing slashes? */  
  667. // c为0表示是最后的具体文件名了  
  668.   if (!c)  
  669.    goto last_component;  
  670. // 跳过中间的'/'  
  671.   while (*++name == '/');  
  672. // 到名称尾, 说明文件名最后一个字符是'/'  
  673.   if (!*name)  
  674.    goto last_with_slashes;  
  675.   /* 
  676.    * "." and ".." are special - ".." especially so because it has 
  677.    * to be able to know about the current root directory and 
  678.    * parent relationships. 
  679.    */  
  680. // 如果第一个字符是'.'  
  681.   if (this.name[0] == '.'switch (this.len) {  
  682.    default:  
  683. // 是一个一'.'开头的文件或目录名称  
  684.     break;  
  685.    case 2:   
  686. // 第2 个字符不是".", 是普通文件或路径名  
  687.     if (this.name[1] != '.')  
  688.      break;  
  689. // 以".."开头, 是父目录, 更新nd为父目录nameidata数据, inode相应更新重新循环  
  690.     follow_dotdot(nd);  
  691.     inode = nd->dentry->d_inode;  
  692.     /* fallthrough */  
  693.    case 1:  
  694. // 以'.'开头的当前目录, 忽略, 重新循环  
  695.     continue;  
  696.   }  
  697.   /* 
  698.    * See if the low-level filesystem might want 
  699.    * to use its own hash.. 
  700.    */  
  701. // 底层FS实现中有自己的HASH算法  
  702.   if (nd->dentry->d_op && nd->dentry->d_op->d_hash) {  
  703.    err = nd->dentry->d_op->d_hash(nd->dentry, &this);  
  704.    if (err < 0)  
  705.     break;  
  706.   }  
  707.   /* This does the actual lookups.. */  
  708. // 根据文件/目录名进行具体的查找  
  709.   err = do_lookup(nd, &this, &next);  
  710.   if (err)  
  711.    break;  
  712.   err = -ENOENT;  
  713. // inode更新为本级文件目录的inode  
  714.   inode = next.dentry->d_inode;  
  715. // 找不到inode, 转错误处理  
  716.   if (!inode)  
  717.    goto out_dput;  
  718.   err = -ENOTDIR;  
  719.   if (!inode->i_op)  
  720.    goto out_dput;  
  721.   if (inode->i_op->follow_link) {  
  722. // 处理符号链接, 在其中考虑了递归互相链接的异常处理  
  723.    err = do_follow_link(&next, nd);  
  724.    if (err)  
  725.     goto return_err;  
  726.    err = -ENOENT;  
  727. // 更新inode为实际的inode  
  728.    inode = nd->dentry->d_inode;  
  729.    if (!inode)  
  730.     break;  
  731.    err = -ENOTDIR;  
  732.    if (!inode->i_op)  
  733.     break;  
  734.   } else  
  735. // nd中得到下一级路径信息  
  736.    path_to_nameidata(&next, nd);  
  737.   err = -ENOTDIR;  
  738.   if (!inode->i_op->lookup)  
  739.    break;  
  740. // 继续循环找下一目录文件名称  
  741.   continue;  
  742.   /* here ends the main loop */  
  743. // 最后的文件名了, 处理和前面类似  
  744. last_with_slashes:  
  745. // 最后一个字符是'/', 是一个目录  
  746.   lookup_flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;  
  747. last_component:  
  748.   /* Clear LOOKUP_CONTINUE iff it was previously unset */  
  749.   nd->flags &= lookup_flags | ~LOOKUP_CONTINUE;  
  750.   if (lookup_flags & LOOKUP_PARENT)  
  751.    goto lookup_parent;  
  752.   if (this.name[0] == '.'switch (this.len) {  
  753.    default:  
  754.     break;  
  755.    case 2:   
  756. // 文件名不是"..", 继续  
  757.     if (this.name[1] != '.')  
  758.      break;  
  759. // 文件名是"..", 到父目录  
  760.     follow_dotdot(nd);  
  761.     inode = nd->dentry->d_inode;  
  762.     /* fallthrough */  
  763.    case 1:  
  764. // 文件名就是".", 跳到返回处理  
  765.     goto return_reval;  
  766.   }  
  767. // 一般文件处理  
  768. // 底层FS实现中有自己的HASH算法  
  769.   if (nd->dentry->d_op && nd->dentry->d_op->d_hash) {  
  770.    err = nd->dentry->d_op->d_hash(nd->dentry, &this);  
  771.    if (err < 0)  
  772.     break;  
  773.   }  
  774. // 查找最后的文件名  
  775.   err = do_lookup(nd, &this, &next);  
  776.   if (err)  
  777.    break;  
  778.   inode = next.dentry->d_inode;  
  779.   if ((lookup_flags & LOOKUP_FOLLOW)  
  780.       && inode && inode->i_op && inode->i_op->follow_link) {  
  781.    err = do_follow_link(&next, nd);  
  782.    if (err)  
  783.     goto return_err;  
  784.    inode = nd->dentry->d_inode;  
  785.   } else  
  786. // 更新nameidata中的mnt, dentry值  
  787.    path_to_nameidata(&next, nd);  
  788.   err = -ENOENT;  
  789.   if (!inode)  
  790.    break;  
  791.   if (lookup_flags & LOOKUP_DIRECTORY) {  
  792.    err = -ENOTDIR;  
  793.    if (!inode->i_op || !inode->i_op->lookup)  
  794.     break;  
  795.   }  
  796.   goto return_base;  
  797. lookup_parent:  
  798. // 复制当前quickstring结构this信息到nd的last中  
  799. // 类型为LAST_NORM  
  800.   nd->last = this;  
  801.   nd->last_type = LAST_NORM;  
  802.   if (this.name[0] != '.')  
  803.    goto return_base;  
  804.   if (this.len == 1)  
  805.    nd->last_type = LAST_DOT;  
  806.   else if (this.len == 2 && this.name[1] == '.')  
  807.    nd->last_type = LAST_DOTDOT;  
  808.   else  
  809.    goto return_base;  
  810. return_reval:  
  811. // 返回  
  812.   /* 
  813.    * We bypassed the ordinary revalidation routines. 
  814.    * We may need to check the cached dentry for staleness. 
  815.    */  
  816.   if (nd->dentry && nd->dentry->d_sb &&  
  817.       (nd->dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT)) {  
  818.    err = -ESTALE;  
  819.    /* Note: we do not d_invalidate() */  
  820.    if (!nd->dentry->d_op->d_revalidate(nd->dentry, nd))  
  821.     break;  
  822.   }  
  823. return_base:  
  824.   return 0;  
  825. out_dput:  
  826.   dput_path(&next, nd);  
  827.   break;  
  828.  }  
  829. // 到这里属于出错了  
  830.  path_release(nd);  
  831. return_err:  
  832.  return err;  
  833. }  
  834.    
  835. /* 
  836.  *  It's more convoluted than I'd like it to be, but... it's still fairly 
  837.  *  small and for now I'd prefer to have fast path as straight as possible. 
  838.  *  It _is_ time-critical. 
  839.  */  
  840. static int do_lookup(struct nameidata *nd, struct qstr *name,  
  841.        struct path *path)  
  842. {  
  843.  struct vfsmount *mnt = nd->mnt;  
  844. // 从系统缓存的dentry的hash表中查找父dentry是nd->dentry, 名称为name的dentry  
  845.  struct dentry *dentry = __d_lookup(nd->dentry, name);  
  846. // 没找到dentry, 进行真正从存储硬盘中查找  
  847.  if (!dentry)  
  848.   goto need_lookup;  
  849. // 需要进行revalidate操作时先进行validate操作  
  850.  if (dentry->d_op && dentry->d_op->d_revalidate)  
  851.   goto need_revalidate;  
  852. done:  
  853. // 找到, 填充path参数: 挂接点mnt和目录项dentry  
  854.  path->mnt = mnt;  
  855.  path->dentry = dentry;  
  856.  __follow_mount(path);  
  857.  return 0;  
  858. need_lookup:  
  859. // 进行真正的查找, 不过read_lookup会重新调用__d_lookup, 找不到才调用底层的fs实现去查找  
  860. // 好象是重复操作了  
  861. // real_lookup中的操作才反映了各个fs底层和相关标志的区别处理  
  862.  dentry = real_lookup(nd->dentry, name, nd);  
  863.  if (IS_ERR(dentry))  
  864.   goto fail;  
  865.  goto done;  
  866. need_revalidate:  
  867. // 进行validate操作  
  868.  dentry = do_revalidate(dentry, nd);  
  869.  if (!dentry)  
  870.   goto need_lookup;  
  871.  if (IS_ERR(dentry))  
  872.   goto fail;  
  873.  goto done;  
  874. fail:  
  875.  return PTR_ERR(dentry);  
  876. }  
  877.   
  878. /* 
  879.  * This is called when everything else fails, and we actually have 
  880.  * to go to the low-level filesystem to find out what we should do.. 
  881.  * 
  882.  * We get the directory semaphore, and after getting that we also 
  883.  * make sure that nobody added the entry to the dcache in the meantime.. 
  884.  * SMP-safe 
  885.  */  
  886. static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, struct nameidata *nd)  
  887. {  
  888.  struct dentry * result;  
  889.  struct inode *dir = parent->d_inode;  
  890.  mutex_lock(&dir->i_mutex);  
  891.  /* 
  892.   * First re-do the cached lookup just in case it was created 
  893.   * while we waited for the directory semaphore.. 
  894.   * 
  895.   * FIXME! This could use version numbering or similar to 
  896.   * avoid unnecessary cache lookups. 
  897.   * 
  898.   * The "dcache_lock" is purely to protect the RCU list walker 
  899.   * from concurrent renames at this point (we mustn't get false 
  900.   * negatives from the RCU list walk here, unlike the optimistic 
  901.   * fast walk). 
  902.   * 
  903.   * so doing d_lookup() (with seqlock), instead of lockfree __d_lookup 
  904.   */  
  905. // 查找缓存中的dentry项  
  906.  result = d_lookup(parent, name);  
  907.  if (!result) {  
  908. // 没找到, 新建dentry项  
  909.   struct dentry * dentry = d_alloc(parent, name);  
  910.   result = ERR_PTR(-ENOMEM);  
  911.   if (dentry) {  
  912. // 调用inode的查找操作, 这是和具体文件系统相关  
  913.    result = dir->i_op->lookup(dir, dentry, nd);  
  914.    if (result)  
  915. // 失败, 释放dentry  
  916.     dput(dentry);  
  917.    else  
  918. // 成功, 找到的dentry作为结果返回  
  919.     result = dentry;  
  920.   }  
  921.   mutex_unlock(&dir->i_mutex);  
  922.   return result;  
  923.  }  
  924.  /* 
  925.   * Uhhuh! Nasty case: the cache was re-populated while 
  926.   * we waited on the semaphore. Need to revalidate. 
  927.   */  
  928. // 在缓存中找到dentry项, 进行validate操作  
  929.  mutex_unlock(&dir->i_mutex);  
  930.  if (result->d_op && result->d_op->d_revalidate) {  
  931.   result = do_revalidate(result, nd);  
  932.   if (!result)  
  933.    result = ERR_PTR(-ENOENT);  
  934.  }  
  935.  return result;  
  936. }  
  937.   
  938. 小结一下函数调用顺序:  
  939. path_lookup_open    path_lookup_create  
  940.      |                     |  
  941.      V                     V  
  942.    __path_lookup_intent_open  
  943.                |  
  944.                V  
  945.         do_path_lookup  
  946.                |  
  947.                V  
  948.         link_path_walk  
  949.                |  
  950.                V  
  951.       __link_path_walk  
  952.                |  
  953.                V  
  954.            do_lookup  
  955.                |  
  956.                V  
  957.           real_lookup  
  958.   
  959. 这些函数操作都属于虚拟文件系统操作, 对所有类型的文件系统都适用, 而从各个FS的具体实现才能看出差异和相关标志的作用.  
  960.   
  961. 4.3 open_namei_create  
  962.   
  963. static int open_namei_create(struct nameidata *nd, struct path *path,  
  964.     int flag, int mode)  
  965. {  
  966.  int error;  
  967. // nd当前的dentry  
  968.  struct dentry *dir = nd->dentry;  
  969.  if (!IS_POSIXACL(dir->d_inode))  
  970.   mode &= ~current->fs->umask;  
  971.  error = vfs_create(dir->d_inode, path->dentry, mode, nd);  
  972.  mutex_unlock(&dir->d_inode->i_mutex);  
  973.  dput(nd->dentry);  
  974.  nd->dentry = path->dentry;  
  975.  if (error)  
  976.   return error;  
  977.  /* Don't check for write permission, don't truncate */  
  978.  return may_open(nd, 0, flag & ~O_TRUNC);  
  979. }  
  980.   
  981. 4.4 path_to_nameidata  
  982.   
  983. // 将路径参数赋值到nameidata结构中  
  984. static inline void path_to_nameidata(struct path *path, struct nameidata *nd)  
  985. {  
  986. // 释放原来的目录项  
  987.  dput(nd->dentry);  
  988. // 如果挂接点也不同,释放掉原来的  
  989.  if (nd->mnt != path->mnt)  
  990.   mntput(nd->mnt);  
  991. // 将新路径参数赋值到nameidata结构中  
  992.  nd->mnt = path->mnt;  
  993.  nd->dentry = path->dentry;  
  994. }  
  995.   
  996. 5. 结论  
  997.   
  998. 打开文件时, 目的是要生成一个struct file的结构的指针, 该结构中有相关文件名的名称, dentry指针, 挂接点文件系统等信息, 而struct nameidata作为一个中间过程结构保存相关的处理结果, 最终返回需要的文件信息。

原创粉丝点击