Linux中删除文件,磁盘空间未释放问题追踪

时间:2021-09-29 12:44:32

在客户使用我们产品后,发现一个问题:在删除了文件后。磁盘空间却没有释放。是有进程在打开这个文件,还是其它情况?我们一起来看看一下两个场景

一. 场景一:进程打开此文件

当一个文件正在被一个进程使用时。用户删除此文件,文件仅仅会从文件夹结构中删除,但并没有从磁盘删除。当使用这个文件的进程结束后,文件才会真正的从磁盘删除,释放占有的空间。

我们发现剩余磁盘空间比較少时,回去删除一些大的暂时文件或者log文件。假设删除之后会发现磁盘空间并未降低。那么能够通过“lsof”命令去查看正在使用该文件的进程。然后再重新启动该进程或者服务。

【样例】

如今发现磁盘空间的占用了99%。剩余空间仅仅剩下522M。

SUSE11X64-001:/test # df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda2 29G 27G 522M 99% /
devtmpfs 972M 116K 972M 1% /dev
tmpfs 972M 0 972M 0% /dev/shm

找到一个文件"vmcore"占用了接近900M空间。但这个文件不须要再使用了,于是採用“rm”命令删除此文件,但是删除后,发现磁盘空间并没有真正的降低。

SUSE11X64-001:/test # rm vmcore
SUSE11X64-001:/test # df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda2 29G 27G 522M 99% /
devtmpfs 972M 116K 972M 1% /dev
tmpfs 972M 0 972M 0% /dev/shm
//10.204.16.2/home/splx/iceking 6.3T 1.6T 4.7T 25% /mnt/iceking

也就是说非常有可能有其它进程正在使用这个文件,使用“lsof”命令去查看正在使用该文件的进程。

SUSE11X64-001:/test # lsof | grep vmcore
a.out 2610 root 3r REG 8,2 941331144 1643779 /test/vmcore (deleted)

进程号为2610(进程名为"a.out")的进程,正在使用vmcore文件。也能够看到其后有“deleted”:其表示正在使用的文件被删除,但并没有真正从磁盘上移除。

如今我们删除这个进程,并查看磁盘空间此时占用率减少为95%。剩余空间添加到1.4G。

SUSE11X64-001:/test # df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda2 29G 26G 1.4G 95% /
devtmpfs 972M 116K 972M 1% /dev
tmpfs 972M 0 972M 0% /dev/shm

二. 场景二:内核模块Bug

在文件系统处理文件须要的信息都存放在索引节点(inode)中,假设在删除文件的时候索引节点的引用计数不为0(表示文件正在被使用),则不会在磁盘中真正的删除文件。从而保证正在使用此文件的进程可以正常的处理文件。

首先我们一起来看一下内核中关于文件系统的一些重要数据结构的关联。当一个进程打开一个文件后,便会在内核中创建一个file对象,这个对象主要描写叙述了进程怎样与文件进行交互。file对象中将指向一个dentry结构(文件夹项)。文件夹项中描写叙述了文件夹项名称,父文件夹项信息,子文件夹项信息等。而dentry中的d_inode所指向的inode节点中则包括了实际的文件存储在磁盘上的信息。

Linux中删除文件,磁盘空间未释放问题追踪

当多个进程打开同一个文件时,内核中变会创建对应的file对象,可是他们都公用同一个dentry,仅仅只是每一次打开文件dentry的引用计数d_count加1。

而且对于打开的同一个文件而言,inode也是唯一的。inode的引用计数i_count一般为文件硬链接的数目。

看过一些中文博客,说“同一个文件。每打开一次,则inode中引用计数i_count则加1”。这样的说法通过我的验证结果是错误的。实验结果是:对于同一个文件。每打开一次,则inode中的引用计数不变,但对应的dentry引用计数加1.

这次客户在删除文件后。磁盘空间没有释放,通过"lsof"命令也没有找到正在占用此文件的进程。于是再次怀疑这是因为产品的内核模块早成的。后经分析得到:在上一篇博文《Linux
Kernel模块内存泄露查找 (2)》
中解释过因为在产品内核模块中,对dentry引用,并使用完之后并没有对其引用计数减1。从而造成内存泄露。

在这样的情况下。dentry不会被释放。则inode也就一直被引用着,从而也导致了即使删除文件,也不会从磁盘删除。

并且针对以上的问题和分析,假设不能及时给客户修这个问题,那也仅仅能让其又一次启动OS,空暇的磁盘空间才会释放出来。