当进程尝试读取其他进程已经删除的文件时出现“过时的文件句柄”错误。

15

我正在编写应力测试套件,以测试通过NFS进行分布式文件系统的性能。

在某些情况下,当某个进程删除文件时,同时另一个进程试图从该文件中读取数据时,会出现“过期文件句柄”错误(116)。

这种类型的错误在这种竞争条件下是否是预期且可接受的?

测试工作如下:

  1. 启动 x 个客户端机器
  2. 每个客户端机器运行 y 个进程
  3. 每个进程可以执行任何文件操作,例如 stat/read/delete/open
  4. 上述文件操作是标准的Python方法 - os.stat/read/os.remove/open
  5. 所有文件都是空的 0 字节数据

文件存在,因为成功的 stat 操作显示:

controller_debug.log.2:2016-10-26 15:02:30,156;INFO - [LG-E27A-LNX:0xa]: finished 640522b4d94c453ea545cb86568320ca, result: success | stat | /JUyw481MfvsBHOm1KQu7sHRB6ffAXKjwIATlsXmOgWh8XKQaIrPbxLgAo7sucdAM/o6V266xE8bTaUGzk8YDMfDAJp0YIfbT4fIK1oZ2R20tRX3xFCvjISj7WuMEwEV41 | data: {} | 2016/10/26 15:02:30.156

客户端 CLIENT-A 上的进程 0x1 成功删除了该文件:

controller_debug.log.2:2016-10-26 15:02:30,164;INFO - [CLIENT-A:0x1]: finished 5f5dfe6a06de495f851745a78857eec1, result: success | delete |

3毫秒后,客户端CLIENT-B上的进程0xb由于"Stale file handle"而失败了"read"操作。

controller_debug.log.2:2016-10-26 15:02:30,164;INFO - [CLIENT-B:0xb]:完成e84e2064ead042099310af1bd44821c0,结果:失败|读取|/mnt/DIRSPLIT-node0.b27-1/JUyw481MfvsBHOm1KQu7sHRB6ffAXKjwIATlsXmOgWh8XKQaIrPbxLgAo7sucdAM/o6V266xE8bTaUGzk8YDMfDAJp0YIfbT4fIK1oZ2R20tRX3xFCvjISj7WuMEwEV41 | [errno:116] | Stale file handle | 142 | data: {} | 2016/10/26 15:02:30.160 controller_debug.log.2:2016-10-26 15:02:30,164;ERROR - 因为文件句柄过期,文件JUyw481MfvsBHOm1KQu7sHRB6ffAXKjwIATlsXmOgWh8XKQaIrPbxLgAo7sucdAM/o6V266xE8bTaUGzk8YDMfDAJp0YIfbT4fIK1oZ2R20tRX3xFCvjISj7WuMEwEV41上的操作读取意外失败。

感谢


2
是的,在这种情况下,这是一个可以接受的错误代码(请参见https://access.redhat.com/solutions/29626,条件2),但这可能不是唯一可能的响应。您必须阅读规格和源代码才能确定。您能否澄清什么,如果有什么,表明这可能不是适当的响应? - Sage Mitchell
@JakeMitchell 谢谢你提供的链接,Jake。我确实知道 ESTALE 可以用于目录,但是我找不到关于文件的 ESTALE 的任何信息。由于我正在测试开发中的文件系统,所以我不能相信它如何处理 nfs 错误。你有其他的链接和规范资料吗? - Samuel
你使用的是哪个版本的Python?你如何启动测试进程?这可能与fork的行为有关,因为文件描述符依赖于POSIX,不允许使用分叉进程。 - Thomas Moreau
@ThomasMoreau ESTALE错误是在通过NFS对文件进行操作时引起的错误,而并非在进程本身中。 - Samuel
@Samuel 是的,但是文件描述符用于进程操作和 NFS 操作。如果一个 fd 被关闭,无论谁试图访问它,都应该失败。 - Thomas Moreau
@ThomasMoreau,你是在说和这个链接https://access.redhat.com/solutions/29626里解释的一样的事情,对吗? - Samuel
1个回答

14

这是完全可以预料的。NFS规范明确规定在对象(无论是文件还是目录)被删除后,对文件句柄的使用情况。 第4节 明确阐述了这一点。例如:

当文件系统对象被删除时,持久的文件句柄将变为陈旧或无效。当服务器接收到引用已删除对象的持久文件句柄时,它必须返回错误 NFS4ERR_STALE。

这是一个常见的问题,在NFS FAQ 的A.10节中甚至有专门的条目描述了它,其中说ESTALE错误的一个常见原因是:

文件句柄指向已删除的文件。在服务器上删除文件后,客户端直到尝试使用他们从先前的LOOKUP缓存的文件句柄访问该文件时才发现。使用rsync或mv替换正在其他客户端上使用的文件是导致ESTALE错误的常见场景。

预期的解决方案是,客户端应用程序必须关闭并重新打开文件以查看发生了什么。或者,如FAQ所述:

...要从ESTALE错误中恢复,应用程序必须关闭发生错误的文件或目录,并重新打开它,以便NFS客户端可以再次解析路径名并检索新的文件句柄。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接