Ext4 文件系统详解
Ext4 是 Linux 最常用的文件系统,提供了高性能、可靠性和可扩展性。
Ext4 架构
磁盘布局
┌─────────────────────────────────────────────────┐
│ Block 0: Boot Block │
├─────────────────────────────────────────────────┤
│ Block Group 0 │
│ ┌─────────────────────────────────────────┐ │
│ │ Super Block │ │
│ ├─────────────────────────────────────────┤ │
│ │ Group Descriptors │ │
│ ├─────────────────────────────────────────┤ │
│ │ Data Block Bitmap │ │
│ ├─────────────────────────────────────────┤ │
│ │ Inode Bitmap │ │
│ ├─────────────────────────────────────────┤ │
│ │ Inode Table │ │
│ ├─────────────────────────────────────────┤ │
│ │ Data Blocks │ │
│ └─────────────────────────────────────────┘ │
├─────────────────────────────────────────────────┤
│ Block Group 1 │
│ ... │
├─────────────────────────────────────────────────┤
│ Block Group N │
└─────────────────────────────────────────────────┘
超级块信息
# 查看超级块信息
sudo dumpe2fs /dev/sda1 | head -50
# 输出示例:
# Filesystem volume name: root
# Filesystem features: has_journal ext_attr resize_inode dir_index
# Filesystem state: clean
# Block count: 26214400
# Inode count: 6553600
# Block size: 4096
# Inode size: 256
inode 结构
Ext4 inode
// fs/ext4/ext4.h
struct ext4_inode {
__le16 i_mode; // 文件模式
__le16 i_uid; // 所有者 UID
__le32 i_size_lo; // 文件大小(低 32 位)
__le32 i_atime; // 访问时间
__le32 i_ctime; // 状态改变时间
__le32 i_mtime; // 修改时间
__le32 i_dtime; // 删除时间
__le16 i_gid; // 组 GID
__le16 i_links_count; // 硬链接数
__le32 i_blocks_lo; // 块数
__le32 i_flags; // 文件标志
union {
struct {
__le32 l_i_version;
} linux1;
struct {
__u32 h_i_translator;
} hurd1;
} osd1;
__le32 i_block[EXT4_N_BLOCKS]; // 块指针
__le32 i_generation; // 文件版本
__le32 i_file_acl_lo; // 文件 ACL
__le32 i_size_high; // 文件大小(高 32 位)
// ... 更多字段
};
// EXT4_N_BLOCKS = 15
// i_block[0-11]: 直接块指针
// i_block[12]: 一级间接块
// i_block[13]: 二级间接块
// i_block[14]: 三级间接块
inode 寻址
文件大小 vs 块指针:
块大小 4KB 时:
- 直接块:12 × 4KB = 48KB
- 一级间接:1024 × 4KB = 4MB
- 二级间接:1024 × 1024 × 4KB = 4GB
- 三级间接:1024 × 1024 × 1024 × 4KB = 4TB
最大文件大小:48KB + 4MB + 4GB + 4TB ≈ 4TB
Extent 树(Ext4 新特性)
传统间接块:
文件偏移 → 块号 → 块号 → ... → 数据
Extent 方式:
文件偏移 → (起始块, 长度) → 连续的数据块
优势:
- 减少元数据
- 提高大文件性能
- 减少碎片
查看 extent 信息:
# 查看文件的 extent
debugfs -R "extents <inode>" /dev/sda1
# 或使用 filefrag
filefrag -v /path/to/file
日志(Journal)
日志模式
# 三种日志模式:
1. journal(最安全,最慢)
- 元数据和数据都写入日志
2. ordered(默认,平衡)
- 元数据写入日志
- 数据先于元数据写入
3. writeback(最快,最不安全)
- 元数据写入日志
- 数据写入顺序不保证
# 查看当前日志模式
sudo tune2fs -l /dev/sda1 | grep features
# 或
mount | grep sda1
# 修改日志模式(挂载选项)
mount -o remount,data=ordered /
# 永久修改
# /etc/fstab
/dev/sda1 / ext4 defaults,data=ordered 0 1
日志信息
# 查看日志状态
sudo dumpe2fs /dev/sda1 | grep -i journal
# 输出:
# Journal inode: 8
# Journal backup: inode blocks
# Journal features: journal_incompat_revoke journal_64bit
# Journal size: 128M
# Journal sequence: 0x00012345
目录索引
HTree(Hash Tree)
# 目录索引特性(dir_index)
# 使用哈希树加速大目录查找
# 查看是否启用
sudo tune2fs -l /dev/sda1 | grep dir_index
# 查看目录的 HTree 信息
debugfs -R "htree /path/to/dir" /dev/sda1
Ext4 特性
延迟分配(Delayed Allocation)
传统方式:
写入数据 → 立即分配块 → 写入磁盘
延迟分配:
写入数据 → 暂存内存 → 批量分配块 → 写入磁盘
优势:
- 减少碎片
- 提高性能
- 更好的块分配
多块分配(Multi-block Allocation)
# 一次分配多个连续块
# 提高大文件写入性能
# 查看块分配情况
stat /path/to/file | grep Blocks
filefrag -v /path/to/file
快速 fsck
# uninit_bg 特性
# 未使用的块组不需要检查
# 启用特性
sudo tune2fs -O uninit_bg /dev/sda1
# fsck 时间对比
time fsck.ext4 -n /dev/sda1
在线碎片整理
# Ext4 支持在线碎片整理
# 无需卸载文件系统
# 检查碎片程度
filefrag -v /path/to/file
# 整理单个文件
e4defrag /path/to/file
# 整理整个文件系统
e4defrag /mount/point
# 查看整理效果
e4defrag -c /mount/point
文件系统操作
创建文件系统
# 基本创建
mkfs.ext4 /dev/sdb1
# 指定参数
mkfs.ext4 \
-b 4096 \ # 块大小
-i 16384 \ # inode 比例
-J size=128 \ # 日志大小(MB)
-L mydata \ # 卷标
-m 1 \ # 保留块百分比
-O ^has_journal \ # 禁用日志
/dev/sdb1
# 查看详细信息
mkfs.ext4 -n /dev/sdb1 # 模拟运行
调整文件系统
# 查看文件系统信息
tune2fs -l /dev/sda1
# 设置卷标
tune2fs -L newlabel /dev/sda1
# 设置挂载次数检查
tune2fs -c 30 /dev/sda1 # 30 次挂载后检查
tune2fs -c -1 /dev/sda1 # 禁用次数检查
# 设置时间间隔检查
tune2fs -i 6m /dev/sda1 # 6 个月后检查
tune2fs -i 0 /dev/sda1 # 禁用时间检查
# 设置保留块
tune2fs -m 1 /dev/sda1 # 保留 1%
# 启用/禁用特性
tune2fs -O has_journal /dev/sda1
tune2fs -O ^has_journal /dev/sda1
扩展文件系统
# 在线扩展(Ext4 支持)
# 1. 扩展分区(使用 parted/fdisk)
parted /dev/sdb resizepart 1 100%
# 2. 通知内核分区变化
partprobe /dev/sdb
# 3. 扩展文件系统
resize2fs /dev/sdb1
# 离线扩展
umount /mount/point
e2fsck -f /dev/sdb1
resize2fs /dev/sdb1
mount /dev/sdb1 /mount/point
缩小文件系统
# Ext4 只能离线缩小
# 1. 卸载文件系统
umount /mount/point
# 2. 检查文件系统
e2fsck -f /dev/sdb1
# 3. 缩小到指定大小
resize2fs /dev/sdb1 50G
# 4. 缩小分区(使用 parted)
parted /dev/sdb resizepart 1 50G
# 5. 重新挂载
mount /dev/sdb1 /mount/point
文件系统检查和修复
fsck 工具
# 检查文件系统(只读,不修复)
fsck.ext4 -n /dev/sda1
# 自动修复错误
fsck.ext4 -y /dev/sda1
# 交互式修复
fsck.ext4 /dev/sda1
# 强制检查(即使标记为干净)
fsck.ext4 -f /dev/sda1
# 详细输出
fsck.ext4 -v /dev/sda1
# 检查坏块
fsck.ext4 -c /dev/sda1 # 只读测试
fsck.ext4 -cc /dev/sda1 # 读写测试(危险)
debugfs 调试
# 进入 debugfs
debugfs /dev/sda1
# 常用命令:
# stat <inode> - 显示 inode 信息
# stat <filename> - 显示文件信息
# ls - 列出目录
# cd <dir> - 切换目录
# pwd - 显示当前目录
# cat <file> - 显示文件内容
# dump <file> <output> - 导出文件
# blocks <file> - 显示文件块
# extents <inode> - 显示 extent 信息
# 示例:恢复删除的文件
debugfs -w /dev/sda1
debugfs: lsdel
# 找到要恢复的 inode
debugfs: dump <inode> /tmp/recovered_file
debugfs: quit
性能优化
挂载选项优化
# /etc/fstab 优化选项
# noatime - 不更新访问时间
/dev/sda1 / ext4 defaults,noatime 0 1
# nodiratime - 不更新目录访问时间
/dev/sda1 / ext4 defaults,nodiratime 0 1
# commit=60 - 延长提交间隔(秒)
/dev/sda1 / ext4 defaults,commit=60 0 1
# data=writeback - 最快的日志模式
/dev/sda1 / ext4 defaults,data=writeback 0 1
# barrier=0 - 禁用写屏障(风险)
/dev/sda1 / ext4 defaults,barrier=0 0 1
I/O 调度器
# 查看当前调度器
cat /sys/block/sda/queue/scheduler
# 设置调度器
echo deadline > /sys/block/sda/queue/scheduler
echo noop > /sys/block/sda/queue/scheduler
echo cfq > /sys/block/sda/queue/scheduler
# 永久设置(Grub)
# /etc/default/grub
GRUB_CMDLINE_LINUX="elevator=deadline"
update-grub
预读优化
# 查看预读大小(扇区数)
blockdev --getra /dev/sda
# 设置预读大小
blockdev --setra 4096 /dev/sda # 2MB
# 临时测试效果
hdparm -t /dev/sda
监控和统计
iostat 监控
# 监控文件系统 I/O
iostat -x 1
# 监控特定设备
iostat -x sda 1
文件系统统计
# 查看 inode 使用
df -i
# 查看块使用
df -h
# 详细统计
dumpe2fs /dev/sda1 | grep -E "Block count|Free blocks|Inode count|Free inodes"
下一步:学习 磁盘 I/O 子系统 章节。