Ubuntu 24.04 磁盘爆满"灵异"事件:Btrfs, Snapper 与删不掉的空间
Ultimate Guide: Solving "No Space Left on Device" on Ubuntu 24.04 (Btrfs) - When rm -rf Fails to Free Space
写在前面 :
2025年末,在配置深度学习环境(CUDA 13.1 + Torch)的过程中,我遭遇了一次极其诡异的**"磁盘假死"**事件。在
df -h显示根目录 100% 爆满的情况下,我手动删除了近 500GB 的模型权重和缓存,但系统依然提示No space left on device,导致 GDM 图形界面崩溃、Apt 锁死、SSH 险些断连。本文记录了在 Ubuntu 24.04 (Btrfs文件系统) 下,如何揪出吞噬硬盘的"幽灵"------Snapper 快照,并彻底解决这一问题的完整链路。
1. 问题现象与环境
硬件与系统环境:
- OS: Ubuntu 24.04.3 LTS
- Filesystem: Btrfs (默认安装配置)
- Disk: 1.1T NVMe SSD
故障描述 :
系统运行中突然由于磁盘写满导致服务雪崩。
- 基础服务崩溃 :
zsh无法写入历史记录,apt无法更新锁文件,mkdir报错。 - 图形界面挂死 :
systemctl status gdm显示Failed to start GNOME Display Manager。 - 空间悖论:
- 使用
df -h查看,根目录/使用率稳居 100%。 - 使用
rm -rf删除了.cache(180G) 和anaconda3(140G) 等大目录后,df -h依然显示 100%,没有任何空间释放。 - 使用
du -sh /*统计全盘文件,发现当前可见文件总和远小于磁盘总量(仅用了约 50%)。
关键报错日志:
bash
# Zsh 报错
zsh: locking failed for /home/lff8888/.zsh_history: 设备上没有空间: reading anyway
# Apt 报错
E: 无法建立临时文件(mkstemp) /tmp/clearsigned.message.eAmY3X (28: 设备上没有空间)
# 日志清理报错
rm: cannot remove 'xxx': No space left on device
2. 核心故障分析 (Root Cause Analysis)
经过排查,这并非传统的"文件未释放占用(deleted but open)",而是 Btrfs 文件系统特性 与 Snapper 自动快照 共同导致的"幽灵占用"。
- Btrfs 的 CoW (Copy-on-Write) 机制 :
在 Btrfs 文件系统中,删除文件(rm)并不会物理擦除数据块,只要有"快照(Snapshot)"指向这些数据块,它们就会被永久保留在磁盘上。 - Snapper 的静默吞噬 :
Ubuntu/OpenSUSE 等发行版默认启用了 Snapper 进行系统备份。它可以针对apt操作或时间轴(Timeline)自动创建快照。
- 元凶发现 :通过
sudo snapper list发现,系统中积累了数千个快照(Timeline 快照保留了长达一年的历史),这些快照完整锁住了我刚才删除的那几百 GB 数据。
- Metadata(元数据)耗尽 :
Btrfs 需要独立的 Metadata 空间。当快照过多或碎片化严重时,即便 Data 区域有空位,Metadata 满了也会导致文件系统变为 Read-Only 或无法写入,报No space left on device。
3. 解决方案 (Step-by-Step)
第一步:诊断快照堆积
首先确认是否是 Snapper 在作祟。
bash
# 查看快照列表
sudo snapper list
如果看到列表中有几千行,且 Type 包含大量的 timeline 或 number (apt),那么恭喜你,找到原因了。
第二步:紧急释放空间(批量删除快照)
注意 :在 Btrfs 下,唯有删除快照才能真正释放 rm 操作后的空间。
可以使用范围删除来快速清理(保留最近几天的即可):
bash
# 语法:sudo snapper delete [ID范围]
# 例如删除 ID 从 4000 到 5700 的所有旧快照
sudo snapper delete 4000-5700
执行后,系统需要几分钟时间进行后台清理(Btrfs commit)。稍等片刻再次运行 df -h,你会发现空间瞬间"回来"了。
第三步:防止复发(修改 Snapper 策略)
默认的保留策略过于激进(保留数年),对于开发机来说是灾难。必须修改配置文件。
- 编辑配置:
bash
sudo nano /etc/snapper/configs/root
- 修改以下关键参数(建议值):
bash
# 限制 APT 操作的快照保留数量(原值可能是 50)
NUMBER_LIMIT="10"
# 限制时间线快照(最关键!原值 YEARLY="10" 会吃光硬盘)
TIMELINE_LIMIT_DAILY="7" # 保留最近7天
TIMELINE_LIMIT_WEEKLY="2" # 保留最近2周
TIMELINE_LIMIT_MONTHLY="1" # 保留最近1个月
TIMELINE_LIMIT_YEARLY="0" # 关闭年度保留
- 应用更改并触发清理:
bash
sudo snapper cleanup number
sudo snapper cleanup timeline
第四步:Btrfs 元数据平衡(进阶维护)
为了防止 Metadata 爆满导致的假死,建议定期执行 Balance 操作。
bash
# 检查元数据使用情况
sudo btrfs filesystem usage /
# 平衡数据块(回收利用率低于 5% 的块)
sudo btrfs balance start -dusage=5 /
4. 验证与恢复
完成上述操作后,进行最终验证:
- 检查空间:
bash
df -h
# 此时 / 分区使用率应大幅下降,例如从 100% 降至 40%
- 恢复图形界面 :
空间释放后,GDM 终于可以写入日志并启动了。
bash
sudo systemctl restart gdm
总结 (Conclusion)
在现代 Linux 发行版使用 Btrfs 时,传统的运维经验(看到盘满就 rm -rf)往往是无效的。
- 警惕快照 :如果
df和du数据对不上,第一时间检查snapper list。 - 配置调优 :装机后第一时间修改
/etc/snapper/configs/root,关闭YEARLY保留策略。 - 正确的删除姿势:大文件删除后,必须配合快照清理,空间才会真正释放。
这次"灵异事件"本质上是先进文件系统特性与默认配置不匹配的结果。希望这篇复盘能帮大家守住宝贵的 SSD 空间!