← LeisureLinux 文章索引
LeisureLinux · 微信公众号文章

运维避坑:为什么 rm 了 5GB 日志,磁盘空间还是 100%?

安全/漏洞 阅读原文(微信)↗

最近有一位刚入行 DevOps 的同学跑来问我一个诡异的现象:生产服务器磁盘告警,他反手一个 rm 删除了 5GB 的大日志,结果 df -h 一看,空间占用纹丝不动。

这其实是 Linux 系统中 "文件删除机制""进程引用计数" 之间的一个经典博弈。

1. 解耦的设计:文件名并不等于文件

在 Linux 的虚拟文件系统(VFS)中,一个文件被拆分为两个核心维度:

  • dentry (Directory Entry): 我们在 Shell 里看到的"文件名",本质上只是一个指向 Inode 的指针。

  • Inode: 真正的文件元数据(元信息),包含权限、属主以及指向磁盘 Data Blocks 的地址。

当你执行 rm 命令时,内核调用的是 unlink()。这个操作仅仅是删除了 dentry,并将 Inode 的 i_link(硬链接数) 减 1。

2. 关键变量:i_count 引用计数

除了 i_link,内核还维护着一个关键指标:i_count(进程引用计数)。 在上述案例中,Web Server 进程依然打开着该日志文件,持有其文件描述符(File Descriptor)。此时:

  • i_link = 0(文件名已消失)

  • i_count > 0(进程句柄未关闭)

Linux 内核的准则: 只有当 i_linki_count 同时为 0 时,指向磁盘 Data Blocks 的指针才会被释放,空间才会被标记为"空闲"。

3. df 与 du 的"情报差"

这就是为什么你会看到 dfdu 的数据冲突:

  • du (Disk Usage): 基于文件树扫描。因为 dentry 没了,它找不到这个文件,所以报告空间已释放。

  • df (Disk Free): 基于超级块(Superblock)的磁盘块分配表。因为 i_count > 0,内核依然认为这些块是 Active 状态,所以报告空间依然占满。

4. 专家级处理方案

在生产环境中,严禁对正在被进程写入的日志执行 rm

  • 优雅方案(在线清空):
使用 `true > /var/log/access.log`{index-in-node="15" path-to-node="19,0,0"}  `truncate -s 0`{index-in-node="44" path-to-node="19,0,0"}\

这会触发内核将 Data Blocks 直接置空,而无需改变 Inode 状态,进程可以无感地继续写入,且空间立即释放。

  • 事后补救(寻找隐形文件): 如果已经删了文件,可以使用以下命令定位这些"幽灵文件":
[Bash]{ngcontent-ng-c3649887988=""}
    lsof +L1  # 查找 link count 小于 1 且仍被打开的文件
找到对应的 PID 通过 `> /proc/[PID]/fd/[FD]`{index-in-node="15" path-to-node="19,1,2"} 强制截断或者优雅地 `reload`{index-in-node="48" path-to-node="19,1,2"} 该服务

{#section path-to-node="21"}

{#section-1 path-to-node="21"}

LeisureLinux 禅悟

在 Linux 的世界里,看到的(文件名)不一定是真实的,看不到的(Inode/FD)才是系统运行的基石。理解了 引用计数,你才算真正跨过了运维开发的初阶门槛。

本文整理自微信公众号 LeisureLinux 的原创内容(Linux / AI / 安全 硬核技术)。

· 阅读原文(微信公众号)

· 关注公众号 LeisureLinux,第一时间获取技术深度内容。

LeisureLinux 公众号二维码(微信扫一扫关注)