《Linux 内核设计与实现》13. 虚拟文件系统

news2024/11/19 5:50:27

通用文件接口

VFS 使得可以直接使用 open()、read()、write() 这样的系统调用而无需考虑具体文件系统和实际物理介质。

好处:新的文件系统和新类型的存储介质需要挂载时,程序无需重写,甚至无需重新编译。

VFS 将各种不同的文件系统抽象后采用统一的方式进行操作。

image-20230427193920113

文件系统抽象层

可以使用这种通用接口对所有类型的文件系统进行操作,是因为内核在它的底层文件系统接口上建立了一个抽象层。

为了支持多文件系统,VFS 提供了一个通用文件系统模型,该模型囊括了任何文件系统的常用功能集和行为。

VFS 抽象层之所以能衔接各种各样的文件系统,是因为它定义了所有文件系统都支持的、基本的、概念上的接口和数据结构。

文件系统需要和 VFS 所定义的概念保持一致(其实就是规则、约束)。文件系统提供 VFS 所期望的抽象接口和数据结构,这样内核就可以和任何文件系统协同工作。

在内核中,在文件系统之外的其它部分,并不需要了解其文件系统内部细节:

ret = write(fd, buf, len); // 系统调用
// 其具体实现:sys_write

系统调用是通用 VFS 接口,提供给用户使用。系统调用的具体实现由文件系统中的具体文件实现,实现的是 VFS 所需要的 sys_write() 方法。

image-20230427193850774

Unix 文件系统

  • 目录是特殊的文件,即目录文件。
  • 根目录:/
  • 文件相关的信息,乘作为文件的元数据,这些元数据被存储到 inode 结构体中。
  • 文件系统的相关信息,即文件系统的元数据,被存储在超级块中。

VFS 对象及其数据结构

VFS 采用面向对象思想来设计的。其对象使用结构体表示。

VFS 四个主要的对象类型:

  • 超级块对象:代表一个具体的已安装文件系统。
  • 索引节点对象:代表一个具体文件。
  • 目录项对象:代表一个目录项,是路径的一个组成部分。
  • 文件对象:代表由进程打开的文件。

每个对象中都包含一个操作对象,这些操作对象描述了内核针对主要对象可以使用的方法:

  • super_operations 对象:包含内核针对特定文件系统所能调用的方法,比如 write_inode() 和 sync_fs() 等。
  • inode_operations 对象:包含内核针对特定文件所能调用的方法,比如 create() 和 link() 等。
  • dentry_operations 对象:包含内核针对特定目录所能调用的方法,比如 d_compare() 和 d_delete() 等。
  • file_operations 对象:包含进程针对已打开文件所能调用的方法,比如 read() 和 write() 等。

并不止这些对象…

超级块对象

各种文件系统都必须实现超级块对象,该对象用于存储特定文件系统的信息,通常对应于存放在磁盘特定扇区中的文件系统超级块或文件系统控制块。其它并非基于磁盘的文件系统(如基于内存的文件系统 sysfs),它们会在使用现场创建超级块并将其保存到内存中。

超级块的结构体为 super_block,位于 include/linux/fs.h:

image-20230427200942704

对超级块的操作,位于:fs/super.c

超级块对象通过 alloc_super() 函数创建并初始化。在文件系统安装时,文件系统会调用该函数以便从磁盘读取文件系统超级块,并且将其信息填充到内存中的超级块对象中。

超级块操作

超级块对象 super_block 中的 s_op 域指向超级块的操作函数表。

超级块的操作函数表用 super_operations 结构体表示,位于 include/linux/fs.h

struct super_operations {
   	struct inode *(*alloc_inode)(struct super_block *sb);
	void (*destroy_inode)(struct inode *);

   	void (*dirty_inode) (struct inode *);
	int (*write_inode) (struct inode *, struct writeback_control *wbc);
	void (*drop_inode) (struct inode *);
	void (*delete_inode) (struct inode *);
	void (*put_super) (struct super_block *);
	void (*write_super) (struct super_block *);
	int (*sync_fs)(struct super_block *sb, int wait);
	int (*freeze_fs) (struct super_block *);
	int (*unfreeze_fs) (struct super_block *);
	int (*statfs) (struct dentry *, struct kstatfs *);
	int (*remount_fs) (struct super_block *, int *, char *);
	void (*clear_inode) (struct inode *);
	void (*umount_begin) (struct super_block *);

	int (*show_options)(struct seq_file *, struct vfsmount *);
	int (*show_stats)(struct seq_file *, struct vfsmount *);
#ifdef CONFIG_QUOTA
	ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
	ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
#endif
	int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t);
};

Tips:

