从磁盘硬件到Ext文件系统-Linux磁盘级文件系统学习笔记

从磁盘硬件到 Ext 文件系统:一次彻底搞懂 Linux 磁盘级文件系统(学习笔记)

本文是我学习 Linux 磁盘与文件系统部分(7.12--7.14)的整理笔记。

路线:磁盘物理结构 → CHS / LBA 寻址 → 块(Block) → 分区分组 → inode → 位图与删除文件的真相

前置知识:进程视角下的文件(已打开的文件)。本文回答的是那个更本质的问题------文件在没被打开之前,到底是什么?


一、为什么要先学磁盘?(7.12)

之前我们聊的都是「已打开的文件」:语言级函数、系统调用、缓冲区、进程的文件描述符表......但文件总得有个「家」。文件在打开之前,就躺在磁盘上。所以要理解文件系统,必须先理解磁盘这个硬件。

对机械磁盘的第一印象:

  • 它是计算机中唯一的机械设备 ------CPU、内存都是电子器件,纳秒级响应;磁盘要转动 、要磁头摆动,慢了几万倍不止;
  • 但它容量大、价格便宜、数据断电不丢,所以注定长期担任「存储主力」;
  • 磁盘装进服务器,服务器放进机柜,机柜再进机房------这就是「磁盘 → 服务器 → 机柜 → 机房」的层级。

一个重要的细节:磁头不接触盘面。 磁头悬浮在离盘面几十纳米的高度,靠盘面高速旋转带起的气流「托」住。一旦接触(划伤、高温),数据就可能丢失------这就是为什么磁盘不能摔、不能刮花、不能消磁。


二、磁盘是怎么存数据的?(7.13 上)

2.1 磁性存储的本质

磁盘上布满了数以亿计的微小磁铁(磁性材料),用南北极方向表示 0 和 1。磁头通过电流改变磁场方向,就完成了写入;读取时感应磁场方向变化,就完成了读出。

关键性质:

  • 磁性不会自发退磁 → 所以叫永久磁盘(断电不丢数据);
  • 想彻底销毁数据?高温消磁整个盘面即可。

2.2 磁盘的物理结构

一块磁盘自上而下有多个盘片 ,每个盘片有正反两个盘面(例如 3 个盘片 = 6 个盘面,配 6 个磁头)。每个盘面上:

  • 磁道(Track):一圈圈的同心圆;
  • 扇区(Sector) :磁道被切分成的弧段,是磁盘 IO 的最小物理单元 ,一般 512 字节(或 4KB)。

所有磁头固定在同一组臂上,共进退 ------同一时刻,所有盘面上的磁头都指向各自盘面的同一号磁道。这些同半径的磁道在空间上叠成一个柱面(Cylinder)

一个有意思的工程取舍:内圈扇区面积小、外圈大,理论上外圈能存更多数据。但那需要更复杂的适配算法,市面上的磁盘干脆让每个扇区容量相等------简单,且效率可预期。

2.3 CHS 定位:三维数组的下标

要在磁盘上找到数据,本质是三步定位:

  1. 找到哪个柱面(Cylinder)------磁头臂摆动到目标磁道;
  2. 确定哪个磁头(Head)------即哪个盘面;
  3. 等盘片旋转,让目标扇区(Sector)转到磁头下。

所以磁盘在逻辑上就是一个三维数组:

c 复制代码
Sector disk[C][H][S];  // 柱面 × 磁头 × 扇区

CHS 就是这个三维数组的下标。柱面 == 磁道(磁头共进退,摆动的本质就是选磁道);盘片旋转的本质是选扇区(转得越快,效率越高);最后选定磁头读数据。


三、从 CHS 到 LBA:把三维数组拉直(7.13 下)

三维数组太麻烦,寻址要给三个数字。我们换个视角:

  1. 把一个盘面的所有磁道拉直,盘面就成了一个线性结构;
  2. 把 6 个盘面的线性结构首尾相接,整个磁盘就成了一个一维数组

于是每个扇区都有了一个唯一的线性下标------这就是 LBA(Logical Block Address,逻辑块地址)

3.1 CHS vs LBA

CHS LBA
视角 磁盘物理结构(三维数组) 逻辑线性(一维数组)
寻址 需要三个下标 一个数字搞定
谁在用 磁盘硬件内部 文件系统 / 操作系统

