CentOS 7 删除文件却不释放空间?从 inode、文件描述符到 VFS 的底层原理解析

这是在帮一个用户看服务器遇到的问题,他用的是Hostease的独立服务器,因为服务器用的时间也比较长了,磁盘比较满,所以做了一次清理,但是在删除文件之后,发现他删除掉几百个G的数据之后,磁盘空间并没有空出来。

我拿到之后先df -h看了下:

光看df结果,文件确实已经满的再满了,此时用户已经删除大量文件,空间却没有释放;并且紧接着重启了服务,而重启前后前后,df 变化也不明显。

这类问题,99% 本质都与 inode 引用计数有关。

理解 Linux 删除文件的真实过程

很多人误以为:

rm = 删除文件内容

实际上:

rm 只是删除"目录项"(directory entry)

我们必须理解 Linux 文件系统的三个核心概念:

1️.inode

inode 保存的是以下信息:

文件大小

权限

数据块指针

链接数(link count)

时间戳

文件名不存储在 inode 里。

2️.目录项(dentry)

目录本质是:

文件名 → inode 号

删除文件时,删除的是目录项,而inode和数据块仍然存在。

3️.文件描述符(File Descriptor)

当进程打开文件:

fd = open("test.log", O_WRONLY);

内核会在进程表中创建 file descriptor,引用对应 inode,增加引用计数。

什么时候磁盘空间才会真正释放?

磁盘空间释放的条件:

1.link count == 0

2.没有进程持有该 inode

只有两个条件同时满足,内核才会释放 inode和数据块,回收空间。

为什么 lsof | grep deleted 会出现大量文件?

执行:

lsof | grep deleted

示例:

php-fpm 4510 root 3u REG ... /tmp/ZCUDnRoeZv (deleted)

简单来说就是,目录项已删除,link count 已为 0,但进程仍持有 file descriptor,inode 仍被引用,数据块无法释放。

这是一种非常经典的"幽灵文件"。

从内核角度看"deleted 文件"

在 /proc 下可以看到:

ls -l /proc/4510/fd/

会看到类似:

3 -> /tmp/ZCUDnRoeZv (deleted)

实际上文件名已不存在,但 fd 仍然指向 inode,进程依然可以写入,这也是为什么日志文件可以"删掉还继续增长"。

df 与 du 为什么会不一致?

df 统计的是文件系统已分配的数据块数量,它直接读取超级块(superblock)信息。

而du 是遍历目录树,统计可见文件的 inode 占用。

deleted 文件会导致什么?

df 统计的是实际已用 block

du 统计的是当前目录可见文件

因此:

df 显示 100%

du 却找不到大文件

这几乎可以确定:

存在被进程占用的 deleted 文件

真实排查流程(技术向)

1.查看磁盘使用

df -h

2.查看目录占用

du -xhd1 / 2>/dev/null | sort -hr

如果 du 总和远小于 df,说明存在"不可见占用"。

3️.检查 deleted inode

lsof | grep deleted

或:

lsof -nP | grep '(deleted)'

4️.查看具体进程 fd

ls -l /proc/PID/fd

5. 释放方式

推荐方式

优雅重启服务:

systemctl restart 服务名

非优雅方式(极端场景)

直接 kill 进程:

kill -9 PID

不建议生产环境滥用。

隐藏回收站目录的本质

例如:

/.Recycle_bin

这不是内核机制,而是:

面板逻辑层实现

文件被移动而非删除

底层发生的是:

rename(old_path, /.Recycle_bin/xxx)

inode 不变,仅目录项变化。

因此:

du 会看到

df 会统计

但用户误以为已删除

在这个客户的案例里,虽然存在一些幽灵文件,但实际上大头是在/.Recycle_bin 中:

ext4 延迟分配与日志机制补充

在 ext4 下:

采用延迟分配(delayed allocation)

使用 journal 日志机制

如果磁盘 100%:

journal 无法提交

某些写入可能阻塞

服务异常

因此:

根分区长期 100% 是非常危险的状态。

进阶:如何快速统计 deleted 占用总量?

可以使用:

lsof | grep deleted | awk '{print 7}' \| awk '{sum+=1} END {print sum/1024/1024 " MB"}'

用于估算被占用空间。

总结

删除文件 ≠ 释放空间,真正释放空间的条件是:

inode link count = 0

且无 file descriptor 引用

df 与 du 不一致的根本原因是df 统计 block,du 统计目录可见 inode,当你理解了 inode 与 file descriptor 的关系,这类问题将不再神秘。

相关推荐
火红色祥云2 小时前
Python机器学习经典实例_笔记
笔记·python·机器学习
yq1982043011562 小时前
基于Python爬虫原理的Pinterest视频资源获取技术解析与工具实践
爬虫·python·django·音视频
喵手2 小时前
Python爬虫实战:自动化质量护航 - 构建爬虫数据的“熔断与巡检”规则引擎实战!
爬虫·python·自动化·爬虫实战·零基础python爬虫教学·自动化质量护航·数据熔断
一切尽在,你来2 小时前
AI大模型应用开发前置知识:Python 异步编程
python·ai编程
一切尽在,你来2 小时前
LangGraph 概览
人工智能·python·langchain·ai编程
CeshirenTester12 小时前
9B 上端侧:多模态实时对话,难点其实在“流”
开发语言·人工智能·python·prompt·测试用例
Starry_hello world12 小时前
Python (2)
python
礼拜天没时间.12 小时前
Docker自动化构建实战:从手工到多阶段构建的完美进化
运维·docker·容器·centos·自动化·sre
ID_1800790547312 小时前
Python爬取京东商品库存数据与价格监控
jvm·python·oracle