虚拟文件系统(VFS)

news/2024/11/16 11:53:36/

        为支持各种本机文件系统,且在同时允许访问其他操作系统的文件,Linux内核在用户进程(或C标准库)和文件系统实现之间引入了一个抽象层。该抽象层称之为虚拟文件系统(Virtual File System),简称VFS。VFS的任务并不简单。一方面,它用来提供一种操作文件、目录及其他对象的统一方法。另一方面,它必须能够与各种方法给出的具体文件系统的实现达成妥协。

图1 用作文件系统抽象的VFS层

1 文件系统类型 

文件系统一般可以分为下面3种。

(1) 基于磁盘的文件系统(Disk-based Filesystem)是在非易失介质上存储文件的经典方法,用以在多次会话之间保持文件的内容。实际上,大多数文件系统都由此演变而来。比如,一些众所周知的文件系统,包括Ext2/3、Reiserfs、FAT和iso9660。

(2)虚拟文件系统(Virtual Filesystem)在内核中生成,是一种使用户应用程序与用户通信的方法。proc文件系统是这一类的最佳示例。它不需要在任何种类的硬件设备上分配存储空间。相反,内核建立了一个层次化的文件结构,其中的项包含了与系统特定部分相关的信息。

(3)网络文件系统(Network Filesystem)是基于磁盘的文件系统和虚拟文件系统之间的折中。这种文件系统允许访问另一台计算机上的数据,该计算机通过网络连接到本地计算机。在这种情况下,数据实际上存储在一个不同系统的硬件设备上。

2 通用文件模型

        VFS不仅为文件系统提供了方法和抽象,还支持文件系统中对象(或文件)的统一视图。VFS提供一种结构模型,包含了一个强大文件系统所应具备的所有组件。但该模型只存在于虚拟中,必须使用各种对象和函数指针与每种文件系统适配。所有文件系统的实现都必须提供与VFS定义的结构配合的例程,以弥合两种视图之间的差异。当然,虚拟文件系统的结构并非是幻想出来的东西,而是基于描述经典文件系统所使用的结构。VFS抽象层的组织显然也与Ext2文件系统类似。

        在处理文件时,内核空间和用户空间使用的主要对象是不同的。对用户程序来说,一个文件由一个文件描述符标识。该描述符是一个整数,在所有有关文件的操作中用作标识文件的参数。文件描述符是在打开文件时由内核分配,只在一个进程内部有效。两个不同进程可以使用同样的文件描述符,但二者并不指向同一个文件。基于同一个描述符来共享文件是不可能的。

        内核处理文件的关键是inode。每个文件(和目录)都有且只有一个对应的indoe,其中包含元数据(如访问权限、上次修改的日期,等等)和指向文件数据的指针。但inode并不包含一个重要的信息项,即文件名,这看起来似乎有些古怪。通常,假定文件名称是其主要特征之一,因此应该被归入用于管理文件的对象(inode)中。

2.1 inode

2.1.1 基本概念

        如何用数据结构表示目录的层次结构?如前所述,inode对文件实现来说是一个主要的概念,但它也用于实现目录。换句话说,目录只是一种特殊的文件,它必须正确地解释。inode的成员可能分为下面两类。

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

2.1.2 举个栗子        

        为阐明如何用inodes来构造文件系统的目录层次结构,我们来考察内核查找对应于/usr/bin/ emacs的inode过程。

        查找起始于inode,它表示根目录/,对系统来说必须总是已知的。该目录由一个inode表示,其数据段并不包含普通数据,而是根目录下的各个目录项。这些项可能代表文件或其他目录。每个项由两个成员组成。

① 该目录项的数据所在inode的编号。
② 文件或目录的名称。

        系统中所有inode都有一个特定的编号,用于唯一地标识各个inode。文件名和inode之间的关联即通过该编号建立。

(1)查找操作中的第一步是查找子目录usr的inode。这一步会扫描根inode的数据段,直至找到一
个名为usr的目录项(如果查找失败,则返回File not found错误)。相关的inode可以根据inode编号定位。

