前面对linux虚拟文件系统的架构以及设计到的数据结构有了一个整体的认识,这里看看linux内核怎么根据给定的文件路径名在内存中找到和建立代表着目标文件或目录的dentry结构和inode结构。文件路径的搜索是文件系统中最基本也是最重要的一部分之一,后面我们会看到,文件的打开、关闭等等操作都将涉及到文件路径的搜索。下面我们看看linux内核中时怎么实现的。

一、搜索中所用数据结构

[cpp] view plain copy  print?
  1. /*这个数据结构是临时的,只在路径搜索的过程中返回搜索的结果。
  2. */
  3. struct nameidata {
  4. struct path path;/*将目录结构和mount结构封装在path结构中*/
  5. struct qstr last;
  6. struct path root;
  7. unsigned int    flags;/*对应搜索的标志*/
  8. int     last_type;
  9. unsigned    depth;
  10. char *saved_names[MAX_NESTED_LINKS + 1];
  11. /* Intent data */
  12. union {
  13. struct open_intent open;
  14. } intent;
  15. };
[cpp] view plain copy  print?
  1. /*用来存放路径名中当前节点的杂凑值以及节点名的长度*/
  2. struct qstr {
  3. unsigned int hash;
  4. unsigned int len;
  5. const unsigned char *name;
  6. };

二、搜索

[cpp] view plain copy  print?
  1. /*name指向在用户空间的路径名;
  2. flag为一些标志位,nd为搜索返回值
  3. */
  4. int path_lookup(const char *name, unsigned int flags,
  5. struct nameidata *nd)
  6. {
  7. return do_path_lookup(AT_FDCWD, name, flags, nd);
  8. }

实际工作都是由上面的do_path_lookup()函数实现的,在这里我们就他进行分析。

[cpp] view plain copy  print?
  1. /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */
  2. static int do_path_lookup(int dfd, const char *name,
  3. unsigned int flags, struct nameidata *nd)
  4. {   /*找到搜索的起点,保存在nd中*/
  5. int retval = path_init(dfd, name, flags, nd);
  6. if (!retval)
  7. /*一旦找到了搜索的起点,从起点开始路径的搜索
  8. 其中nd用来返回搜索结果*/
  9. retval = path_walk(name, nd);
  10. if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry &&
  11. nd->path.dentry->d_inode))
  12. audit_inode(name, nd->path.dentry);
  13. if (nd->root.mnt) {
  14. path_put(&nd->root);
  15. nd->root.mnt = NULL;
  16. }
  17. return retval;
  18. }

2.1 初始化阶段

初始化阶段是由函数path_init()函数实现

