2.1.3节分析了VFS中dentry的数据结构和作用,为了进一步理解dentry,我们用图2-2来解释dentry的链接关系。
如图2-2所示,根目录下有usr和home两个目录,usr目录下有wj和nk两个文件,home目录下有个mnt目录,这是另外一个文件系统,挂载(mount)到当前文件系统。在mnt目录下有个cj文件。
文件系统的dentry链表图如图2-3所示。这只是个示意图,但是展示了几个重要的概念。
1)每个文件的dentry链接到父目录的dentry,形成了文件系统的结构树。
具体说,就是usr和home两个dentry的d_child成员链接到根目录dentry的d_subdirs成员。而wj和nk两个dentry结构链接到usr这个dentry。
2)所有的dentry都指向一个dentry_hashtable。
dentry_hashtable是个数组,它的数组成员是第1章介绍过的hash链表数据结构。这里所说的dentry,指的是在内存中的dentry。如果某个文件已经被打开过,内存中就应该有该文件的dentry结构,并且该dentry被链接到dentry_hashtable数组的某个hash链表头。后续再访问该文件的时候,就可以直接从hash链表里面找到,避免了再次读硬盘。这是dentry的cache概念。
3)home目录下的mnt目录指向一个挂载的文件系统。
如何判断目录不是一个普通的目录,而是一个文件系统?这是dentry的d_mounted成员的功能。如果该成员不为0,代表该dentry是个挂载点,有文件系统挂载,需要特殊处理。
从图2-3可以看到,挂载过来的文件系统本身也有一个dentry树,也有自己的根目录。两个dentry树之间并没有链接关系。如何查找到挂载的文件系统哪?我们用图2-4来解释。
图2-4展示了一个新的数据结构vfsmount。对这个数据结构不做过多的探讨,只需要知道每个文件系统都有这样一个结构。当文件系统被挂载的时候,它的vfsmount结构就被链接到内核的一个全局链表—mount_hashtable数组链表。
mount_hashtable是个数组,它的每个成员都是一个hash链表。上文的例子有两个vfsmount,cj文件所在文件系统的vfsmount被链接到mount_hashtable。这样当发现mnt目录是个特殊的目录时,从mount_hashtable数组找到hash链表头,再遍历整个hash链表,就能找到cj文件所在文件系统的vfsmount,然后mnt目录的dentry就被替换,置换为新文件系统的根目录。具体过程参考打开文件的代码分析。