ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

【Linux系统】16 Ext系列⽂件系统(下)

【Linux系统】16 Ext系列⽂件系统(下)

1、Ext2 文件系统整体架构

格式化分区(mkfs.ext2)本质:把分区划分成多个块组 Block Group,每个块组内部存放一套管理信息 + 数据。

分区布局: Boot Sector (1KB 启动块) | Block Group0 | Block Group1 | Block Group2 | ... Block Group N

启动块 Boot Sector:固定 1KB,保存引导程序,文件系统无权修改。

每个块组 Block Group 内部结构:

  1. Super Block 超级块
  2. GDT 块组描述符表
  3. Block Bitmap 块位图
  4. Inode Bitmap inode 位图
  5. Inode Table inode 表
  6. Data Blocks 数据块区

1.1 Super Block 超级块

记录整个分区全局信息:

  • inode 总数量、空闲 inode 数量
  • block 总数量、空闲 block 数量
  • block 大小、inode 大小
  • 挂载时间、写入时间、校验时间
  • magic 魔数,标识是 ext2 文件系统

⚠️超级块损坏,整个文件系统直接报废!为了容错,超级块会在多个块组做备份。

1.2 GDT 块组描述符表 ext2_group_desc

每一个块组对应一个描述符,记录:

  • 本块组的块位图在哪一个块
  • 本块组 inode 位图在哪一个块
  • inode 表起始块号
  • 空闲 block 计数、空闲 inode 计数、目录计数

GDT 同样多处备份。

1.3 Block Bitmap 块位图

每 1bit 代表一个数据块: bit=1:块已经被占用;bit=0:块空闲。 快速寻找空闲数据块。

1.4 Inode Bitmap inode 位图

每 1bit 代表一个 inode: bit=1:inode 已占用;bit=0:inode 空闲。 创建新文件时,快速找空闲 inode。

1.5 Inode Table inode 表

本块组所有 inode 集中存放,每个 inode128/256 字节。inode 号仅在当前分区唯一。

1.6 Data Blocks 数据块

存放普通文件、目录文件的实际内容。目录文件的内容就是文件名 <--> inode号映射表。

格式化mkfs.ext4 /dev/sdb1做的事情: 将分区切分成若干 Block Group;写入 SuperBlock、GDT、两个位图、inode 表;初始化管理数据。

2、路径解析原理

问题:我们访问文件给的是字符串路径,例如/home/whb/test.c,内核如何找到 inode?

2.1 原生磁盘路径解析(不考虑缓存)

  1. 根目录/inode 号是系统开机就知道,不需要查找。
  2. 读取根目录的数据块,遍历目录条目,找到名字叫home对应的 inode 号。
  3. 使用 home 的 inode,读取 home 目录的数据块,找到whb对应的 inode。
  4. 使用 whb 的 inode,读取目录,找到test.c的 inode。
  5. 通过 test.c 的 inode,读取 i_block 数据块指针,拿到文件内容。

本质是递归逐级打开每一级目录,出口是根目录/。

痛点:每次访问磁盘,磁盘 IO 很慢,如果每一次打开文件都从根目录磁盘逐级读目录,性能极差。

2.2 dentry 目录项缓存(struct dentry)

Linux 内核内存中维护struct dentry目录项缓存。

  • dentry 内存对象保存:文件名、父目录 dentry 指针、关联 inode 指针。
  • 所有打开过的目录 / 普通文件,内存生成 dentry,构建内存树。
  • 查找文件优先查 dentry 缓存,命中直接拿到 inode,不用读磁盘。
  • LRU 淘汰:很久不用的 dentry 释放内存,下次访问重新从磁盘加载。

📌重点:磁盘上没有 dentry,dentry 是内核内存中的缓存结构,加速路径解析。磁盘只存 inode 和 block。

进程结构体task_struct -> fs_struct保存进程根目录、CWD 当前工作目录对应的 dentry。pwd命令获取的当前工作目录,本质读进程的 CWD。

所以:open("/home/whb/test.c"),优先在 dentry 缓存树查找,找不到再去磁盘读取目录填充 dentry 缓存。

3、mount 挂载原理

问题:inode 号是分区局部唯一。系统有多个磁盘分区,内核怎么知道这个 inode 属于哪一个分区?

分区格式化完成之后,不能直接访问!必须挂载到某个目录,才能使用。

实操演示 loop 回环设备模拟磁盘分区

