虚拟文件系统

简介: Linux内核中的虚拟文件系统用来管理挂接各种具体文件系统。具体的文件系统可设计成可加载模块,在系统需要时进行加载。 挂载具体文件系统时,VFS读取它的超级块,得到具体文件系统的拓扑结构,并将这些信息映射到VFS超级块结构中。

Linux内核中的虚拟文件系统用来管理挂接各种具体文件系统。具体的文件系统可设计成可加载模块,在系统需要时进行加载。

挂载具体文件系统时,VFS读取它的超级块,得到具体文件系统的拓扑结构,并将这些信息映射到VFS超级块结构中。

当进程或shell命令访问目录和文件时,shell命令及应用程序分解成系统调用,系统调用进入内核空间,遍历虚拟文件系统的VFS节点(inode),而VFS节点指向了具体文件系统的节点。通过底层块I/O函数调用IDE接口,再通过块驱动程序访问块设备(如硬盘),得到文件数据。文件系统的运行流程如图所示。

 

1 VFS的超级块、dentry和节点结构

Linux的目录和文件实际上都是一种文件,目录应称为目录文件,一个目录文件就是一个目录项的列表,其中的每一个目录项都有一个数据结构来描述。每个目录的头两项总是标准目录项“.”和“..”,分别指向目录、父目录的inode。

VFS超级块

VFS超级块是在这些文件系统中描整个文件系统信息的全局数据结构。VFS超级块是各种逻辑文件系统在安装时建立,并在这些文件系统卸载时自动删除。可见,VFS超级块确实只存在于内存中。

超级块结构super_block列出如下:

 

dentry

为保持从目录访问inode的高效率,Linux维护了表达路径与inode对应的关系的dentry结构。dentry结构描述了路径信息并链接到结点inode。每个文件有一个dentry结构,被文件系统使用过的目录将会存入dentry结构中。这样,同一目录被再次访问时,可直接从dentry中得到,不必重复访问存储文件系统的设备。

dentry结构列出如下:

 

inode

VFS中的每个文件、目录文件等都有惟一的VFS inode表示。每个VFS inode中的信息通过文件系统从实际文件系统中得到。

结构inode列出如下:

 

2 与进程联系的文件系统相关结构

进程是通过文件描述符而不是文件名来访问文件的,文件描述符实际上是一个整数,规定每个进程最多能同时使用NR_OPEN个文件描述符,这个值在fs.h中定义为256.每个进程用一个file_struct的结构来记录文件描述符的使用情况,它是进程的私有数据。

每个文件都有一个32位的整数来表示下一个读写的字节位置,即文件位置。每次打开一个文件,默认是从文件的开始处操作,可以通过系统调用lseek对这个文件位置进行修改。

在进程的task_struct中的文件系统相关的数据成员,列出如下:

 

结构fs_struct给出了文件系统信息,列出如下:

 

结构files_struct是用户打开文件描述符表,它给出了文件描述符的使用情况,其file结构成员给出了每个文件描述符的信息,结构files_struct分析如下:

 

结构files_struct中成员fd_array主要是一个256项的file结构数组,数组的下标是文件描述符,而其内容就是对应的file结构。在一个进程启动后,文件描述符0,1,2,已经被分配并可供使用:0表示标准输入设备,1表示标准输出设备,2表示标准错误输出设备。所以,能使用的第一个文件描述符是3.

结构file保存打开文件的信息,通过文件描述符查找文件描述符数组fd_arrayfile可得到file结构。结构file分析如下:

 

3 系统有关操作函数集的结构

VFS毕竟是虚拟的,它无法 设计具体文件系统的细节,所以,必须在VFS和具体结构文件系统之间有一些接口。VFS的数据结构就好像是一个标准,具体文件系统要想被Linux支持,就必须提供VFS标准应具有的结构及操作函数。实际上,具体文件系统在使用前,必须将自己的结构及操作函数映射到VFS中,这样才能被访问到。

super_operatirons

结构super_operations是对文件系统超级块进行操作的函数集。这个结构分析如下:

 

inode_operations

结构inode_operations定义了节点的操作函数集,分析如下:

file_operations

结构file_operations中存有对文件进行操作的函数,这个结构分析如下:

4 文件系统的各种缓存

Linux能支持多种文件系统并且保持很高的性能,这是因为文件系统有各种各种的缓存,组织成了各种hash表,有效地提高了访问速度。文件系统使用的各种缓存如下:

 

块缓存buffer

