Linux文件系统I

引言

从文件是否打开的角度,我们可以将文件管理分为管理已经被打开的文件和管理没有被打开的文件(文件的存储)。本文将介绍在Linux中,将如何管理没有被打开的文件,即文件的存储问题。题目所说的文件系统,用途就是管理未打开的文件。

我们都知道,一个文件被分为文件内容和文件属性这两部分。所以存储文件的时候就需要存储文件的内容和文件的属性。在Linux中,文件的内容和属性是分开存储的,文件的内容以块形式进行存储,而文件的属性则以 inode 形式进行存储。对于这一点,我们之后都会谈到。在这之前,我们需要先了解硬盘。

我们将要了解的硬盘并不是现在笔记本用的SSD,而是十几年前用的机械硬盘。虽然现在笔记本并不用机械硬盘了,但它仍有市场。而且,在Linux出现的时候,硬盘已经出现并且技术成熟。可以说Linux是诞生在硬盘之上的操作系统,文件就存储在硬盘中。所以了解硬盘对我们了解文件系统是有所帮助的。注:之后说到的硬盘指的都是机械硬盘。

机械硬盘

物理构成

虽然硬盘可以存储数据,但是它并不属于冯·诺依曼体系结构中的存储器,它是计算机的外设。硬盘是一种机械设备,我们可以看硬盘的内部照片:

图中的磁盘便是硬盘存储数据的地方,磁头便是用来读写磁盘上的内容。在计算机读写数据的时候,磁盘会高速旋转,同时磁头会向内或者向外移动,目的便是让磁头悬停在需要读写的数据所在的位置。磁头和磁盘距离很近,但他们两者并不会相互接触,对于这一点我们不必深究,只要了解即可。

那么磁盘怎么存储数据呢?怎么向磁盘上写数据呢?我们知道,计算机只认识二进制,它也只能处理二进制。计算机存储数据的时候是以二进制的形式进行存储的,所以磁盘存储的就是二进制。想要存储二进制,就需要两种状态表示 0 和 1。假设我有一个灯泡,定义灯泡灭是0,亮是1。那么我就可以通过灯泡的亮和灭表示一个二进制位。现在我有足够多的灯泡,只需要令每个灯泡的亮和灭和需要存储的每一个二进制位对应起来,并让这些灯泡一直保持这种状态不变,这不就是将二进制数据存储下来了吗?

磁盘便是通过这种思路存储二进制数据的。读者有没有玩过吸铁石(磁铁)呢?磁铁的两端具有不同的磁极,即南极(S极)和北极(N极)。我们可以通过一些手段,将磁铁的南北极位置进行调换。调换之后和调换之前的状态可以用来表示0和1,至于哪种状态表示0,哪种状态表示1,这是需要人为规定的。磁盘也是通过磁极的不同存储二进制位的。磁盘表面存在许多的磁性粒子,这些磁性粒子表现出来的磁极方向就代表二进制位,许多磁性粒子的组合便能够表示二进制数据,之后只要这些磁性粒子的状态不改变,那么磁盘便能够存储二进制数据。

知道磁盘是怎么存储数据后,写数据也就很简单了(实现肯定不简单)。只要改变磁盘上磁性粒子的状态,那么就能往磁盘上写数据了。这个过程便是由磁头完成。对于磁盘的存储和修改到此就结束了,如果对此感兴趣,请自行查阅相关资料。

存储构成

知道了硬盘的物理构成后,接下来我们便来了解一下硬盘的存储构成。

首先我们需要知道一些名词:扇面、磁道、扇区和柱面。从硬盘的内部照片中可以看出,一个硬盘中有许多磁盘,而一个磁盘有上下两面,这两面都可以用来存储数据。我们将磁盘的一面叫做扇面。那么什么是磁道呢?我们可以看下面一张图:

在磁盘上通过多个同心圆,我们可以将磁盘的扇面分为多个圆环,这些圆环就被称作磁道。而扇区便是在磁道的基础上继续划分,如图:

过磁盘圆心做多条长度和磁盘环宽相等的线段,将磁道分为多个部分,其中这一个部分就被称作扇区。相同磁道上的扇区面积是相同的。而磁盘上各个扇区的存储大小是相同的,一般而言是512B 或者 4KB。至于柱面,它也和磁道有关系。一个硬盘会有多张磁盘,即多个扇面。为了能够对这些扇面上的数据进行读写,就存在多个磁头。这些磁头都连接在同一个马达上,所以这些磁头是同时移动的。这也就造成了磁头到达一个扇面的某个磁道时,其他磁头也到达各自的磁道,从上往下看,这些磁道便组成一个面。如图:

我们在磁盘上存储数据,并不是在磁盘上随便找个空位置开始存储,而是根据这样的划分,在磁盘的某个盘面的某个磁道上的某个扇区开始存储数据。可以这么说,磁盘被访问的基本单元就是扇区。这时,我们可以将磁盘看做是由无数个扇区组成的存储介质。那么向磁盘真正写数据前需要定位一个扇区(确认地址),即确定扇面(磁头),寻找磁道(柱面),确定扇区,这便是CHS寻址方式。所以上面所说的磁头的移动,目的是确定柱面。盘片的旋转便是为了定位扇区。

硬盘效率

CHS寻址方式是依靠磁盘旋转和磁头移动的,简单地说,运动越少,效率越高。所以在软件设计上,设计者要有意识地将相关数据放在一起,例如同一柱面上。

对磁盘的逻辑抽象

在磁盘上我们采用的是CHS寻址方式,但在Linux系统中管理磁盘空间时采用的是LBA寻址方式。在讲LBA寻址方式之前,我们先讲一个题外话。不知读者有没有见过或者用过磁带。我们在使用磁带时,磁带会进行旋转。在旋转的同时,机器会读出存在磁带上的数据。正常情况下,我们看磁带是一个圆,但如果我们将其延展开,它就是一条线。如下图:

也就是说,虽然磁带是圆形的,但逻辑上,它是一个线性的。磁盘也是同样的道理,我们在逻辑上可以将磁盘看成是线性的。磁盘的每个扇面有多个磁道,每个磁道有多个扇区,那么整个磁盘就相当于一个基于扇区的数组。在这个基础上任意的扇区就有下标,我们根据下标就能确认该下标对应的扇面,磁道,以及磁道中的扇区。即逻辑扇区地址可以转化成为物理扇区地址,这种寻址方式便是LBA寻址方式。

文件系统(ext2文件系统)

在说文件系统的时候,我们需要搞懂一个问题:我们有一定容量的磁盘空间,哪些存文件属性呢,哪些存文件内容呢?在回答这个问题之前,我们需要一些知识。

首先,当磁盘空间很大,很难管理时,怎么办?ext2文件系统采用分治的思想。第一步便是对磁盘空间进行分区,实际上我们每个人刚买电脑时就做过这事。那怎么分区呢?确定区域开始和结束的扇区下标。

在分区之后,我们只要将一个区域管理好,那么管理其他的区域时只要复制粘贴即可,因为每个分区本质上是相同的,即以扇区为单位的一个有限数组。那么怎么管理一个分区呢?Linux将分区又分为几个部分进行管理。具体如图:

一个分区,首先会分成1个 boot block 区和多个 block group 区。

Boot Block

boot block 区位于分区开始位置,并且它的大小固定。这个区域一般存储着引导加载程序。在系统启动时,如果该分区被设置为启动分区,那么 BIOS/UEFI 会读取该区域的代码来加载操作系统。如果该分区不是启动分区那么该区域一般为空或者未使用,但它仍会存在,以保持兼容性和一致性。

Block group

当一个分区存在多个 group 时,我们只需要管理好一个 group,便能管理好所有 group,从而管理好一个分区,进而管理好整个磁盘空间。那么怎么管理一个 group呢?继续分成几部分进行管理。

Data blocks

这个区域被用来存放文件内容,以块的形式呈现。常见的块大小为 4KB,这是文件系统的块大小,当然也存在 1KB、2KB等。我们可以通过相关指令更改文件系统的块大小,具体的需要读者自行搜索。

虽然整个磁盘是以扇区为单位进行管理,但是文件系统对这个区域进行操作时,是以块为单位进行操作的。例如,如果我需要 1KB 的空间来存储文件,文件系统会给我一个块的空间存储这个文件。而且通常即使一个块未被写满,该块也不能存储其他文件的数据。很明显,这种以块为单位的分配是可能造成空间浪费的,但是一个文件也不一定只占用一个块,所以空间的浪费并不严重。

inode Table

顾名思义,这个区域用来存放文件的inode。至于为什么被称作表,具体原因这里不详谈,读者请自行搜索资料。

那什么是 inode 呢?之前说道,inode存储的是文件的属性,但这只是inode的作用。实际上,inode 是 ext2 文件系统的核心数据结构,他并不是一种文件。类似于在C语言中创建一个结构体,该结构体名字是 inode,里面存储的是文件的所有属性。一般一个 inode 的大小是 128B,并且一个文件对应一个 inode。

同时,在 Linux 中,文件属性并不包含文件名。那么在 Linux 中怎么区分文件呢?通过 inode 编号。每个 inode 都有一个唯一的编号,又因为一个文件对应一个 inode,所以可以通过 inode 标识一个文件。指令 ls -i 可以显示文件的 inode 编号。

既然我们可以通过 inode 编号标识文件,那么如果只知道 inode 编号,怎么知道文件内容存储在哪里呢?inode 中除了有文件属性外,它还有一个定长的 blocks 数组(通常包含15个元素),这个数组中存放的是文件内容所在的块编号(Data Blocks 区域不仅以块的形式呈现,每个块都拥有自己的编号)。通过这个数组中存储的编号我们可以找到文件内容。

