硬链接删了文件还在、空间也没释放:一个文件可以有好几个名字

Linux 管理员偶尔会撞上两个怪象:一个是 rm 删了某个文件,再按原来的路径看,文件居然还在;另一个是明明把大文件删了,df 一看磁盘空间根本没释放。这两个怪象很多时候都指向同一个机制:硬链接——一个文件同时拥有好几个名字。

一个 inode,多个名字

要理解硬链接,先分清两个概念:inode 和文件名。inode 是文件在文件系统里的"本体",存着数据块位置、权限、属主这些元信息;文件名只是目录里的一条记录,指向某个 inode。通常一个 inode 对应一个名字,但硬链接允许一个 inode 同时被多个名字指向——ln 命令不做任何复制,只是给同一个 inode 在另一个目录里添了一条新的名字记录。

用 ls -i 可以看到 inode 编号:两个路径的编号相同,它们就是同一个文件的两个名字,不是两份拷贝。这正是硬链接最实用的特性——不占额外空间的多份"引用",增量备份和去重存储方案里大量用到它。

“删除"删掉的是名字

rm 命令做的事,准确说是"删掉一个名字”,而不是"删掉文件"。inode 内部维护着一个链接计数:几个名字指向它,计数就是几。rm 一次,计数减一;减到零,没有任何名字指向这个 inode 了,文件系统才真正回收它的数据块——文件这才算真消失。

前面两个怪象由此可解。

“删了还在”:你删的只是几个名字中的一个,还有别的名字(甚至原路径本身)指向这个 inode,文件当然还在——你以为删的是文件本体,其实删的是它的别名之一。确认方法很简单:ls -i 对比两个路径的 inode 编号,或 stat 看链接计数(Links 大于 1,说明有多个名字)。

“删了空间没释放”:删的确实是一个名字,但如果还有别的名字挂着——比如某个备份脚本建的链接、某个目录里的副本入口——链接计数没归零,空间就不会释放。还有一种相邻情况:文件的名字全删了,但仍有进程打开着它,数据块照样保留,直到进程退出。这两种场景是"删了不瘦"的两大来源,排查时用 lsof 看看有没有进程还攥着已删除的文件。

怎么确认和处置

想确认两个路径是不是同一个文件:ls -i 对比编号,编号相同即同一本体。想真正释放空间:把指向它的所有名字都删掉,再确认没有进程占用。想保留本体又删掉某个入口:直接删那个名字即可,其他名字的访问完全不受影响——这正是共享数据文件、备份快照类设计的用法。

机制账记住了,怪象就不怪了

“名字与本体分离"是 Unix 文件系统的地基之一。看懂"删名字不等于删文件、计数归零才释放"这条规则,文件系统里一大类灵异现象——删了还在、删了不瘦、du 和 df 对不上——都会变成可以推理的正常行为。du 统计的是文件本体、df 看的是块分配,中间夹着已删除但仍被进程占用的文件时,两个数字出现缺口,答案往往就在 lsof 的输出里。贵州诚鑫致达科技在存储与备份系统交付中经常遇到依赖这套机制的设计——理解机制,排障时才不会误判成"磁盘坏了”。