本文从磁盘的物理扇区出发,经过 CHS/LBA 寻址、分区、格式化、挂载、路径解析,直到软硬链接的使用。
这是一条从硬件到用户视角的完整路径,理解它,就能回答"我写的一个字节,到底存在哪里、怎么被找到"这样的终极问题。
第一部分:磁盘物理结构
1.1 机械硬盘的物理组成
一块传统的机械硬盘(HDD)内部包含:
-
盘片(Platter):圆形磁性介质,数据记录在表面。一块硬盘通常有多个盘片。
-
磁头(Head):每个盘片表面有一个读写磁头,负责读取和写入。
-
主轴(Spindle):带动盘片高速旋转(常见 5400/7200 RPM)。
-
磁臂(Actuator Arm):带动磁头在盘片表面径向移动。
1.2 磁道、柱面、扇区
数据在盘片上的组织方式:
-
磁道(Track):盘片表面被划分为一圈圈同心圆,每一圈叫一个磁道。
-
柱面(Cylinder) :所有盘片上半径相同的磁道组成的集合。因为磁头是同步移动的,同一柱面的磁道可以"无寻道"地连续访问。
-
扇区(Sector) :磁道被划分为若干弧段,每段是一个扇区,是磁盘最小的物理读写单位 。传统扇区大小为 512 字节 ,现代硬盘多为 4096 字节(4K 扇区)。
盘片俯视图 ┌─────────────┐ │ ╭─────╮ │ ← 磁道(同心圆) │ ╭───────╮ │ │ ╭─────────╮ │ │ │ ● 主轴 │ │ │ ╰─────────╯ │ │ ╰───────╯ │ │ ╰─────╯ │ └─────────────┘ 扇区是磁道上的一小段弧
1.3 为什么这些概念重要?
磁盘访问时间由三部分组成:
-
寻道时间:磁头移动到目标磁道所需时间(机械动作,最慢)。
-
旋转延迟:等待目标扇区转到磁头下方(与转速相关)。
-
传输时间:读写数据的实际时间。
由此得出一个重要结论:顺序访问连续扇区远快于随机访问。这也是文件系统要尽量让文件数据连续存放的根本原因,也是 Ext4 引入 Extents 和多块分配的动机。
第二部分:CHS 与 LBA 地址
2.1 CHS 寻址:三维坐标定位
早期磁盘使用 CHS(Cylinder-Head-Sector) 寻址,用三个参数定位一个扇区:
-
C:柱面号(Cylinder)
-
H:磁头号(Head),即盘面号
-
S :扇区号(Sector),从 1 开始编号
一个 CHS 地址 (C, H, S) 唯一确定一个扇区。传统 BIOS 的 CHS 参数上限为:
-
柱面 0--1023(10 位)
-
磁头 0--255(8 位)
-
扇区 1--63(6 位)
这样最大可寻址 1024 × 256 × 63 × 512B ≈ 7.8GB,这就是著名的 8GB 寻址壁垒。
2.2 LBA 寻址:一维线性编号
LBA(Logical Block Address) 把整个磁盘的所有扇区从 0 开始连续编号,每个扇区对应一个唯一的整数地址。操作系统和现代硬盘控制器普遍使用 LBA,因为它简单、线性、易于计算。
2.3 CHS 与 LBA 的转换
在传统几何参数下(每磁道 63 扇区,每柱面 255 磁头),转换公式为:
CHS → LBA:
LBA = (C × 磁头数 + H) × 每磁道扇区数 + (S - 1)
LBA → CHS:
C = LBA / (磁头数 × 每磁道扇区数)
H = (LBA / 每磁道扇区数) % 磁头数
S = (LBA % 每磁道扇区数) + 1
注意扇区号在 CHS 中从 1 开始,在 LBA 中从 0 开始,所以公式里有 S - 1 和 + 1。
2.4 现代磁盘的真实情况
现代硬盘早已不暴露真实的物理 CHS 几何结构,固件内部进行地址映射。操作系统看到的"CHS"只是兼容性的逻辑几何。LBA 才是现代存储的事实标准。SSD 更是完全没有物理磁道和扇区,但对外仍以 LBA 扇区为单位呈现。
第三部分:分区
3.1 什么是分区?
一块物理磁盘可以被划分为多个分区,每个分区是一段连续的 LBA 地址范围,可以独立格式化为不同的文件系统,独立挂载。分区表记录了每个分区的起止位置、类型等信息。
3.2 MBR 分区表
MBR(Master Boot Record) 位于磁盘的第一个扇区(LBA 0),共 512 字节,布局为:
| 偏移 | 大小 | 内容 |
|---|---|---|
| 0 | 446 字节 | 引导代码 |
| 446 | 64 字节 | 分区表(4 个 16 字节表项) |
| 510 | 2 字节 | 结束标志 0x55AA |
MBR 的限制:
-
最多 4 个主分区(或 3 主分区 + 1 扩展分区,扩展分区内再划分逻辑分区)。
-
分区表项中用 32 位记录起始 LBA 和扇区数,配合 512 字节扇区,最大支持 2TB 磁盘。
3.3 GPT 分区表
GPT(GUID Partition Table) 是为解决 MBR 限制而设计的现代分区方案:
-
支持最多 128 个分区(可扩展)。
-
使用 64 位 LBA 寻址,支持超大磁盘。
-
每个分区有唯一的 GUID 标识。
-
分区表在磁盘开头和末尾各存一份,互为备份。
-
磁盘开头保留一个保护性 MBR,防止旧工具误判。
3.4 分区操作
bash
# 查看磁盘和分区
lsblk
sudo fdisk -l /dev/sda
sudo parted /dev/sda print
# 使用 fdisk 交互式分区(MBR/GPT 均可)
sudo fdisk /dev/sdb
# n 新建分区
# d 删除分区
# p 打印分区表
# t 修改分区类型
# w 写入并退出
# 使用 parted 创建 GPT 分区表
sudo parted /dev/sdb mklabel gpt
sudo parted /dev/sdb mkpart primary ext4 1MiB 10GiB
分区完成后,内核中会出现 /dev/sdb1、/dev/sdb2 等设备节点。
第四部分:Ext 系列文件系统原理
4.1 块组布局
每个块组包含:超级块(备份)→ 块组描述符表 → 块位图 → inode 位图 → inode 表 → 数据块。
4.2 inode 与数据寻址
-
Ext2/3:直接块 + 一级/二级/三级间接块。
-
Ext4 :Extents (
起始块号, 长度)组成的树,小文件的 extent 树直接内嵌在 inode 中。
4.3 三代演进要点
| Ext2 | Ext3 | Ext4 | |
|---|---|---|---|
| 日志 | 无 | 有 | 有 + 校验 |
| 寻址 | 间接块 | 间接块 | Extents |
| 分配 | 即时单块 | 即时单块 | 延迟分配 + 多块 |
| 容量 | 2TB/16TB | 2TB/16TB | 16TB/1EB |
4.4 关键结构速查
-
超级块:文件系统全局参数。
-
GDT:各块组的位置和空闲统计。
-
位图:块和 inode 的分配状态。
-
inode 表:所有文件的元数据。
-
目录项(dentry):目录文件中"文件名 → inode 号"的映射。
第五部分:格式化
5.1 格式化做了什么?
"格式化"在 Linux 语境下通常指创建文件系统 (mkfs),而不是低级格式化。以 mkfs.ext4 为例,它会在分区上:
-
写入超级块,记录块大小、inode 总数等全局参数。
-
划分块组,为每组写入 GDT、位图、inode 表。
-
初始化根目录 inode(inode 2) 和根目录的数据块。
-
建立日志区域(Ext3/4)。
-
将空闲块和空闲 inode 在位图中标记为可用。
5.2 常用命令
bash
# 创建 Ext4 文件系统
sudo mkfs.ext4 /dev/sdb1
# 指定块大小和卷标
sudo mkfs.ext4 -b 4096 -L "mydata" /dev/sdb1
# 查看文件系统信息
sudo dumpe2fs -h /dev/sdb1
sudo tune2fs -l /dev/sdb1
5.3 格式化的本质
格式化不擦除数据,它只是重建元数据结构。原数据块的内容可能仍残留在磁盘上,直到被新数据覆盖。这也是数据恢复工具能够工作的原理之一。
第六部分:挂载与路径解析
6.1 挂载是什么?
Linux 没有 Windows 那样的"C 盘、D 盘"概念,所有文件系统都被组织在一棵以 / 为根的目录树 中。挂载就是把一个文件系统"接"到目录树的某个节点(挂载点)上,使其内容在该节点下可见。
bash
# 挂载
sudo mount /dev/sdb1 /mnt/data
# 查看当前挂载
mount | grep sdb1
findmnt /mnt/data
# 卸载
sudo umount /mnt/data
6.2 挂载时内核做了什么?
-
读取分区上的超级块,识别文件系统类型。
-
创建
vfsmount结构,记录挂载点和文件系统信息。 -
将该文件系统的根目录 inode 与挂载点目录的 inode 关联起来。
-
此后访问挂载点路径,就会进入新文件系统的根目录。
6.3 VFS:统一抽象层
Linux 的 VFS(Virtual File System) 为所有文件系统提供统一接口。无论底层是 Ext4、XFS、NFS 还是 procfs,上层都通过相同的 open/read/write 系统调用访问。挂载的本质就是让 VFS 在路径解析时"切换"到另一个文件系统的根。
6.4 持久化挂载:/etc/fstab
bash
# /etc/fstab 示例
UUID=xxxx-xxxx /mnt/data ext4 defaults 0 2
字段含义:设备、挂载点、文件系统类型、挂载选项、dump 标志、fsck 顺序。
6.5 路径解析过程
当执行 open("/home/alice/doc.txt") 时,内核的路径解析大致如下:
-
从根目录 inode(inode 2) 开始。
-
在根目录的数据块(目录项列表)中查找
"home",得到其 inode 号。 -
读取该 inode,确认是目录,进入其数据块。
-
查找
"alice",得到 inode 号,进入。 -
查找
"doc.txt",得到最终 inode 号。 -
检查权限,返回文件描述符。
每一步都会查询 dentry 缓存 (目录项缓存),命中则跳过磁盘读取。/、.、.. 有特殊处理:. 指向当前目录自身,.. 指向父目录。
6.6 挂载点与路径解析的交互
如果 /mnt/data 是一个挂载点,路径解析走到 /mnt/data 时,VFS 会检测到该目录是一个挂载点,自动切换到被挂载文件系统的根目录继续解析。这就是挂载"透明"的原因。
第七部分:软链接与硬链接
7.1 硬链接(Hard Link)
本质 :多个目录项指向同一个 inode。它们共享同一份数据,没有"原文件"和"副本"之分。
bash
ln original.txt hardlink.txt
-
inode 的链接计数(link count) 加 1。
-
删除其中一个名字,只是链接计数减 1;计数归零时 inode 和数据块才真正释放。
-
硬链接不能跨文件系统(inode 号只在单个文件系统内唯一)。
-
硬链接不能指向目录(防止目录树出现环,简化路径解析)。
查看:
bash
ls -li original.txt hardlink.txt
# 两个文件 inode 号相同,链接计数为 2
7.2 软链接(Symbolic Link)
本质 :一个独立的文件 ,有自己的 inode,其数据内容是目标文件的路径字符串。
bash
ln -s /path/to/target symlink
-
类型为
l,ls -l显示为symlink -> /path/to/target。 -
可以跨文件系统,可以指向目录。
-
目标被删除后,软链接变成悬空链接(dangling),访问会失败。
-
访问软链接时,内核解析其内容得到目标路径,再重新进行路径解析。
7.3 对比总结
| 特性 | 硬链接 | 软链接 |
|---|---|---|
| 本质 | 同一 inode 的另一个名字 | 独立文件,内容是目标路径 |
| inode 号 | 与原文件相同 | 与原文件不同 |
| 跨文件系统 | 不可以 | 可以 |
| 指向目录 | 不可以 | 可以 |
| 原文件删除后 | 数据仍可访问(计数未归零) | 变成悬空链接 |
| 创建命令 | ln src dst |
ln -s src dst |
7.4 使用场景
-
硬链接 :节省空间地给同一文件起多个名字(如备份快照、包管理器中的多版本共存);
rsync --link-dest增量备份就大量使用硬链接。 -
软链接 :指向库的版本(
libfoo.so -> libfoo.so.1.2);跨目录、跨文件系统引用;配置文件切换(如current -> releases/v1.2)。
第八部分:完整链路串讲
把本文的内容串成一条线:
bash
物理磁盘(盘片/磁道/扇区)
│ 用 CHS 或 LBA 定位
▼
分区表(MBR/GPT)划分出分区 /dev/sdb1
│ mkfs.ext4 写入元数据
▼
Ext4 文件系统(块组、超级块、inode、数据块)
│ mount 到 /mnt/data
▼
VFS 目录树,路径解析逐级查找 inode
│ open("/mnt/data/doc.txt")
▼
返回文件描述符,读写通过页缓存与磁盘交互
│ ln / ln -s
▼
硬链接共享 inode,软链接存储路径
小结
| 主题 | 核心要点 |
|---|---|
| 磁盘物理结构 | 盘片、磁道、柱面、扇区;顺序访问远快于随机访问 |
| CHS 与 LBA | CHS 三维坐标;LBA 线性编号;转换公式;现代以 LBA 为准 |
| 分区 | MBR(4 主分区、2TB 限制)vs GPT(128 分区、64 位 LBA、备份表) |
| Ext 系列 | 块组、超级块、GDT、位图、inode;间接块 → Extents;日志与校验 |
| 格式化 | mkfs.ext4 重建元数据结构,不擦除数据 |
| 挂载 | VFS 统一抽象,把文件系统接到目录树节点;/etc/fstab 持久化 |
| 路径解析 | 从根 inode 开始逐级查目录项,dentry 缓存加速,挂载点自动切换 |
| 软硬链接 | 硬链接共享 inode,软链接是存路径的独立文件 |
这条从物理扇区到目录树的链路,是理解 Linux 存储的完整地图。打开终端,把分区、格式化、挂载、链接都亲手做一遍,会有"打通任督二脉"的感觉!