首页 电脑教程 电脑知识 Linux的文件系统(File System)架构简析

Linux的文件系统(File System)架构简析

Mar 11, 2024 pm 03:31 PM
文件系统 架构 linux操作系统 vfs

Linux的文件系统(File System)架构简析

本文主要讨论虚拟文件系统。Linux文件系统的架构包括具体文件系统(如Ext2、Ext3和XFS等)与应用程序之间的抽象层,即虚拟文件系统(Virtual File System,简称VFS)。VFS允许应用程序与不同类型的文件系统进行通信而无需了解底层文件系统的细节。通过VFS,文件系统的实现可以被隔离并与应用程序解耦,从而提高了系统的灵活性和可维护性。VFS还允许Linux内核支持多种文件系统类型,并提供了一个统一的接口供应用程序访问文件系统。在VFS的框架下,不同的文件系统可以通过实现标准的文件系统操作接口来与内核进行交

图片

上图显示,这一架构的中心是虚拟文件系统VFS。VFS提供了一个文件系统框架,本地文件系统可以基于VFS实现。它主要完成以下几项工作:

1) VFS作为抽象层为应用层提供了统一的接口(read、write和chmod等)。

2) 在VFS中实现了一些公共的功能,如inode缓存和页缓存等。

3) 规范了具体文件系统应该实现的接口。

根据以上设定,其他具体的文件系统只需遵循VFS的约定,实现相应的接口和内部逻辑,并注册到系统中。用户在格式化并挂载文件系统后,便可以利用硬盘资源进行基于该文件系统的操作。

在Linux操作系统中,在格式化磁盘后需要通过mount命令将其挂载到系统目录树的某个目录下面,这个目录称为挂载点(mount point)。完成挂载后,我们就可以使用基于该文件系统格式化的硬盘空间了。在Linux操作系统中,挂载点几乎可以是任意目录,但为了规范化,挂载点通常是mnt目录下的子目录。    

下面展示的是一个相对复杂的目录结构。在这个目录结构中,根目录位于硬盘sda上,并且在mnt目录下有三个子目录分别是ext4、xfs和nfs,它们分别挂载了Ext4文件系统(构建在sdb硬盘上)、XFS文件系统(构建在sdc硬盘上)和NFS文件系统(通过网络挂载)。

图片

目录树中多个文件系统的关系是内核中的一些数据结构表示的。在进行文件系统挂载的时候会建立文件系统间的关系,并且注册具体文件系统的API。当用户态调用打开文件的API时,会找到对应的文件系统API,并关联到文件相关的结构体(例如file和inode等)。

上面的描述比较概要,大家可能还是有点云里雾里的感觉。不过大家不要着急,我们接下来会结合代码更加详细的介绍VFS及如何实现对多种文件系统的支持。

1.从文件系统API到VFS,再到具体文件系统

Linux的VFS并不是一开始就有的,最早发布的Linux版本并没有VFS。而且,VFS并非是在Linux发明的,它最早于1985年由Sun公司在其SunOS2.0中开发。开发VFS的主要目的是为了适配其本地文件系统和NFS文件系统。

VFS通过一套公共的API和数据结构实现了对具体文件系统的抽象。当用户调用操作系统提供的文件系统API时会通过软中断的方式调用内核VFS实现的函数。如下表所示是部分文件API与内核VFS函数的对应关系。    

用户态API

内核函数

说明

open

do_sys_open

打开文件

close

ksys_close

关闭文件

read

ksys_read/vfs_read

读取数据

write

ksys_write/vfs_write

写入数据

mount

do_mount

挂载文件系统

由上表可以看出每个用户态的API都有一个内核态的函数与之对应。当应用程序调用文件系统的API时会触发内核态的对应函数。这里列举的只是文件系统API中的一个比较小的子集,目的是为了说明API与VFS的关系。如果大家想了解其他API请自行阅读内核源代码,本文不再赘述。

为了让大家能够对VFS与具体文件系统的关系有个感性的认识,本节以Ext2的写API为例来展示一下从API到VFS函数,再到Ext2文件系统函数的调用关系。如下图所示,API函数write通过软中断触发内核的ksys_write函数,该函数经过若干处理后最终会通过函数指针(file->f_op->wirte_iter)的方式调用Ext2文件系统的ext2_file_write_iter函数。    

图片

在上图中内核流程的入口是ksys_write函数,通过实现代码可以看出,这里主要是获取一个fd,然后以fd中的成员file作为参数调用vfs_write。其中fd是一个结构体,其格式如下图所示,file成员是比较核心的数据结构。从上图可以看出,正是通过这个成员中的内容才调到了Ext2文件系统的函数。    