[cpp] view plain copy  print?
  1. /*path_init主要是初始化查询,设置nd结构指向查询开始处的文件,这里分两种情况:
  2. a,绝对路径(以/开始),获得根目录的dentry。它存储在task_struct中fs指向的fs_struct结构中。
  3. b,相对路径,直接从当前进程task_struct结构中的获得指针fs,它指向的一个fs_struct,
  4. fs_struct中有一个指向“当前工作目录”的dentry。
  5. */
  6. static int path_init(int dfd, const char *name, unsigned int flags, struct nameidata *nd)
  7. {
  8. int retval = 0;
  9. int fput_needed;
  10. struct file *file;
  11. /*在搜索的过程中,这个字段的值会随着路径名当前搜索结果而变;
  12. 例如,如果成功找到目标文件,那么这个字段的值就变成了LAST_NORM
  13. 而如果最后停留在了一个.上,则变成LAST_DOT(*/
  14. nd->last_type = LAST_ROOT; /* if there are only slashes... */
  15. nd->flags = flags;
  16. nd->depth = 0;
  17. nd->root.mnt = NULL;
  18. if (*name=='/') {/*路径名以'/'开头*/
  19. set_root(nd);/*设置nd的root为当前进程fs的root*/
  20. nd->path = nd->root;/*保存根目录*/
  21. path_get(&nd->root);/*递增引用计数*/
  22. } else if (dfd == AT_FDCWD) {/*相对路径*/
  23. struct fs_struct *fs = current->fs;
  24. read_lock(&fs->lock);
  25. nd->path = fs->pwd;/*保存当前路径*/
  26. path_get(&fs->pwd);/*递增引用计数*/
  27. read_unlock(&fs->lock);
  28. } else {/*???*/
  29. struct dentry *dentry;
  30. /*fget_light在当前进程的struct files_struct中根据所谓的用户空间
  31. 文件描述符fd来获取文件描述符。另外,根据当前fs_struct
  32. 是否被多各进程共享来判断是否需要对文件描述符进行加
  33. 锁,并将加锁结果存到一个int中返回
  34. */
  35. file = fget_light(dfd, &fput_needed);
  36. retval = -EBADF;
  37. if (!file)
  38. goto out_fail;
  39. dentry = file->f_path.dentry;
  40. retval = -ENOTDIR;
  41. if (!S_ISDIR(dentry->d_inode->i_mode))
  42. goto fput_fail;
  43. /*权限检查*/
  44. retval = file_permission(file, MAY_EXEC);
  45. if (retval)
  46. goto fput_fail;
  47. /*获得path*/
  48. nd->path = file->f_path;
  49. path_get(&file->f_path);
  50. /*解锁*/
  51. fput_light(file, fput_needed);
  52. }
  53. return 0;
  54. fput_fail:
  55. fput_light(file, fput_needed);
  56. out_fail:
  57. return retval;
  58. }

2.2 实际搜索操作

[cpp] view plain copy  print?
  1. static int path_walk(const char *name, struct nameidata *nd)
  2. {
  3. current->total_link_count = 0;
  4. return link_path_walk(name, nd);
  5. }
[cpp] view plain copy  print?
  1. /*
  2. * Wrapper to retry pathname resolution whenever the underlying
  3. * file system returns an ESTALE.
  4. *
  5. * Retry the whole path once, forcing real lookup requests
  6. * instead of relying on the dcache.
  7. */
  8. static __always_inline int link_path_walk(const char *name, struct nameidata *nd)
  9. {
  10. struct path save = nd->path;
  11. int result;
  12. /* make sure the stuff we saved doesn't go away */
  13. path_get(&save);/*递增path的引用计数*/
  14. /*实际的工作*/
  15. result = __link_path_walk(name, nd);
  16. if (result == -ESTALE) {
  17. /* nd->path had been dropped */
  18. nd->path = save;
  19. path_get(&nd->path);
  20. nd->flags |= LOOKUP_REVAL;
  21. result = __link_path_walk(name, nd);
  22. }
  23. path_put(&save);
  24. return result;
  25. }
