Ext系列文件系统

2982 字
15 分钟
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)) // SPT S = (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 文件访问过程(路径解析)#

  1. 用户通过路径(如 /home/user/file.txt)访问文件。

  2. 从根目录 / 开始解析,根目录的 inode 是系统预知的。

  3. 打开根目录文件,读取其数据块,找到 home 对应的 inode。

  4. 打开 home 目录,读取数据块,找到 user 对应的 inode。

  5. 打开 user 目录,读取数据块,找到 file.txt 对应的 inode。

  6. 通过该 inode 找到文件的数据块,读取内容。

路径解析效率优化:内核维护一个 dentry 缓存(目录项缓存),将最近访问过的路径解析结果以树形结构保存在内存中,避免每次都从磁盘读取目录 每个文件其实都要有对应的dentry结构,包括普通文件。这样所有被打开的文件,就可以在内存中形成整个树形结构 • 整个树形节点也同时会隶属于LRU(Least Recently Used,最近最少使用)结构中,进行节点淘汰 • 整个树形节点也同时会隶属于Hash,方便快速查找 • 更重要的是,这个树形结构,整体构成了Linux的路径缓存结构,打开访问任何文件,都在先在这棵树下根据路径进行查找,找到就返回属性inode和内容,没找到就从磁盘加载路径,添加dentry结构,缓存新路径

4.6 touch新文件系统工作流程#

Terminal window
[root@localhost linux]# touch abc
[root@localhost linux]# ls -i abc
263466 abc

图片

创建⼀个新文件主要有以下4个操作:

  1. 存储属性 内核先找到一个空闲的i节点(这里是263466)。内核把文件信息记录到其中。

  2. 存储数据 该文件需要存储在三个磁盘块,内核找到了三个空闲块:300,500,800。将内核缓冲区的第⼀块数据复制到300,下⼀块复制到500,以此类推。

  3. 记录分配情况 文件内容按顺序300,500,800存放。内核在inode上的磁盘分布区记录了上述块列表。

  4. 添加文件名到目录 新的文件名abc。linux如何在当前的目录中记录这个文件?内核将入口(263466,abc)添加到目录文件。文件名和inode之间的对应关系将文件名和文件的内容及属性连接起来。

5. 挂载(Mount)#

  • 格式化后的分区不能直接使用,必须挂载到某个目录(挂载点)上。

  • 挂载将分区与目录关联,此后通过该目录访问文件时,系统就知道去哪个分区查找。

  • 查看当前挂载情况:df -h 或 mount。

  • 挂载示例:

Terminal window
# 创建一个磁盘镜像文件并格式化
dd if=/dev/zero of=./disk.img bs=1M count=5
mkfs.ext4 disk.img
# 创建挂载点并挂载
mkdir /mnt/mydisk
sudo mount -t ext4 ./disk.img /mnt/mydisk
# 查看挂载后的分区
df -h
# 卸载
sudo umount /mnt/mydisk
  • 挂载点可以是任意空目录,通过路径前缀判断文件所在分区。

6. 软链接与硬链接#

  • 多个文件名指向同一个 inode(即共享同一个文件属性和数据)。

  • 创建硬链接:ln 源文件 目标文件

  • 特点:

    • 硬链接文件与源文件 inode 号相同。

    • 删除一个硬链接只是减少 inode 的链接计数,只有当计数变为 0 时才真正删除文件。

    • 不能跨分区创建硬链接。

    • 不能对目录创建硬链接(. 和 .. 除外)。

      • 允许用户创建目录硬链接可能导致路径环(循环引用),破坏文件系统树结构。
      • 因此 Linux 禁止用户对目录建立硬链接,但保留 . 和 .. 作为特殊入口以方便命令行操作。
  • 示例:

Terminal window
$ touch abc
$ ln abc def
$ ls -li abc def
263466 -rw-r--r-- 2 root root 0 Sep 15 17:45 abc
263466 -rw-r--r-- 2 root root 0 Sep 15 17:45 def # 相同 inode,链接数为2
  • 创建一个独立的文件,其内容是指向另一个文件的路径。

  • 创建软链接:ln -s 目标文件 链接名

  • 特点:

    • 软链接拥有自己的 inode(独立文件)。

    • 删除源文件后,软链接失效(变成“悬空链接”)。

    • 可以跨分区、跨文件系统。

    • 类似 Windows 的快捷方式。

  • 示例:

Terminal window
$ ln -s abc abc.s
$ ls -li
263563 -rw-r--r-- 2 root root 0 Sep 15 17:45 abc
261678 lrwxrwxrwx 1 root root 3 Sep 15 17:53 abc.s -> abc # 不同 inode

6.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,软链接是独立文件存储路径

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

Profile Image of the Author
HandlerOne
おかえり
公告
本站已整理 138 篇技术笔记,并按 8 条主线排成学习路线(141 站);站内搜索与桌宠对话均已上线。
分类
标签
最新动态
站点统计
文章
138
分类
12
标签
42
总字数
597,044
站点信息
构建平台
腾讯云 · Nginx
博客版本
v6.16.8
文章目录