【Linux】文件系统


前言

在上一篇文章中我们谈论到的文件都是被打开的文件,那么被打开文件被放在哪里呢? 它们一定不在内存中!只能在磁盘等外设中静静的存放着!!

那么在磁盘中的这些文件又衍生出很多问题,这些文件该如何合理存储着呢?标识一个文件(文件名)?如何定位一个文件?如何对文件进行读取和写入?等等诸多问题,要想了解这些问题。我们必须先来了解磁盘的结构,然后引出操作系统对磁盘的管理。

一、磁盘的物理结构

硬盘内部主要部件为磁盘盘片、传动手臂、读写磁头和主轴马达。实际数据都是写在盘片上,读写主要是通过传动手臂上的读写磁头来完成。实际运行时,主轴马达让磁盘盘片转动,然后传动手臂可伸展让读取头在盘片上进行读写操作。磁盘物理结构如下图所示:

在这里插入图片描述

由于单一盘片容量有限,一般硬盘都有两张以上的盘片,每个盘片有两面,都可记录信息,所以一张盘片对应着两个磁头。盘片被分为许多扇形的区域,每个区域叫一个扇区,硬盘中每个扇区的大小固定为512字节。盘片表面上以盘片中心为圆心,不同半径的同心圆称为磁道,不同盘片相同半径的磁道所组成的圆柱称为柱面。磁道与柱面都是表示不同半径的圆,在许多场合,磁道和柱面可以互换使用。磁盘盘片垂直视角如下图所示:

在这里插入图片描述

那么根据上述磁盘物理硬件结构图,我们是如何定位一个扇区的呢?

首先我们要定位扇区在哪一个盘片上,一个盘片有两个盘面,对应两个磁头,我们知道磁头的编号就能知道此时扇区处于哪个盘面上了;确定在哪一个盘面之后我们需要确定它在哪一个磁道上,磁道由我们的半径决定,确定在哪个磁道之后;磁道由各种不同的扇区组成,我们根据扇区编号就可以找到扇区的位置了!!

我们根据磁头(head)、柱面(磁道--> cylinder)和扇区(sector)就能定位任意一个扇区的位置了,这种寻找方法也叫做CHS定位法!!

那么对于一个普通文件(内容 + 属性)来说它们都是数据,无非就是占用一个或多个扇区来对数据进行存储的,我们既然能通过CHS来定位一个扇区那么就能定位任意多个扇区,从而将文件从硬件的角度进行读取或者写入!!

二、磁盘的逻辑结构

上述中我们知道磁盘定位一个地址的方式为CHS,那么操作系统是否也是按照这种方式来进行定位呢?

不是。第一,操作系统是软件,磁盘是硬件。硬件通过CHS来定位一个地址,而如果操作系统也使用了这种方式的话,万一我们的硬件更新了结构变化了,那么操作系统的定位方式也要跟着变化,所以我们将操作系统和硬件进行解耦,两者采用不同的方式来定位地址,这样即使硬件更新了操作系统的定位方式也不会发生变化;第二,硬件的基本单位是扇区,这也就意味着我们每次IO的数据块基本单位为512字节,但是对于文件IO来讲,这个数据量也是很小的,所以操作系统为了提高IO效率,实际进行IO时基本数据块的单位是1KB、2KB、4KB等,它是可以被调整的。

操作系统需要一套新的定位方式来进行数据块的IO,我们的磁盘是圆形的,例如像磁带这种硬件,我们可以很直观的知道它可以被拉直,我们就可以把它抽象成为一种线性结构。

在这里插入图片描述

此时我们就完成了从物理地址到逻辑地址的抽象过程,如此定位一个扇区只需要一个下标就能定位了。上述过程中我们假设OS以4KB作为IO的基本单位,所以8个扇区就组成了一个数据块。计算中常规的访问方式:起始地址 + 偏移量(语言->数据类型),那么此时对于访问磁盘中的某个数据时,我们只需要知道数据块的起始地址(首扇区的下标地址) + 4KB就能够访问对应的数据块了,用数组下标的方式就能定位任意一个块了,这种定位方式也叫做逻辑区块地址(LAB)定位

OS是如何管理磁盘的呢? 先描述再组织。 将磁盘看成是一个大数组,对磁盘的管理,本质上就是对数组的管理。

三、文件系统