[cpp] view plain copy  print?
  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. /*如果路径名以'/'开头,就把他跳过去,因为在这种情况下nd中
  16. path已经指向本进程的根目录了,注意,这里多个连续的'/'与一个
  17. ‘/’是等价的,如果路径名中仅仅包含有'/'字符的话,那么其
  18. 目标就是根目录,所以任务完成,不然需要继续搜索*/
  19. while (*name=='/')
  20. name++;
  21. if (!*name)
  22. goto return_reval;
  23. /*作为path_walk起点的节点必定是一个目录,一定有相应的索引节点
  24. 存在,所以指针inode一定是有效的,而不可能是空指针*/
  25. inode = nd->path.dentry->d_inode;
  26. /*进程的task_struct结构中有个计数器link_count.在搜索过程中有可能
  27. 碰到一个节点(目录项)只是指向另一个节点的链接,此时就用这个计数器来对
  28. 链的长度进行计数,这样,当链的长度达到某一个值时就可以终止搜索而失败
  29. 返回,以防陷入循环。另一方面,当顺着符号链接进入另一个设备上的文件系统
  30. 时,有可能会递归地调用path_walk。所以,进入path_walk后,如果发现这个
  31. 计数器值非0,就表示正在顺着符号链接递归调用path_walk往前搜索过程中,
  32. 此时不管怎样都把LOOKUP_FOLLOW标志位设成1.*/
  33. if (nd->depth)
  34. lookup_flags = LOOKUP_FOLLOW | (nd->flags & LOOKUP_CONTINUE);
  35. /* At this point we know we have a real path component. */
  36. for(;;) {
  37. unsigned long hash;
  38. struct qstr this;
  39. unsigned int c;
  40. nd->flags |= LOOKUP_CONTINUE;
  41. /*检查当前进程对当前节点的访问权限,这里所检查的是相对路径中
  42. 的各层目录(而不是目标文件)的访问权限。注意,对于中间节点所需
  43. 的权限为执行权,即MAY_EXEC*/
  44. err = exec_permission_lite(inode);
  45. if (err)
  46. break;
  47. this.name = name;
  48. c = *(const unsigned char *)name;
  49. hash = init_name_hash();
  50. do {
  51. name++;
  52. hash = partial_name_hash(c, hash);
  53. c = *(const unsigned char *)name;
  54. } while (c && (c != '/'));/*路径名中的节点定以‘/’字符分开的,*/
  55. this.len = name - (const char *) this.name;
  56. this.hash = end_name_hash(hash);
  57. /* remove trailing slashes? */
  58. if (!c)/*最后一个字符为'\0',就是说当前节点已经是路径名中的最后一节*/
  59. goto last_component;/*跳转*/
  60. /*循环跳过'/'*/
  61. while (*++name == '/');
  62. /*当前节点实际上已经是路径名的最后一个节点,只不过在此后面又多添加了
  63. 若干个'/'字符,这种情况常常发生在用户界面上,特别是在shell的命令中
  64. 当然这种情况要求最后的节点必须是个目录*/
  65. if (!*name)
  66. goto last_with_slashes;/*跳转*/
  67. /*运行到这里,表示当前节点为中间节点,所以'/'字符后面还有其他字符*/
  68. /*
  69. * "." and ".." are special - ".." especially so because it has
  70. * to be able to know about the current root directory and
  71. * parent relationships.
  72. */
  73. /*以'.'开头表示这是个隐藏的文件,而对于代表着目录的节点则只有在两种
  74. 情况下才是允许的。一种是节点名为'.',表示当前目录,另一种是'..',表示
  75. 当前目录的父目录*/
  76. if (this.name[0] == '.') switch (this.len) {
  77. default:
  78. break;
  79. case 2:
  80. if (this.name[1] != '.')
  81. break;
  82. follow_dotdot(nd);/*为'..',到父目录中去*/
  83. inode = nd->path.dentry->d_inode;
  84. /* fallthrough */
  85. /*2中没有break语句,也就是所继续执行1中的语句,
  86. 将会跳到for语句的开头处理路径中的下一个节点*/
  87. case 1:
  88. continue;
  89. }
  90. /*
  91. * See if the low-level filesystem might want
  92. * to use its own hash..
  93. */
  94. /*特定文件系统提供他自己专用的杂凑函数,所以在这种情况下就通过这个
  95. 函数再计算一遍当前节点的杂凑值*/
  96. if (nd->path.dentry->d_op && nd->path.dentry->d_op->d_hash) {
  97. err = nd->path.dentry->d_op->d_hash(nd->path.dentry,
  98. &this);
  99. if (err < 0)
  100. break;
  101. }
  102. /* This does the actual lookups.. */
  103. /*实际的搜索工作*/
  104. err = do_lookup(nd, &this, &next);
  105. if (err)
  106. break;
  107. err = -ENOENT;
  108. inode = next.dentry->d_inode;
  109. if (!inode)
  110. goto out_dput;
  111. /*涉及到具体文件系统的相关操作*/
  112. if (inode->i_op->follow_link) {
  113. err = do_follow_link(&next, nd);
  114. if (err)
  115. goto return_err;
  116. err = -ENOENT;
  117. inode = nd->path.dentry->d_inode;
  118. if (!inode)
  119. break;
  120. } else/*将path中的相关内容转化到nd中*/
  121. path_to_nameidata(&next, nd);
  122. err = -ENOTDIR;
  123. if (!inode->i_op->lookup)
  124. break;
  125. continue;
  126. /* here ends the main loop */
  127. last_with_slashes:
  128. lookup_flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
  129. last_component:
  130. /* Clear LOOKUP_CONTINUE iff it was previously unset */
  131. nd->flags &= lookup_flags | ~LOOKUP_CONTINUE;
  132. if (lookup_flags & LOOKUP_PARENT)/*要寻找的不是路径终点,而是他的上一层*/
  133. goto lookup_parent;
  134. if (this.name[0] == '.') switch (this.len) {
  135. default:
  136. break;
  137. case 2:
  138. if (this.name[1] != '.')
  139. break;
  140. follow_dotdot(nd);/*向上层移动*/
  141. inode = nd->path.dentry->d_inode;
  142. /* fallthrough */
  143. case 1:
  144. goto return_reval;
  145. }
  146. /*具体文件系统的操作*/
  147. if (nd->path.dentry->d_op && nd->path.dentry->d_op->d_hash) {
  148. err = nd->path.dentry->d_op->d_hash(nd->path.dentry,
  149. &this);
  150. if (err < 0)
  151. break;
  152. }/*顺次查找路径节点,下一个存放在next中*/
  153. err = do_lookup(nd, &this, &next);
  154. if (err)
  155. break;
  156. inode = next.dentry->d_inode;
  157. if ((lookup_flags & LOOKUP_FOLLOW)/*当终点为符号链接时*/
  158. && inode && inode->i_op->follow_link) {
  159. err = do_follow_link(&next, nd);
  160. if (err)
  161. goto return_err;
  162. inode = nd->path.dentry->d_inode;
  163. } else
  164. /*path转化为nd*/
  165. path_to_nameidata(&next, nd);
  166. err = -ENOENT;
  167. if (!inode)
  168. break;
  169. if (lookup_flags & LOOKUP_DIRECTORY) {
  170. err = -ENOTDIR;
  171. if (!inode->i_op->lookup)
  172. break;
  173. }
  174. goto return_base;
  175. lookup_parent:
  176. nd->last = this;
  177. nd->last_type = LAST_NORM;/*根据终点节点名设置*/
  178. if (this.name[0] != '.')
  179. goto return_base;
  180. if (this.len == 1)
  181. nd->last_type = LAST_DOT;
  182. else if (this.len == 2 && this.name[1] == '.')
  183. nd->last_type = LAST_DOTDOT;
  184. else
  185. goto return_base;
  186. return_reval:
  187. /*
  188. * We bypassed the ordinary revalidation routines.
  189. * We may need to check the cached dentry for staleness.
  190. */
  191. if (nd->path.dentry && nd->path.dentry->d_sb &&
  192. (nd->path.dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT)) {
  193. err = -ESTALE;
  194. /* Note: we do not d_invalidate() */
  195. if (!nd->path.dentry->d_op->d_revalidate(
  196. nd->path.dentry, nd))
  197. break;
  198. }
  199. return_base:
  200. return 0;
  201. out_dput:
  202. path_put_conditional(&next, nd);
  203. break;
  204. }
  205. path_put(&nd->path);
  206. return_err:
  207. return err;
  208. }

