umount 什么时候sync
一、先理清:只有卸载真实块设备挂载根、且 super_block 无其他引用时,才会触发 sync_filesystem 全局刷脏
mount --bind 只是别名,umount bind 目标不会刷;下面构造能真实触发 umount 时刷脏的完整可复现例子(XFS/ext4 通用)。
前置准备:临时 loop 磁盘(独立文件系统,拥有独立 super_block)
-
创建1G空镜像文件
dd if=/dev/zero of=/tmp/disk.img bs=1M count=1024 -
格式化为xfs(换成mkfs.ext4也可以)
mkfs.xfs /tmp/disk.img -
创建两个目录,一个原始挂载点,一个bind别名
mkdir -p /mnt/orig /mnt/bind
场景流程:会触发 umount 刷脏的完整步骤
步骤 1:挂载真实文件系统(独立 sb)
bash
运行
mount -o loop /tmp/disk.img /mnt/orig
此时 /mnt/orig 对应一个全新 super_block,s->s_active = 1。
步骤 2:制造脏页(写文件不 sync)
bash
运行
写入大文件,只留在page cache,不刷磁盘
dd if=/dev/urandom of=/mnt/orig/test.dat bs=1M count=200
不执行sync/syncfs,数据现在是脏页
步骤 3:关键 —— 不保留任何 bind、不打开文件(保证 sb->s_active 始终 = 1)
不要打开 /mnt/orig 下任何文件、不要 cd 进去;
这里我们先不创建 bind,保证只有原始挂载一条引用。
步骤 4:umount 原始挂载点,观察自动刷脏
bash
运行
开另一个终端监控sync_filesystem
/usr/share/bcc/tools/stackcount -P -D 200 sync_filesystem
执行卸载
umount /mnt/orig
观测现象:
stackcount 立刻捕获 sync_filesystem 调用;
内核把 /tmp/disk.img 里所有脏页、元数据、日志全部刷入 loop 磁盘;
走完 deactivate_super → down_write → kill_sb → generic_shutdown_super。
二、对比反例:加 bind 后 umount bind 不会刷脏(印证之前结论)
复现不刷脏流程
bash
运行
重新挂载
mount -o loop /tmp/disk.img /mnt/orig
创建bind别名
mount --bind /mnt/orig /mnt/bind
写脏数据
dd if=/dev/urandom of=/mnt/orig/test2.dat bs=1M count=200
监控sync_filesystem
/usr/share/bcc/tools/stackcount -P -D 200 sync_filesystem
卸载bind别名
umount /mnt/bind
现象:无任何 sync_filesystem 输出,脏页还留在内存。
原因:
umount /mnt/bind 只删除 vfsmount 别名,底层 sb 依然被 /mnt/orig 持有,s->s_active=2,不会进入 deactivate_super 的销毁分支。
此时再执行:
bash
运行
umount /mnt/orig
才会触发 sync_filesystem 刷脏。
三、内核链路对照(能刷脏的那条路径)
plaintext
umount /mnt/orig
do_umount
deactivate_super(sb)
s->s_active == 1
atomic_add_unless返回false
down_write(&s->s_umount) // 获取卸载锁
deactivate_locked_super(sb)
atomic_dec_and_test(&s->s_active) → 0
fs->kill_sb(sb)
generic_shutdown_super(sb)
sync_filesystem(sb) // 全局刷所有脏页
四、安全实操提示
仅卸载原始块设备挂载、无 bind / 无进程打开文件,才会自动刷脏;
卸载 bind 挂载别名永远不会主动刷脏,数据存在丢失风险;
操作 bind 解绑前建议手动落盘:
bash
运行
syncfs /mnt/orig
umount /mnt/bind
[root@anolis mnt]# mount -o loop /tmp/disk.img /mnt/orig
mount: /mnt/orig: wrong fs type, bad option, bad superblock on /dev/loop0, missing codepage or helper program, or other error.
dmesg(1) may have more information after failed mount system call.
报错原因
/tmp/disk.img 只是全 0 空文件,没有正确格式化文件系统,内核识别不到合法 superblock,挂载失败。
分两步修复:格式化镜像 + 重新挂载。
重新制作并格式化镜像
bash
运行
重建镜像(覆盖旧的损坏镜像)
dd if=/dev/zero of=/tmp/disk.img bs=1M count=200
格式化为 ext4(兼容性最好,anolis 无需额外xfs工具)
mkfs.ext4 -F /tmp/disk.img
-F 强制格式化普通文件(非块设备)
不要用 mkfs.xfs,最小镜像容易报错且依赖 xfs 工具包
2. 重新挂载
bash
运行
mkdir -p /mnt/orig /mnt/bind
mount -o loop /tmp/disk.img /mnt/orig
3. 验证挂载成功
bash
运行
df /mnt/orig
完整复现「umount 触发刷脏」流程(修复后)
终端 1:监控刷脏调用
bash
运行
安装bcc工具(无则先 yum install bcc-tools -y)
tracepoint 't:fs:sync_filesystem'
终端 2:制造脏数据、卸载原始挂载触发 sync
bash
运行
写入脏文件,不手动sync
dd if=/dev/urandom of=/mnt/orig/dirty.dat bs=1M count=100
无bind、无进程占用,直接卸载原始挂载,会触发sync_filesystem
umount /mnt/orig
你会在监控终端看到 sync_filesystem 事件,代表内核自动刷全分区脏页。
对比反例(umount bind 不刷脏)
bash
运行
mount -o loop /tmp/disk.img /mnt/orig
mount --bind /mnt/orig /mnt/bind
dd if=/dev/urandom of=/mnt/orig/dirty2.dat bs=1M count=100
卸载bind别名,监控无任何sync输出
umount /mnt/bind
只有卸载真实挂载点才会刷脏
umount /mnt/orig
补充:如果不想装 bcc,改用 dmesg 间接验证
卸载原始挂载后看 IO 刷盘日志:
bash
运行
dmesg -w
卸载瞬间能看到文件系统刷数据、回收 inode 的内核日志;卸载 bind 别名不会出现该日志。

浙公网安备 33010602011771号