上述中我谈及到的操作系统更具体的来讲是文件系统,实际上操作系统层面操作硬盘是通过类似于网络的分层结构进行的,下图显示了Linux系统中对于磁盘的一次读请求在核心空间中所要经历的层次模型。从图中看出:对于磁盘的一次读请求,首先经过虚拟文件系统层(VFS Layer),其次是具体的文件系统层(例如Ext2),接下来是Cache层(Page Cache Layer)、通用块层(Generic Block Layer)、I/O调度层(I/O Scheduler Layer)、块设备驱动层(Block Device Driver Layer),最后是物理块设备层(Block Device Layer)。

在这里插入图片描述

VFS Layer

VFS(Virtual File System)虚拟文件系统是一种软件机制,更确切的说扮演着文件系统管理者的角色,与它相关的数据结构只存在于物理内存当中。它的作用是:屏蔽下层具体文件系统操作的差异,为上层的操作提供一个统一的接口。正是因为有了这个层次,Linux中允许众多不同的文件系统共存并且对文件的操作可以跨文件系统而执行。

VFS的下一层即是具体的文件系统,也就是本篇文章的重点内容,下面我们就来具体介绍一下Linux的Ext2文件系统。

一个文件系统一般使用块设备上一个独立的逻辑分区,类似windows中C、D盘。对于Ext2文件系统来说,硬盘分区首先被划分为一个个的Block,一个Ext2文件系统上的每个Block都是一样大小的。但是不同的文件系统,Block大小可能不同,这是在创建Ext2系统决定的,一般为1k或者4k。由于Block数量很多,为了方便管理,Ext2将这些Block聚集在一起分为几个大的块组(Block Group),每个块组包含的等量的物理块,在块组的数据块中存储文件或目录。Ext2文件系统存储结构如下图所示:

在这里插入图片描述

  • Boot Block是指文件系统中的一个固定位置,通常位于文件系统的第一个扇区或第一组扇区,用于存储引导程序和相关的引导信息。引导程序是计算机在启动时加载到内存中的程序,它负责检测和初始化硬件设备、加载操作系统内核以及启动操作系统。引导扇区信息包括分区表、文件系统类型等信息,它们是为了帮助操作系统正确地识别文件系统和分区的位置和大小。
    Boot Block的作用非常重要,它是启动计算机的第一步。在计算机启动时,BIOS会读取硬盘的Boot Block,然后执行其中的引导程序,从而加载操作系统内核。如果Boot Block出现问题,计算机就无法启动,这就需要使用其他工具进行修复或重新安装操作系统。
  • 超级块(Super Block):存放文件系统本身的结构信息。记录的信息主要有:bolck 和 inode的总量,未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个文件系统结构就被破坏了。
  • GDT,Group Descriptor Table:块组描述符,描述块组属性信息,如该块组内inode总数、block总大小等信息。
  • 块位图(Block Bitmap):Block Bitmap中每个bit位记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用。
  • inode位图(inode Bitmap): inode Bitmap中每个bit位记录着inode table中的inode是否处于空闲状态。
  • inode table(索引结点表):存放该组内所有文件的inode结点,存储文件属性的区域就叫做inode(索引结点),一个inode结点占128字节。
  • Data Block(数据区):存放文件内容。

Q:为什么每个Block Group中都存在Super Block?而Boot Block只存在一份即可?

在文件系统的设计中,Boot Block和Super Block都是固定位置的数据结构,它们在分配磁盘空间时被分配了固定的位置。Super Block存储了文件系统的元数据信息,如文件系统的总大小、空闲块的数量、使用的块数等等,而Boot Block则只存储了引导程序和引导扇区信息,如果Super Block出现了故障那么整个分区的所有数据都不能被使用,而Boot Block出现故障虽然导致操作系统不能成功运作,但是数据不会丢失。因此每个Block Group中存在一份Super Block是为了避免单点故障,提高文件系统的可靠性和可恢复性。如果一个Block Group中的Super Block出现问题,可以使用其他Block Group中的备份Super Block来恢复文件系统。

四、inode

在Linux中,文件 = 内容 + 属性,它们是两个分离的版块但是又必定存在一定的联系。文件数据存储在块中,那么还必须找到一个地方存储文件的元信息,比如文件的创建者、文件的创建日期、文件的大小等等。这种存储文件元信息的区域就叫做inode,中文译名为索引结点。因此,一个文件必须占用一个inode,但至少占用一个block。