2.2.1 处理double dot

所谓double dot为访问上层目录

[cpp] view plain copy  print?
  1. static __always_inline void follow_dotdot(struct nameidata *nd)
  2. {
  3. set_root(nd);
  4. while(1) {
  5. struct vfsmount *parent;
  6. struct dentry *old = nd->path.dentry;
  7. /*如果已经达到本进程的根节点,这时不能再往上跑了
  8. 所以保持不变*/
  9. if (nd->path.dentry == nd->root.dentry &&
  10. nd->path.mnt == nd->root.mnt) {
  11. break;
  12. }
  13. spin_lock(&dcache_lock);
  14. /*已经到达节点与其父节点在同一个设备上。在这种情况下
  15. 既然已经到达的这个节点的dentry结构已经建立,则其父节点的
  16. dentry结构也必然已经建立在内存中,而且dentry结构中的指针
  17. d_parent就指向其父节点,所以往上跑一层是很简单的事情*/
  18. if (nd->path.dentry != nd->path.mnt->mnt_root) {
  19. nd->path.dentry = dget(nd->path.dentry->d_parent);/*往上走一层,并且对应用计数加一*/
  20. spin_unlock(&dcache_lock);
  21. dput(old);/*释放就得目录的引用*/
  22. break;
  23. }
  24. spin_unlock(&dcache_lock);
  25. spin_lock(&vfsmount_lock);
  26. /*运行到这里,表示已经到达节点就是其所在设备上的根节点
  27. 往上跑一层就要跑到另一个设备上去了,当将一个存储设备安装到
  28. 另一个设备上的某个节点时,内核会分配和设置一个vfsmount
  29. 结构,通过这个结构将两个设备以及两个节点连接起来。
  30. 所以,每个已经安装的存储设备都有一个vfsmount结构,结构
  31. 中有个指针mnt_parent指向其父设备,另一个指针mnt_mountpoint
  32. 指向代表这安装点的dentry结构*/
  33. /*保存nd指定的mnt的父mnt*/
  34. parent = nd->path.mnt->mnt_parent;
  35. /*当前的vfsmount结构代表这跟设备*/
  36. if (parent == nd->path.mnt) {
  37. spin_unlock(&vfsmount_lock);
  38. break;
  39. }
  40. /*当前设备不是跟设备*/
  41. mntget(parent);
  42. /*指向该设备上的安装点的上一层目录*/
  43. nd->path.dentry = dget(nd->path.mnt->mnt_mountpoint);
  44. spin_unlock(&vfsmount_lock);
  45. dput(old);
  46. mntput(nd->path.mnt);
  47. nd->path.mnt = parent;/*指向上层设备上的vfsmount 结构*/
  48. }
  49. follow_mount(&nd->path);/*mnt向子节点移动一个*/
  50. }
