在临时 loop 文件系统里复现磁盘写满,练习定位、清理与验证恢复

演练目标

环境准备

准备一台 Linux 虚拟机或一次性特权容器,具备 root、mkfs.ext4、mount 和 losetup,/tmp 至少留 200 MB。所有写入只发生在 /tmp/lab-disk 和 /tmp/lab-mnt,不要对 /、/var、/home 做填充实验。

sudo -i
mkdir -p /tmp/lab-disk /tmp/lab-mnt
truncate -s 128M /tmp/lab-disk/disk.img
mkfs.ext4 -q -F /tmp/lab-disk/disk.img
mount -o loop /tmp/lab-disk/disk.img /tmp/lab-mnt
findmnt -T /tmp/lab-mnt
df -h /tmp/lab-mnt

确认 findmnt 的挂载点是 /tmp/lab-mnt、源设备是 loop 设备后再继续。若机器不支持 loop 挂载,可改用 mount -t tmpfs -o size=128m tmpfs /tmp/lab-mnt,其余步骤不变。

注入故障

先写入一个接近容量的文件,再追加数据触发 ENOSPC:

dd if=/dev/zero of=/tmp/lab-mnt/fill.bin bs=1M count=120 status=progress
dd if=/dev/zero of=/tmp/lab-mnt/more.bin bs=1M count=16 status=progress

第二条命令应报 No space left on device。接着制造“已删除但仍被打开”的文件,模拟日志进程占着空间:

bash -c 'exec 3<>/tmp/lab-mnt/hold.log; rm -f /tmp/lab-mnt/hold.log; sleep 600' &
echo $! > /tmp/lab-disk/holder.pid

观察现象

df -h /tmp/lab-mnt
df -i /tmp/lab-mnt
du -x -h --max-depth=1 /tmp/lab-mnt | sort -h
lsof +L1 | grep lab-mnt

预期结果是:df -h 使用率接近 100%,普通写入失败;df -i 仍有富余,说明不是 inode 耗尽;du 统计明显小于 df 的已用量,差额来自已删除但仍被打开的 hold.log;lsof +L1 能看到该文件的 (deleted) 记录。

判断与定位

  1. 先确认报错发生在哪个挂载点,不要只看整机 df -h 的根分区。
  2. df -h 满而 df -i 正常,是空间耗尽;反过来则是 inode 耗尽。
  3. du 与 df 差异大时,优先检查 lsof +L1、文件系统保留块和快照。
  4. 容易误判:df 显示 100% 不代表所有进程都不能写。ext4 默认给 root 保留约 5%,root 仍可能写入,普通用户已经失败。也不能因为 du 统计偏小就认为空间“凭空消失”。
  5. 容器场景要确认满的是容器可写层、挂载卷,还是宿主机分区。

修复

rm -f /tmp/lab-mnt/fill.bin
kill "$(cat /tmp/lab-disk/holder.pid)"
df -h /tmp/lab-mnt
dd if=/dev/zero of=/tmp/lab-mnt/verify.bin bs=1M count=1 status=none

写入 verify.bin 成功即表示恢复。生产环境还应检查日志轮转、core dump、镜像层和备份目录,并补充容量告警。

清理与回滚

kill "$(cat /tmp/lab-disk/holder.pid)" 2>/dev/null || true
umount /tmp/lab-mnt
rm -f /tmp/lab-disk/disk.img /tmp/lab-disk/holder.pid
rmdir /tmp/lab-mnt /tmp/lab-disk

umount 失败时先用 lsof +f -- /tmp/lab-mnt 找到占用者,不要直接对挂载点执行 rm -rf。

复盘

延伸阅读

读完自测

  1. df -h 显示 100%,但 du 统计只有一半,可能是什么原因?
  2. 为什么 ext4 满盘时 root 仍可能写入成功?
  3. 删除文件后空间没有释放,应该先做什么?
答案
  1. 常见原因是已删除但仍被进程打开的文件、文件系统保留块、快照,或 du 没有覆盖到对应挂载点。
  2. ext4 默认预留约 5% 空间给 root,普通用户先遇到 ENOSPC。
  3. 用 lsof +L1 找到持有已删除文件的进程,重载或重启它,而不是继续盲目删除。