(2)重复上述步骤,但这一次在usr对应inode的数据段中查找名为bin的目录项,以便根据其inode编号定位inode。下一步在bin的inode数据段中,将查找名为emacs的目录项。这仍然会返回一个inode编号,这一次的inode表示文件而非目录。图8-2给出了查找过程结束时的情形(所经由的路径由对象之间的指针表示)。

(3)最后一个inode的文件内容,与前三个inode不同。前三个inode都表示目录,其文件内容是目录项的一个列表,包括子目录和文件。与emacs文件关联的inode,其数据段存储了文件的内容。

图2 查找/usr/bin/emacs的操作

2.2 链接

        链接(link)用于建立文件系统对象之间的联系。linux中有两种类型的链接,分别是符号链接(软链接)与硬链接。

        符号链接可以认为是“方向指针”(至少从用户程序来看是这样),表示某个文件存在于特定的位置。当然我们都知道,实际的文件在其他地方。符号链接可以认为是一个目录项,其中除了指向文件名的指针,并不存在其他数据。目标文件删除时,符号链接仍然继续保持。对每个符号链接都使用了一个独立的inode。相应inode的数据段包含一个字符串,给出了链接目标的路径。

        对于符号链接,可以区分原始文件和链接。对于硬链接,情况不是这样。在硬链接已经建立后,无法区分哪个文件是原来的,哪个是后来建立的。在硬链接建立时,创建的目录项使用了一个现存的inode编号。删除符号链接并不困难,但硬链接的处理有一点技巧。

        我们假定硬链接(B)与原始文件(A)共享同一个inode。一个用户现在想要删除A。这通常会销毁相关的inode连同其数据段,以便释放存储空间供后续使用。那么接下来B就不能继续访问了,因为相关的inode和文件信息不再存在了。当然,这不是我们想要的行为。在inode中加入一个计数器,即可防止这种情况。每次对文件创建一个硬链接时,都将计数器加1。如果其中一个硬链接或原始文件被删除(不可能区分这两种情况),那么将计数器减1。只有在计数器归0时,我们才能确认该inode不再使用,可以从系统删除。

2.3 编程接口

        用户进程和内核的VFS实现之间的接口照例由系统调用组成,其中大多数涉及对文件、目录和一般意义上的文件系统的操作。对上述的操作,内核提供了50多个系统调用。我们只考察最重要的调用,以阐明关键原则。

        文件使用之前,必须用open或openat系统调用打开。在成功打开文件之后,内核向用户层返回一个非负的整数。这种分配的文件描述符起始于3。我们知道,尽管没有明确规定,这个标识符号之所以不从0开始,是因为所有的进程都分配了前3个标识符(0~2)。0表示标准输入,1表示标准输出,2表示标准错误输出。

        在文件已经打开后,其名称就没什么用处了。它现在由其文件描述符唯一标识,所有其他库函数都需要传递文件描述符作为一个参数(进一步传递到系统调用)。尽管传统上文件描述符在内核中足以标识一个文件,但现在情况不再如此。由于多个命名空间和容器的引入,具有相同数值的多个文件描述符可以共存于内核中。对文件的唯一表示由一个特殊的数据结构(struct file)提供,我将在下文讨论。我们在示例程序调用close的部分会看到文件描述符,该调用关闭与文件的“连接”(释放文件描述符,以便在后续打开其他文件时使用)。 read也需要将文件描述符作为第一个参数,以标识读取数据的来源。

        在一个打开文件中的当前位置保存在文件位置指针(file pointer)中,这是一个整数,指定了当前位置与文件起始点的偏移量。对随机存取文件而言,该指针可以设置为任何值,只要不超出文件存储容量范围即可。这用于支持对文件数据的随机访问。其他文件类型,如命名管道或字符设备的设备文件,不支持这种做法。它们只能从头至尾顺序读取。在文件打开时,可以指定各种标志(如O_RDONLY),用来规定文件的存取模式。

2.4 将文件作为通用接口

        UNIX是基于少量审慎选择的范型而建立的。一个非常重要的隐喻贯穿内核的始终(特别是VFS),尤其是在有关输入和输出机制的实现方面。

