Contents

Linux中的陈旧文件处理

1. 概述

在本教程中,我们将处理Linux 中的陈旧文件 句柄。在处理文件(尤其是共享文件)时,它们是相对常见的情况。为了解决陈旧的文件句柄,首先,我们必须澄清文件的一般概念。

本教程中的代码已经在 Debian 10.10 (Buster) 和 GNU Bash 5.0.3 上进行了测试。它是 POSIX 兼容的,应该可以在任何这样的环境中工作。

2. 索引节点

**索引节点 ( inode ) 是文件系统元素,它描述了其他类似的元素。**本质上,必须存在 inode 才能使文件或目录等对象也存在。本文使用术语文件来表示任何具有与其关联的 inode 的文件系统对象。

我们使用stat (统计)命令来显示特定文件的详细信息:

user@itcodingman:~$ stat filename
File: filename
Size: 583 Blocks: 8 IO Block: 4096 regular file
Device: 810h/2064d Inode: 666 Links: 1
[...]

文件*filename *引用 inode 编号 666(最后一行)。

但是谁引用了该文件?

3.文件句柄

文件句柄(文件描述符)只是整数。进程使用它们来索引打开文件的系统表(文件描述)。与文件系统元素不同,文件句柄不驻留在文件系统上或随文件系统更新。相反,它们被进程用来保存其打开文件的寄存器。

我们通过在proc(进程信息) 伪文件系统上应用带有*-l*(长列表格式)标志的ls (list)命令来列出这个寄存器:

user@itcodingman:~$ ls -l /proc/1296/fd
total 0
lrwx------ 1 user user 64 Jul 1 10:49 0 -> /dev/pts/1
lrwx------ 1 user user 64 Jul 1 10:49 1 -> /dev/pts/1
lrwx------ 1 user user 64 Jul 1 10:49 2 -> /dev/pts/1
lrwx------ 1 user user 64 Jul 1 10:50 3 -> /home/user/filename

输出显示文件描述符 3 指向文件*/home/user/filename*。在该描述符上使用带有*-L*(取消引用链接)标志的stat会显示文件的 inode 编号:

user@itcodingman:~$ stat -L /proc/1296/fd/3
File: /proc/1296/fd/3
Size: 583 Blocks: 8 IO Block: 4096 regular file
Device: 810h/2064d Inode: 666 Links: 1
[...]

文件引用 inode。通过文件句柄处理参考文件。那么,文件句柄如何变得陈旧?

4. 过时的文件句柄

文件可能以许多名称存在,指向同一个 inode。但是,一旦一个 inode 没有被引用或硬链接 ,它就会被释放以供将来使用。

**此时,相关文件句柄继续指向一个不存在或不匹配(不同 inode 编号)的文件。它们现在是陈旧的文件句柄。**即使我们重新创建有问题的文件,内核也几乎不可能重用相同的 inode 编号。

产生的错误以不同的方式出现,但标准代码是ESTALE 116,带有消息Stale file handle

user@itcodingman:~$ cd /mounted
-bash: cd: /mounted: Stale file handle

如果该进程不处理错误,它可能只是不输出任何内容或声明丢失的文件。

这种情况通常有一个标准修复。

5. 解决陈旧的文件句柄

当进程重新打开文件时,会刷新陈旧的文件句柄。这样做会使用文件的新 inode 编号(如果存在)更新文件描述。在大多数情况下,进程必须在内部执行此操作。否则,我们可能不得不重新启动它。

这个解决方案虽然简单,但对于已挂载的共享目录来说并非易事。

不刷新陈旧文件句柄的最常见情况是NFS 或 CIFS 挂载的共享目录。此类协议的实现通常缺乏标准化的缓存和文件句柄同步。这种情况通常需要重新挂载(可能使用不同的选项),甚至需要重新启动服务器进程。这两种操作都可能导致停机。