[cpp] view plain copy  print?
  1. static void follow_mount(struct path *path)
  2. {
  3. while (d_mountpoint(path->dentry)) {/*如果该文件系统已经安装*/
  4. /*找到指定的孩子mnt*/
  5. struct vfsmount *mounted = lookup_mnt(path);
  6. if (!mounted)/*如果没有孩子mnt了*/
  7. break;
  8. /*递减引用计数*/
  9. dput(path->dentry);
  10. mntput(path->mnt);
  11. path->mnt = mounted;/*找到的mnt作为path的mnt*/
  12. path->dentry = dget(mounted->mnt_root);/*递增引用计数,将找到的mnt文件系统的根目录赋给path*/
  13. }
  14. }

2.2.2 实际的路径搜索工作

[cpp] view plain copy  print?
  1. /*
  2. *  It's more convoluted than I'd like it to be, but... it's still fairly
  3. *  small and for now I'd prefer to have fast path as straight as possible.
  4. *  It _is_ time-critical.
  5. */
  6. static int do_lookup(struct nameidata *nd, struct qstr *name,
  7. struct path *path)
  8. {
  9. struct vfsmount *mnt = nd->path.mnt;
  10. /*在内存中寻找该节点已经建立的dentry结构。内核中有个hash表dentry_hashtable
  11. 是一个list_head指针数组,一旦在内存中建立起一个目录节点的dentry结构
  12. 就根据其节点名的hash值挂入hash表中的某个队列,需要寻找时则还是根据hash值从
  13. hash表着手*/
  14. struct dentry *dentry = __d_lookup(nd->path.dentry, name);
  15. if (!dentry)/*如果没有找到,转向下面*/
  16. goto need_lookup;
  17. if (dentry->d_op && dentry->d_op->d_revalidate)
  18. goto need_revalidate;
  19. done:/*内存中找到了dentry*/
  20. path->mnt = mnt;
  21. path->dentry = dentry;
  22. /*访问下一个mnt,其实就是现在mnt的子mnt*/
  23. __follow_mount(path);
  24. return 0;
  25. need_lookup:/*到这里是在内存中没有找到dentry结构*/
  26. /*到磁盘上通过其所在的目录寻找,找到后在内存中为其建立起
  27. dentry结构并将之挂入hash表中某个队列中*/
  28. dentry = real_lookup(nd->path.dentry, name, nd);
  29. if (IS_ERR(dentry))
  30. goto fail;
  31. goto done;
  32. need_revalidate:
  33. dentry = do_revalidate(dentry, nd);
  34. if (!dentry)
  35. goto need_lookup;
  36. if (IS_ERR(dentry))
  37. goto fail;
  38. goto done;
  39. fail:
  40. return PTR_ERR(dentry);
  41. }
