Linux 文件系统之虚拟文件系统

news2024/9/24 15:23:21

文章目录

  • 一、简介
  • 二、进程读写文件示例
  • 三、VFS高速缓存
  • 参考资料

一、简介

虚拟文件系统(Virtual File System,简称 VFS)是内核中的软件层,为用户空间程序提供文件系统接口。它还在内核中提供了一个抽象层,允许不同的文件系统实现共存。

VFS 系统调用,如 open()、stat()、read()、write()、chmod() 等,在进程上下文中被调用。

VFS 是内核中的一个重要组件,提供了统一的接口,使用户空间程序能够与各种不同的文件系统进行交互,而无需了解底层文件系统实现的具体细节。

当用户空间程序调用诸如 open()、stat()、read()、write()、chmod() 等系统调用时,这些调用是在用户进程的上下文中发起的。VFS 拦截这些系统调用,并将其转换为特定于所访问的文件系统的操作。它负责将请求路由到适当的文件系统驱动程序上,然后驱动程序在实际的文件系统上执行请求的操作。

VFS承载着各种文件系统的共有属性。
VFS只管理挂载到系统中的实际文件系统。
VFS给不同的文件系统提供一个通用的文件模块(比如系统调用sleek())。

通过提供一个通用的接口来与不同的文件系统交互,VFS 使应用程序能够访问和操作文件,而无需了解底层文件系统的类型或实现细节。这种抽象层简化了与文件系统相关的应用程序的开发,提供了更大的灵活性和可移植性。

VFS支持三种类型的文件系统:
(1)磁盘文件系统:ext 文件系统家族、XFS(eXtended File System)、Btrfs(B-Tree File System)等。
(2)网络文件系统:NFS(Network File System)等
(3)基于内存的特殊文件系统:procfs、sysyfs、tmpfs、ramfs等

如下图所示:
在这里插入图片描述

VFS中主要有四个类型对象:
struct super_block:超级块对象表示一个挂载的文件系统实例。每个挂载的文件系统都有一个对应的超级块对象,它包含了文件系统的元数据信息,如文件系统类型、挂载选项、设备信息等。超级块对象是文件系统在内核中的核心表示。
请参考:Linux文件系统 struct super_block 结构体解析

struct inode:索引节点对象表示文件或目录。每个文件或目录在文件系统中都有一个对应的索引节点对象。索引节点对象包含了文件或目录的元数据,如文件类型、访问权限、大小、指向数据块的指针等。它是文件系统中的关键概念,用于表示和管理文件和目录的属性和状态。
请参考:Linux文件系统 struct inode 结构体解析

struct file:文件对象表示一个打开的文件。当应用程序通过系统调用打开文件时,内核会创建一个文件对象来跟踪该文件的状态和位置信息。文件对象包含了文件的读写位置、访问模式、引用计数等。它允许内核管理打开的文件,并提供对文件的读写操作。
请参考:Linux文件系统 struct file 结构体解析

struct dentry:目录项对象表示文件系统中的目录项(即文件名)。每个文件或目录在文件系统中都有一个对应的目录项对象,它包含了文件名和与之关联的索引节点对象。目录项对象用于在文件系统中进行路径解析和文件查找操作。
请参考:Linux文件系统 struct dentry 结构体解析

其中super block对象和inode对象在存储介质中都是有实际映射的,即存储介质中也存在超级块和inode。但是由于不同类型的文件系统差异,超级块和inode的结构不尽相同。
如下图所示:
在这里插入图片描述
这是ext/2/3/4系列文件系统的格式,可以看到其磁盘数据结构就有super block结构体和inode结构体的描述。

而dentry对象和file对象没有对应的磁盘数据结构,比如VFS根据字符串形式的路径名在操作文件时在内存中创建dentry对象。
dentry对象和file对象这两种并非真正保存在磁盘上,所以这两个对象结构体没有是否被修改的标志,即是否为脏,是否需要写回磁盘的标志。

比如一个打开的文件file内容被修改,虽然file对象没有是否被修改的标志,但是其对应的inode对象有是否被修改的标志:

