这个问题发生在挖站否的免费空间服务器上。由于某个域名的错误日志高达50GB,在我删除之后使用df -h统计,发现硬盘大小仍然不变,最开始让我怀疑是Linux有回收站的功能。后来才发现df会统计已删除但却仍有进程引用的文件。
正常情况下,删除文件会立刻释放相关指针,并将imap和bmap中相关的位图标记为未使用。bmap只要一改变,文件系统立刻就能知道每个块组中哪些数据块是空闲的,哪些数据块是被使用的,这些信息都会更新到分区的superblock中。于是df能立刻统计到实时的空间信息。
但是当一个文件被删除时,如果还有进程在引用这个文件,根据前文的分析,bmap中不会将这个文件的data block标记为未使用,也就不会将数据块的使用情况更新到superblock中。由于df是根据superblock中空闲和使用数据块的数量来计算空闲空间和已使用空间的,所以df统计的时候会将这个已被”删除”的文件统计到已使用空间中。
例如,创建一个较大一点的文件放在”/”目录下,并du和df统计根目录的已使用空间。
[root@xuexi ~]# dd if=/dev/zero of=/my.iso bs=1M count=1000 [root@xuexi ~]# df -hT / Filesystem Type Size Used Avail Use% Mounted on /dev/sda2 ext4 18G 2.7G 14G 17% / [root@xuexi ~]# du -sh --exclude="/mnt" / 2>/dev/null 2.7G /
它们在GB级的单位上是相等的。
现在使用一个进程来引用这个文件,然后删除这个文件,再du和df统计。
[root@xuexi ~]# tail -f /my.iso & [root@xuexi ~]# rm -rf /my.iso [root@xuexi ~]# ls /my.iso ls: cannot access /my.iso: No such file or directory [root@xuexi ~]# du -sh --exclude="/mnt" / 2>/dev/null 1.8G / [root@xuexi ~]# df -hT / Filesystem Type Size Used Avail Use% Mounted on /dev/sda2 ext4 18G 2.7G 14G 17% /
可以发现,外界已经获取不到my.iso文件了,所以du无法统计这个文件。而df却将该文件大小统计进去了,因为my.iso占用的data block还未被标记为未使用。
再关掉tail进程,然后df再统计空间,结果将和du一样显示为正常的大小。
[root@xuexi ~]# jobs [1]+ Running tail -f /my.iso & [root@xuexi ~]# kill %1 [root@xuexi ~]# df -hT / Filesystem Type Size Used Avail Use% Mounted on /dev/sda2 ext4 18G 1.7G 15G 11% /
如果不知道文件系统中哪些已被删除,但却还被进程引用的文件,可以使用lsof来获取。通过它还能获取到文件的大小,看看到底是哪个文件在”占着茅坑以及占了多少茅坑”。
例如,关掉tail进程前,使用lsof查看。可以看到tail进程占用了/my.iso,且这个文件的大小为1048576000字节。
[root@xuexi ~]# lsof | grep deleted php-fpm 12597 root txt REG 8,2 4058416 931143 /usr/sbin/php-fpm (deleted) php-fpm 12657 nobody txt REG 8,2 4058416 931143 /usr/sbin/php-fpm (deleted) php-fpm 12707 nobody txt REG 8,2 4058416 931143 /usr/sbin/php-fpm (deleted) php-fpm 12708 nobody txt REG 8,2 4058416 931143 /usr/sbin/php-fpm (deleted) tail 14437 root 3r REG 8,2 1048576000 7171 /my.iso (deleted)