[cpp] view plain copy  print?
  1. /*
  2. * This is called when everything else fails, and we actually have
  3. * to go to the low-level filesystem to find out what we should do..
  4. *
  5. * We get the directory semaphore, and after getting that we also
  6. * make sure that nobody added the entry to the dcache in the meantime..
  7. * SMP-safe
  8. */
  9. static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, struct nameidata *nd)
  10. {
  11. struct dentry * result;
  12. struct inode *dir = parent->d_inode;
  13. mutex_lock(&dir->i_mutex);
  14. /*
  15. * First re-do the cached lookup just in case it was created
  16. * while we waited for the directory semaphore..
  17. *
  18. * FIXME! This could use version numbering or similar to
  19. * avoid unnecessary cache lookups.
  20. *
  21. * The "dcache_lock" is purely to protect the RCU list walker
  22. * from concurrent renames at this point (we mustn't get false
  23. * negatives from the RCU list walk here, unlike the optimistic
  24. * fast walk).
  25. *
  26. * so doing d_lookup() (with seqlock), instead of lockfree __d_lookup
  27. */
  28. result = d_lookup(parent, name);
  29. if (!result) {
  30. struct dentry *dentry;
  31. /* Don't create child dentry for a dead directory. */
  32. result = ERR_PTR(-ENOENT);
  33. if (IS_DEADDIR(dir))
  34. goto out_unlock;
  35. /*从slab中分配dentry并且初始化*/
  36. dentry = d_alloc(parent, name);
  37. result = ERR_PTR(-ENOMEM);
  38. if (dentry) {
  39. /*调用具体文件系统的loopup函数*/
  40. result = dir->i_op->lookup(dir, dentry, nd);
  41. if (result)
  42. dput(dentry);
  43. else
  44. result = dentry;
  45. }
  46. out_unlock:
  47. mutex_unlock(&dir->i_mutex);
  48. return result;
  49. }
  50. /*
  51. * Uhhuh! Nasty case: the cache was re-populated while
  52. * we waited on the semaphore. Need to revalidate.
  53. */
  54. mutex_unlock(&dir->i_mutex);
  55. if (result->d_op && result->d_op->d_revalidate) {
  56. result = do_revalidate(result, nd);
  57. if (!result)
  58. result = ERR_PTR(-ENOENT);
  59. }
  60. return result;
  61. }

2.2.2.1 分配dentry并且初始化

