深入理解Linux内核--虚拟文件

news2024/11/26 16:36:26

虚拟文件系统(VFS)的作用

虚拟文件系统(Virtual Filesystem)也可以称之为虚拟文件系统转换(Virtual Filesystem Switch,VFS),
是一个内核软件层,
用来处理与Unix标准文件系统相关的所有系统调用。
其健壮性表现在能为各种文件系统提供一个通用的接口。

在这里插入图片描述

VFS支持的文件系统可以划分为三种主要类型:
1.磁盘文件系统
这些文件系统管理在本地磁盘分区中可用的存储空间
或者其他可以起到磁盘作用的设备(比如说一个USB闪存)。
VFS支持的基于磁盘的某些著名文件系统还有:

在这里插入图片描述
在这里插入图片描述

2.网络文件系统
这些文件系统允许轻易地访问属于其他网络计算机的文件系统所包含的文件。
虚拟文件系统所支持的一些著名的网络文件系统有:
NFS、Coda、AFS(Andrew文件系统)、
CIFS(用于Microsoft Windows的通用网络文件系统)
以及NCP(Novell 公司的NetWare Core Protocol)。
3.特殊文件系统
这些文件系统不管理本地或者远程磁盘空间。
/proc文件系统是特殊文件系统的一个典型范例(参见稍后“特殊文件系统“一节)。

根目录包含在根文件系统(root filesystem)中,
在Linux中这个根文件系统通常就是Ext2或Ext3类型。
其他所有的文件系统都可以被“安装“在根文件系统的子目录中

基于磁盘的文件系统通常存放在硬件块设备中,
如硬盘、软盘或者CD-ROM。
Linux VFS 的一个有用特点是能够处理如/dev/loop0这样的虚拟块设备,
这种设备可以用来安装普通文件所在的文件系统。
作为一种可能的应用,用户可以保护自己的私有文件系统,
这可以通过把自己文件系统的加密版本存放在一个普通文件中来实现。

通用文件模型

VFS所隐含的主要思想在于引入了一个通用的文件模型(common file model),
这个模型能够表示所有支持的文件系统。
该模型严格反映传统Unix文件系统提供的文件模型。
这并不奇怪,因为Linux希望以最小的额外开销运行它的本地文件系统。
不过,要实现每个具体的文件系统,
必须将其物理组织结构转换为虚拟文件系统的通用文件模型。

例如,在通用文件模型中,每个目录被看作一个文件,
可以包含若干文件和其他的子目录。
但是,存在几个非Unix的基于磁盘的文件系统,
它们利用文件分配表(File Allocation Table,FAT)存放每个文件在目录树中的位置,
在这些文件系统中,存放的是目录而不是文件。
为了符合VFS的通用文件模型,
对上述基于FAT的文件系统的实现,
Linux必须在必要时能够快速建立对应于目录的文件。
这样的文件只作为内核内存的对象而存在。

从本质上说,
Linux内核不能对一个特定的函数进行硬编码来执行诸如read()或ioct1()这样的操作,
而是对每个操作都必须使用一个指针,指向要访问的具体文件系统的适当函数。
为了进一步说明这一概念,
参见图12-1,其中显示了内核如何把read()转换为专对MS-DOS文件系统的一个调用。
应用程序对read()的调用引起内核调用相应的sys_read()服务例程,
这与其他系统调用完全类似。
我们在本章后面会看到,
文件在内核内存中是由一个file数据结构来表示的。
这种数据结构中包含一个称为f_op的字段,
该字段中包含一个指向专对MS-DOS文件的函数指针,
当然还包括读文件的函数。
sys_read()查找到指向该函数的指针,并调用它。
这样一来,应用程序的read()就被转化为相对间接的调用:
file->f_op->read(...);
与之类似,write()操作也会引发一个与输出文件相关的Ext2写函数的执行。
简而言之,内核负责把一组合适的指针分配给与每个打开文件相关的file变量,
然后负责调用针对每个具体文件系统的函数(由f_op字段指向)。

在这里插入图片描述
在这里插入图片描述

如图12-2所示是一个简单的示例,说明进程怎样与文件进行交互。
三个不同进程已经打开同一个文件,
其中两个进程使用同一个硬链接。
在这种情况下,其中的每个进程都使用自己的文件对象,
但只需要两个目录项对象,
每个硬链接对应一个目录项对象。
这两个目录项对象指向同一个索引节点对象,
该索引节点对象标识超级块对象,以及随后的普通磁盘文件。