万物皆文件

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

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

        要注意,上述的某些对象不一定联系到文件系统中的某个项。例如,管道是通过特殊的系统调用生成,然后由内核在VFS的数据结构中管理,管道并不对应于一个可以用通常的rm、ls等命令访问的真正的文件系统项。我们特别感兴趣的是访问块设备和字符设备的设备文件。这些是真正的文件,通常位于/dev目录。其内容是在进行读写操作时由相关的设备驱动程序动态生成的。 

3 VFS的结构

        既然我们已经熟悉了VFS的基本结构和用户接口,下面我们将重点讨论其实现细节。在VFS接口的实现中,涉及大量数据结构,有些非常冗长。因此最好草拟出各个组成部分的一个大体概观,并说明其联结方式。

图3 各个VFS组件的相互关系

未完待续 ... 

参考书目:

《深入Linux内核架构》 


http://www.ppmy.cn/news/796635.html

相关文章

Stable Diffusion WebUI Ubuntu 22.04 LTS RTX2060 6G 极限显存出图

模型 默认选中 chilloutmix_Ni.safetensors&#xff0c;重启webui.sh进程 正向词 best quality, ultra high res, (photorealistic:1.4), 1girl, <lora:koreanDollLikeness_v15:1> ,<lora:yaeMikoRealistic_yaemikoMixed:1>, 反向词 paintings, sketches, (…

java8新特性:Lambda表达式【详细】

文章目录 一、Lambda表达式介绍1.1概念1.2基础语法1.3方法引用1.4变量的作用域1.5Lambda表达式和匿名内部类的区别 二、Lambda表达式的使用2.1集合中使用2.2多线程中使用2.3排序2.6过滤2.7映射2.8聚合2.9函数式编程 一、Lambda表达式介绍 1.1概念 Java8里面最重要的一个技术就…

oracle传入两个参数的的replace函数替换成hive方式

oracle2个参数的replace转换成hive实现 replace(abcedf, edf) efls ---原oracl格式 regexp_replace(abcedf, edf,) efls ----hive格式总结&#xff1a;oracle支持传入2个参数&#xff0c;但是hive支持传入3个参数&#xff0c;那么可以将第三个参数写为空字符串

语言模型BERT理解

一、BERT概述 BERT是由Google在2018年提出的一种预训练语言模型。BERT的创新之处在于采用了双向Transformer编码器来生成上下文相关的词向量表示。 传统的单向语言模型只考虑了左侧或右侧的上下文信息&#xff0c;而BERT则同时考虑了左侧和右侧的上下文信息&#xff0c;使得生…

安装ubuntu22.04 解决wifi6驱动问题 + 没有Realtek rtl8852be 驱动(本人电脑:Redimbook R7 5800H)

Ubuntu 没有wifi图标&#xff0c;没有Realtek rtl8852be 驱动 问题原因&#xff1a; 由于该系列无线网卡属于“螃蟹网卡”&#xff0c;inter12代 内核版本 > 5.18&#xff0c;Ubuntu22.04 没有相应的网卡驱动导致 解决&#xff1a; 在window系统&#xff0c;Xiaomi电脑管…

Realtek 8852BE Think Book 14 + 在Arch Linux下安装网卡驱动

Realtek 8852BE Think Book 14 在Arch Linux下安装网卡驱动 原链接&#xff1a;https://gith删ub.com/lwfinger/rtw89 不要选择下图方法&#xff0c;在我的电脑上试了无数次就是不成功 请选择此方法: sudo pacman -S linux-headers sudo pacman -S base-devel git clone ht…

解决安装Realtek HD Audio Driver失败的问题

早两天办公电脑重装系统(WIN2003), 主板是ASUS PUB-5S&#xff0c;芯片组是Intel965GCICH7&#xff0c;按照先主板驱动&#xff0c;后显卡&#xff0c;再声卡&#xff0c;结果却装来一个鸟“安装Realtek HD Audio Driver失败”的提示&#xff0c;晕。又怕是光盘里的驱动程序有问…

Win11找不到realtek高清晰音频管理器怎么办?

Win11找不到realtek高清晰音频管理器怎么解决&#xff1f;很多用户表示更新完Win11之后&#xff0c;找不到realtek高清晰音频管理器&#xff1f;这是怎么回事&#xff1f;下面小编给大家带来了有效的方法&#xff0c;希望可以帮助到大家。 方法如下&#xff1a; 首先&#xff0…