# 1、生成5M镜像文件,模拟一块磁盘分区 dd if=/dev/zero of=./disk.img bs=1M count=5 # 2、格式化为ext4文件系统 mkfs.ext4 disk.img # 3、创建空目录作为挂载点 mkdir -p /mnt/mydisk # 4、挂载镜像文件到目录,loop设备把文件模拟成块设备 mount -t ext4 ./disk.img /mnt/mydisk # 查看挂载情况,可以看到/dev/loop0 df -h # 测试写文件 touch /mnt/mydisk/hello.txt # 卸载 umount /mnt/mydisk
  • /dev/loop0:loop 回环伪块设备,可以把普通文件模拟成磁盘块设备。
  • 挂载的本质:把分区文件系统的根,嫁接挂载到某个目录 dentry 节点上。
  • 访问路径的时候,匹配路径前缀,就知道当前操作属于哪一个超级块(哪一个分区)。
  • 卸载 umount 之后,目录恢复原来空状态,文件系统隔离。

关键点:inode 号只在本分区有效;挂载之后,内核通过路径前缀识别属于哪个分区的 super_block。

4、硬链接 vs 软链接(符号链接)

4.1 硬链接 ln

touch abc ln abc def ls -li abc def

输出:

263466 abc 263466 def
  • abc 和 definode 编号完全相同。多个文件名映射同一个 inode。
  • inode 里面有i_links_count硬链接计数。
  • 删除文件rm def:只是删除目录里面的文件名映射,链接计数减 1。只有链接计数变成 0,才释放 inode 和数据块。

硬链接特点:

  1. 不能跨分区(inode 分区局部有效)。
  2. 不可以给目录创建硬链接(系统内部...是目录硬链接,用户禁止手动创建)。
  3. 多个文件名完全等价,没有主次之分。
  4. 删除其中一个文件名,其他不受影响。

.当前目录,..上级目录,本质就是硬链接。

4.2 软链接 ln -s(符号链接,类似 Windows 快捷方式)

ln -s abc abc.s ls -li abc abc.s
263466 abc 261678 lrwxrwxrwx abc.s -> abc
  • 软链接是独立文件,拥有自己全新的 inode 号!
  • 软链接的数据块里面保存的是目标文件的字符串路径。
  • 如果源文件被删除,软链接变成悬空链接,访问报错。

软链接特点:

  1. 可以跨分区。
  2. 可以对目录做软链接。
  3. 源文件删除,软链接失效。
  4. 本身是独立文件,占用 inode 和 block。

软硬链接对比表格

表格

特性硬链接软链接(符号链接)
inode和源文件同一个 inode全新独立 inode
跨分区❌不支持✅支持
对目录用户不能创建✅支持
删除源文件链接数减 1,文件依旧存在软链接悬空失效
本质目录新增一条文件名‑inode 映射独立文件,存储目标路径字符串
占用磁盘几乎不消耗额外空间需要 inode + 数据块存储路径

文件三个时间(stat 命令)

  1. Access(atime):最后访问文件内容时间,读取文件更新。
  2. Modify(mtime):文件内容被修改时间,写文件更新。
  3. Change(ctime):文件属性修改时间(chmod、chown、硬链接计数变化都会更新 ctime)。

注意:ctime 不是创建时间!ext4 才有 btime birth 创建时间。

5、rm 删除文件到底做了什么?

  1. 在目录文件的数据块中,删除该文件名对应的条目。
  2. 将 inode 的硬链接计数i_links_count减一。
  3. 如果链接计数变成 0:
    • 释放 inode(inode 位图 bit 置 0)
    • 释放所有对应的数据块(块位图 bit 置 0)

⚠️删除只是把位图标记空闲,磁盘上原有数据还保留,没有覆盖写之前,数据可以恢复。

下篇完整总结

  1. Ext2 文件系统将分区划分为多个 Block Group;每个块组包含超级块、GDT、块位图、inode 位图、inode 表、数据块。
  2. 超级块记录分区全局信息,多处备份防止损坏;位图用来快速查找空闲 block 和 inode。
  3. 路径解析:磁盘上逐级读取目录效率低;内核使用struct dentry目录项缓存,内存构建目录树加速路径查找,LRU 淘汰旧缓存。
  4. mount 挂载:把分区文件系统根嫁接挂载点目录;inode 号分区局部有效,内核依靠路径前缀区分不同分区。loop 回环设备可以用普通文件模拟磁盘分区做实验。
  5. 硬链接:多个文件名指向同一个 inode,链接计数;不能跨分区,不能链接目录。
  6. 软链接:独立 inode 文件,存储目标路径字符串,可以跨分区、链接目录;源文件删除后软链接失效。
  7. rm 删除:只是减少硬链接计数,标记 inode 和块为空闲,磁盘数据不会立刻擦除。

返回列表