在这里插入图片描述

VFS除了能为所有文件系统的实现提供一个通用接口外,
还具有另一个与系统性能相关的重要作用。
最近最常使用的目录项对象被放在所谓目录项高速缓存(dentrycache)的磁盘高速缓存中,
以加速从文件路径名到最后一个路径分量的索引节点的转换过程。

一般说来,磁盘高速缓存(diskcache)属于软件机制,
它允许内核将原本存在磁盘上的某些信息保存在RAM中,
以便对这些数据的进一步访问能快速进行,而不必慢速访问磁盘本身。

注意,磁盘高速缓存不同于硬件高速缓存或内存高速缓存,
后两者都与磁盘或其他设备无关。
硬件高速缓存是一个快速静态RAM,
它加快了直接对慢速动态RAM的请求(参见第二章中的“硬件高速缓存”一节)。
内存高速缓存是一种软件机制,
引入它是为了绕过内核内存分配器(参见第八章中的“slab分配器”一节)。

除了目录项高速缓存和索引结点高速缓存之外,
Linux还使用其他磁盘高速缓存。
其中最重要的一种就是所谓的页高速缓存,我们将在第十五章中进行详细介绍。

VFS所处理的系统调用

表12-1列出了VFS的系统调用,
这些系统调用涉及文件系统、普通文件、目录文件以及符号链接文件。
另外还有少数几个由VFS处理的其他系统调用,
诸如ioperm()、ioct1()、pipe()和mknod(),涉及设备文件和管道文件,
这些将在后续章节中讨论。
最后一组由VFS处理的系统调用,
诸如socket()、connect()和bind()属于套接字系统调用,
并用于实现网络功能。
与表12-1列出的系统调用对应的一些内核服务例程,
我们会在本章或第十八章中陆续进行讨论。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

前面我们已经提到,
VFS是应用程序和具体文件系统之间的一层。
不过,在某些情况下,一个文件操作可能由VFS本身去执行,无需调用低层函数。
例如,当某个进程关闭一个打开的文件时,并不需要涉及磁盘上的相应文件,
因此VFS只需释放对应的文件对象。
类似地,当系统调用lseek()修改一个文件指针,
而这个文件指针是打开文件与进程交互所涉及的一个属性时,
VFS就只需修改对应的文件对象,而不必访问磁盘上的文件,
因此,无需调用具体文件系统的函数。
从某种意义上说,
可以把VFS看成“通用“文件系统,它在必要时依赖某种具体文件系统。

VFS的数据结构

每个VFS对象都存放在一个适当的数据结构中,
其中包括对象的属性和指向对象方法表的指针。
内核可以动态地修改对象的方法,
因此可以为对象建立专用的行为。下面几节详细介绍VFS的对象及其内在关系。

超级块对象

超级块对象由super_block结构组成,表12-2列举了其中的字段。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

所有超级块对象都以双向循环链表的形式链接在一起。
链表中第一个元素用super_blocks变量来表示,
而超级块对象的s_list字段存放指向链表相邻元素的指针。
sb_lock自旋锁保护链表免受多处理器系统上的同时访问。

s_fs_info字段指向属于具体文件系统的超级块信息;
例如,我们在第十八章将会看到,
假如超级块对象指的是Ext2文件系统,
该字段就指向ext2_sb_info数据结构,
该结构包括磁盘分配位掩码和其他与VFS的通用文件模型无关的数据。
通常,为了效率起见,由s_fs_info字段所指向的数据被复制到内存。
任何基于磁盘的文件系统都需要访问和更改自己的磁盘分配位图,
以便分配或释放磁盘块。
VFS允许这些文件系统直接对内存超级块的s_fs_info字段进行操作,
而无需访问磁盘。

但是,这种方法带来一个新问题:
有可能VFS超级块最终不再与磁盘上相应的超级块同步。
因此,有必要引入一个s_dirt标志来表示该超级块是否是脏的
——那磁盘上的数据是否必须要更新。
缺乏同步还会导致产生我们熟悉的一个问题:
当一台机器的电源突然断开而用户来不及正常关闭系统时,
就会出现文件系统崩溃。
我们将会在第十五章的“把脏页写入磁盘“一节中看到,
Linux是通过周期性地将所有“脏“的超级块写回磁盘来减少该问题带来的危害。