sb->s_op->write_super(sb);
// 因为这不是对象,只是将其看成对象
// 结构体无 this 指向
// 因此只能手动传入 sb 对象,间接实现 this 指向 sb

索引节点对象

索引节点对象包含了内核在操作文件或目录时需要的全部信息。

image-20230427203843419

一个索引节点代表文件系统中的一个文件,它也可以是设备或管道这样的特殊文件。但索引节点只有当文件被访问时,才能在内存中创建。

索引节点操作

struct inode_operations {
	int (*create) (struct inode *,struct dentry *,int, struct nameidata *);
	struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
	int (*link) (struct dentry *,struct inode *,struct dentry *);
	int (*unlink) (struct inode *,struct dentry *);
	int (*symlink) (struct inode *,struct dentry *,const char *);
	int (*mkdir) (struct inode *,struct dentry *,int);
	int (*rmdir) (struct inode *,struct dentry *);
	int (*mknod) (struct inode *,struct dentry *,int,dev_t);
	int (*rename) (struct inode *, struct dentry *,
			struct inode *, struct dentry *);
	int (*readlink) (struct dentry *, char __user *,int);
	void * (*follow_link) (struct dentry *, struct nameidata *);
	void (*put_link) (struct dentry *, struct nameidata *, void *);
	void (*truncate) (struct inode *);
	int (*permission) (struct inode *, int);
	int (*check_acl)(struct inode *, int);
	int (*setattr) (struct dentry *, struct iattr *);
	int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
	int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
	ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
	ssize_t (*listxattr) (struct dentry *, char *, size_t);
	int (*removexattr) (struct dentry *, const char *);
	void (*truncate_range)(struct inode *, loff_t, loff_t);
	long (*fallocate)(struct inode *inode, int mode, loff_t offset,
			  loff_t len);
	int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
		      u64 len);
};

目录项对象

image-20230427211519800

目录项对象没有对应的磁盘数据结构,VFS 根据字符串形式的路径在内存中创建它,因此目录项对象并非真正保存在磁盘上。可以看到该结构体也没有磁盘相关的域。

目录项状态

状态有三:被使用、未被使用、负状态。

**被使用:**一个被使用的目录项对应一个有效的索引节点(即 d_inode 指向相应的索引节点)并且表面该对象存在一个或多个使用者(d_count 为正)。一个目录项处于被使用状态,意味着它正被 VFS 使用并且指向有效的数据,因此不能被丢弃。

未被使用: 一个未被使用的目录项对应一个有效的索引节点(d_inode 指向一个索引节点),但是应指明 VFS 当前并未使用它(d_count 为 0)。该目录项对象仍然指向一个有效对象,而且被保留在缓存中以便需要时再使用它。以后若再需要它,就不必重新创建。若要回收内存,也可以撤销未使用的目录项。

负状态: 其实就是无效目录项,一个负状态的目录项没有对应的有效索引节点(d_inode 为 NULL),因为索引节点已被删除,或路径不在正确,但目录项仍然可以保留,以便快速解析以后的路径查询。

目录项对象释放后也可以保存到 slab 对象缓存中。此时,任何 VFS 或文件系统代码都没有指向该目录项对象的有效引用。

目录项缓存

内核将目录项对象缓存在目录项缓存中。

目录项缓存包括三个主要部分:

image-20230427214346521

目录项操作

include\linux\dcache.h

struct dentry_operations {
	int (*d_revalidate)(struct dentry *, struct nameidata *);
	int (*d_hash) (struct dentry *, struct qstr *);
	int (*d_compare) (struct dentry *, struct qstr *, struct qstr *);
	int (*d_delete)(struct dentry *);
	void (*d_release)(struct dentry *);
	void (*d_iput)(struct dentry *, struct inode *);
	char *(*d_dname)(struct dentry *, char *, int);
};

文件对象

VFS 的文件对象表示进程已打开的文件。文件对象是已打开的文件在内存中的表示。该对象(切记,不是具体的文件,即不是物理的,而只是存在于内存中的,因此 VFS 的文件对象没有对应的磁盘数据)由相应的 open() 系统调用创建,由 close() 系统调用撤销。

image-20230428101619847

文件操作

/*
 * NOTE:
 * read, write, poll, fsync, readv, writev, unlocked_ioctl and compat_ioctl
 * can be called without the big kernel lock held in all filesystems.
 */
