参考文献:
《Linux内核设计与实现》
http://www.ibm.com/developerworks/cn/linux/l-cn-vfs/
http://www.ibm.com/developerworks/cn/linux/l-linux-filesystem/
http://www.ibm.com/developerworks/cn/linux/l-cn-read/index.html
3. 结构关系
图Linux 文件系统组件的体系结构
该图反应的Linux的文件系统的体系结构用户空间包含一些应用程序(例如,文件系统的使用者)和 GNU C 库(glibc),它们为文件系统调用(打开、读取、写和关闭)提供用户接口。VFS 是底层文件系统的主要接口。这个组件导出一组接口,然后将它们抽象到各个文件系统,各个文件系统的行为可能差异很大。同时有两个针对文件系统对象的缓存(inode 和 dentry)。它们缓存最近使用过的文件系统对象。
每个文件系统的实现(比如 ext2、JFS 等等)都会导出一组通用接口,供 VFS 使用。缓冲区缓存(Buffer cache)会缓存文件系统和相关块设备之间的请求。例如,对底层设备驱动程序的读写请求会通过缓冲区缓存来传递。这就允许在其中缓存请求,减少访问物理设备的次数,加快访问速度。以最近使用(LRU)列表的形式管理缓冲区缓存。注意,可以使用 sync
命令将缓冲区缓存中的请求发送到存储媒体(迫使所有未写的数据发送到设备驱动程序,进而发送到存储设备)。
图超级块、安装点和具体的文件系统的关系
从图中可以看到安装点与超级块是一一对应的(安装点通过mnt_sb指向超级块);并且三种结构都通过链表来组织它们的对象。vfsmount通过mnt_list链接、super_block通过s_list链接,同时s_instances又链接着相同文件系统类型的super_block,如图中的第1个与第3个就是相同的文件系统,所以它们通过s_instances链接了起来,另外它们的s_type也指向了相同的file_systems(第1个)、最后file_systems通过next链接,并且fs_supers指向有相同类型的super_block,如因为图中的第1个超级块与第3个超级块类型一样,所以fs_supers指向了第1个超级块。
从图中可知:进程通过task_struct中的一个域files_struct files来了解它当前所打开的文件对象;而我们通常所说的文件描述符其实是进程打开的文件对象数组的索引值。文件对象通过域f_dentry找到它对应的dentry对象,再由dentry对象的域d_inode找到它对应的索引节点(通过索引节点又可以得到超级块的信息,也就可以得到最终操作文件的方法,在open文件的时候就是使用这样一个过程),这样就建立了文件对象与实际的物理文件的关联。最后,还有一点很重要的是, 文件对象所对应的文件操作函数列表是通过索引节点的域i_fop得到的,而i_fop最终又是通过struct super_operations *s_op来初始化的。