与超级块关联的方法就是所谓的超级块操作。
这些操作是由数据结构super_operations 来描述的,
该结构的起始地址存放在超级块的s_op字段中。
每个具体的文件系统都可以定义自己的超级块操作。
当VFS需要调用其中一个操作时,比如说read_inode(),
它执行下列操作:
sb->s_op->read_inode(inode);
这里sb存放所涉及超级块对象的地址。
super_operations表的read_inode字段存放这一函数的地址,
因此,这一函数被直接调用。
让我们简要描述一下超级块操作,
其中实现了一些高级操作,
比如删除文件或安装磁盘。
下面这些操作按照它们在super_operation表中出现的顺序来排列:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

前述的方法对所有可能的文件系统类型均是可用的。
但是,只有其中的一个子集应用到每个具体的文件系统;
未实现的方法对应的字段置为NULL。
注意,系统没有定义get_super方法来读超级块,
那么,内核如何能够调用一个对象的方法而从磁盘读出该对象?
我们将在描述文件系统类型的另一个对象中找到等价的get_sb方法
(参见后面的“文件系统类型注册“一节)。

索引节点对象

文件系统处理文件所需要的所有信息都放在一个名为索引节点的数据结构中。
文件名可以随时更改,但是索引节点对文件是唯一的,
并且随文件的存在而存在。
内存中的索引节点对象由一个inode数据结构组成,其字段如表12-3所示。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

每个索引节点对象都会复制磁盘索引节点包含的一些数据,
比如分配给文件的磁盘块数。
如果i_state字段的值等于I_DIRTY_SYNC、I_DIRTY_DATASYNC或I_DIRTY_PAGES,该索引节点就是“脏“的,
也就是说,对应的磁盘索引节点必须被更新。
I_DIRTY宏可以用来立即检查这三个标志的值(详细内容参见后面)。
i_state字段的其他值有I_LOCK(涉及的索引节点对象处于I/O传送中)、I_FREEING(索引节点对象正在被释放)、
I_CLEAR(索引节点对象的内容不再有意义)以及I_NEW(索引节点对象已经分配但还没有用从磁盘索引节点读取来的数据填充)。

每个索引节点对象总是出现在下列双向循环链表的某个链表中(所有情况下,指向相邻元素的指针存放在i_list字段中):
1.有效未使用的索引节点链表,
典型的如那些镜像有效的磁盘索引节点,且当前未被任何进程使用。
这些索引节点不为脏,且它们的i_count字段置为0。
链表中的首元素和尾元素是由变量inode_unused的next字段和prev字段分别指向的。
这个链表用作磁盘高速缓存。
2.正在使用的索引节点链表,也就是那些镜像有效的磁盘索引节点,
且当前被某些进程使用。
这些索引节点不为脏,但它们的i_count字段为正数。
链表中的首元素和尾元素是由变量inode_in_use引用的。
3.脏索引节点的链表。
链表中的首元素和尾元素是由相应超级块对象的s_dirty字段引用的。
这些链表都是通过适当的索引节点对象的i_list字段链接在一起的。

此外,每个索引节点对象也包含在每文件系统(per-filesystem)的双向循环链表中,
链表的头存放在超级块对象的s_inodes字段中;
索引节点对象的i_sb_list字段存放了指向链表相邻元素的指针。

最后,索引节点对象也存放在一个称为inode_hashtable的散列表中。
散列表加快了对索引节点对象的搜索,
前提是系统内核要知道索引节点号及文件所在文件系统对应的超级块对象的地址。
由于散列技术可能引发冲突,
所以索引节点对象包含一个i_hash字段,
该字段中包含向前和向后的两个指针,
分别指向散列到同一地址的前一个索引节点和后一个索引节点;
该字段因此创建了由这些索引节点组成的一个双向链表。

与索引节点对象关联的方法也叫索引节点操作。
它们由inode_operations结构来描述,该结构的地址存放在i_op字段中。
以下是索引节点的操作,以它们在inode_operations表中出现的次序来排列:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