struct file {
	struct path		f_path;
}
struct path {
	struct dentry *dentry;
} __randomize_layout;
struct dentry {
	struct inode *d_inode;
}

二、进程读写文件示例

进程要想往文件系统里面读写数据,需要很多层的组件一起合作。
(1)在应用层,进程在进行文件读写操作时,可通过系统调用如 sys_open、sys_read、sys_write 等。
(2)在内核,每个进程都需要为打开的文件,维护一定的数据结构。
(3)在内核,整个系统打开的文件,也需要维护一定的数据结构。
(4)Linux 可以支持多达数十种不同的文件系统。它们的实现各不相同,因此 Linux 内核向用户空间提供了虚拟文件系统这个统一的接口,来对文件系统进行操作。它提供了常见的文件系统对象模型,例如 inode、directory entry、mount 等,以及操作这些对象的方法,例如 inode operations、directory operations、file operations 等。
(5)然后就是对接的是真正的文件系统,比如ext4 文件系统。
(6)为了读写 ext4 文件系统,要通过块设备 I/O 层,也即 BIO 层。这是文件系统层和块设备驱动的接口。
(7)为了加快块设备的读写效率,我们还有一个缓存层。
(8)最下层是块设备驱动程序。

如下图所示:
在这里插入图片描述
系统调用read的流程如下所示:

-->read()
	-->sys_read()
		-->vfs_read()
			-->file->f_op->read_iter()
				-->ext4_file_read_iter()
					-->generic_file_read_iter()

大部分文件系统(比如ext2/3/4,xfs,nfs等)的读取过程,都是将read_iter置为generic_file_read_iter来实现的。或者在read_iter中做一些简单的处理,然后再调用generic_file_read_iter。

对大部分文件系统来说,其实读取文件数据的流程相差无几。所以VFS提供了一些通用的文件操作函数。

而inode->i_fop是在初始化inode时,在ext4_iget中赋值为&ext4_file_operations,因此:

file->f_op->read_iter() = ext4_file_operations.ext4_file_read_iter()
const struct file_operations ext4_file_operations = {
	.read_iter	= ext4_file_read_iter,
}
-->ext4_iget()
	-->__ext4_iget()
	{
		struct inode *inode;
		inode->i_fop = &ext4_file_operations;
	}

图片来自:极客时间趣谈操作系统

在这里插入图片描述
图片来自:极客时间趣谈操作系统

三、VFS高速缓存

在虚拟文件系统(VFS)中,提供了三种高速缓存机制来提高文件系统的性能和效率。这些高速缓存机制包括:
(1)索引节点高速缓存(Inode Cache):
索引节点高速缓存是用于缓存文件系统中的索引节点对象(struct inode)的数据结构。
当应用程序访问文件时,内核会首先尝试从索引节点高速缓存中查找对应的索引节点对象,以避免频繁的磁盘访问和索引节点的重复创建。
索引节点高速缓存提高了文件系统的访问速度,减少了文件系统操作的开销。

(2)目录项高速缓存(Dentry Cache):
目录项高速缓存是用于缓存文件系统中的目录项对象(struct dentry)的数据结构。
目录项高速缓存存储了文件名和与之关联的索引节点对象的映射关系。
当应用程序通过路径访问文件时,内核会首先尝试从目录项高速缓存中查找对应的目录项对象,以加速路径解析和文件查找的过程。
目录项高速缓存提高了文件系统的路径解析速度和文件查找效率。

(3)页高速缓存(Page Cache):
页高速缓存用于缓存文件系统中的数据页(或称为文件页)。
当应用程序读取或写入文件时,内核会将文件的数据读取到页高速缓存中进行缓存,以便后续的读取和写入操作能够更快地访问数据。
页高速缓存提高了文件的读取和写入性能,减少了频繁的磁盘访问。

如下图所示:
在这里插入图片描述
图片来自于:极客时间Linux性能优化实战

