概述

每个文件除了有一个索引节点inode(文件inode索引节点)数据结构外,还有一个目录项dentry(directory enrty)数据结构**。**

dentry 结构中有个d_inode指针指向相应的inode结构。
读者也许会问,既然inode结构和dentry结构都是对文件各方面属性的描述,那为什么不把这两个结构“合而为一”呢?这是因为二者所描述的目标不同

  • dentry结构代表的是逻辑意义上的文件,所描述的是文件逻辑上的属性,因此,目录项对象在磁盘上并没有对应的映像;
  • 而inode结构代表的是物理意义上的文件,记录的是物理上的属性,对于一个具体的文件系统(如Ext2),Ext2_ inode结构在磁盘上就有对应的映像。

所以说,一个索引节点对象可能对应多个目录项对象。由于dentry结构是文件系统中的核心数据结构,也是文件访问和为文件访问而做的文件路径搜索操作的枢纽。要明白文件系统的结构,那么就必须很好的理解dentry结构。所以本文主要是详细的说明一下文件系统中的dentry结构。

目录项是描述文件的逻辑属性,只存在于内存中,并没有实际对应的磁盘上的描述,更确切的说是存在于内存的目录项缓存,为了提高查找性能而设计。注意不管是文件夹还是最终的文件,都是属于目录项,所有的目录项在一起构成一颗庞大的目录树。例如:open一个文件/home/xxx/yyy.txt,那么/、home、xxx、yyy.txt都是一个目录项,VFS在查找的时候,根据一层一层的目录项找到对应的每个目录项的inode,那么沿着目录项进行操作就可以找到最终的文件。

dentry结构体的元素定义

  1. struct dentry {
  2. atomic_t d_count; /* 目录项引用计数器 */
  3. unsigned int d_flags; /* 目录项标志 */
  4. struct inode * d_inode; /* 与文件名关联的索引节点 */
  5. struct dentry * d_parent; /* 父目录的目录项 */
  6. struct list_head d_hash; /* 目录项形成的哈希表 */
  7. struct list_head d_lru; /*未使用的 LRU 链表 */
  8. struct list_head d_child; /*父目录的子目录项所形成的链表 */
  9. struct list_head d_subdirs; /* 该目录项的子目录所形成的链表*/
  10. struct list_head d_alias; /* 索引节点别名的链表,也就是连接到同一个inode对象的所有的dentry对象组成的一个队列*/
  11. int d_mounted; /* 目录项的安装点 */
  12. struct qstr d_name; /* 这是一个结构体,该结构体中存放着目录项名的长度、目录项名对应的杂凑值和目录项名(可快速查找),这个主要是用于路径查询的时候来存放中间查询值 */
  13. unsigned long d_time; /* 由 d_revalidate函数使用 */
  14. struct dentry_operations *d_op; /* 目录项的函数集*/
  15. struct super_block * d_sb; /* 目录项树的根 (即文件的超级块)*/
  16. unsigned long d_vfs_flags;
  17. void * d_fsdata; /* 具体文件系统的数据 */
  18. unsigned char d_iname[DNAME_INLINE_LEN]; /* 短文件名 */
  19. };

对于dentry对象的一些解释

首先是对于dentry对象中的六个队列的解释。dentry中实际上由6个list_head,即d_vfsmnt、d_hash、d_lru、d_child、d_subdirs和d_alias。这里的list_head既可以用来作为一个队列的头,也可以用来将其所在的数据结构挂入到某个队列中。
(1)d_vfsmnt队列仅在该dentry结构为一个安装点的时候才使用。一个dentry结构一经建立就通过其d_hash挂入杂凑表dentry_hashtable中的某个队列中,当dentry结构的d_count为0即共享技术变成0的时候则通过d_lru挂入LRUdentry_unused队列中。
(2)dentry结构通过d_child挂入在其父节点(上一层目录)的d_subdirs队列中。同时该dentry结构的d_parent指向其父目录的dentry结构。
(3)该目录项的各个子目录的dentry结构则是在该目录项本身的d_subdirs队列中。
(4)对于d_alias队列:一个有效的dentry结构必定有一个inode结构,这是因为一个目录项要么代表着一个文件,要么代表着一个目录,而目录实际上也是文件。所以,只要dentry结构是有效的,则其指针d_inode必定指向一个inode结构。可是,反过来则不然,一个inode却可能对应着不止一个dentry结构;也就是说,一个文件可以有不止一个文件名或路径名。这是因为一个已经建立的文件可以被连接(link)到其他文件名。所以在inode结构中有一个队列i_dentry,凡是代表着同一个文件的所有目录项都通过其dentry结构中的d_alias域挂入相应inode结构中的i_dentry队列。也就是说目录项中的d_alias队列将会挂入inode节点中的i_dentry队列中。
(5)在内核中有一个哈希表dentry_hashtable ,是一个list_head的指针数组(该数组中的每个元素就是代表一个队列,从这个意义上讲,这个数组的元素个数为6)。一旦在内存中建立起一个目录节点的dentry 结构,该dentry结构就通过其d_hash域链入哈希表中的某个队列中。内核中还有一个队列dentry_unused,凡是已经没有用户(count域为0)使用的dentry结构就通过其d_lru域挂入这个队列。

关于dentry结构对象的总结

(1) 每个dentry结构都通过队列头d_hash连入杂凑表dentry_hashtable中的某个队列里面。
(2) 共享计数为0的dentry结构通过队列头d_lru链入LRU队列dentry_unused,在队列中等待释放或者是“东山再起”。
(3) 每个dentry结构都通过指针d_inode指向一个inode数据结构。但是多个dentry结构可以指向同一个inode结构。
(4) 指向同一个inode结构的dentry结构都通过队列头d_alias连接在一起,在在该inode结构的i_dentry队列中。
(5) 每个dentry结构都通过指针d_parent指向其父目录节点的dentry结构,并通过队列头d_child跟同一目录中的其他节点的dentry结构链接在一起,都在父目录节点的d_subdirs队列中(会构成一个整体的目录树,形成了文件系统的结构树)。
(6) 每个dentry结构都通过指针d_sb指向一个super_block数据结构。
(7) 每个dentry结构通过指针d_op指向一个dentry_operations数据结构。
(8) 每个dentry结构都有个队列头d_vfsmnt,用于文件系统的安装。