【Linux】系统部分——磁盘存储结构与文件系统
16.磁盘存储结构与文件系统
文章目录
- 16.磁盘存储结构与文件系统
- 一、磁盘的物理结构(简单了解)
- 核心结构
- CHS寻址与LBA地址
- 二、文件系统
- “块”的概念
- “分区”的概念
- “inode”的概念
- ext2文件系统
- Block Group
- 格式化
- 文件的操作过程
- ⽬录与⽂件名以及路径
- 总结
一、磁盘的物理结构(简单了解)
机械磁盘是计算机中唯一的机械设备,其特点是容量大、价格便宜但速度较慢。机械磁盘通过内部的小磁铁阵列存储二进制数据,规定北极代表1、南极代表0(如磁铁烧红后可消磁)。SSD固态硬盘价格较高、存储效率高,但容量成本不适用于企业冷数据存储。磁盘数据存储基于物理硬件的二进制表达:在磁盘上通过改变微小磁铁的南北极状态(N/S)表示0和1。例如,写入“1”需将S极改为N极。 销毁磁盘数据时,需彻底消磁(如高温火烧),仅删除文件或格式化无法完全清除数据,可能造成泄露。
核心结构
-
磁盘有盘面,所有数据存储在盘面上。磁头用于向盘面写入数据,这一圈圈同心圆我们称之为磁道。
-
数据存储在磁盘盘面上,盘面很光滑,肉眼看不到,但数据是一圈一圈存储的。磁盘有一圈完整的磁道,所有磁道被分成一段段,中间有间隙,这一小段被称为扇区。磁盘以主轴为分割点,俯视时,磁盘可能包含多个盘片,每个盘片有两面,如图上有三个盘片,共六面,六面正反均可存储数据,由无数个同心圆构成,称为磁道。同半径的磁道在不同盘面上,共同构成逻辑上的概念,叫柱面。
-
当磁盘通电后,盘片会以特定速度顺时针旋转。磁盘有多种类型,如普通云盘、高性能盘、直连盘等,最常见的是SARS盘,转速不同,有千级别的7200转,也有更快的1万2000转,甚至两万转。盘片以固定速率旋转,磁头左右摆动,在半径方向上移动,传动臂可定位到磁盘的任何位置。磁头摆动的本质是在定位磁道或柱面。磁头摆动时,会访问不同位置的扇区。当磁盘旋转时,若磁头限定在某个位置,该位置有一圈同心圆,即一个磁道。盘片不断旋转时,可将不同扇区依次置于磁头正下方。磁头感应扇区上的零01值,磁盘旋转的目的是定位扇区。只要找到磁盘特定的磁道,并通过盘片旋转定位到某个扇区,即可保存数据。扇区是磁盘存储数据的基本单位。
-
它对应的大小一般是512字节,在当代磁盘技术中,也存在单个扇区大小为4kp的情况,但这里我们讲最常见的磁盘,其最终单位大小是512字节。换句话说,如果想往磁盘的特定位置写数据,本质是把数据写在一个或多个扇区里,哪怕要修改整个磁盘中一个扇区的一个比特位,也必须把512字节全部读到内存里,设置好对应的比特位,再重新把这512字节数据写到磁盘的特定扇区。这时我们称之为在读写磁盘时,不是以字节为单位,而是以512字节这个小块为单位,所以磁盘叫做块设备。
CHS寻址与LBA地址
想要从磁盘中获取指定数据就先要知道这个数据存放在磁盘中的那一个位置。 柱⾯(cylinder),磁头(head),扇区(sector),显然可以定位数据了,这就是数据定位(寻址)⽅式之⼀,CHS寻址⽅式。
-
柱面是一个逻辑上的概念,每一面上相同半径的磁道逻辑上构成一个面,这叫做柱面。
-
对于磁盘的某一个盘面的某一个磁道,将其展开可以看到其结构与一维数组类似。
-
而我们将一个柱面上的磁道分别展开就得到了一个二维数组
-
继而对整个磁盘展开,其结构就是一个三维数组
寻址⼀个扇区:先找到哪⼀个柱⾯(Cylinder) ,在确定柱⾯内哪⼀个磁道(其实就是磁头位置, Head),在确定扇区(Sector),所以就有了CHS。 所以,每⼀个扇区都有⼀个下标,我们叫做LBA(Logical Block Address)地址,其实就是线性地址。 磁盘就是⼀个三维数组,我们把它看待成为⼀个"⼀维数组",数组下标就是LBA,每个元素都是扇区。
二、文件系统
“块”的概念
前面已经提到了磁盘是一种块设备,操作系统读取硬盘数据的时候,其实是不会⼀个个扇区地读取,这样效率太低,⽽是⼀次性连续读取多个扇区,即⼀次性读取⼀个”块”(block)。 硬盘的每个分区是被划分为⼀个个的”块”。⼀个”块”的⼤⼩是由格式化的时候确定的,并且不可以更改,最常⻅的是4KB,即连续⼋个扇区组成⼀个 ”块”。”块”是⽂件存取的最⼩单位。
每个扇区都有LBA,那么8个扇区⼀个块,每⼀个块的地址我们也能算出来。
“分区”的概念
其实磁盘是可以被分成多个分区(partition)的,以Windows观点来看,你可能会有⼀块磁盘并且将它分区成C,D,E盘。那个C,D,E就是分区。分区从实质上说就是对硬盘的⼀种格式化。 柱⾯是分区的最⼩单位 。
-
我们可以通过分区的方式来管理,只要管好一个分区,就可以将这种管理方式复制到其他分区,从而管好每一个分区。
-
可以给分区设置不同的文件系统,因为分区之间互相独立,这样即使一个分区出现问题,也不会影响其他分区。
“inode”的概念
在文件系统中,文件由内容和属性组成。内容即我们编写的文本或二进制数据,属性也是数据形式。在Linux系统中,这些属性最终以结构体的方式构建。这个结构体我们称之为inode。简单来说,一个文件对应一个inode,不存在一个文件对应两个inode的情况。当然,也存在少数情况,一个文件可能没有inode。inode,我们也称之为i结点,它是文件属性数据的集合,它包含inode的编号、权限、文件的拥有者及所属组等信息,还包括文件的访问时间、修改时间、状态改变时间,以及文件的大小,即文件的属性集。
-
Linux下⽂件的存储是属性和内容分离存储的
-
Linux下,保存⽂件属性的集合叫做inode,⼀个⽂件,⼀个inode,inode内有⼀个唯⼀的标识符,叫做inode号
-
但是,在Linux系统中,文件名这个属性并不保存在inode里。
ext2文件系统
我们想要在硬盘上储⽂件,必须先把硬盘格式化为某种格式的⽂件系统,才能存储⽂件。⽂件系统的⽬的就是组织和管理硬盘中的⽂件。在 Linux 系统中,最常⻅的是 ext2 系列的⽂件系统。
ext2⽂件系统将整个分区划分成若⼲个同样⼤⼩的块组 (Block Group),如下图所⽰。只要能管理⼀个分区就能管理所有分区,也就能管理所有磁盘⽂件
在一个分组里可能有非常多的inode,所以这里就有了一张inode table。Inode table对应的是我们所有组里面的所有文件的属性集。
Block Group
超级块(Super Block) | 存放⽂件系统本⾝的结构信息,描述整个分区的⽂件系统信息。记录的信息主要有:bolck 和 inode的总量,未使⽤的block和inode的数量,⼀个block和inode的⼤⼩,最近⼀次挂载的时间,最近⼀次写⼊数据的时间,最近⼀次检验磁盘的时间等其他⽂件系统的相关信息。Super Block的信息被破坏,可以说整个⽂件系统结构就被破坏了。 |
---|---|
GDT(Group Descriptor Table) | 块组描述符表,描述块组属性信息,整个分区分成多个块组就对应有多少个块组描述符。每个块组描述符存储⼀个块组 的描述信息,如在这个块组中从哪⾥开始是inode Table,从哪⾥开始是Data Blocks,空闲的inode和数据块还有多少个等等。 |
块位图(Block Bitmap) | Block Bitmap中记录着Data Block中哪个数据块已经被占⽤,哪个数据块没有被占⽤ |
inode位图(Inode Bitmap) | 每个bit表⽰⼀个inode是否空闲可⽤ |
i节点表(Inode Table) | 存放⽂件属性 如 ⽂件⼤⼩,所有者,最近修改时间等 当前分组所有Inode属性的集合 inode编号以分区为单位,整体划分,不可跨分区 |
Data Block | 数据区:存放⽂件内容,也就是⼀个⼀个的Block。 根据不同的⽂件类型有以下⼏种情况: • 对于普通⽂件,⽂件的数据存储在数据块中。 • 对于⽬录,该⽬录下的所有⽂件名和⽬录名存储在所在⽬录的数据块中,除了⽂件名外,ls -l命令看到的其它信息保存在该⽂件的inode中。 • Block 号按照分区划分,不可跨分区 |
分区之后的格式化操作,就是对分区进⾏分组,在每个分组中写⼊SB、GDT、Block Bitmap、Inode Bitmap等管理信息,这些管理信息统称: ⽂件系统。只要知道⽂件的inode号,就能在指定分区中确定是哪⼀个分组,进⽽在哪⼀个分组确定是哪⼀个inode。拿到inode⽂件属性和内容就全部都有了
格式化
在了解Block Group的结构之后,我们可以继续学习格式化的内容:
格式化并不是把磁盘“擦干净”,而是:
- 将 inode bitmap、block bitmap 清零;
- 写入 superblock(超级块,记录整个文件系统的元信息);
- 按照设计好的比例,为 inode table 和 data blocks 分配区域。
这就像在一张白纸上先画好格子,标明哪些格子用来写文字,哪些用来放图片。实际上,文件的数据内容并没有立刻被抹掉,只是 inode 和 block 的位图被清零,系统认为这些资源“空闲”了。所以,格式化就是一种 “重新安排磁盘秩序” 的操作。
【补充】这也是为什么专业的数据恢复工具,往往能在“误格式化”后找回一部分文件的原因——因为数据本身可能还在,只是没有了索引。
文件的操作过程
-
创建文件
假设你执行:
touch test.txt
底层过程大致是:
-
在 inode bitmap 找到一个空闲位,置为 1;
-
在 inode table 初始化这个 inode,写入属性(时间戳、权限、uid/gid 等);
-
在 block bitmap 中不分配数据块(因为新文件内容为空),只是预留 inode;
-
在 当前目录文件的数据块 中增加一条映射:
test.txt → inode号12345
于是,文件就被“创建”了。
-
-
打开与读取文件
假设你执行:
cat test.txt
底层过程:
- 路径解析,找到
test.txt
对应的 inode; - 根据 inode 里的指针找到文件内容的 block 号;
- 将数据块读入内存缓存;
- 把缓存数据交给进程。
【补充】Linux 内核用 页缓存(page cache) 来优化文件读取,避免频繁访问磁盘。
- 路径解析,找到
-
修改文件
假设你往
test.txt
写入内容:echo "hello" >> test.txt
底层过程:
- 在 inode 中更新文件大小、修改时间戳;
- 在 block bitmap 中找到空闲数据块,分配给该文件;
- 在 inode 的指针数组里,填入对应的 block 号;
- 把字符串 “hello” 写入数据块。
-
删除文件
假设你执行:
rm test.txt
底层过程:
- 在当前目录文件的数据块里,删除
"test.txt → inode号12345"
这条映射; - 把 inode bitmap 对应位置从 1 改为 0;
- 把 block bitmap 对应位置从 1 改为 0;
- inode table 和 data block 的内容并不会立即清空,只是被标记为“可用”。
因此,文件删除并不等于内容消失,而是“失去了入口”。
【补充】这就是为什么用
unlink
删除文件时,如果还有进程持有该文件的文件描述符,内容仍然可以继续读写,直到最后一个引用关闭为止。 - 在当前目录文件的数据块里,删除
⽬录与⽂件名以及路径
在linux下一切皆文件,⽬录也是⽂件,但是磁盘上没有⽬录的概念,只有⽂件属性+⽂件内容的概念 。与普通文件不同的是:内容保存的是⽂件名和Inode号的映射关系 。访问⽂件,必须打开当前⽬录,根据⽂件名,获得对应的inode号,然后进⾏⽂件访问 。打开目录文件 → 在目录内容里按名字查到 inode 号 → 根据 inode 读取文件属性并定位数据块 → 访问文件内容。
Linux中,在内核中维护树状路径结构的内核结构体叫做: struct dentry
- 每个⽂件其实都要有对应的dentry结构,包括普通⽂件。这样所有被打开的⽂件,就可以在内存中形成整个树形结构
- 整个树形节点也同时会⾪属于LRU(Least Recently Used,最近最少使⽤)结构中,进⾏节点淘汰
- 整个树形节点也同时会⾪属于Hash,⽅便快速查找
- 更重要的是,这个树形结构,整体构成了Linux的路径缓存结构,打开访问任何⽂件,都在先在这棵树下根据路径进⾏查找,找到就返回属性inode和内容,没找到就从磁盘加载路径,添加dentry结构,缓存新路径
总结
磁盘作为块设备,数据以扇区(通常512字节)为单位存储,通过CHS或LBA地址进行寻址。文件系统(如ext2)将磁盘分区划分为多个块组,每个块组包含超级块、块组描述符、位图、inode表和数据块等结构,用于管理文件属性和内容。文件操作(创建、读写、删除)本质上是通过inode和位图机制实现对磁盘块的分配与释放。目录也是一种特殊文件,其内容存储文件名与inode号的映射关系,内核通过dentry结构维护路径缓存,提升文件访问效率。