一般而言,一个文件的所有属性信息保存在inode结点中,一个文件就对应一个inode结点,那么在一个分区中必定存在大量文件,即会存在大量inode结点,我们要将inode结点区分开来,所以每一个inode结点都会有一个自己的inode编号,inode编号也属于对应文件属性id,即在inode结点中存在;
而一个文件的内容是通过[1,n]个数据块保存的,那么文件是如何知道自己所占的是哪几个数据块呢?
实际在inode中定义了一个block数组,里面记录了该文件所占数据块的编号。由此初步猜测在Linux中查找一个文件先是根据inode编号来定位文件的,进而根据inode属性中的block数组找到文件所占数据块(文件的内容)!! 一个文件对应一个inode编号,该文件inode编号与该文件对应的数据块是有映射关系的!!

4.1 inode内容

下面我将带大家看一看Linux内核源码,大家自己也可以下载一份,我下的是Linux-6.1.6版本的,下面我将etxt2文件系统为例,在fs/ext2/ext2.h中可以找到Linux内核对于inode结构体的定义,我们的目的就是看懂一部分就可以了:
在这里插入图片描述

使用stat命令我们就可以直接看到某个文件的inode信息:

在这里插入图片描述

在Linux系统内部其实并不使用文件名去查找一个文件,而是使用inode号码来识别文件,对于系统来说文件名只是inode号码,便于识别的别称,文件名是方便用户看的!!

在上述inode结点中我们也确实没有看到文件名,那么文件名究竟在哪里?

4.2 文件名究竟放在哪里

我们来重新认识一下目录,目录是什么?

文件,Linux下一切皆文件。它有内容吗?有的,它的内容是什么?
它所占的数据块。更直观的来说任何一个文件都一定存在于目录之中,所以目录下有绝大多数情况下都有文件,每一个文件对应一个inode编号,每一个文件对应一个inode结点,inode结点中保存着它所对应的数据块。我们通常查找一个文件是在该目录下进行查找的,所以目录的数据块里面一定保存着文件名和该文件inode编号的对应关系,在目录内文件名与inode互为key值!!

结论:文件名存在于目录文件中,它与inode编号构成映射关系!!

我们查看一下内核源码来验证一下:

在这里插入图片描述

如此在Linux中对一个文件进行读写操作我们就有一个整体的认知了:

  • 1.在特定的目录下找到对应的文件名,根据文件名与inode编号的映射关系得到inode编号
  • 2.通过inode编号,获取inode属性信息
  • 3.根据inode属性信息,找到该文件所在的数据块,并读出数据。

其实系统还要根据inode信息,看用户是否具有访问的权限,有就指向对应的数据(block),没有就返回权限拒绝。

inode与文件名的映射关系:

在这里插入图片描述

由于inode号码与文件名分离,导致一些Unix/Linux系统具备以下几种特有的现象:

  • 文件名包含特殊字符,可能无法正常删除。这时直接删除inode,能够起到删除文件的作用。
  • 移动文件或重命名文件,只是改变文件名,不影响inode号码;
  • 打开一个文件以后,系统就以inode号码来识别这个文件,不再考虑文件名。
    这种情况使得软件更新变得简单,可以在不关闭软件的情况下进行更新,不需要重启。因为系统通过inode号码,识别运行中的文件,不通过文件名。更新的时候,新版文件以同样的文件名,生成一个新的inode,不会影响到运行中的文件。等到下一次运行这个软件的时候,文件名就自动指向新版文件,旧版文件的inode则被回收。

4.3 inode与Block的对应关系

上述inode的内容中我们看到inode用一个数组保存着该文件对应的Block编号,通过Block编号来读取对应的数据块(内容)。Inode要记录的数据非常多,但大小仅为固定的128字节,同时记录一个Block号码就需要4字节,假设一个文件有400MB且每个Block为4K时,那么至少也要10wKB来记录Block号码。Inode不可能有这么多的记录信息,因此Ext2将Inode记录Block号码的区域定义为12个直接、一个间接、一个双间接与一个三间接记录区。Inode存储结构如下图所示:

在这里插入图片描述

在这里插入图片描述