图片

看上去很简单,VFS只要调用具体文件系统注册的函数指针即可。但是这里有个问题没有解决,VFS中的函数指针是什么时候被注册的呢?

Ext2的函数指针是在打开文件的时候被初始化的(具体细节请参考《文件系统技术内幕》3.1.2.2节)。大家都知道,用户态的程序在打开一个文件的时候返回的是一个文件描述符,但在内核中表示文件的结构体file与之对应。这个结构体里面比较重要的几个成员包括f_inode、f_ops和f_mapping等,具体如下图所示。

图片

在上图中,f_inode是该文件对应的inode节点。f_ops是具体文件系统(例如Ext2)文件操作的函数指针集合,它是在打开文件的时候被初始化的。VFS正是通过该函数指针集合来实现对具体文件系统访问的。

上面又涉及到VFS的另外一个概念inode。在Linux中,inode是index node的缩写,他表示了文件系统中的一个具体的对象(比如文件或者目录)。在VFS中有一个名称为inode的数据结构,他是对具体文件系统inode的抽象。比如在Ext2文件系统中具体定义为ext2_inode_info,在XFS中则是通过数据结构xfs_inode表示的。而且具体文件系统的inode数据结构与VFS的inode有个内在的关联,大家可以自行阅读代码。

2.inode缓存与dentry缓存

在架构图中我们看到在VFS中有若干个缓存实现,包括页缓存、inode缓存和dentry缓存等。其中inode缓存和dentry缓存实现方式相同,也比较简单。所以,本文先介绍一下这两个缓存。

其实这两个缓存是通过哈希表实现的,哈希表的概念大家都比较清楚,本文不再赘述。以inode缓存为例,如下图是其初始化的过程,通过参数ihash_entries可以看出其大小是动态的(其大小跟系统内存相关,系统内存阅读,inode缓存就越大)。

图片

由于访问文件时会经常访问inode和dentry,所以将两者缓存起来能够避免从硬盘读取数据导致的性能损失。

3.页缓存(Page Cache)

VFS页缓存(Cache)的作用主要用来提升文件系统的性能。缓存技术是指在内存中存储文件系统的部分数据和元数据而提升文件系统性能的技术。由于内存的访问延时是机械硬盘访问延时的十万分之一(如下图所示,以寄存器为基准单位1s),因此采用缓存技术可以大幅提升文件系统的性能。

图片

缓存通过三方面的IO优化来提升文件系统的性能,分别是热点数据、预读和IO合并。很多应用都会有热点数据,比如作者在编辑文档的时候,当前这个数据块及附近的数据块就是热点数据。或者当出现一个爆款文章时,这篇文章的内容就是热点数据。底层存储设备对于大块读写的性能往往较好,预读就是提前从底层设备读取大块数据缓存起来,这样可以通过缓存来响应应用的请求。IO合并则是针对写请求,写请求不马上持久化到后端设备,而是缓存一下,拼成大块IO再写入。

由于内存的容量要比硬盘的容量小的多,因此页缓存自然不能缓存所有硬盘的数据。这样缓存中只能存储文件系统数据的一个子集。当用户持续写入数据的时候就会面临缓存满的情况,此时就涉及如何将缓存数据刷写磁盘,然后存储新数据的问题。

这里将缓存刷写到磁盘,并且存储新数据的过程称为缓存替换。缓存替换有很多种算法,每种算法用于解决不同的问题。接下来我们介绍几种常见的缓存替换算法。

LRU算法,LRU的全称是Least Recently Used,也就是最近最少使用。该算法依据的是时间局部性原理,也就是如果一个数据最近被使用过,那么接下来有很大的概率还会被使用。因此该算法会将最近没有使用过的缓存释放掉。

LRU算法通常使用一个链表来实现,刚被使用过的缓存会被插到表头的位置,而经常没有被使用过的数据则慢慢被挤到链表的尾部。为了更加清晰的理解LRU的原理,我们结合下图进行说明。    

图片

在该例中,我们以全命中为例进行介绍。假设缓存中有6个数据块,如图第一行所示,方块中的数字代表该数据块的编号。假设第一次访问(可以是读或者写)的是3号数据块,由于其被访问过,因此将其移动到链表头。

第二次访问时访问的是第4号数据块,按照相同的原则,该数据块也被移动到链表头。具体如上图第2行所示。

以此类推,当经过4轮访问后,被访问过的数据都被前移了,而没有被访问过的数据块(例如1和2)则被慢慢挤到了链表的后面。这在一定程度上预示着这两个数据块在后面被访问的可能性也比较小。