两者可以通过固定的逻辑运算互相转换 ,而这个转换由磁盘内部的伺服系统自动完成

结论:磁盘是一个黑盒。操作系统只需要传入一个 LBA 数字,伺服系统负责把它翻译成 CHS 三步定位,读写任意扇区。

3.2 为什么硬件访问如此昂贵?(7.14 补充)

以机械硬盘为例:磁头要等盘面达到额定转速、产生的气流能托住磁头后才能进场工作。而从 0 加速到额定转速要 1~2 秒,寻道、旋转等待与电信号相比慢数万倍。结论:

调用这个硬件的代价极高,要尽可能少地调用它、每次调用多干点活。(底层磁盘因此支持一次连续读写多个扇区。)这也是后面「块」「预读」「内核缓冲区」一系列设计的原始动机------和「用户态切内核态代价高」是同一种思路。


四、文件系统的引入:块、分区、分组(7.13 下)

4.1 为什么不按 512B 访问,而按 4KB 访问?

磁盘最小物理单元是 512 字节扇区,但操作系统(以 Ext2 为例)与磁盘打交道的基本单位是 4KB 的「块(Block)」= 8 个扇区。原因:

  1. 效率 :访问一次硬件代价太大,一次读 4KB 配合预读机制,摊薄成本;写入则配合刷新机制;
  2. 软硬件解耦 :OS 全程只说「块号」,由 块号 → LBA → CHS 层层翻译,磁盘细节被彻底屏蔽(Attention 机制:细节蒙蔽);

于是在 OS 眼中,磁盘不再是 C/H/S,而是:

复制代码
一块 800GB 的磁盘 ÷ 4KB = 一维的块号数组(0 ~ 1亿+ 个块)

块号在功能上就类似于指针------一个数字,指向一块 4KB 的存储。

4.2 先分区,再分组

800GB 太大,直接管理不现实。OS 的思路依旧是「先描述、再组织」:

c 复制代码
struct disk { /* ... */ };  // 先描述磁盘
  • 分区:按块号范围把磁盘切成几个大区(C/D/E 盘的由来);
  • 分组 :每个分区还是太大,再按块号切成一个个块组(Block Group)

真正被管理的粒度就是块组。而**「格式化」的本质,就是往分区里写入全新的文件系统管理信息。**

4.3 文件 = 内容 + 属性,分开存储

Linux 下:文件 = 文件内容(Data Blocks)+ 文件属性(inode) ,二者分开存储

inode:文件的身份证
  • 每个文件的属性存在一个 struct inode{} 里:权限、所属组、大小、ACM 时间等;
  • inode 大小固定,一般 128 字节------固定大小就是为了方便数组化管理;
  • 一个文件一个 inode
  • 有意思的点:文件名不在 inode 里! 文件名只是给用户看的,内核全靠 inode 编号。
inode Table:属性的数组

inode 也和其他数据一样,以 4KB 为单位存放,不搞特殊:

复制代码
一个 4KB 的 inode Table 数据块 = 4096 ÷ 128 = 32 个 inode

所以 inode Table 可以看作一个数组:拿到下标 N,就 inode[N] 拿到该文件的属性------这个下标就是常说的 inode 编号

i_block\[\]:内容和属性的桥梁

内容和属性分开存,那它们怎么关联?答案是 inode 里的一个数组:

c 复制代码
le32 i_block[N];  // 记录该文件占用的各个 4KB data block 的块号

只要找到 inode,就能顺着 i_block\[\] 找到文件的全部数据块 。例如文件占 3 个块,则 i_block[0..2] 有效。


五、位图、Super Block 与「删除文件」的真相(7.14)

5.1 一个块组里的五大区域

区域 作用
Super Block 整个分区的「总说明书」,记录分区整体参数
GDT(块组描述符表) 管理当前这一个块组的资源
Block Bitmap 位图,标记块组内每个 data block 是否被占用
Inode Bitmap 位图,标记每个 inode 是否被使用
Inode Table 存放本组所有文件的 inode 档案
Data Blocks 真正存文件内容的地方

为什么要两份位图?因为 inode Table 和 Data Blocks 都是数组,必须有 O(1) 的方式判断「某个下标有没有数据」------位图正是干这个的,就像 O(1) 进程调度算法里用位图快速判断进程数组中的 PCB 是否存在一样。