最左边为Inode本身(128 bytes),里面有12个直接指向Block号码的对照,这12笔记录能够直接取得Block号码。至于所谓的间接就是再拿一个Block来当作记录Block号码的记录区,例如:24号中保存着12、10、5号Block号码,要想知道12号Block的数据就要先找到24号,找到24号后在从里面找到12号,这是一种非常巧妙的定位方式极大的节省了空间。如果文件太大时,就会使用这种间接的Block来记录编号。 同理,如果文件持续长大,那么就会利用所谓的双间接,第一个Block仅再指出下一个记录编号的Block在哪里,实际记录的在第二个Block当中。依此类推,三间接就是利用第三层Block来记录编号。

4.4 inode耗尽故障

由于硬盘分区的inode总数在格式化后就已经固定,而每个文件必须有一个inode,因此就有可能发生inode节点用光,但是硬盘还未存满的情况,这时,就无法在硬盘上创建新文件。同时这也是一种攻击的方式,所以一些公用的文件系统就要做磁盘限额,以防止影响到系统的正常运行。

实际问题:在一台配置较低的Linux服务器(内存、硬盘比较小)的/data分区内创建文件时,系统提示磁盘空间不足,用df -h命令查看了一下磁盘使用情况,发现/data分区只使用了66%,还有12G的剩余空间,按理说不会出现这种问题。 后来用df -i查看了一下/data分区的索引节点(inode),发现已经用满(IUsed=100%),导致系统无法创建新目录和文件。

  • 查找原因:/data/cache目录中存在数量非常多的小字节缓存文件,占用的Block不多,但是占用了大量的inode。
  • 解决方案:
      1、删除/data/cache目录中的部分文件,释放出/data分区的一部分inode。
      2、用软连接将空闲分区/opt中的newcache目录连接到/data/cache,使用/opt分区的inode来缓解/data分区inode不足的问题:ln -s /opt/newcache /data/cache

五、软硬链接

5.1 硬链接

通过文件系统的inode链接来产生的新的文件名,而不是产生新的文件,称为硬链接。说的再通俗一点硬链接就是给原文件起了一个别名,类似于C++中的引用操作。因为它们两者除了文件名不一样之外,其他都是一样的。一般情况下,每个inode号码对应一个文件名,但是Linux允许多个文件名指向同一个inode号码,这也就意味着可以使用不同的文件名访问相同的内容。

5.1.1 创建硬链接
ln 原文件 目标文件

在这里插入图片描述

为myfile.txt创建硬链接之后,我们可以看到myfile.txt与hard_file.txt的inode号码相同,一个文件对应一个inode号码,这也就意味着它们两者指向同一个文件。

下面我们删除其中一个文件看看会出现什么现象:

在这里插入图片描述

我们发现删除myfile.txt之后,依然能看到hard_file.txt的内容,这说明此时inode结点并没有从inode table中移除掉,这是为何?

这是因为inode信息中有一项叫做"链接数"(Links),记录指向该inode的文件名总数。当我们为myfile.txt创建硬连接时,这时就增加1,反过来,删除一个文件名,就会使得inode节点中的"链接数"减1。当这个值减到0时,才表明没有文件名指向这个inode,系统才会回收这个inode号码以及其所对应block区域,这一点跟我们的rm删除普通文件的原理是相似的。所以上述过程中hard_file.txt依然存在,只是硬连接数-1了。

所以其实所谓创建硬链接很简单,就是多了一个文件名指向对应的inode号码,在目录项中多添加一个文件名与inode号码建立映射关系,多对一的映射关系,但实际两者没有任何区别,属性和数据块都是一样的,只是文件名不同罢了,删除一个硬链接文件并不影响其他有相同inode 号的文件,硬链接数-1。

5.1.2 目录文件的链接数

在这里插入图片描述

通过上图我们可以看到dir空目录的硬链接数为2,这是为何?

我们猜想它肯定与它的路径下的隐藏文件(./..)有关系,我们来分析一下:

在这里插入图片描述

dir是一个目录,但是它也是一个文件,既然是文件一定有对应的inode号码,而进入dir目录后,我们知道每创建一个目录,默认会创建./..这两个隐藏文件,我们发现.这个隐藏文件我们通常认为它表示当前目录文件,而确实它的inode也与dir目录的inode号码相同,这也就说明它们两者都指向同一个文件,所以硬链接数为2!!

结论:在Linux中,任何一个目录文件至少有2个链接数!!

下面我们继续来做做实验:

在这里插入图片描述

那为什么每创建一个目录文件当前目录文件的链接数就会+1呢?

