【Kernel】虚拟文件系统

【Kernel】虚拟文件系统

一、概念

虚拟文件系统(VFS)作为内核子系统为用户空间程序提供了文件和文件系统相关的接口。系统中所有文件不但依赖VFS共存,而且也依靠VFS系统协同工作。通过虚拟文件系统,程序可以利用标准的Unix系统调用对不同的文件系统,甚至不同介质上的文件系统进行读写操作。(把各种不同的文件系统抽象后采用统一的方式进行操作)。

VFS定义了所有文件系统都支持的、基本的、概念上的接口和数据结构。下图是进行一次write系统调用所涉及vfs的具体流程。总的来说,vfs是一种文件系统的抽象,它提供了一个通用的文件系统模型。
在这里插入图片描述

二、Unix文件系统

Unix使用了四种和文件系统相关的传统抽象概念:文件、目录项、索引节点和安装点(mount point)。

**从本质上讲文件系统是特殊的数据分层存储结构,它包含文件、目录和相关控制信息。**文件系统的通用操作包含创建、删除和安装等。在Unix中,文件系统被安装在一个特定的安装点上,该安装点在全局层次结构中被称为命名空间,所有的已安装文件系统都作为根文件系统树的枝叶出现在系统中。与这种单一的、统一的树形成鲜明对照的就是DOS和Windows的表现,它将文件的命名空间分类为驱动字母,例如C:。这种将命名空间划分为设备和分区的做法,相当于将硬件信息“泄漏”给文件系统抽象层。对用户而言,如此的描述有点随意,甚至产生混淆,这是Linux统一命名空间所不屑一顾的。

文件其实可以做一个有序的字节串,字节串的第一个字节是文件的头,最后一个字节是文件的尾。每一个文件为了便于系统和用户识别,都被分配一个便于理解的名字。典型的文件操作有读、写、创建和删除等。Unix文件的概念和面向记录的文件系统(如OpenVMS的File-11)形成鲜明的对照。面向记录的文件系统提供更丰富、更结构化的表示,而简单的面向字节流抽象的Unix文件则以简单性和相当的灵活性为代价

文件通过目录组织起来。文件目录好比一个文件夹,,用来容纳相关文件。因为目录也可以包含其它目录,即子目录,所以目录可以层层嵌套,形成文件路径。路径中的每一部分都被称为目录条目。"/home/wolfman/butter"是文件路径的一个例子——根目录/,目录home,wolfman和文件buffer都是目录条目,它们统称为目录项。在Unix中,目录属于普通文件,它列出包含在其中的所有文件。由于VFS把目录当作文件对待,所以可以对目录执行和文件相同的操作。

Unix系统将文件的相关信息和文件本身这两个概念加以区分,例如访问控制权限、大小、拥有者、创建时间等信息。文件相关信息,有时被称作文件的元数据(也就是说,文件的相关数据),被存储在一个单独的数据结构里中,该结构被称为索引节点(inode),它其实是index node的缩写,不过近来术语“inode”使用的更为普遍一些。

所有这些信息都和文件系统的控制信息密切相关,文件系统的控制信息存储在超级块中,超级块是一种包含文件系统信息的数据结构。有时,把这些收集起来的信息称为文件系统的数据元,它集单独文件信息和文件系统的信息于一身。

一直以来,Unix文件系统在它们物理磁盘布局中也是按照上述概念实现的。比如说在磁盘上,文件(目录也属于文件)信息按照索引节点形式存储在单独的块中;控制信息被集中存储在磁盘的超级块中,等等。Unix中文件的概念从物理上被映射到存储介质。Linux的VFS的设计目标就是要保证能与支持和实现了这些概念的文件系统协同工作。像如FAT或NTFS这样非Unix风格的文件系统,虽然也可以在Linux上工作,但是它们必须经过封装,提供一个符合这些概念的界面。比如,即使一个文件系统不支持索引节点,它也必须在内存中封装索引节点结构体,就像它本身包含索引节点一样。再比如,如果一个文件系统将目录看做一种特殊对象,那么要想使用VFS,就必须将目录重新表现为文件形式。通常,这种转换需要在使用现场(on the fly)引入一些特殊处理,是的非Unix文件系统能够兼容Unix文件系统的使用规则并满足VFS的需求。这种文件系统当然仍能工作,但是其带来的开销则不可思议(开销太大了)。

三、VFS对象及其数据结构

VFS中四个主要的对象类型,它们分别是:

  • 超级块对象,它代表一个具体的已安装文件系统。
  • 索引节点对象,它代表一个具体的文件。
  • 目录项对象,它代表一个目录项,是路径的一个组成部分。
  • 文件对象,它代表由进程打开的文件。

(以下对四种对象类型的介绍不包含源码及结构内容,仅进行简单介绍)

超级块对象

各种文件系统中都必须实现超级块对象,用于存储特定文件系统的信息,通常对应于存放在磁盘特定扇区中的文件系统超级块或文件系统控制块。对于并非基于磁盘的文件系统(如sysfs是基于内存的文件系统),他们会在使用现场创建超级块并将其保存到内存中。

超级块对象由super_block结构体表示,定义在include/linux/fs.h,其具体结构和域此处不进行描述。

创建、管理和撤销超级块对象的代码位于文件fs/super.c中。超级块对象通过alloc_supper()函数创建并初始化,函数都是VFS在进程上下文中调用,这其中一些函数是可选的,除了dirty_inode(),其他函数在必要时都可以阻塞。

索引节点对象

索引节点对象包含了内核在操作文件或目录时需要的全部信息。索引节点对象必须在内存中创建,以便文件系统使用。

索引节点对象由inode结构体表示,定义在文件include/linux/fs.h,其具体结构和域此处不进行描述。

目录项对象

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

目录项对象由dentry结构体表示,定义在文件include/linux/dcache.h中,其具体结构和域此处不进行描述。

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

目录项对象有三种有效状态:被使用、未被使用和负状态(即不存在)。

文件对象

文件对象是已打开文件在内存中的表示。该对象(不是物理文件)由相应的open()系统调用创建,由close()系统调用撤销,所有这些文件相关的调用实际上都是文件操作表中定义的方法。

文件对象由file结构体表示,定义在include/linux/fs.h中,其具体结构和域此处不进行描述。

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

四、参考资料和补充

《Linux内核设计与实现》

猜你喜欢

转载自blog.csdn.net/qq_40392981/article/details/123041074
今日推荐