为加速对物理设备的访问,Linux维护一组缓冲区,用做对块设备上的数据的块缓存。需要使用块设备上的数据时,系统把数据块调入块缓存中。下次再访问该数据块时,不必访问物理设备了。常用的数据块会一直留在块缓存中,这样减少了访问设备的时间。

Linux以struct buffer_head规定的数据格式封装缓存。buffer_head结构对块缓存进行管理,多个块缓存组成了块缓存页,每页中的块缓存buffer_head结构形成了一个环形链表,页的私有数据指针指向这个环形链表的头部。

结构buffer_head包含了用于描述缓冲区内容的信息,例如,所在设备号,起始物理块号,包含在缓冲区的字节数,还包含了缓冲区状态,例如,是否有用数据,是否正在使用,重新利用之前是否要写回磁盘等。

结构buffer_head分析如下:

 

块缓存独立于任何类型的文件系统。文件系统中凡涉及磁盘读写,几乎都要通过块缓存;有些甚至直接利用缓冲区缓存保存信息。

每个块缓存由两部分组成:第一部分称为块缓存首部,用数据结构buffer_head表示;第二部分是块缓存数据区,结构buffer_head与块缓存数据分别存储,结构buffer_head用b_page来指明数据区所在的页,b_size表示数据的大小。

 

相关文章
|
小程序
微信小程序根据日期和时间进行排序
最近接手了一个小程序的项目,有这样一个需求要对列表进行日期和时间的排序,于是小试牛刀,操作了一番,终于搞出来,在这里给大家总结分享一下经验,希望对大家有一定的帮助
1074 0
|
Linux Shell Windows
通过Linux挂载Windows端NFS服务实现板端Linux传输文件到PC
通过Linux挂载Windows端NFS服务实现板端Linux传输文件到PC
1406 0
|
4月前
|
存储 人工智能 并行计算
别再搞混了!一文看懂“显存”与“内存”:从办公桌到实验室的硬核分工
本文以生动比喻与硬核解析,深入浅出地讲清内存(RAM)与显存(VRAM)的本质区别:内存是CPU的通用工作台,显存是GPU的专用高速实验室。二者分工明确,数据需通过PCIe传输,无法互相替代。尤其在AI训练中,显存容量与带宽直接决定模型能否运行。文章结合代码实例、性能对比表及排错指南,帮助开发者理解“CUDA out of memory”等常见问题,并提供优化策略与云平台建议,是迈向高效AI开发的必读指南。
3032 0
|
JSON Java API
优雅地进行全局异常处理、统一返回值封装、自定义异常错误码——Graceful-Response推荐
Graceful Response是一个Spring Boot体系下的优雅响应处理器,提供一站式统一返回值封装、全局异常处理、自定义异常错误码等功能,使用Graceful Response进行web接口开发不仅可以节省大量的时间,还可以提高代码质量,使代码逻辑更清晰。
635 0
|
存储 缓存 网络协议
第五问:一个程序从点击到启动发生了什么?
一个可执行程序从用户点击启动到运行,经历了8个主要阶段:用户触发启动、操作系统查找文件、进程创建、可执行文件加载到内存、初始化程序上下文、执行程序入口点、程序运行和程序退出。涉及硬盘、内存、缓存等硬件交互。
|
数据采集 JSON API
.NET 3.5 中 HttpWebRequest 的核心用法及应用
【9月更文挑战第7天】在.NET 3.5环境下,HttpWebRequest 类是处理HTTP请求的一个核心组件,它封装了HTTP协议的细节,使得开发者可以方便地发送HTTP请求并接收响应。本文将详细介绍HttpWebRequest的核心用法及其实战应用。
838 6
|
JavaScript
Vue学习之--------插槽【默认插槽、具名插槽、作用域插槽】
这篇文章详细介绍了Vue.js中的插槽概念,包括默认插槽、具名插槽和作用域插槽的使用方式和实际应用示例,通过代码演示了如何在组件中定义和使用插槽来实现内容的灵活替换和展示。
Vue学习之--------插槽【默认插槽、具名插槽、作用域插槽】
|
存储 IDE 编译器
C++从入门到精通:1.3.1了解IDE与C++程序的编写、编译和运行
C++从入门到精通:1.3.1了解IDE与C++程序的编写、编译和运行
330 0
|
存储 缓存 算法
Python缓存神器cachetools:提高程序性能的利器,一文详解其缓存算法
Python缓存神器cachetools:提高程序性能的利器,一文详解其缓存算法
Python缓存神器cachetools:提高程序性能的利器,一文详解其缓存算法

热门文章

最新文章