df 与 du 对不上:文件删了空间没释放的定位与处置

举报
yd_291384559 发表于 2026/11/13 11:38:07 2026/11/13
【摘要】 删了文件 df 却不释放,多半是进程还持有已删文件的 fd。本文讲清 unlink 与链接计数机制,给出 lsof +L1 与 /proc/<pid>/fd 的定位方法、truncate 免重启的处置、logrotate 策略选择,以及挂载点覆盖、硬链接等正常差异的排查顺序。

现象

执行 rm 删掉一个大日志或大镜像后,df -h 的已用空间纹丝不动,而 du -sh 统计的目录总和不增反减,两者差出几十 GB,重启服务甚至重启机器才恢复。这类问题几乎都不是 df 统计出错,而是文件已经被删,但仍有进程打开着它。

原理:unlink 只摘掉目录项

Linux 删除文件实际是 unlink():把文件名从目录项里摘掉,并让 inode 的链接计数减一。数据块只有在链接计数为 0、且没有任何进程持有该文件的打开描述符时才真正释放。如果进程还持有 fd(尤其是长期运行、通过重定向写日志的进程),文件名消失了、inode 和数据块却仍被引用,df 自然看不到释放。

定位:先分清是被占用还是统计口径不同

  1. 确认同一文件系统:df -h /var/log 与 du -xsh /var/log,-x 保证不跨挂载点。
  2. 查已删除但仍被打开的文件:lsof +L1 列出链接数为 0 的打开文件,lsof +L1 /var 可限定目录;没有 lsof 时直接看 ls -l /proc/*/fd 并过滤 deleted。
  3. 确认占用进程与大小:lsof +L1 按 SIZE/OFF 排序取头部,那就是仍被占住的空间;再配合 ls -l /proc/<pid>/fd 找到具体文件。

处置:不要用重启凑合

三种做法,按风险从低到高:

  • 日志类文件:truncate -s 0 /proc/<pid>/fd/<n>,进程继续往同一个 fd 写,只是从 0 开始,不用重启。
  • 非日志的大文件(如已删的临时镜像):只能让持有进程关闭该 fd,通常是重启对应服务;若进程支持 reload,优先 reload。
  • 确认可以接受数据丢失时,也可对 /proc 路径 truncate 后观察 du 与 df 回归一致。

注意 lsof 显示的路径带 (deleted) 后缀,此时用原路径 truncate 会报 No such file,必须走 /proc/<pid>/fd/<n>。

预防

  • logrotate 的 copytruncate 与 create 两种策略要想清楚:copytruncate 不改变 inode、不要求进程重开文件,但复制窗口内可能丢日志;create 加 postrotate 重载进程才真正换 inode。
  • 应用侧优先用按大小或时间滚动的日志库,避免长期持有同一个 fd 写单个文件。
  • 监控里同时采集 df 使用率与 du 总和,两者持续背离就该查 deleted 文件。

还有几种正常的差异

排除 deleted 文件后,df 与 du 不一致还有几类常见原因:挂载点覆盖(目录里原有文件被新挂载遮住,du 数得到、df 不计入)、硬链接被 du 重复计算、稀疏文件与预分配文件(du 按块、df 按实际占用)、ext4 默认给 root 预留 5% 空间、NFS 客户端缓存延迟。判断顺序建议固定为:先 lsof +L1,再看挂载与硬链接,最后才怀疑文件系统本身。

小结

df 与 du 对不上,第一反应应该是有没有进程还开着已删文件,而不是统计坏了。一条 lsof +L1 通常就能定位,处置优先 truncate 而非重启,预防则落在日志滚动策略上。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。