51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

Linux文件删除原理

在Linux文件系统中,文件的删除操作涉及到两个核心的概念i_nlink和i_count,当执行rm命令删除文件时,Linux内核并不是立即将文件数据从磁盘中擦除,而是进行以下操作:

1、删除文件:执行rm命令删除文件,这会导致文件的链接数(i_nlink)减少。

2、检查链接数:如果文件的链接数(i_nlink)减少到0,表示没有其它文件指向它。

3、检查引用数:如果文件的链接数(i_nlink)为0,但引用数(i_count)不为 0,说明文件仍然被某些进程打开并使用。在这种情况下,文件的数据和inode不会立即被删除,而是继续保留,直到所有引用该文件的进程关闭该文件(即i_count减少到0)。

4、释放资源:只有当文件的链接数(i_nlink)和引用数(i_count)都为0时,文件系统才会真正释放该文件的inode和数据块,将其标记为可用,以便将来存储新的数据。


i_nlink和i_count

i_nlink(链接数):当前有多少个硬链接指向这个文件的inode,当执行rm命令删除文件时,i_nlink链接计数会减少。如果链接计数减少到0,并且没有进程引用该文件(即i_count等于0),那么该文件会真正的被删除。

i_count(引用数):当前有多少个进程正在引用该文件的inode,即使i_nlink减少到0,只要有进程仍在使用该文件(比如文件被打开),i_count仍然会大于0,此时文件的实际数据和inode依旧存在,未被释放。


举例:模拟MySQL空间不释放问题分析

以MySQL数据库日志为例,模拟日志爆满并删除日志,空间无法释放。

我这里生成一个10GB文件写入MySQL error.log中,打满磁盘(我这里磁盘10GB)
cd /data/mysql seq 1000000000 >>error.log;echo "test"

|-----|---------------------------------------------------------| | 1 2 | cd /data/mysql seq 1000000000 >>error.log;echo "test" |

执行删除操作
rm -f error.log

|---|-----------------| | 1 | rm -f error.log |

删除文件后,查看磁盘空间


神奇的情况出现了,磁盘使用率依旧是100%,空间并没有被释放,但是我们的的确确删除了error.log,所以此时我们就可以得出来一个结论,error.log并没有真正的被删除,即i_count≠0。


i_nlink查看方法

查看i_nlink的值非常容易,我们只需要执行ls -l命令即可。

例如:查看当前目录下demo文件的i_nlink值,并通过硬链接增加i_nlink值。
ls -l demo -rw-r--r-- 1 root root 20K Sep 24 20:00 demo

|-----|---------------------------------------------------------| | 1 2 | ls -l demo -rw-r--r-- 1 root root 20K Sep 24 20:00 demo |

这里的数字1,就表示i_nlink值为1。
ln demo demo2 ls -l demo -rw-r--r-- 2 root root 20K Sep 24 20:00 demo

|-------|-----------------------------------------------------------------------| | 1 2 3 | ln demo demo2 ls -l demo -rw-r--r-- 2 root root 20K Sep 24 20:00 demo |

通过ln对该文件创建硬链接,那么此时i_nlink值就变为2了。
ls -il 33559053 -rw-r--r-- 2 root root 20K Sep 24 20:00 demo 33559053 -rw-r--r-- 2 root root 20K Sep 24 20:00 demo2

|-------|---------------------------------------------------------------------------------------------------------------------| | 1 2 3 | ls -il 33559053 -rw-r--r-- 2 root root 20K Sep 24 20:00 demo 33559053 -rw-r--r-- 2 root root 20K Sep 24 20:00 demo2 |

通过ls -il查看demo和demo2的inode值相同,因为是通过硬链接创建的文件,这意味着这两个文件实际上是同一个文件,即它们指向同一个物理数据块,在这种情况下,对其中一个文件的修改会影响到另一个文件,因为它们共享相同的内容。如果rm删除其中一个文件,那另一个文件的i_nlink值就会减1,即i_nlink值为1。

i_count查看方法

i_count是内核内部的一个计数器,通常用于跟踪有多少个进程当前打开了这个文件。这个计数器并不直接暴露给用户空间,因此没有直接的命令可以查看i_count的值。

但是我们可以通过一些间接的方法来了解哪些进程打开了某个文件,这可以帮助你推测i_count的值。

lsof命令可以列出所有打开的文件以及它们被哪个进程打开。

fuser命令也可以用来列出正在使用某个文件的进程,显示正在使用该文件的进程ID列表。

例如:通过tail命令打开demo文件
tail -f demo &

|---|-----------------| | 1 | tail -f demo & |

通过lsof命令
lsof demo COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME tail 2679202 root 3r REG 253,0 20480 33559053 demo

|-------|-----------------------------------------------------------------------------------------------------------------| | 1 2 3 | lsof demo COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME tail 2679202 root 3r REG 253,0 20480 33559053 demo |

COMMAND:使用该文件的进程名,这里是 tail。
PID:进程标识符,这里是 2679202。
USER:拥有该进程的用户,这里是 root。
FD:文件描述符,这里是 3r,表示文件描述符是 3,并且是以只读的方式打开(r)。
TYPE:文件类型,这里是 REG,表示这是一个常规文件。
DEVICE:设备号,表示该文件所在的设备,这里是 253,0。
SIZE/OFF:文件大小或偏移量,这里是20K。
NODE:文件的 inode 号,这里是 33559053。
NAME:文件的名称,这里是 demo,表示正在访问的文件名。