这是由于这个新目录文件的隐藏文件(..)指向了当前目录,比如当前我们进入的是mytest1,那么cd .. 就可以回到上级目录lesson17,..与lesson17目录文件inode号码一致也就是同一个文件,所以lesson17目录文件的链接数会+1。在lesson17目录下创建一个子目录,子目录中的..指向lesson17所以lesson17的链接数会随着子目录的增加而增加。

结论:某个目录文件的链接数 = 2 + 子目录文件个数!!

Q:下面有个问题:上述实验我们都是给普通文件建立硬链接,可以给目录建议硬链接吗?

不可以,这样会造成环路路径的问题,例如:/home/curry/lesson17,假设我们给在lesson17目录下为curry创建一个硬链接hard-link,那么当我们想查找某个文件,在Linux下查找文件时,默认会根据路径递归查找,这意味着系统将从指定路径开始,在该路径下的所有目录中查找文件,并在每个子目录中重复此过程,直到找到匹配的文件或搜索完整个文件系统。当从lesson17目录下的hard-link查找文件时,此时hard-link与curry指向的是同一个文件,所以hard-link又会返回curry进行查找,由此就造成了环路路径,一直出不来。

在这里插入图片描述

5.1.3 硬链接的特性
  • (1)文件具有相同的inode和data block
  • (2)只能对已存在的文件进行创建
  • (3)不能交叉文件系统进行硬链接的创建
  • (4)不能对目录进行创建,只可对文件创建
  • (5)删除一个硬链接文件并不影响其他有相同inode 号的文件。

5.2 软链接

软链接(symbolic link),也称为符号链接,是一种在文件系统中创建指向另一个文件或目录的特殊文件类型。软链接类似于 Windows 操作系统中的快捷方式,可以提供一个指向另一个文件或目录的路径,使得可以通过这个路径来访问原文件或目录。软链接是一种非常有用的特性,可以用于很多场景,例如:为长路径创建一个短的别名、在不同目录中共享文件等…

我们平时在Window中通过点击图标来打开一个软件,本质上这个图标就是一个快捷方式,它的内容是源文件的路径,点击之后就会执行该路径下某种指令,我们平时通过这种方式很快的就能找到我们的软件了,另外如果我们想删除这个软件的话,并不是把这个图标(快捷方式)删除,我们要将源文件删除了才算真正的删除:

在这里插入图片描述

5.2.1 创建软链接
ln -s 源文件/目录  目标文件/目录

在这里插入图片描述

5.2.2 删除源文件

我们知道软链接是目标文件链接源文件的路径,通过源文件的路径读取到它的内容,那么当源文件被删除之后,该文件还能读取到源文件的内容的吗?初步猜想肯定是不行的,下面我们来实验一下:

在这里插入图片描述

除了rm删除文件之外,我们还可以通过unlink来删除文件:

unlink 源文件/目录

在这里插入图片描述

从上图我们还可以发现,当删除源文件之后soft_file就找不到源文件了,soft_file一直在闪烁,当重新创建源文件之后,此时soft_file又重新与源文件建立起了关系!!

5.2.3 软链接特性
  • (1)软链接有自己的文件属性及权限等;
  • (2)可对不存在的文件或目录创建软链接;
  • (3)软链接可交叉文件系统;
  • (4)软链接可对文件或目录创建;
  • (5)创建软链接时,链接数不会增加;
  • (6)删除软链接并不影响被指向的文件,但若被指向的原文件被删除,则相关软连接被称为死链接(即 dangling link,若被指向路径文件被重新创建,死链接可恢复为正常的软链接)。

5.3 软硬链接的区别

硬链接软链接
本质同一个文件不是同一个文件
跨设备不支持支持
inode编号相同不同
目录不支持支持
链接数创建新的硬链接,链接数会增加,删除硬链接,链接数减少创建或删除,链接数不会变化
删除源文件只是链接数减一,但链接文件的访问不受影响链接文件将无法访问
文件类型和原文件相同链接文件,和原文件无关
文件大小和原文件相同原文件的路径的长度
相对路径原始文件相对路径是相对于当前工作目录原始文件的相对路径是相对于链接文件的相对路径

5.4 ACM时间

我们先来看看这三个时间:

在这里插入图片描述

  • Access 最后访问时间
  • Modify 文件内容最后修改时间
  • Change 属性最后修改时间

下面我们来实验一下:

在这里插入图片描述


  • 16
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

malloc不出对象

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值