这些高速缓存机制能够显著提升文件系统的性能,减少了与磁盘的交互次数,加快了文件的访问速度。通过缓存常用的索引节点、目录项和数据页,VFS 能够更高效地响应应用程序的文件操作请求,提供更好的用户体验。同时,这些高速缓存机制还遵循一定的缓存策略和管理机制,比如最近最少使用(LRU)等策略,以保证缓存的一致性和正确性。

需要注意的是,缓存机制引入了内存使用和性能之间的权衡。较大的缓存可以通过减少磁盘访问来提高性能,但也会消耗更多的内存资源。因此,可以根据系统的具体需求和可用资源来调整缓存行为和大小。

参考资料

https://zhuanlan.zhihu.com/p/268375848
https://www.thomas-krenn.com/en/wikiEN/images/8/83/Linux-storage-stack-diagram_v6.2.png
极客时间趣谈操作系统
极客时间Linux性能优化实战

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

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

相关文章

SQL 通用数据类型

SQL 通用数据类型 数据类型定义了存储在列中的值的类型。 SQL 通用数据类型 数据库表中的每一列都需要有一个名称和数据类型。 SQL 开发人员必须在创建 SQL 表时决定表中的每个列将要存储的数据的类型。数据类型是一个标签,是便于 SQL 了解每个列期望存储什么类型的…

[GKCTF 2021]easycms 禅知cms

一道类似于渗透的题目 记录一下 首先扫描获取 登入界面 admin/12345登入 来到了后台 然后我们开始测试有无漏洞点 1.文件下载 设计 自定义 导出 然后进行抓包 解密后面的内容 发现是绝对路径了 所以这里我们要获取 flag 就/flag即可 L2ZsYWc /admin.php?mui&fdownlo…

linux的使用学习(1)

Linux 修改root密码 1.以 root 用户或具有 sudo 权限的登录到 Linux 系统。 2.打终端,并执行以下命令以更改 root 用户的密码: sudo passwd root 3.然后,系统会要求你输入新的 root 密码。请注意,在输入密码时,终端界…

图、深度优先(DFS)、广度优先(BFS)

图 基本介绍 表示方式 图的创建 from typing import Listclass Graph:vertex_list: List[str] [] # 存储顶点的数组edges: List[list] [] # 存储图中各条边的邻接矩阵num_edges: int 0 # 边的数总数def __init__(self, n: int):"""根据传入的顶点个数初始…

11、插件注入到vue实例中