综合来看,这个输出结果表明,root用户使用tail命令正在以只读方式访问名为demo的常规文件,进程ID为2679202。

通过fuser命令
fuser -uv demo USER PID ACCESS COMMAND /root/demo: root 2679202 f.... (root)tail

|-------|----------------------------------------------------------------------------------| | 1 2 3 | fuser -uv demo USER PID ACCESS COMMAND /root/demo: root 2679202 f.... (root)tail |

root用户使用tail命令,正在以读取或写入的方式访问/root/demo文件,进程ID 2677467,但没有其他权限。

通过lsof和fuser这两个命令可以看出,当前只有一个进程占用,所以可以说i_count值等于1。

如果此时rm删除demo文件,那么i_nlink值减1。假设此时i_nlink值等于0,只要当前tail进程依旧打开着demo文件(i_count值不等于0),那么demo文件依旧存在于系统中,并没有真正的被删除,我们还可以通过一些方法来恢复demo文件。


i_count≠0文件能否恢复

通过前面的讲解,现在我们应该知道一个文件是否被删除,需要同时满足i_nlink=0和i_count=0。

在文件被删除后,i_count不等于0,文件的数据块可能不会立刻被释放或者重写,因为系统认为inode仍然在使用中,所以此时有一定概率可以成功的恢复被删除的文件。

但即使i_count不等于0,并不能保证你总能成功地恢复被删除的文件。这里有几个原因:

1、文件系统的差异:不同的文件系统(如ext4, XFS, Btrfs等)处理删除文件的方式有所不同。某些文件系统可能会更快地回收并重用inode和数据块。

2、数据覆盖:如果数据块已经被其他文件部分或完全覆盖,原始数据可能已不复存在。

3、工具和权限:恢复文件需要适当的工具和系统权限。某些恢复工具可能无法正确地解析残留的文件系统数据,特别是在文件系统受损或非常满的情况下。

4、文件的状态:即使inode未被回收,文件内容可能已经开始被操作系统覆盖,特别是在高IO操作的系统中,被删除文件的数据块很快就会被重新分配和使用。

虽然i_count 不为0增加了恢复文件的可能性,但这并不是一个绝对的保证。如果文件很重要,最好的策略是定期备份数据,并在删除任何重要文件之前仔细确认。在文件删除之后,如果需要恢复,最好尽快进行,以减少数据被覆盖的风险,并使用可靠的数据恢复工具来增加成功的机会。

i_count≠0文件恢复演示

ibdata1文件是MySQL数据库中InnoDB存储引擎的一个重要文件,网上有些文章讲到MySQL空间清理时,会告诉大家该文件过大可以删除,实际这样做法是错误的,假设如果你真的这么做了,千万不要重启,在不重启的情况下,有一定概率可以找回,但是一旦重启MySQL,ibdata1文件可能就真的没了。

演示过程如下:

1、通过wlnmp源安装MySQL8.0

我这里以RockyLinux8为例,wlnmp源使用见https://www.wlnmp.com/install
curl -fsSL "https://sh.wlnmp.com/wlnmp.sh" | bash yum install wmysql8 -y /etc/init.d/mysql start

|-------|---------------------------------------------------------------------------------------------------| | 1 2 3 | curl -fsSL "https://sh.wlnmp.com/wlnmp.sh" | bash yum install wmysql8 -y /etc/init.d/mysql start |

2、删除ibdata1
rm -f /data/mysql/ibdata1

|---|---------------------------| | 1 | rm -f /data/mysql/ibdata1 |

注意:删除后不要重启MySQL,重启后该文件的进程将被释放,文件将会真正的被删除。

3、查找i_count
lsof | grep /data/mysql/ibdata1

|---|----------------------------------| | 1 | lsof | grep /data/mysql/ibdata1 |


得到PID 44901

4、找回ibdata1
ll -h /proc/44901/fd | grep ibdata1 lrwx------ 1 root root 64 Sep 25 16:57 10 -> /data/mysql/ibdata1 (deleted) cp /proc/44901/fd/10 /data/mysql/ibdata1 chown mysql.mysql /data/mysql/ibdata1

|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 | ll -h /proc/44901/fd | grep ibdata1 lrwx------ 1 root root 64 Sep 25 16:57 10 -> /data/mysql/ibdata1 (deleted) cp /proc/44901/fd/10 /data/mysql/ibdata1 chown mysql.mysql /data/mysql/ibdata1 |

此时ibdata1文件就被找回了,可以通过这个例子进行举一反三,但是就像我们前面所讲的那样,并不能保证你总能成功地恢复被删除的文件。

总结

在Linux文件系统中,当执行rm命令删除文件时,系统并不会立即擦除文件数据,而是通过减少文件的链接数(i_nlink )和引用数(i_count )来管理文件的删除过程。只有当这两个计数都为0时,文件的数据和inode才会被真正释放。

这种设计确保了即使文件被删除,只要有进程在使用它,文件数据仍然可以被访问,直到所有引用它的进程都关闭文件为止。

赞(0)
未经允许不得转载:工具盒子 » Linux文件删除原理