struct file_operations {
	struct module *owner;
	loff_t (*llseek) (struct file *, loff_t, int);
	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
	ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
	ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
	int (*readdir) (struct file *, void *, filldir_t);
	unsigned int (*poll) (struct file *, struct poll_table_struct *);
	int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
	long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
	long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
	int (*mmap) (struct file *, struct vm_area_struct *);
	int (*open) (struct inode *, struct file *);
	int (*flush) (struct file *, fl_owner_t id);
	int (*release) (struct inode *, struct file *);
	int (*fsync) (struct file *, struct dentry *, int datasync);
	int (*aio_fsync) (struct kiocb *, int datasync);
	int (*fasync) (int, struct file *, int);
	int (*lock) (struct file *, int, struct file_lock *);
	ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
	unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
	int (*check_flags)(int);
	int (*flock) (struct file *, int, struct file_lock *);
	ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
	ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
	int (*setlease)(struct file *, long, struct file_lock **);
};

和文件系统相关的数据结构

内核定义了用来管理文件系统的数据结构。

file_system_type 用来描述各种特定文件系统类型:

缺图

每种文件系统,不管有多少个实例安装到系统中,还是根本就没有安装到系统中,都只有一个 file_system_type 结构。

当文件系统被安装时,将有一个 vfsmount 结构体在安装点被创建。该结构体用来代表文件系统的实例,即代表一个安装点。

缺图

vfsmount 结构体中维护的各种链表,用于理清文件系统和所有其它安装点间的关系。

vfsmount 结构保存了在安装时指定的标志信息,该信息存储在 mnt_flags 域中。

缺图

和进程相关的数据结构

系统中每个进程都有自己的一组打开的文件。file_struct、fs_strruct、namespace 结构体将 VFS和系统的进程紧密联系在一起。

file_struct 结构体,该结构体由进程描述符中的 files 目录项指向。所有与单个进程相关的信息都保护在其中:

include\linux\fdtable.h

缺图

fs_struct 结构体,该结构由进程描述符的 fs 域指向。它包含了文件系统和进程相关的信息。

include\linux\fs_struct.h

缺图

namespace 结构体,由进场描述符中的 mmt_namespace 域指向。它使得每个进程在系统中都看到唯一的安装文件系统,不仅是唯一的根目录,而且是唯一的文件系统层次结构。

缺图

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

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

相关文章

[强网杯 2022]factor有感

可直接私信+Q 3431550587 此题记录主要是他运用了几个新看见的攻击思路和拜读了一篇论文,所以写写。题目源码: #encoding:utf-8 from Crypto.Util.number import * from gmpy2 import * from random import randint from flag import flagd…

云服务仿真:完全模拟 AWS 服务的本地体验 | 开源日报 No.45

localstack/localstack Stars: 48.7k License: NOASSERTION LocalStack 是一个云服务仿真器,可以在您的笔记本电脑或 CI 环境中以单个容器运行。它提供了一个易于使用的测试/模拟框架,用于开发云应用程序。主要功能包括: 在本地机器上完全…

CTF之CTF(夺旗赛)介绍

什么是CTF? CTF(Capture The Flag,中文一般译作“夺旗赛”)在网络安全领域中指的是网络安全技术人员之间进行技术竞技的一种比赛形式。CTF起源于1996年DEFCON全球黑客大会,用以代替之前黑客们通过互相发起真实攻击进行…

最新AI智能创作系统源码SparkAi系统V2.6.3/AI绘画系统/支持GPT联网提问/支持Prompt应用/支持国内AI模型

一、智能AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统,已支持OpenAIGPT全模型国内AI全模型,已支持国内AI模型 百度文心一言、微软Azure、阿里云通义千问模型、清华智谱AIChatGLM、科大讯飞星火大模型等。本期针对源码…

Javascript - 轮播图

轮播图也称banner图、广告图、焦点图、滑片。是指在一个模块或者窗口,通过鼠标点击或手指滑动后,可以看到多张图片。这些图片统称为轮播图,这个模块叫做轮播模块。可以通过运用 javascript去实现定时自动转换图片。以下通过一个小Demo演示如何运用Javascript实现。 <!DOCTYP…

d3dcompiler_47.dll是什么文件?游戏确实d3dcompiler_47.dll的常用解决方法

d3dcompiler_47.dll 是一个动态链接库&#xff08;DLL&#xff09;文件&#xff0c;属于 Microsoft DirectX 软件组件的一部分。它主要负责处理 DirectX 中的图形和多媒体内容&#xff0c;以确保游戏和应用程序能够正常运行。d3dcompiler_47.dll 的主要功能是将 DirectX API 转…

基于SpringBoot的在线宠物用品交易网站

目录 前言 一、技术栈 二、系统功能介绍 用户信息管理 商品分类管理 品牌信息管理 商品信息管理 商品信息 我的收藏 我的订单 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实…

C++设计模式-组合(Composite)

目录 C设计模式-组合&#xff08;Composite&#xff09; 一、意图 二、适用性 三、结构 四、参与者 五、代码 C设计模式-组合&#xff08;Composite&#xff09; 一、意图 将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的…

stm32之手动创建keil工程--HAL库

