努力成为linux kernel hacker的人李万鹏原创作品,为梦而战。转载请标明出处
http://blog.csdn.net/woshixingaaa/archive/2011/05/14/6420103.aspx
特殊文件系统:
当网络和磁盘文件系统能够使用户处理存放在内核之外的信息时,特殊文件系统可以为系统程序员和管理员提供一种容易的方式来操作内核的数据结构并实现操作系统的特殊特征。特殊文件系统不限于物理块设备,然而,内核给每个安装的特殊文件系统分配一个虚拟的块设备,让其主设备号为0而次设备号具有任意值(每个特殊文件系统有不同值)。set_anon_super()函数用于初始化特殊文件系统的超级块;该函数本质上获得一个未使用的次设备号dev,然后用主设备号0和次设备号dev设置新超级块的s_dev字段。而另一个kill_anon_super()函数移走特殊文件系统的超级块。unnamed_dev_idr变量包含一个辅助结构(记录当前使用的次设备号)的指针。尽管有些内核设计者不喜欢虚拟块设备标识符,但这些标识符有助于内核以统一的方式处理特殊文件系统和普通文件系统。
文件系统类型注册:
每个注册的文件系统都用一个类型为file_system_type的对象来表示:
fs_supers字段表示给定类型的已安装文件系统所对应的超级块链表的头,链表元素的向后和向前链接存放在超级块对象的s_instances字段中。在系统初始化期间,调用register_filesystem()函数来注册编译时指定的每个文件系统;该函数把相应的file_system_type对象插入到文件系统类型的链表中。
get_fs_type()函数(接受文件系统名作为它的参数)扫描已注册的文件系统链表以查找文件系统类型的name字段,并返回指向相应的file_system_type对象(如果存在)的指针。
命名空间:
每个进程可拥有自己的已安装文件树——叫做进程的命名空间(namespace);对于每一个进程都有自己的namespace,这可以理解为这个进程的地盘。在这里,所有的文件系统都要挂上来统一管理。
通常大多数进程共享一个命名空间,即位于系统的根文件系统且被init进程使用的已安装文件系统树。不过如果clone()系统调用以CLONE_NEWNS标志创建一个新进程,那么进程将获取一个新的命名空间,这个新的命名空间随后由子进程继承(如果父进程没有以CLONE_NEWNS标志创建这些进程)。
当进程安装或卸载一个文件系统时,仅修改它的命名空间。因此,所做的修改对共享同一命名空间的所有进程都是可见的,并且也只对他们可见。进程甚至可通过使用Linux特有的pivot_root()系统调用来改变它的命名空间的根文件系统。
文件系统的根目录有可能不同于进程的根目录:进程的根目录是与“/”路径对应的目录。缺省情况下,进程的根目录与系统的根文件系统的根目录一致(更准确的说是与进程的命名空间中的根文件系统的根目录一致),但是可以通过chroot()系统调用改变进程的根目录。
Linux有所不同,同一个文件系统被安装多次是可能的。当然,如果一个文件系统被安装了n次,那么它的根目录就可通过n个安装点来访问。尽管同一文件系统可以通过不同的安装点来访问,但是文件系统的的确确是唯一的。因此,不管文件系统被安装了多少次,都仅有一个超级块对象。
把多个安装堆叠在一个单独的安装点上也是可能的。尽管已经使用先前安装下的文件和目录的进程可以继续使用,但在同一安装点上的新安装隐藏前一个安装的文件系统。当最顶层的安装被删除时,下一层的安装再一次变为可见的。
已安装文件系统描述符vfsmount:
vfsmount数据结构保存在几个双向链表中:
1. 参照上边命名空间那个图。对于每一个命名空间,所有属于此命名空间的已安装的文件系统描述符形成了一个双向循环链表。namespace结构的list字段存放链表的头,vfsmount描述符的mnt_list字段包含链表中指向相邻元素的指针。
2. 由父文件系统vfsmount描述符的地址和安装点目录的目录项对象的地址索引的散列表。散列表存放在mount_hashtable数组中,其大小取决于系统中RAM的容量。表中每一项是具有同一散列值的所有描述符形成的双向循环链表的头。描述符的mnt_hash字段包含指向链表中相邻元素的指针。
3. 对于每一个已安装的文件系统,所有已安装的子文件子系统形成了一个双向循环链表。每个链表的头存放在已安装的文件系统描述符的mnt_mounts字段;此外,描述符的mnt_child字段存放指向链表中相邻元素的指针。
总结一下,三个链表就是这张图了:
1.分配和初始化一个已安装文件系统描述符
2.释放由mnt指向的已安装文件系统描述符
3.在散列表中查找一个描述符并返回它的地址(参数mnt是父已安装文件系统描述符,dentry表示安装子已安装文件系统描述符的安装点,函数返回该子文件系统的vfsmount)。如果查找到了,增加子已安装文件系统描述符的引用计数。
lookup_mnt调用__lookup_mnt进行真正的查找,mnt_hashtable是散列表的起始地址,加上偏移hash(mnt,dentry),就得到散列值相同的链表的头节点。然后进行遍历,如果一个vfsmount的mnt_parent域与所给的mnt相同,vfsmount的挂载点的dentry与所给的dentry相同,则就是这个vfsmount。
增加引用计数:
所有文件系统类型的对象都插入到一个单向链表中,由变量file_systems指向链表的第一个元素,而结构中的next字段指向链表的下一个元素。file_systems_lock读/写自旋锁保护整个链表免受同时访问。