如果是全命中的话也就不存在缓存被替换的情况了。实际情况是缓存会经常不够用,而需要将其中的数据释放(视情况确定是否需要刷新到磁盘)来存储新的数据。此时,LRU算法就派上用场了,该算法将尾部的数据块拿来存储新数据,然后放到链表头,具体下图如所示。如果这个数据块里面是脏数据则需要刷写到磁盘,否则直接释放掉就可以。    

图片

LRU算法原理和实现都比较简单,用途却非常广泛。但是LRU算法有个缺点,就是当突然有大量连续数据写入时会替换掉所有的缓存块,从而导致之前统计的缓存使用情况全部失效,这种现象称为缓存污染。为了解决缓存污染问题,有很多改进的LRU算法,其中比较常见的有LRU-K、2Q和LIRS等。

LFU算法,LFU的全称是Least Frequently Used,也就是最近最不经常使用。该算法是根据数据被访问的频度来决策释放哪一个缓存块的。访问频度最低的缓存块会被最先释放掉。

如下图所示是LFU算法的示意图。其中第1行是原始状态,方块中的数字表示该缓存块被访问的次数。新数据的加入和缓存块的淘汰都是从尾部进行。假设某一块(虚线框)数据被访问了4次,则其访问次数从12变成了16,因此需要移动到新的位置,也就是图中第2行的样子。

图片

本书以链表为例说明LFU的原理是为了便于理解,但是在工程实现的时候是绝对不会用链表来实现的。因为当数据块的访问次数变化时需要找新的位置,链表查找操作是非常耗时的。为了能够实现快速查找,一般采用搜索树来实现。    

LFU也有其缺点,如果某个数据块在很久之前的某个时间段高频访问,而以后不再访问,那么该数据会一直停留在缓存中。但是由于该数据不会被访问了,所以导致缓存的有效容量减少了。也就是说LFU算法没有考虑最近的情况。

本文主要介绍了LRU和LFU等2种非常基础的替换算法。除了上述算法外,还有还很多替换算法,大多以LRU和LFU的理论为基础,比如2Q,MQ,LRFU,TinyLFU和ARC等等。限于篇幅,本书不再赘述,大家可以自行阅读相关的论文。

数据预读也是有一定的算法的,预读算法通过识别IO模式方式来提前将数据从磁盘读到缓存中。这样,应用读取数据时就可以直接从缓存读取数据,从而极大的提高读数据的性能。

预读算法里面最为重要的是触发条件,也就是在什么情况下出发预读操作。通常有两种情况会触发预读:一个是有多个地址连续的读请求时会触发预读操作;另外一个是应用访问到有预读标记的缓存时。这里,预读标记的缓存是在预读操作完成时在缓存页做的标记,当应用读到有该标记的缓存时会触发下一次的预读,从而省略对IO模式的识别。

图片

为了更加清晰的解释预读的逻辑,我们通过上图来介绍一下整个流程。当文件系统识别IO模式需要预读的时候,会多读出一部分内容(称为同步预读),如时间1(第一行)所示。同时,对于同步预读的数据,文件系统会在其中某个块上打上标记。这个标记的目的是为了在缓存结束前能够尽早的触发下一次的预读。    

第2个时间点,当应用继续读取数据时,由于读到了有标记的缓存块,因此会同时触发下一次的预读。此时数据会被从磁盘一步读取,可以从图中看出缓存增加。

接下来时间点3,4,应用可以直接从缓存读取数据。由于没有读到有标记的缓存块,因此也不会触发下一次的预读。在时间点5,由于有预读标记,因此又会触发预读的流程。

通过上述分析可以看出,由于预读特性将数据提前读到了缓存当中。应用可以直接从缓存读取数据,而不用再访问磁盘,因此整个访问性能将得到大幅的提升。

以上是Linux的文件系统(File System)架构简析的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

修复事件ID 55,50,98,140磁盘错误在事件查看器 修复事件ID 55,50,98,140磁盘错误在事件查看器 Mar 19, 2024 am 09:43 AM

若您在Windows11/10的事件查看器中发现事件ID55、50、140或98,或遇到磁盘文件系统结构损坏且无法使用的错误,请按照以下指南解决此问题。什么是事件55,磁盘上的文件系统结构损坏和不可用的意思?第55届会议,Ntfs磁盘上的文件系统结构损坏且无法使用。请在卷上运行chkMSK实用程序当NTFS无法将数据写入事务日志时,会触发事件ID55的错误,这将导致NTFS无法完成无法写入事务数据的操作。这种错误通常发生在文件系统损坏的情况下,可能是由于磁盘上存在坏扇区或文件系统对磁盘子系统的不