上述列举的方法对所有可能的索引节点和文件系统类型都是可用的。
不过,只有其中的一个子集应用到某一特定的索引节点和文件系统;
未实现的方法对应的字段被置为NULL。

文件对象

文件对象描述进程怎样与一个打开的文件进行交互。
文件对象是在文件被打开时创建的,由一个file结构组成,
其中包含的字段如表12-4所示。
注意,文件对象在磁盘上没有对应的映像,因此file结构中没有设置“脏“字段来表示文件对象是否已被修改。

在这里插入图片描述
在这里插入图片描述

存放在文件对象中的主要信息是文件指针,
即文件中当前的位置,下一个操作将在该位置发生。
由于几个进程可能同时访问同一文件,因此文件指针必须存放在文件对象而不是索引节点对象中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/867562.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

mybatis-plus逻辑删除的坑

一旦在逻辑字段上加了TableLogic逻辑删除的配置,并且使用mybatis-plus自带的方法时(如果自己用xml写SQL不会出现下面的情况) 查询、修改时会自动排除逻辑删除的数据 当使用mybatis-plus自带的查询方法时,就不用每次查询的时候跟…

软件外包开发的桌面客户端开发

跨平台桌面客户端开发工具允许开发者在多个操作系统上构建应用程序,从而实现一次编码、多平台运行的目标。以下是几个常见的跨平台桌面客户端开发工具以及它们的特点,希望对大家有所帮助。北京木奇移动技术有限公司,专业的软件外包开发公司&a…

AcWing算法提高课-4.2.3一个简单的整数问题2

宣传一下算法提高课整理 <— CSDN个人主页&#xff1a;更好的阅读体验 <— 本题链接&#xff08;AcWing&#xff09; 点这里 题目描述 给定一个长度为 N N N 的数列 A A A&#xff0c;以及 M M M 条指令&#xff0c;每条指令可能是以下两种之一&#xff1a; C l r…

C语言案例 字符串反转-13

题目&#xff1a;将字符串“general-zod”返转为“doz-lareneg” 程序分析 这里是将一个字符串进行反转&#xff0c;字符串是根据下标进行输出的&#xff0c;我们可以使用for循环将下标反向输出字符串即可。 步骤一&#xff1a;定义程序目标 编写C程序&#xff0c;将字符串“g…

架构设计第八讲:架构 - 理解架构的模式2 (重点)

架构设计第八讲&#xff1a;架构 - 理解架构的模式2 (重点) 本文是架构设计第8讲&#xff1a;架构 - 理解架构的模式2&#xff0c;整理自朱晔的互联网架构实践心得, 他是结合了 微软给出的云架构的一些模式的基础上加入他自己的理解来总结互联网架构中具体的一些模式。我在此基…

【pinia】解决pinia报hasInjectionContext问题:

文章目录 一、问题:二、分析:三、解决: 一、问题: 二、分析: 三、解决: npm i pinia2.0.36

ACL2023:成分对比学习生成句子嵌入表示

title:Composition-contrastive Learning for Sentence Embeddings 很多基于对比学习的方法用在无监督语料中&#xff0c;通过最大化对齐同一句子的最小扰动&#xff0c;并且鼓励向量在广泛文本语料中的均匀分布。本文方法提出最大化文本与其短语成分的组合之间的对齐。 …

带你深入浅出SQL优化器原理

起源 1979年&#xff0c;第一款基于 SQL 的商业关系型数据库管理系统 Oracle V2 问世&#xff0c;也标志着第一款商用的 SQL 优化器诞生。理论上&#xff0c;成熟的优化器原型&#xff0c;更早可以追溯到 IBM 的 System-R 项目。现今&#xff0c;很多开源数据库和大数据优化器…

C++:模拟实现vector以及vector的迭代器失效和拷贝问题

文章目录 实现的功能模拟实现迭代器失效隐含浅拷贝问题 实现的功能 模拟实现 由于前面实现了string&#xff0c;因此这里实现过程不为重点&#xff0c;重点为关于迭代器失效和拷贝问题 template <class T> class vector { public:typedef T* iterator;typedef const T*…

【EM算法推导】

# 一、必备的基础知识 EM算法用到了大量的概率论与数理统计的知识&#xff0c;必须对基础有一定掌握才能完成EM算法的推导。 ## 1.1 最大似然估计 思想&#xff1a;我们观测到了一组样本&#xff0c;为什么我们能观测到这一组样本呢&#xff1f;因为这一组样本出现的概率比较大…

