linux的文件系统架构
在最底层,linux维护了一个磁盘inode的概念,它代表了一个实际文件,然后在上一层,linux维护了内存inode,它使得操作系统可以提供用户接口来操作磁盘inode,内存inode和磁盘inode是对应的,vfs层将不同文件系统的不同格式的磁盘inode统一成了一致的内存inode,如此一来向上提供的接口将统一,在接口统一之前,数据结构首先要统一。和内存inode相关的是目录项dentry的概念,它绑定一个且只绑定一个内存inode,但是却允许多个dentry绑定同一个内存inode,实际上它就是我们在使用操作系统时看到的每一个文件的内核实体,既然允许dentry和inode的多对一的关系,操作系统很简单地就可以实现诸如链接这样的概念,这个意义上dentry并不是和内存inode处于同一个层次,inode表示文件的本质,而dentry表示操作系统意义上文件的接口。
unix最先实现了vfs,在unix中内存inode成为vnode,这个名称可能更好听些。这个vfs在linux中的实现要更复杂一些,其本质就是这个内存inode数据结构,进而在该数据结构的基础上提供file_operations操作函数集,这些数据结构是怎样组合起来的呢?它们是在什么时候组合在一起的呢?任何事情如果想搞透它就要从起源开始研究,于是sys_open系统调用中必然将这一切联系在了一个,如果说sys_open还不够的话,那么sys_mount作为一个文件系统的开始一定确定了该文件系统的基本模板,比如super_block结构之类的,由于sys_mount还是要使用sys_open,那么sys_open当然是重中之重了。open的轮廓为两层循环,外部的循环解析路径,内层的循环在特定的路径寻找待open路径中下一个元素,路径元素由'/'分割。在进一步处理下一个路径元素之前,必须将当前的dentry设置到当前目录的最顶一层挂载的文件系统的根目录,这个在linux中由follow_mount来实现,这样所有被mount的目录下的原始内容就被隐藏了,原先的树依然存在,只是在这个节点上又长出一个新的根,然后这个新根又扩展成一棵树,任意的树节点上都可以生长出新根,然后递归地长出新树。
系统中每一个被挂载的文件系统都有一个超级块,超级块是该文件系统的元数据 ,所有的同类文件系统的超级块链接成一个链表,在超级块回调函数的指导之下,系统模块可以支持各种各样的文件系统。系统中还有一张挂载表,实际上是挂载树,很多内核实体都是同时连入不同的数据结构,这样就方便在不同场合使用不同的数据结构,比如vm_area_struct既连入链表,又连入红黒树中。这个挂载表的每一项表示一次挂载,包含一个挂载文件系统的超级块信息,被挂载点的inode对应的dentry,挂载文件系统根的inode对应的dentry以及设备号。
每个挂载的文件系统都有一个根,即“/”,它是一个特殊的目录,一般每一类文件系统都会为这个根分配一个固定的内存inode号,然后为后续此挂载文件系统分配挂载范围内唯一的inode号,因此不同挂载点的文件系统中的文件的内存inode号会相同,注意,一般不要提及磁盘inode号是否唯一的问题和概念,因为并不是每一种文件系统都有磁盘inode概念的,unix/linux只是为了实现vfs才将很多的文件系统统一“适配”到内存inode(vnode),比如ntfs就没有inode的概念,当在linux上挂载ntfs分区的时候,内核的ntfs模块会将ntfs文件的元数据装载到内存inode中,这就是适配器模式在linux内核的应用。
本文转自 dog250 51CTO博客,原文链接:http://blog.51cto.com/dog250/1271765