深入Linux内核架构——虚拟文件系统

Linux进程间的虚拟文件系统

Posted by yuchen on March 15, 2016
ch8-虚拟文件系统.html

虚拟文件系统

1.引入VFS的目的

为支持各种本机文件系统,且在同时允许访问其他操作系统文件,Linux内核在用户进程(或C标准库)和文件系统之间引入了一个抽象层,即虚拟文件系统(VFS)。

VFS抽象层

2.VFS的任务

  • VFS用来提供一种操作文件、目录及其他对象的统一方法。
  • VFS必须能够与各种方法给出的具体文件系统的实现达成妥协,这些实现在具体细节、总体设计方面都有一些不同之处。但VFS的回报很高,它使得Linux内核更加灵活了。

3.内核支持的文件系统

内核支持40多种文件系统,其来源各种各样:来自MS-DOS的FAT文件系统、UFS(Berkeley UNIX)、用于CD-ROM的iso9660、网络文件系统(如coda和NFS)和虚拟的文件系统(如proc)。

4.文件系统的类型

  • 基于磁盘的文件系统,如EXT2/3、FAT等
  • 虚拟文件系统,如proc
  • 网络文件系统,是基于磁盘的文件系统和虚拟文件系统之间的折中。由于VFS抽象层的存在,用户空间进程不会看到本地文件系统与网络文件系统之间的区别。

5.通用文件模型

1)并非每一种文件系统都支持VFS中的所有抽象。设备文件无法存储在源自其他系统的文件系统中(如FAT),后者的设计没有考虑到此类对象。
为适配各种文件系统,VFS的方案如下:
提供一种结构模型,包含了一个强大文件系统所应具备的所有组件。但该模型只存在于虚拟中,必须使用各种对象和函数指针与每种文件系统适配。所有文件系统的实现都必须提供与VFS定义的结构配合的例程,以弥合两种视图之间的差异。

2)虚拟文件系统的结构 虚拟文件系统的结构并非是幻想出来的东西,而是基于描述经典文件系统所使用的结构。VFS抽象层的组织显然也与Ext2文件系统类似。所以在Ext2和VFS结构之间转换时,几乎不会损失时间。

3)在处理文件时,内核空间和用户空间使用的主要对象是不同的:

  • 文件描述符:对用户程序来说,一个文件由一个文件描述符标识。文件描述符是在打开文件时由内核分配,只在一个进程内部有效。两个不同进程可以使用同样的文件描述符,但二者并不指向同一个文件。基于同一个描述符来共享文件是不可能的。
  • inode:内核处理文件的关键是inode。每个文件(和目录)都有且只有一个对应的indoe,其中包含元数据(如访问权限、上次修改的日期,等等)和指向文件数据的指针。但inode并不包含一个重要的信息项,即文件名

6.inode

inode对文件实现来说是一个主要的概念,但它也用于实现目录。目录只是一种特殊的文件,它必须正确地解释。

inode的成员可能分为下面两类:

  • 描述文件状态的元数据。例如,访问权限或上次修改的日期。
  • 保存实际文件内容的数据段(或指向数据的指针)。就文本文件来说,用于保存文本。

下面以内核查找对应于/usr/bin/emacs的inode过程为例阐明如何用inode来构造文件系统的目录层次结构:
过程起始于查找根目录/的inode,对系统来说其必须总是已知的。该目录由一个inode表示,其数据段并不包含普通数据,而是根目录下的各个目录项。这些项可能代表文件或其他目录。每个项由两个成员组成。
(1)该目录项的数据所在inode的编号。
(2)文件或目录的名称。
系统中所有inode都有一个特定的编号,用于唯一地标识各个inode。文件名和inode之间的关联即通过该编号建立。
查找操作中的第一步是查找子目录usr的inode。这一步会扫描根inode的数据段,直至找到一个名为usr的目录项(如果查找失败,则返回File not found错误)。相关的inode可以根据inode编号定位。
重复上述步骤,但这一次在usr对应inode的数据段中查找名为bin的目录项,以便根据其inode编号定位inode。下一步在bin的inode数据段中,将查找名为emacs的目录项。这仍然会返回一个inode编号,这一次的inode表示文件而非目录。过程如下图:

文件查找过程

7.链接

链接(link):用于建立文件系统对象之间的联系,分为符号链接和硬链接。

符号链接,亦称为软链接,可以认为是“方向指针”,表示某个文件存在于特定的位置,但实际位置在其他地方。每个符号链接都使用了一个独立的inode,相应的inode的数据段包含一个字符串,给出了链接目标文件的路径,故目标文件删除时,符号链接仍然可以继续保持。对于符号链接可以区分原始文件和链接。

硬链接:在硬链接建立时,创建的目录项使用了一个现存的inode编号。这样,在硬链接建立后,无法区分哪个文件是原来的,哪个是后来建立的。创建/删除硬链接时运用了引用计数的技巧。只有当计数器归0时,才能确认该inode不再使用,可以从系统中删除该inode连同其数据段。

8.编程接口

用户进程和内核的VFS实现之间的接口是由系统调用组成的。文件使用之前,必须用open或openat系统调用打开。在成功打开后,内核向用户层返回一个非负整数,即文件描述符,起始于3。这个标识符号之所以不从0开始,是因为所有的进程都分配了前3个标识符(0~2)。0表示标准输入,1表示标准输出,2表示标准错误输出。

文件已经打开后,其名称便失去作用。它现在由其文件描述符唯一标识,所有其他库函数都需要传递文件描述符作为一个参数(进一步传递到系统调用)。如前所述,两个不同进程可以使用同样的文件描述符,但二者并不指向同一个文件。故而,对文件的唯一表示由一个特殊的数据结构(struct file)提供。

9.将文件作为通用接口

UNIX:万物皆文件(该规则有少数例外,如网络设备)。大多数内核导出、用户程序使用的函数都可以通过VFS定义的文件接口访问。以下是使用文件作为其主要通信手段的一部分内核子系统:

  • 字符和块设备;
  • 进程之间的管道;
  • 用于所有网络协议的套接字;
  • 用于交互式输入和输出的终端。

本文总阅读量