那在 ext2 中,一个文件最大只能占据 15 个块吗?并不是。在 blocks 数组中,前 12 个元素存储的是直接索引,第 13、14、15 个元素分别是一级、二级、三级间接索引。也就是说,前 12 个元素直接指向文件内容所在的块,第 13 个元素指向的块存放的是直接索引,第14个元素指向的块存放的是一级索引,以此类推。如果每个块大小为 4KB,每个直接索引占 4B,那么一个文件最大为

Block bitmap

按照命名,我们就能知道这个区域的作用类似于位图。它映射一个块组中每个块对应的块号,标记一个块是否被使用,从而能够快速寻找未使用的块。一个比特位值为1代表对应的数据块被使用,为0代表空闲

问题1:Data Blocks中的块号分配规则是什么?能够跨group吗?能够跨区吗?

问题2:怎么映射的?

inode bitmap

这个区域的作用和 Block bitmap 类似,不过它映射的是 inode 的编号。

问题1:inode 的编号分配规则又是什么?是仅在一个 group 中 inode 编号唯一还是整个系统中唯一?

问题2:怎么映射的?

问题3:删除和创建文件的具体过程是什么样的?

问题4:删除文件时是否需要清空文件?

Group Descriptor Table(GDT)(简述)

GDT,组描述符表,它的作用是描述整个 group 的基本信息和使用情况,以便快速定位和管理 group 内的资源。比如 GDT 会记录 group 中块位图和 inode 位图的磁盘块号,同时记录 inode Table 的起始磁盘块号。它也会记录 group 中的空闲块和空闲 inode 的数量。总之,可以通过 GDT 更好地管理一个组。

Super Block

Super Block,超级块,它描述整个分区的文件系统的信息。它包含整个分区的基本使用情况:一共有多少组,每个组的大小,每个组的 inode 数量,每个组的 block 数量,每个组的 inode起始编号,文件系统的类型和名称等等这些东西都交由超级块描述。可以认为它是一个分区的管理块。

正因为超级块是隶属于整个分区的,所以没有必要在每个 group 中都存在超级块,否则写磁盘时需要对所有超级块进行更新,浪费时间。不过通常来讲,超级块不止存在一份,系统可能会在部分 group 中复制超级块,防止超级块出问题时导致文件系统挂掉。

既然在有些组中存在超级块,有些组中没有超级块,我们在访问时,怎么判断访问的这块是不是超级块呢?超级块中存在"魔数"字段,它是超级块的唯一标识符。"魔数"存储在超级块中的固定位置,并且它的值也是固定的(具体的读者自行查阅)。我们可以借助"魔数"判断一个块是不是超级块。

什么是文件系统(参考AI)

我们现在知道Linux管理磁盘是先分区管理每个区,对于每个区分组进行管理。简单地说,一个分区的管理方式,就是我们常说的文件系统。形象地说,我们现在有一大块空白的土地(原始磁盘空间),我们想在空地上建一个图书馆来管理书籍(在磁盘上存储并管理数据)。我们首先在空地上划出一块区域专门建立图书馆(磁盘分区),其他区域可以建其他东西(也能用来存储数据)。图书馆建好后我们需要一套管理规则对图书馆进行管理(管理磁盘分区),这套管理规则就相当于文件系统。而 ext2 文件系统就相当于一套具体的管理规则。

正式地说,**文件系统(File System)是一套用于明确、高效地组织、存储、管理、检索、命名和保护磁盘上数据的软件方法、数据结构和规则。**文件系统是一种框架或者模式,而 ext2文件系统便是一种具体实现。

现在我们应该已经对 ext2 文件系统有了一定的了解了,所以可以试着解决一些问题了。

相关推荐
阿成学长_Cain3 小时前
Linux ipcs 命令超全详解:查看共享内存 / 消息队列 / 信号量,IPC 运维必备
linux·运维·服务器·网络·数据库
黯然神伤8883 小时前
AlmaLinux设置软件下载源
linux·alma
青瓦梦滋3 小时前
协议定制/序列化-反序列化(Linux视角)
linux·服务器·网络·c++
运维老郭5 小时前
【K8s运维实战】Kubernetes临时存储卷实战:emptyDir核心用法与gitRepo弃用迁移指南
运维·云原生·kubernetes
珠海西格电力6 小时前
云边端协同架构:零碳园区管理系统的技术底座
大数据·运维·人工智能·算法·架构·能源
阿成学长_Cain6 小时前
Linux dirs命令详解|Bash目录堆栈管理快速切换目录实战教程
linux·运维·前端·数据库
小羊Yveesss7 小时前
2026年微信小程序后端怎么搭建?后台、数据、接口和运维怎么选
运维·微信小程序·小程序
ICECREAM7 小时前
Linux 进程间通讯(IPC)——总结
linux