Super Block 为什么能在分区里存多份、且每个块组附近都有备份?------某一份损坏了,可以拿别的副本恢复,这就是 Ext 文件系统的容错设计。

5.2 删除文件:为什么那么快,数据其实没删?

理解了位图,「删除文件为什么是秒删」就一目了然。删除流程:

  1. 拿 inode 编号 → inode[N] 找到该文件的 inode;
  2. 顺着 i_block[] 找到所有数据块的块号 → 把 Block Bitmap 中对应位由 1 置 0
  3. Inode Bitmap 中对应位由 1 置 0
  4. 完事。

注意:Inode Table 里的属性、Data Blocks 里的内容一个字节都没动! 它们只是「不再被位图承认」。下一次写入新文件时,这些「自由」的块会被覆盖。这就是为什么:

  • 删文件快(只改几个位);
  • 误删后数据还有机会被恢复(旧数据短期内仍在磁盘上)------同理,敏感数据要粉碎必须多次覆写。

5.3 内存视角:struct page 与内核缓冲区

换到内存的视角,上面这些结构一一对应:

  • Data Blocks 在内存中的对应物就是 struct page ------本质就是一个 4KB 的数组 char a[4096]
  • 一个 4KB 的块(8 个扇区) ↔ 一个 page ,而这个 page 正是内核级缓冲区
  • 内核对 page 的管理用基数树(radix tree):通过下标快速定位 page、向 page 写入数据;
  • 文件有个变量记录着「已读到/写到多少字节」(对应 inode 的 i_size),每 30 秒有后台线程(pdflush 类机制)把脏页刷回磁盘

i_size 记录文件的总字节数,i_size ÷ 4096 就能算出文件占了多少个块------属性的完备性再次体现:只凭一个 inode,就能完整还原一个文件。


六、总结:一条完整的抽象链

复制代码
磁铁(0/1) → 扇区(512B) → 磁道/柱面/磁头 → 三维数组 CHS
       → 拉直成一维 → LBA 地址(磁盘黑盒自翻译)
       → 8 扇区打包成 4KB 块 → OS 视角:块号一维数组
       → 分区 → 块组 → SuperBlock/GDT/双位图/InodeTable/DataBlocks
       → 文件 = inode(属性) + DataBlocks(内容),靠 i_block[] 关联

几个贯穿全文的核心思想:

  1. 黑盒 + 抽象:每往上一层,下一层的细节就被屏蔽一次(CHS→LBA→块号);
  2. 空间换管理:位图用 1 bit 换来 O(1) 的占用查询;
  3. 少碰慢设备:块、预读、内核缓冲区、30 秒刷盘,全是为了摊薄昂贵的磁盘访问;
  4. 先描述,再组织:struct 描述磁盘/分区/块组/inode,再用数组、位图组织起来。

后续笔记(7.15--7.18)会继续:Ext2 对大文件的支持(间接块)、软硬链接、目录的本质。敬请期待。


本文基于 2026-07-12 ~ 07-14 的学习笔记整理,如有理解偏差欢迎评论区指正。

相关推荐
星源~1 小时前
Linux - Trae Code Linux 环境嵌入式开发指南
linux·mcu·嵌入式·trae code
蓝速科技1 小时前
信创终端 POC 测试实战与选型避坑指南丨蓝速科技
运维·数据库·人工智能·科技·自然语言处理
曦夜日长1 小时前
Linux系统篇,进程概念(三):进程状态详解、僵尸进程与孤儿进程的深度解析、Slab机制的了解
linux·运维·服务器
小羊没烦恼!1 小时前
Memory 记忆设计讨论:为什么 Agent Memory 不能只靠向量数据库?
java·开发语言·windows·算法·c#
liulilittle2 小时前
为什么采用全局管理缓存及状态:麻将客户端状态管理
服务器·网络·游戏·客户端·异步·mahjong·麻将
wdfk_prog2 小时前
VMware Ubuntu 虚拟机从 124 GB 压缩到 33 GB
运维·缓存·docker·容器
FlightYe2 小时前
音视频修炼之编码器(一):AVC、HEVC编码器内部
android·linux·c++·音视频
云栖梦泽2 小时前
网络设备驱动(1)
linux·arm开发·嵌入式硬件
黑马程序员毕设2 小时前
基于微信小程序的节目活动报名与管理系统设计与实现
java·开发语言·spring boot·后端·电脑