Ext系列文件系统
1. 文件系统基础概念
-
文件 = 内容 + 属性:文件在磁盘上存储时,其数据(内容)和元数据(属性)是分开存放的。
-
文件分类:
-
被打开的文件:存在于内存中,由内核管理。
-
未被打开的文件:存放在磁盘上,需要文件系统来组织和管理。
-
-
文件系统的任务:在磁盘上高效地组织文件,使得用户能够通过目录树结构(路径)方便地访问文件。
2. 磁盘物理结构
2.1 硬件组成
-
机械磁盘是计算机中唯一的机械设备,由盘片、磁头、磁头臂、主轴马达等组成。
-
一个盘片通常有两个盘面(上下面),每个盘面对应一个磁头。
-
所有磁头固定在同一个磁臂上,只能“共进退”(同时移动到相同半径的磁道)。
2.2 数据存储单元
-
扇区(Sector):磁盘读写的最小单位,通常为 512字节。
-
磁道(Track):盘面上同心圆状的存储轨迹,从外圈向内圈编号(0磁道、1磁道…)。
-
柱面(Cylinder):所有盘面上相同半径的磁道组成一个柱面。
-
磁头(Head):每个盘面有一个读写磁头,用于定位到指定盘面。
2.3 寻址方式:CHS
-
早期磁盘使用 CHS(Cylinder-Head-Sector) 地址定位一个扇区:先确定柱面,再选择磁头(盘面),最后定位扇区。
-
CHS 地址容量有限(最大约 8.4GB),现代磁盘已改用 LBA。
2.4 逻辑结构:LBA
-
LBA(Logical Block Address) 将磁盘所有可用扇区从0开始编号,形成一个一维线性地址空间。
-
操作系统只需使用 LBA 访问磁盘,磁盘内部的固件负责将 LBA 转换为 CHS。
-
转换公式(假设已知每磁道扇区数 SPT、磁头数 H):
-
CHS → LBA:
LBA = C * (H * SPT) + H * SPT + (S - 1) -
LBA → CHS:
C = LBA // (H * SPT)H = (LBA % (H * SPT)) // SPTS = (LBA % SPT) + 1
-
3. 文件系统引入
3.1 块(Block)
-
磁盘是块设备,操作系统读写时不以扇区为单位,而以 块 为单位(提高效率)。
-
一个块由连续多个扇区组成,大小在格式化时确定,通常为 4KB(即 8 个扇区)。
-
块号与 LBA 的关系:
块号 = LBA / 8,块起始 LBA = 块号 * 8。
3.2 分区(Partition)
-
分区是将磁盘划分为多个逻辑区域,每个区域可以独立格式化并挂载使用。
-
分区的最小单位是柱面,通过指定起始和结束柱面号来划分。
-
分区表(如 MBR)位于磁盘的第一个扇区(引导扇区)
4. Ext2 文件系统结构
4.1 整体布局
-
一个分区格式化为 Ext2 文件系统后,被划分为若干个块组(Block Group),每个块组结构相同。
-
引导块(Boot Sector)位于分区开头,大小为 1KB,存放引导程序。
磁盘分区 → 多个块组(Block Group 0,1,…,N)每个块组包含:- 超级块(Super Block)- 块组描述符表(GDT)- 块位图(Block Bitmap)- inode 位图(inode Bitmap)- inode 表(inode Table)- 数据块(Data Blocks)4.2 块组内部结构详解
4.2.1 超级块(Super Block)
-
存放整个分区的全局信息,如:
-
block 和 inode 的总量、已用量、空闲量
-
block 大小、每个块组包含的块数
-
文件系统挂载时间、最近写入时间、最近检查时间
-
文件系统状态、魔数(用于识别文件系统类型)
-
-
超级块在每个块组都有备份,以防止损坏。
4.2.2 块组描述符表(GDT,Group Descriptor Table)
-
每个块组对应一个描述符,记录该块组的关键信息:
-
块位图所在的块号
-
inode 位图所在的块号
-
inode 表的起始块号
-
空闲块数、空闲 inode 数、目录数等
-
-
GDT 也在多个块组中备份。
4.2.3 块位图(Block Bitmap)
-
用比特位标记数据块的使用情况:1 表示已占用,0 表示空闲。
-
例如:
0000 0009(此处示例表示某些块已用)。
4.2.4 inode 位图(inode Bitmap)
- 标记 inode 表中每个 inode 是否空闲可用(比特位 1/0)。
4.2.5 inode 表(inode Table)
-
存放所有文件的 inode(索引节点)。
-
每个 inode 大小固定(通常 128 字节或 256 字节),包含文件的属性(元数据)和数据块指针。
-
inode 编号在整个分区内唯一。
4.2.6 数据块(Data Blocks)
-
存放文件的实际内容。
-
对于目录文件,数据块存放的是目录项列表(文件名到 inode 的映射)。
4.3 inode 结构
- inode 中不包含文件名,只包含属性,例如:
struct ext2_inode { __le16 i_mode; // 文件类型和权限 __le16 i_uid; // 所有者 UID __le32 i_size; // 文件大小(字节) __le32 i_atime; // 最后访问时间 __le32 i_ctime; // 创建时间 __le32 i_mtime; // 最后修改时间 __le32 i_dtime; // 删除时间 __le16 i_gid; // 所属组 GID __le16 i_links_count; // 硬链接计数 __le32 i_blocks; // 文件占用的块数 __le32 i_block[15]; // 数据块指针数组(12个直接块 + 3个间接块) // ...};- 数据块指针通过直接块、一级间接块、二级间接块、三级间接块实现对任意大小文件的寻址。
4.4 目录的实现
-
目录也是文件,拥有自己的 inode 和数据块。
-
目录文件的数据块内容是一个个目录项(dirent),每个目录项包含:
-
文件名
-
对应的 inode 编号
-
4.5 文件访问过程(路径解析)
-
用户通过路径(如
/home/user/file.txt)访问文件。 -
从根目录
/开始解析,根目录的 inode 是系统预知的。 -
打开根目录文件,读取其数据块,找到
home对应的 inode。 -
打开
home目录,读取数据块,找到user对应的 inode。 -
打开
user目录,读取数据块,找到file.txt对应的 inode。 -
通过该 inode 找到文件的数据块,读取内容。
路径解析效率优化:内核维护一个 dentry 缓存(目录项缓存),将最近访问过的路径解析结果以树形结构保存在内存中,避免每次都从磁盘读取目录 每个文件其实都要有对应的dentry结构,包括普通文件。这样所有被打开的文件,就可以在内存中形成整个树形结构 • 整个树形节点也同时会隶属于LRU(Least Recently Used,最近最少使用)结构中,进行节点淘汰 • 整个树形节点也同时会隶属于Hash,方便快速查找 • 更重要的是,这个树形结构,整体构成了Linux的路径缓存结构,打开访问任何文件,都在先在这棵树下根据路径进行查找,找到就返回属性inode和内容,没找到就从磁盘加载路径,添加dentry结构,缓存新路径
4.6 touch新文件系统工作流程
[root@localhost linux]# touch abc[root@localhost linux]# ls -i abc263466 abc图片
创建⼀个新文件主要有以下4个操作:
-
存储属性 内核先找到一个空闲的i节点(这里是263466)。内核把文件信息记录到其中。
-
存储数据 该文件需要存储在三个磁盘块,内核找到了三个空闲块:300,500,800。将内核缓冲区的第⼀块数据复制到300,下⼀块复制到500,以此类推。
-
记录分配情况 文件内容按顺序300,500,800存放。内核在inode上的磁盘分布区记录了上述块列表。
-
添加文件名到目录 新的文件名abc。linux如何在当前的目录中记录这个文件?内核将入口(263466,abc)添加到目录文件。文件名和inode之间的对应关系将文件名和文件的内容及属性连接起来。
5. 挂载(Mount)
-
格式化后的分区不能直接使用,必须挂载到某个目录(挂载点)上。
-
挂载将分区与目录关联,此后通过该目录访问文件时,系统就知道去哪个分区查找。
-
查看当前挂载情况:
df -h或mount。 -
挂载示例:
# 创建一个磁盘镜像文件并格式化dd if=/dev/zero of=./disk.img bs=1M count=5mkfs.ext4 disk.img
# 创建挂载点并挂载mkdir /mnt/mydisksudo mount -t ext4 ./disk.img /mnt/mydisk
# 查看挂载后的分区df -h# 卸载sudo umount /mnt/mydisk- 挂载点可以是任意空目录,通过路径前缀判断文件所在分区。
6. 软链接与硬链接
6.1 硬链接(Hard Link)
-
多个文件名指向同一个 inode(即共享同一个文件属性和数据)。
-
创建硬链接:
ln 源文件 目标文件 -
特点:
-
硬链接文件与源文件 inode 号相同。
-
删除一个硬链接只是减少 inode 的链接计数,只有当计数变为 0 时才真正删除文件。
-
不能跨分区创建硬链接。
-
不能对目录创建硬链接(
.和..除外)。- 允许用户创建目录硬链接可能导致路径环(循环引用),破坏文件系统树结构。
- 因此 Linux 禁止用户对目录建立硬链接,但保留
.和..作为特殊入口以方便命令行操作。
-
-
示例:
$ touch abc$ ln abc def$ ls -li abc def263466 -rw-r--r-- 2 root root 0 Sep 15 17:45 abc263466 -rw-r--r-- 2 root root 0 Sep 15 17:45 def # 相同 inode,链接数为26.2 软链接(Symbolic Link / Soft Link)
-
创建一个独立的文件,其内容是指向另一个文件的路径。
-
创建软链接:
ln -s 目标文件 链接名 -
特点:
-
软链接拥有自己的 inode(独立文件)。
-
删除源文件后,软链接失效(变成“悬空链接”)。
-
可以跨分区、跨文件系统。
-
类似 Windows 的快捷方式。
-
-
示例:
$ ln -s abc abc.s$ ls -li263563 -rw-r--r-- 2 root root 0 Sep 15 17:45 abc261678 lrwxrwxrwx 1 root root 3 Sep 15 17:53 abc.s -> abc # 不同 inode6.3 软硬链接对比
| 特性 | 硬链接 | 软链接 |
|---|---|---|
| inode 独立性 | 与源文件共享同一个 inode | 有独立 inode |
| 跨分区 | 不允许 | 允许 |
| 对目录 | 不允许(除 . 和 ..) | 允许 |
| 链接数影响 | 链接数增加 | 不增加源文件链接数 |
| 源文件删除 | 链接仍可访问(数据未删除) | 链接失效(指向的路径不存在) |
| 本质 | 多个文件名映射到同一 inode | 一个文件内容存储另一个文件的路径 |
6.4 用途
-
硬链接:实现文件备份(防止误删)、目录中的
.和..链接。 -
软链接:快捷方式、方便版本切换、跨分区链接。
7. 相关命令总结
-
ls -li:查看文件 inode 号及详细信息。 -
stat 文件名:查看文件 inode 详细信息(包括三个时间戳)。 -
ln 源文件 目标文件:创建硬链接。 -
ln -s 源文件 链接名:创建软链接。 -
df -h:查看磁盘分区挂载情况。 -
mount:挂载分区。 -
umount:卸载分区。 -
mkfs.ext4 /dev/xxx:格式化分区为 ext4 文件系统。 -
dd if=/dev/zero of=file bs=1M count=N:创建指定大小的空白文件(可用于模拟分区)。
8. 文件系统与进程关系图(简化)
-
进程通过
task_struct中的fs_struct记录根目录和当前工作目录的 dentry 和 vfsmount。 -
打开文件时,通过 dentry 缓存找到 inode,进而从磁盘读取数据。
-
文件操作通过一系列函数指针(
file_operations、inode_operations)调用具体文件系统实现。
9. 关键点回顾
-
格式化的本质:在分区上写入文件系统管理信息(超级块、GDT、位图等)。
-
inode 号是文件在分区中的唯一标识,通过目录文件中的映射找到。
-
访问任何文件都必须从根目录开始路径解析,但 dentry 缓存加速了该过程。
-
挂载将分区与目录关联,确定文件所属分区。
-
硬链接是多个文件名共享 inode,软链接是独立文件存储路径
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!