[cpp] view plain copy  print?
  1. struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
  2. {
  3. struct dentry *dentry;
  4. char *dname;
  5. /*从slab中非配dentry*/
  6. dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL);
  7. if (!dentry)
  8. return NULL;
  9. if (name->len > DNAME_INLINE_LEN-1) {
  10. dname = kmalloc(name->len + 1, GFP_KERNEL);
  11. if (!dname) {
  12. kmem_cache_free(dentry_cache, dentry);
  13. return NULL;
  14. }
  15. } else  {
  16. dname = dentry->d_iname;
  17. }
  18. /*初始化非配的dentry结构*/
  19. dentry->d_name.name = dname;
  20. dentry->d_name.len = name->len;
  21. dentry->d_name.hash = name->hash;
  22. memcpy(dname, name->name, name->len);
  23. dname[name->len] = 0;
  24. atomic_set(&dentry->d_count, 1);
  25. dentry->d_flags = DCACHE_UNHASHED;
  26. spin_lock_init(&dentry->d_lock);
  27. dentry->d_inode = NULL;
  28. dentry->d_parent = NULL;
  29. dentry->d_sb = NULL;
  30. dentry->d_op = NULL;
  31. dentry->d_fsdata = NULL;
  32. dentry->d_mounted = 0;
  33. INIT_HLIST_NODE(&dentry->d_hash);
  34. INIT_LIST_HEAD(&dentry->d_lru);
  35. INIT_LIST_HEAD(&dentry->d_subdirs);
  36. INIT_LIST_HEAD(&dentry->d_alias);
  37. if (parent) {
  38. dentry->d_parent = dget(parent);
  39. dentry->d_sb = parent->d_sb;
  40. } else {
  41. INIT_LIST_HEAD(&dentry->d_u.d_child);
  42. }
  43. spin_lock(&dcache_lock);
  44. if (parent)
  45. list_add(&dentry->d_u.d_child, &parent->d_subdirs);
  46. dentry_stat.nr_dentry++;
  47. spin_unlock(&dcache_lock);
  48. return dentry;
  49. }

从上面的代码中可以看到,linux内核中的路径搜索大体工作如下:

1,初始化查询,设置nd结构指向查询开始处的文件;

2,从起点开始路径的搜索,其中nd用来返回搜索结果,在搜索过程中需要根据路径名称一步一步的访问,包括字符‘/‘的处理、访问上层目录的处理(需要考虑超出本文件系统)以及访问的dentry在内存中不存在需要从新分配的情况等;

程序返回后,参数中的nd结构保存了当前的搜索结果信息,包括目标文件或目录的dentry结构和inode结构。