Kali Linux软件卸载全攻略,解决系统稳定难题 Kali Linux软件卸载全攻略,解决系统稳定难题 Mar 23, 2024 am 10:50 AM

本研究全面深入剖析了在KaliLinux的渗透测试和安全审计流程中可能出现的软件卸载难题,为保障系统稳定可靠贡献了解决之道。一、了解软件的安装方式在进行应用程序卸载前kalilinux卸载软件,首先确定其安装路径是至关重要的步骤。进而,根据所选途径相应地挑选出适当的卸载方案。常见的安装方法包括apt-get、dpkg以及源代码编译等各类形式。每种策略都具备自身特性和相应的卸载措施。二、使用apt-get命令卸载软件在KaliLinux系统中,apt-get功能组件被广泛应用于高效便捷地执行软件包

国产操作系统麒麟Linux安装全攻略,15分钟搞定 国产操作系统麒麟Linux安装全攻略,15分钟搞定 Mar 21, 2024 pm 02:36 PM

近日,国产操作系统麒麟Linux广受瞩目,本人身为资深计算机工程师麒麟linux安装教程,对科技创新抱有浓厚兴趣,故亲身体验了该系统的安装流程,现将经验在此和诸位共享。在执行安装程序前,我针对相关步骤进行了充分准备。首要任务是下载并拷贝最新的麒麟Linux操作系统镜像至U盘;其次64位linux,确保已备份个人设备中的重要数据,以应对潜在的安装问题;最后,关闭电脑并插入U盘。进入安装界面重启计算机后,及时按下F12功能键,步入系统启动菜单选择USB优先启动项。随着一个美观且简约的启动画面出现眼前

puppylinux安装u盘 puppylinux安装u盘 Mar 18, 2024 pm 06:31 PM

实际上,电脑使用了较长的一段时间之后,整体的性能都会呈现下降的趋势,而对Windows系统的适应性也会不断地下降。除了电脑本身的原因,Windows系统不断增强和扩展,对硬件要求也越来越高。因此,旧电脑安装Windows系统后出现卡顿现象并不奇怪。之前,很多朋友都在后台询问系统卡顿,旧电脑怎么办?如果你发现将新版Windows10系统安装在旧电脑上会导致卡顿和操作问题,或许考虑转向Linux系统是个不错的选择。大白菜整理了5个微型Linux系统,适合老旧电脑使用,可以有效降低CPU占用率,让你的

WIN10提示文件系统错误2147416359的处理方法 WIN10提示文件系统错误2147416359的处理方法 Mar 27, 2024 am 11:31 AM

1、按win+r进入运行窗口,输入【services.msc】回车即可。2、在服务窗口中,找到【windowslicensemanagerservice】,双击打开。3、在界面中,将启动类型改为【自动】,然后点击【应用→确定】。4、完成上面的设置,重启电脑即可。

Spring Data JPA 的架构和工作原理是什么? Spring Data JPA 的架构和工作原理是什么? Apr 17, 2024 pm 02:48 PM

SpringDataJPA基于JPA架构,通过映射、ORM和事务管理与数据库交互。其存储库提供CRUD操作,派生查询简化了数据库访问。此外,它使用延迟加载,仅在必要时检索数据,从而提高了性能。

解决Linux命令行显示乱码问题的方法 解决Linux命令行显示乱码问题的方法 Mar 21, 2024 am 08:30 AM

解决Linux命令行显示乱码问题的方法在Linux操作系统中,有时候我们在使用命令行界面时会遇到显示乱码的情况,这会影响我们对命令输出结果或文件内容的正常查看和理解。造成乱码的原因可能是由于系统字符集设置不正确、终端软件不支持显示特定字符集、文件编码格式不统一等问题。本文将介绍一些解决Linux命令行显示乱码问题的方法,同时提供具体的代码示例,帮助读者解决类

Linux系统管理员揭秘:红帽版Linux版本解析全攻略 Linux系统管理员揭秘:红帽版Linux版本解析全攻略 Mar 29, 2024 am 09:16 AM

作为资深Linux系统管理员,对于RedHat版Linux系统的分析与诊治,本人已具备深厚的知识储备和独特观感。此篇文章将深入解析RedHat版Linux系统的方方面面,主要包括识别其版本特征、解码版本编号以及递迸测试版本更新的实际步骤等,以期帮助您全面掌握并高效利用RedHat操作系统的功能特性。1.理解RedHat美国市值最高的互联网公司之一,RedHat透过其在开源技术框架下研发的操作系统产品赢得了全球软件市场的领先地位。旗下Linux发行版RedHatEnterpriseLinux(简称

See all articles