第十九章 重要HL7操作场景

文章目录 第十九章 重要HL7操作场景HL7确认(ACK)模式HL7双确认序列 第十九章 重要HL7操作场景 本章描述了一些影响选择配置设置的关键HL7场景。 HL7确认(ACK)模式 HL7确认(ACK)消息确认目的地已收到HL7消息。负ACK (NACK)消息承认目的地知道传输&#xff0c;但没有捕获该消息…

凭借这份python面试宝典,我成功拿到了字节跳动、腾讯、阿里巴巴等六家大厂offer!

前言 2023年&#xff0c;全新的一年开始&#xff0c;新一轮金三银四即将来临&#xff0c;可能还有很多python程序员还有准备转行python的朋友没有拿到理想的offer&#xff0c;而拿到大厂的offer一直是程序员朋友的一个目标&#xff0c;今天给大家分享我拿到大厂offer的利器&am…

计算机组成原理-笔记-第七章

目录 七、第七章——输入输出系统 1、IO设备与IO控制方式 &#xff08;1&#xff09;控制方式&#xff08;查询&#xff0c;中断&#xff0c;DMA&#xff09; &#xff08;2&#xff09;通道控制 &#xff08;3&#xff09;IO系统 &#xff08;4&#xff09;总结 2、外设…

【学习日记】【FreeRTOS】手动任务切换详解

前言 本文是关于 FreeRTOS 中实现两个任务轮流切换并执行的代码详解。目前不支持优先级&#xff0c;仅实现两个任务轮流切换。 一、任务的自传 任务从生到死的过程究竟是怎么样的呢&#xff1f;&#xff08;其实也没死&#xff09;&#xff0c;这个问题一直困扰着我&#xf…

Similarities:精准相似度计算与语义匹配搜索工具包,多维度实现多种算法,覆盖文本、图像等领域,支持文搜、图搜文、图搜图匹配搜索

Similarities&#xff1a;精准相似度计算与语义匹配搜索工具包&#xff0c;多维度实现多种算法&#xff0c;覆盖文本、图像等领域&#xff0c;支持文搜、图搜文、图搜图匹配搜索 Similarities 相似度计算、语义匹配搜索工具包&#xff0c;实现了多种相似度计算、匹配搜索算法&…

QT创建项目

可选择CMake或qmake

港科夜闻|香港科大(广州)熊辉教授、李佳教授分别荣获 ACM SIGKDD2023 服务奖与最佳论文奖(研究)...

关注并星标 每周阅读港科夜闻 建立新视野 开启新思维 1、香港科大(广州)熊辉教授、李佳教授分别荣获 ACM SIGKDD2023 服务奖与最佳论文奖(研究)。第29届SIGKDD会议于2023年8月6日至10日在美国加州长滩举行。该会议是由ACM数据挖掘及知识发现专委会主办的数据挖掘研究领域顶级年…

面试热题(数组中的第K个最大元素)

给定整数数组 nums 和整数 k&#xff0c;请返回数组中第 k 个最大的元素。 请注意&#xff0c;你需要找的是数组排序后的第 k 个最大的元素&#xff0c;而不是第 k 个不同的元素。 输入: [3,2,1,5,6,4] 和 k 2 输出: 5提到数组中最大元素&#xff0c;我们往往想到就是先给数组…

云原生网关API标准背景及发展现状

Gateway API是一个开源的API标准&#xff0c;源自Kubernetes SIG-NETWORK兴趣组。从出身角度讲&#xff0c;可谓根正苗红&#xff0c;自从开源以来备受关注&#xff0c;被寄予厚望。Gateway API旨在通过声明式、可扩展性和面向角色的接口来发展Kubernetes服务网络&#xff0c;并…

Python教程(7)——一文弄懂Python字符串操作(上)|字符串查找|字符串分割|字符串拼接|字符串替换

Python字符串操作 字符串简介字符串查找使用 in 关键字使用 find() 方法使用 index() 方法使用正则表达式 字符串替换使用 replace() 方法使用正则表达式使用字符串模板 字符串分割字符串拼接使用加号 () 运算符使用字符串的格式化方法使用 f-string&#xff08;格式化字符串&a…