在学习 Linux 操作系统的过程中,文件系统是绕不开的核心知识点。它不仅决定了数据如何存储、读取与管理,更是理解 Linux "一切皆文件" 设计思想的关键。
本文将从磁盘物理结构出发,逐步拆解 CHS 与 LBA 寻址、分区与格式化、Ext 文件系统核心组件、inode 原理、目录与路径解析、挂载机制以及软硬链接,带你完整打通 Linux 文件系统的全链路逻辑。
一、磁盘物理结构:数据存储的硬件基础
机械硬盘是计算机中唯一的机械设备,也是 Linux 文件系统的底层载体。理解它的物理结构,是看懂文件系统的第一步。
1. 核心硬件组件
- 盘片(Platter):存储数据的圆盘,一张盘片有正反两个面
- 磁头(Head) :每个面对应一个磁头,负责读写数据,所有磁头共进退
- 传动臂:带动磁头移动,定位磁道
- 主轴:带动盘片高速旋转
2. 磁盘存储三要素
- 扇区(Sector) :磁盘最小存储单位,固定512 字节
- 磁道(Track):盘片上的同心圆轨道
- 柱面(Cylinder):所有盘片相同半径的磁道组成的圆柱面
磁盘容量计算公式:
容量 = 磁头数 × 柱面数 × 每磁道扇区数 × 512字节
二、磁盘寻址:从 CHS 到 LBA 的进化
操作系统要读写数据,必须先定位到具体扇区。
1. 传统 CHS 寻址
通过三个参数唯一确定一个扇区:
- C(Cylinder):柱面号
- H(Head):磁头号(对应盘面)
- S(Sector):扇区号
缺陷:支持容量有限,最大仅约8.4GB,无法满足现代硬盘需求。
2. 现代 LBA 逻辑块寻址
操作系统把整个磁盘抽象成一维数组 ,每个扇区对应一个LBA 地址(数组下标),从 0 开始编号。
CHS ↔ LBA 转换公式
- CHS 转 LBA:
LBA = C × (磁头数×每磁道扇区数) + H × 每磁道扇区数 + S - 1 - LBA 转 CHS:
C = LBA // 单柱面扇区数``H = (LBA % 单柱面扇区数) // 每磁道扇区数``S = (LBA % 每磁道扇区数) + 1
重点:操作系统只使用 LBA,CHS 与 LBA 的转换由磁盘固件自动完成。
三、从扇区到块:操作系统的 IO 优化
扇区仅 512 字节,单次 IO 效率太低。操作系统引入 ** 块(Block)** 概念:
- 块 :文件存取的最小单位,默认4KB(=8 个连续扇区)
- 块号 = LBA / 8
- LBA = 块号 × 8 + 块内偏移
此时,磁盘在操作系统视角下,变成了以块为单位的一维数组。
四、分区与格式化:管理磁盘的分治思想
面对 500GB 的大磁盘,直接管理不现实,Linux 采用分治策略:
1. 分区(Partition)
把大磁盘切分成多个独立区域(如 C 盘、D 盘),分区以柱面为最小单位。
2. 格式化
本质:在分区上写入文件系统,创建管理数据结构(超级块、位图、inode 表等),而非简单清空数据。
五、Ext 文件系统核心:Block Group 结构
Ext2/3/4 将每个分区划分为多个Block Group(块组),每个块组结构完全相同,实现 "管理一个组 = 管理整个分区"。
每个块组包含 6 大核心组件:
1. 启动块(Boot Block)
固定 1KB,存储分区信息与启动数据,所有文件系统通用。
2. 超级块(Super Block)
文件系统的 "总控中心",记录:
- 总块数、总 inode 数
- 空闲块 / 空闲 inode 数量
- 块大小、inode 大小
- 挂载时间、读写时间
超级块在多个块组中备份,防止单点故障。
3. GDT 块组描述符
描述当前块组的元信息:inode 表位置、数据块位置、空闲资源数。
4. 块位图(Block Bitmap)
用 bit 标记数据块是否被占用:1 = 已用,0 = 空闲。
5. inode 位图(Inode Bitmap)
用 bit 标记 inode 是否被占用。
6. inode 表 + 数据块
- inode 表:存储文件属性
- 数据块:存储文件内容
六、inode:文件的 "身份证"
Linux 文件设计核心:文件 = 属性(inode) + 内容(数据块),二者分离存储。
1. inode 是什么
- 每个文件唯一对应一个 inode
- inode 号是文件的唯一标识(分区内唯一)
- 大小固定:128B/256B
- 不存储文件名
2. inode 包含的核心信息
- 文件类型、权限
- 属主、属组
- 文件大小
- 时间戳(访问 / 修改 / 属性变更)
- 数据块指针数组(12 直接 + 1 一级 + 1 二级 + 1 三级间接)
3. 数据块索引机制
- 12 个直接块:存小文件(≤48KB)
- 一级间接块:支持中等文件
- 二级 / 三级间接块:支持超大文件
七、目录:特殊的文件
很多人困惑:文件名不在 inode 里,那存在哪?
答案:目录是特殊文件。
目录的本质
- 目录也有 inode(属性)
- 目录的数据块存储:文件名 ↔ inode 号 的映射表
例:ls -li 看到的就是目录数据块的内容。
八、路径解析:Linux 如何找到你的文件
访问文件 /home/whb/test.txt 的完整流程:
- 从 ** 根目录 /** 开始(根目录 inode 固定,系统开机已知)
- 解析根目录数据块,找到
home的 inode - 解析
home目录,找到whb的 inode - 解析
whb目录,找到test.txt的 inode - 通过 inode 找到数据块,读取文件内容
内核优化:dentry 路径缓存
Linux 内核用struct dentry结构在内存中维护路径树,避免每次都从磁盘递归解析,大幅提升访问速度。
九、挂载:让分区真正可用
分区格式化后不能直接使用,必须通过 ** 挂载(Mount)** 关联到系统目录树。
挂载流程
- 创建空目录(挂载点)
- 执行
mount命令,将分区关联到该目录 - 访问目录即访问分区数据
核心作用:解决inode 不能跨分区的问题,通过路径前缀识别分区。
十、软硬链接:文件的两种引用方式
1. 硬链接(Hard Link)
ln 源文件 目标文件- 多个文件名指向同一个 inode
- 不能跨分区、不能链接目录
- 删除文件仅减少链接数,为 0 才真正释放空间
2. 软链接(Soft Link/Symbolic Link)
ln -s 源文件 目标文件- 独立文件,有独立 inode
- 相当于 Windows 快捷方式
- 可跨分区、可链接目录
- 源文件删除后失效
十一、文件增删查改底层逻辑
1. 创建文件(touch)
- 分配空闲 inode(查 inode 位图)
- 写入文件属性到 inode
- 分配空闲数据块(查块位图)
- 写入数据到块
- 在目录数据块添加
文件名:inode映射
2. 删除文件(rm)
- 目录中删除
文件名:inode记录 - inode 链接数 - 1
- 链接数 = 0 时,释放 inode 与数据块(位图置 0)
3. 查找 / 修改文件
通过路径解析拿到 inode,直接访问属性与数据块。
十二、总结:Linux 文件系统核心思想
- 磁盘抽象:三维物理结构 → 一维 LBA 数组 → 块数组
- 分离设计:文件属性(inode)与内容(数据块)分离
- 分治管理:磁盘→分区→块组,逐级管理
- 目录本质:存储文件名与 inode 映射的特殊文件
- 路径解析:从根目录递归查找,内核 dentry 缓存加速
- 挂载机制:将分区融入目录树,实现多分区统一访问
理解这套逻辑,你就真正吃透了 Linux 文件系统,无论是排查磁盘问题、优化存储、还是编写底层代码,都能游刃有余。