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 的关系,这类问题将不再神秘。

相关推荐
YuanDaima204836 分钟前
[CrewAI] 第15课|构建一个多代理系统来实现自动化简历定制和面试准备
人工智能·python·面试·agent·crewai
WHS-_-20221 小时前
Python 算法题学习笔记一
python·学习·算法
码界筑梦坊1 小时前
353-基于Python的大湾区气候数据可视化分析系统
开发语言·python·信息可视化·数据分析·django·vue·毕业设计
如何原谅奋力过但无声2 小时前
【chap11-动态规划(上 - 基础题目&背包问题)】用Python3刷《代码随想录》
数据结构·python·算法·动态规划
云姜.2 小时前
JSON Schema使用
python·json
Sunshine for you2 小时前
使用Flask快速搭建轻量级Web应用
jvm·数据库·python
qwehjk20082 小时前
如何从Python初学者进阶为专家?
jvm·数据库·python
小熊Coding2 小时前
重庆市旅游景点数据可视化分析系统
爬虫·python·数据挖掘·数据分析·计算机毕业设计·数据可视化分析·旅游景点
sg_knight2 小时前
CentOS 裸机实操:5分钟完成 MinIO 单机部署与公网访问
linux·python·centos·文件管理·minio·ftp·oss
dgvri2 小时前
Linux(CentOS)安装 MySQL
linux·mysql·centos