Linux虚拟文件系统(节点路径搜索)相关推荐

  1. Linux虚拟文件系统

    从文件 I/O 看 Linux 的虚拟文件系统 1 引言 Linux 中允许众多不同的文件系统共存,如 ext2, ext3, vfat 等.通过使用同一套文件 I/O 系统 调用即可对 Linux ...

  2. linux虚拟文件系统浅析

    linux虚拟文件系统浅析 虚拟文件系统(VFS) 在我看来, "虚拟"二字主要有两层含义: 1, 在同一个目录结构中, 可以挂载着若干种不同的文件系统. VFS隐藏了它们的实现细 ...

  3. Linux虚拟文件系统:数据结构与文件系统注册、文件打开读写

    数据结构 超级块 - super_block 索引节点 - inode 目录项 - dentry 文件结构 - file 虚拟文件系统实现 注册文件系统 - register_filesystem 打 ...

  4. linux 目录防篡改,一种基于Linux虚拟文件系统的防篡改方法及系统的制作方法

    一种基于Linux虚拟文件系统的防篡改方法及系统的制作方法 [技术领域] [0001]本发明涉及文件防护技术领域,特别涉及一种基于Linux虚拟文件系统的防篡改方法及系统. [背景技术] [0002] ...

  5. Linux 虚拟文件系统(一)概述

    Linux 虚拟文件系统(一)概述 tags: Linux源码 Linux 虚拟文件系统一概述 文章梗概 正文 文件系统 虚拟文件系统架构 虚拟文件系统如何知道可用的文件系统有哪些的 不太喜欢的环节 ...

  6. Linux 虚拟文件系统四大对象:超级块、inode、dentry、file之间关系

    一:文件系统 1. 什么是文件系统? 操作系统中负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统. 通常文件系统是用于存储和组织文件的一种机制,便于对文件进行方便的查找与访问. 文件系统 ...

  7. linux 文件系统 vfs,linux虚拟文件系统vfs

    <操作系统>课程设计报告课程设计题目:操作系统课程设计 设计时间:2016/1/10一. 课程设计目的与要求需要完成的内容:(1) 安装虚拟机:Vmware.Vmware palyer ( ...

  8. Linux虚拟文件系统解析

    概述 虚拟文件系统(Virtual Filesystem Switch,简称VFS)所有的数据结构都是在运行以后建立的,并在卸载时删除,在磁盘中并没有存储这些数据结构.虚拟文件系统只有和实际文件系统( ...

  9. Linux虚拟文件系统简介

    本文将对Linux下的VFS做一个简单介绍,主要包括VFS里面的一些概念,以及文件系统是如何与VFS交互的. 本文所涉及的代码摘自Linux-4.4.0-59 什么是VFS VFS的全称为virtua ...

  10. 网络与IO知识扫盲(一):Linux虚拟文件系统,文件描述符,IO重定向

    系统IO原理 在 Linux 中: VFS(Virtual Filesystem Switch):虚拟文件系统,是一个目录树.树上不同的节点可以映射到物理的文件地址,可以挂载. 相当于一个解耦层,在具 ...

最新文章

  1. 3D点云配准(二多幅点云配准)
  2. 【原创+整理】简述何为调用约定,函数导出名以及extern C
  3. 成功解决VMware虚拟机中的please remove the installation medium then press enter
  4. canopen c++程序编写_JAVA、C、C++、Python同样是高级语言,为什么只有C和C++可以编写单片机程序?...
  5. MFC和QT等UI框架的特点
  6. 工作总结10:解决vuex刷新数据消失
  7. 高级转录组分析和R语言数据可视化第十二期 (线上线下同时开课)
  8. vue+axios+qs序列化 “三步解析”【含demo实例】- 代码篇
  9. Kafka 2.8与ZooKeeper正式分手
  10. js 判断剪切板内容是否为text_Python+selenium自动化之EC模块之text_to_be_present_in_element...
  11. can't select mysql database_ERROR 1006 (HY000) Can't create database (errno: 13) MySQL 5.6.12
  12. 初探在容器上构建持续部署!
  13. 查询Linux的公网及内网IP
  14. JBOSS EAP6.2.0的下载安装、环境变量配置以及部署
  15. 1-22 在“终端”里,运行“top”命令
  16. 【元胞自动机】基于matlab元胞自动机交通流模拟仿真【含Matlab源码 1252期】
  17. LordPE 查看程序依赖项的好工具
  18. 「干货」那些必知的物联网行业术语
  19. 早起的奇迹:那些能够在早晨8:00前改变人生的秘密
  20. Hbase篇(7)-Region的分裂

热门文章

  1. phpcms v9二次开发之模型类的应用(2)
  2. HDU 3639 Hawk-and-Chicken
  3. ntp时间同步软件_NTP服务器的搭建和时间同步
  4. Java之品优购课程讲义_day03(6)
  5. nagios扩展开发之check_ping
  6. DevExpress控件TExtLookupComboBox实现多列模糊匹配输入的方法
  7. Linux C enum
  8. URL对象中前而几个方法都非常容易理解,而该对象提供的openStream()可以读取该 URL资源...
  9. .NET URL 301转向方法的实现
  10. js 中 ! + - ~ 符号和匿名函数