用CubeMx创建了好多stm32的工程&#xff0c;这里记录下手动创建keil工程的过程。 一、准备工作 1.1、下载对应的HAL库&#xff0c; 这里使用的是stm32f103c8t6, 下载地址stm32HAL库 在页面中输入对应型号点击进行二级页面进行下载 1.2、准备工程 各文件夹下具体操作如下&am…

Qt之QDial(表盘)

简介 QDial类提供了一个四舍五入的范围控制&#xff08;如速度计或电位计&#xff09;&#xff0c;非常适合需要循环计数的情况&#xff0c;例如角度等。 头文件&#xff1a;#include <QDial> qmake&#xff1a;QT widgets 继承&#xff1a;QAbstractSlider …

在WIN10平台上体验Microsoft古老的Quick C 1.0编程

前言&#xff1a; 90年代初&#xff0c;微软出了Quick系统对抗Borland Turbo系列&#xff0c;其中包括 QuickBasic, QuickPascal和Quick C。1991年&#xff0c;Quick C for Windows 1.0发布&#xff0c;后来它被Visual C取代。我自己觉得微软成就在那个winstub.exe桩上&#xf…

连接虚拟机工具推荐

连接虚拟机工具推荐 连接虚拟机的工具有很多种&#xff0c;以下是一些常用的推荐&#xff1a; PuTTY&#xff1a;这是一个非常常用的SSH和telnet客户端&#xff0c;适用于Windows系统。它允许你在本地机器上通过命令行接口远程登录到虚拟机。 SecureCRT&#xff1a;这是一个支…

vscode 配置自定义code snippets 来快速生成你的常用代码

一、功能介绍 什么是 snippets 功能&#xff1f; 其实大家可能体验过vscode 预先内置的许多 snippets, 比如 for 循环。 在输入 for Tab 的时候&#xff0c;就可以自动生成代码模版&#xff0c; 展开就是这样的代码 有一个小窍门是通过 tab 键可以在参数之间进行跳转&#xf…

力扣 -- 1745. 分割回文串 IV

解题步骤&#xff1a; 参考代码&#xff1a; class Solution { public:bool checkPartitioning(string s) {int ns.size();vector<vector<bool>> dp(n,vector<bool>(n));for(int in-1;i>0;i--){for(int ji;j<n;j){if(s[i]s[j]){dp[i][j]i1<j?dp[i…

【C++设计模式之观察者模式:行为型】分析及示例

简介 观察者模式&#xff08;Observer Pattern&#xff09;是一种行为型设计模式&#xff0c;它定义了一种一对多的依赖关系&#xff0c;使得当一个对象的状态发生变化时&#xff0c;所有依赖它的对象都能够自动收到通知并更新。 描述 观察者模式由两个核心件组成&#xff1…

抄写Linux源码(Day18:读取硬盘前的准备工作有哪些?)

回忆我们需要做的事情&#xff1a; 为了支持 shell 程序的执行&#xff0c;我们需要提供&#xff1a; 1.缺页中断(不理解为什么要这个东西&#xff0c;只是闪客说需要&#xff0c;后边再说) 2.硬盘驱动、文件系统 (shell程序一开始是存放在磁盘里的&#xff0c;所以需要这两个东…

[论文精读]U-Net: Convolutional Networks for BiomedicalImage Segmentation

论文原文&#xff1a;U-Net: Convolutional Networks for Biomedical Image Segmentation (arxiv.org) 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔…

[笔记] Windows内核课程:保护模式《二》段寄存器介绍

文章目录 前言1、什么是段寄存器? 有哪些 ?2. 段寄存器的结构 前言 段寄存器&#xff0c;页寄存器 1、什么是段寄存器? 有哪些 ? 当我们用汇编读写某一个地址时: mov dword ptr ds:[0x123456],eax我们真正读写的地址是: ds.base 0x123456ES、CS、SS、DS、FS、GS、LDTR…

Linux和Hadoop的学习

目录 1. Linux的常用快捷键2. Hadoop集群部署问题汇总 1. Linux的常用快捷键 复制&#xff1a;CtrlshiftC 粘贴&#xff1a;CtrlshiftV TAB&#xff1a;补全命令 编写输入&#xff1a;i 退出编写&#xff1a;esc 保存并退出&#xff1a;shift&#xff1a; 2. Hadoop集群部署问…

网络安全(黑客)从零开始的自学指南(第一章)

第一章&#xff1a;网络安全概述 1.1 什么是网络安全 网络安全是指保护计算机网络系统和网络中的数据免受未经授权的访问、使用、破坏、篡改或泄露的一系列措施和技术。随着互联网的普及和信息化的发展&#xff0c;网络安全问题日益突出&#xff0c;对个人、组织和国家的安全…