向下之旅(十八):虚拟文件系统

Posted 画家丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了向下之旅(十八):虚拟文件系统相关的知识,希望对你有一定的参考价值。

  目录项对象

  VFs把目录当做文件对待,所以在路径/bin/vi中,bin和vi都属于文件——bin是特殊的目录文件而vi是一个普通文件。路径中的每个组成部分都由一个索引节点对象表示。虽然它们可以统一由索引节点表示,但是VFS经常需要执行目录相关的操作,比如路径名查找等。路径名查找需要解析路径中的每一个组成部分,不但要确保它有效,而且还需要再进一步寻找路径中的下一个部分。

  为了方便查找操作。VFS引入了目录项的概念。每个dentry代表路径中的一个特定的部分,对前一个例子来说,/、bin和vi都属于目录项对象。前两个是目录,最后一个是普通文件。必须明确一点:在路径中,包括普通文件在内,每一个部分都是目录项对象。

  目录项也可包括安装点。在路径/mnt/cdrom/foo中,/、mnt、cdrom和foo都属于目录项对象。VFS在执行目录操作时——如果需要的话——会现场创建目录项对象。目录项对象由dentry结构体表示:

技术分享

  不同于前面两个对象,目录项对象没有对应的磁盘数据结构,VFS根据字符串形式的路径名现场创建它。而且由于目录项对象并非真正保存在磁盘上,所以目录项结构没有是否被修改的标志(即是否为脏,是否需要写回磁盘的标志)。

  目录项状态

  目录项对象由三种有效状态:被使用、未被使用和负状态。

  一个被使用的目录项对应一个有效的索引节点,当处于被使用状态时,意味着它正被VFS使用并且指向邮箱的索引节点,因此不能被丢弃。

  一个未被使用的目录项对应一个有效的索引节点,但是应指明VFS当前并未使用它,该目录项对象仍然指向一个有效对象,而且被保留在缓存中以便需要的时候使用它。若需要回收内存的话,可以销毁未使用的目录项。

  一个负状态的目录项没有对应的有效索引节点,以为索引节点已被删除了,或者路径不在正确了,但是目录项仍然保留,以便快速解析以后的路径查询。如果需要的话,可以销毁它。目录项对象释放后也可以保存在slab对象缓存中去。此时,任何VFS或文件系统代码都没有指向该目录项对象的有效引用。

  目录项缓存

  如果VFS层遍历路径名中所有的元素并将它们逐个的解析成目录项对象,这将是一件非常费力的工作。所以内核将目录项对象缓存在目录项缓存(dcache)中,主要包括三个部分:

  1.“被使用的”目录项链表。该链表通过索引节点对象中的i_dentry项链接相关的索引节点。因为一个给定的索引节点可能有多个链接,所以就可能有多个目录项对象,因此用一个链表来链接它们。

  2.“最近被使用的”双向链表。该链表含有未被使用和负状态的目录项对象。

  3.散列表和相应的三列函数用来快速的将给定路径解析为相关目录项对象。

  目录项操作

  dentry_operations结构体指明了VFS操作目录项的所有方法:

技术分享

  文件对象

  VFS的最后一个主要对象时文件对象。文件对象表示进程已打开的文件。如果站在用户空间来看待VFS,文件对象会首先进入我们的视野。进程后直接处理的是文件,而不是超级块、索引节点或目录项。

  文件对象是已打开的文件在内存中的表示。该对象(不是物理文件)由相应的open()系统调用创建,由close()系统调用销毁。所有这些文件相关的调用实际上都是文件操作表中定义的方法。因为多个进程可以同时打开或操作同一文件,所以同一个文件也可能存在多个对应的文件对象。文件对象仅仅在进程观点上代表已打开文件,它反过来指向目录项对象(反过来指向索引节点),其实只有目录项对象才表示已打开的实际文件。虽然一个文件对应的文件对象不是唯一的,但是对应的索引节点和目录项对象是唯一的。文件对象file结构体如下:

技术分享

  类似于目录项对象,文件对象实际上没有对应的磁盘数据。所以在结构体中没有代表其对象是否为脏,是否需要写回磁盘的标志。文件对象通过f_dentry指针指向相关的目录项对象。目录项会指向相关的索引节点,索引节点会记录文件是否为脏。

  文件操作

  文件对象的操作由file_operations结构体表示,结构如下:

技术分享

  和文件系统相关的数据结构

  除了以上几种VFS基础对象外,内核还使用了另外一些标准数据结构来管理文件系统的其他相关数据。第一个结构体是file_system_type,用来描述各种特定文件系统类型,比如ext3或XFS。第二个结构体是vfsmount,用来描述一个安装文件系统的实例。

  因为Linux支持众多不同的文件系统,所以内核必须由一个特殊的结构来描述每种文件系统的功能和行为。结构如下:

技术分享

  get_sb()函数从磁盘上读取超级块,并且在文件系统被安装时,在内存中组装超级块对象。剩余的函数描述文件系统的属性。

  当文件系统被实际安装时,将有一个vfsmount结构体在安装点被创建。该结构体用来代表文件系统的实例——即代表一个安装点。具体结构如下:

技术分享

  理清文件系统和所有其他安装点间的关系,是维护所有安装点链表中最复杂的工作。所以vfsmount结构体中维护的各种链表就是为了能够跟踪这些关系信息。

  vfsmount结构还保存了在安装时指定的标志信息,该信息存储在mnt_flags域中。

技术分享

  安装那些管理员不充分信任的移动设备时,这些标志很有用处。

  和进程相关的数据结构

  系统中的每一个进程都有自己的一组打开的文件,像根文件系统、当前工作目录、安装点等等。有三个数据结构将VFS层和系统的进程紧密联系在一起。它们分别是:files_struct、fs_struct和namespace结构体。

  files_struct结构体由进程描述符的files域指向。所有与每个进程相关的信息如打开的文件及文件描述符都包含在其中,其结构和描述如下:

技术分享

  fd数组指针指向已打开的文件对象链表,因为NR_OPEN_DEFAULT等于32,所以可以容纳32个文件对象,当进程所打开的文件超过32个时,会创建一个新的数组,为了优化性能,可以适当的增大NR_OPEN_DEFAULT的预定义的值。

  和进程相关的第二个结构体是fs_struct。该结构由进程描述符的fs域指向。它包含文件系统和进程相关的信息。结构如下:

技术分享

  该结构包含了当前进程的当前工作目录(pwd)和根目录。

  最后一个结构体是namespace,由进程的namespace域指向。在2.4版内核后,单进程命名空间被加入到内核中,它是的每一个进程在系统中都看到唯一的安装文件系统——不仅是唯一的根目录,而且是唯一的文件系统层次结构。结构如下:

  技术分享

  默认情况下,所有的进程共享同样的命名空间(也就是,它们都从相同的挂载表中看到同一个文件系统层次结构)。

  Linux支持了相当多种类的文件那系统,从本地文件系统到网络文件系统,Linux在标准内核中已支持的文件系统超过50种。VFS层提供给这些不同的文件系统一个统一的实现框架,而且还提供了能和标准系统调用交互工作的统一接口。使得在Linux上实现新文件系统的工作变得简单起来,它可以轻松的使这些文件系统通过标准Unix系统调用而协同工作。

 

  参考自:《Linux Kernel Development》.

 

以上是关于向下之旅(十八):虚拟文件系统的主要内容,如果未能解决你的问题,请参考以下文章

Python学习之旅(十八)

JAVA之旅(十八)——基本数据类型的对象包装类,集合框架,数据结构,Collection,ArrayList,迭代器Iterator,List的使用

Python学习之旅(二十八)

Linux虚拟文件系统(VFS)

文件系统VFS数据结构(超级块 inode dentry file)(收集整理)

Python学习之旅(三十八)