新建插件 nuxt-demo2\plugins\vue-inject.js import Vue from "vue"Vue.prototype.$test function (str) {console.log(str) }配置插件 nuxt-demo2\nuxt.config.js export default {...// Plugins to run before rendering page: https://go.nuxtjs.dev/config-…

表格识别软件:科技革新引领行业先锋,颠覆性发展前景广阔

表格识别软件的兴起背景可以追溯到数字化和自动化处理的需求不断增加的时期。传统上,手动处理纸质表格是一项费时费力的工作,容易出现错误,效率低下。因此,开发出能够自动识别和提取表格数据的软件工具变得非常重要。 随着计算机…

Xcode运行程序提示 Executable Path is a Directory 问题解决

一、首先运行模拟器报错(没有记录),解决办法: TARGET->Build Settings->Architectures -> Exclude Architectures里面填入arm64,后运行模拟器成功 二、其次模拟器开发完成后,xcode运行真机调试&…

canvas:理解canvas / 基础使用 / Demo效果

一、理解Canvas Canvas是一个HTML5元素,用于在Web页面上绘制2D或3D图形。它允许使用JavaScript在网页上创建和操作图形。Canvas的主要功能是绘图,但也可以用来实现其他功能,如动画和交互式游戏。 使用Canvas,可以创建各种形状、…

【AOP进阶】实现重试机制

📚目录 ⚙️简介:✨注解定义:⛳RetryMechanism ⌛编写AOP代码:⚓RetryMechanismAspect 切面 ⛵演示:⛴如何使用RetryMechanism:⚡️正常请求如下:☘️测试异常并且重试:☄️测试异常…

WSL2 Ubuntu安装CUDA Toolkit

目前CUDA ToolKit需要切换到WSL2,在WLS1下不支持。之前折腾了很久,才从WSL1的坑中爬出来,仅写此文避免大家再从坑里走一次。 Windows WSL2相关 检查正在运行的 WSL 版本 可列出已安装的 Linux 发行版,并通过在 PowerShell 或 W…

Android NDK开发详解之ndk-gdb

Android NDK开发详解之ndk-gdb 要求用法选项 线程支持 NDK 包含一个名为 ndk-gdb 的 Shell 脚本,可以启动命令行原生调试会话。偏好使用 GUI 的用户则应阅读在 Android Studio 中调试这篇文档。 要求 要运行命令行原生调试,必须满足以下要求&#xff1…

SDK 消息处理

目录 消息处理 窗口通知消息处理 鼠标消息 键盘消息 绘图消息 WM_PAINT 客户区与非客户区 WM_PAINT消息 BeginPaint && EndPaint 模仿记事本输入字符功能 定时器 消息处理 窗口的过程函数接收到消息后并且进行处理。平时常用的消息以及官方参考文档&#xf…

“ 1+2+N “打造“北斗+智慧城市”,让城市生活更美好

10月31日是世界城市日。世界城市日是联合国首个以城市为主题的国际日,也是第一个由中国政府倡议并成功设立的国际日,出自2010年10月31日上海世博会高峰论坛上发布的《上海宣言》中的倡议。世界城市日秉承了中国2010年上海世博会“城市,让生活…

前端知识与基础应用#2

标签的分类 关于标签我们可以分为 : 单标签:img, br hr 双标签:a,h,div 按照属性可分为: 块儿标签(自己独自占一行):h1-h6, p,div 行内(内联)标签&#xff08…

【1】C语言实现顺序表

文章目录 Ⅰ 概念及结构1. 静态顺序表2. 动态顺序表 Ⅱ 基本操作实现1. 定义顺序表2. 初始化顺序表3. 销毁顺序表4. 输出顺序表5. 扩容顺序表6. 尾插法插入数据7. 头插法插入数据8. 尾删法删除数据9. 头删法删除数据10. 顺序表查找11. 在指定位置 pos 插入数据12. 删除指定位置…

【算法】动态规划之LeetCode 53.最大子数组和

目录 文章目录 **目录**📑前言1.题目描述2. 动态规划法 📑文章末尾 📑前言 本文主要是leetcode题解析,如果有什么需要改进的地方还请大佬指出⛺️ 🎬作者简介:大家好,我是青衿🥇 ☁…

联想方案服务斩获CCF技术发明奖,助力云原生技术发展

10月27日,中国计算机学会(CCF)公布了我国计算机科技领域最具权威性的科技奖项——2023年度“CCF科技成果奖”评选结果,共有41个项目荣获2023年度CCF科技成果奖。由联想集团与上海交通大学等共同研究开发的《面向互联网服务的云原生…

【机器学习合集】模型设计之网络宽度和深度设计 ->(个人学习记录笔记)

文章目录 网络宽度和深度设计1. 什么是网络深度1.1 为什么需要更深的模型浅层学习的缺陷深度网络更好拟合特征学习更加简单 2. 基于深度的模型设计2.1 AlexNet2.2 AlexNet工程技巧2.3 VGGNet 3. 什么是网络宽度3.1 为什么需要足够的宽度 4. 基于宽度模型的设计4.1 经典模型的宽…

错误 LNK1112 模块计算机类型“x64”与目标计算机类型“X86”冲突

这个错误表明你在进行链接时,模块的计算机类型与目标计算机类型冲突。 在这里,“x64”代表64位系统,“X86”代表32位系统。 要解决这个问题,你需要确保你的所有模块(包括库文件和依赖项)都是与你的目标计…

《算法通关村—队列基本特征和实现问题解析》

《算法通关村—队列基本特征和实现问题解析》 队列的基本特征 队列(Queue)是一种常见的数据结构,具有以下基本特征: 先进先出(FIFO):队列中的元素按照它们被添加到队列的顺序排列,…