重命名()原子性和NFS?
rename() atomicity and NFS?
参考:Is rename() atomic?
我问的是类似的问题,但 完全 不一样,因为我想知道的是,在什么时候依赖 rename()
的原子性是否安全使用 NFS?
这是我正在处理的场景 - 我有一个必须始终存在的 'index' 文件。
所以:
- 客户端创建一个新文件
- 客户端在 'old' 索引文件上重命名新文件。
独立客户端:
- 读取索引文件
- 指基于索引的磁盘结构。
这是假设 rename()
是原子意味着 - 总会有一个 'index' 文件(尽管它可能是一个过时的版本,因为缓存和计时)
但是我遇到的问题是这个 - 这发生在 NFS 上 - 并且正在工作 - 但我的几个 NFS 客户端 偶尔 报告 "ENOENT" -无此文件或目录。 (例如,在以 5 米为间隔发生的数百次操作中,我们每隔几天就会收到此错误)。
所以我希望有人能启发我 - 在这种情况下实际上不可能获得 'ENOENT' 吗?
我问的原因是 RFC 3530 中的这个条目:
The RENAME operation must be atomic to the client.
我想知道这是否意味着 只是 发出重命名的客户端,而不是查看目录的客户端? (我可以接受 cached/out 的日期目录结构,但此操作的要点是此文件将始终以某种形式 'present')
操作顺序(从执行写操作的客户端开始)是:
21401 14:58:11 open("fleeg.ext", O_RDWR|O_CREAT|O_EXCL, 0666) = -1 EEXIST (File exists) <0.000443>
21401 14:58:11 open("fleeg.ext", O_RDWR) = 3 <0.000547>
21401 14:58:11 fstat(3, {st_mode=S_IFREG|0600, st_size=572, ...}) = 0 <0.000012>
21401 14:58:11 fadvise64(3, 0, 572, POSIX_FADV_RANDOM) = 0 <0.000008>
21401 14:58:11 fcntl(3, F_SETLKW, {type=F_WRLCK, whence=SEEK_SET, start=1, len=1}) = 0 <0.001994>
21401 14:58:11 open("fleeg.ext.i", O_RDWR|O_CREAT, 0666) = 4 <0.000538>
21401 14:58:11 fstat(4, {st_mode=S_IFREG|0600, st_size=42, ...}) = 0 <0.000008>
21401 14:58:11 fadvise64(4, 0, 42, POSIX_FADV_RANDOM) = 0 <0.000006>
21401 14:58:11 close(4) = 0 <0.000011>
21401 14:58:11 fstat(3, {st_mode=S_IFREG|0600, st_size=572, ...}) = 0 <0.000007>
21401 14:58:11 open("fleeg.ext.i", O_RDONLY) = 4 <0.000577>
21401 14:58:11 fstat(4, {st_mode=S_IFREG|0600, st_size=42, ...}) = 0 <0.000007>
21401 14:58:11 fadvise64(4, 0, 42, POSIX_FADV_RANDOM) = 0 <0.000006>
21401 14:58:11 fstat(4, {st_mode=S_IFREG|0600, st_size=42, ...}) = 0 <0.000007>
21401 14:58:11 fstat(4, {st_mode=S_IFREG|0600, st_size=42, ...}) = 0 <0.000007>
21401 14:58:11 read(4, "PAX[=10=][=10=]O}0065\t[=10=]3RD[=10=][=10=][=10=][=10=]\r[=10=][=10=]\n"..., 42) = 42 <0.000552>
21401 14:58:11 close(4) = 0 <0.000013>
21401 14:58:11 fcntl(3, F_SETLKW, {type=F_RDLCK, whence=SEEK_SET, start=466, len=68}) = 0 <0.001418>
21401 14:58:11 pread(3, "@34I0322d61701#2034&J347-6LA53"..., 38, 534) = 38 <0.000010>
21401 14:58:11 pread(3, "@34I0322d61701#2034&J347-6LA53"..., 38, 534) = 38 <0.000010>
21401 14:58:11 pread(3, "\"113167232F6]01-x7b756261.64"..., 68, 466) = 68 <0.000010>
21401 14:58:11 pread(3, "2d47O7C]MxxM740196k1N225R23SH"..., 62, 300) = 62 <0.000011>
21401 14:58:11 pread(3, "2cv'4]7q2N2/255006037>7i`61Cy0"..., 104, 362) = 104 <0.000010>
21401 14:58:11 pwrite(3, "27423.\v7347C2P3\n~1Foh/0a5\n16"..., 127, 572) = 127 <0.000012>
21401 14:58:11 pwrite(3, "2Q5135657\WT$75[\63205[=10=]49A;2U"..., 68, 699) = 68 <0.000009>
21401 14:58:11 pwrite(3, "2Kc(!.07i3hkl~45H0.d[=10=]36\r2\v254"..., 38, 767) = 38 <0.000009>
21401 14:58:11 fsync(3) = 0 <0.001007>
21401 14:58:11 fstat(3, {st_mode=S_IFREG|0600, st_size=805, ...}) = 0 <0.000009>
21401 14:58:11 open("fleeg.ext.i.tmp", O_RDWR|O_CREAT|O_TRUNC, 0666) = 4 <0.001813>
21401 14:58:11 fstat(4, {st_mode=S_IFREG|0600, st_size=0, ...}) = 0 <0.000007>
21401 14:58:11 fadvise64(4, 0, 0, POSIX_FADV_RANDOM) = 0 <0.000007>
21401 14:58:11 write(4, "PAX[=10=][=10=]qT2565\t[=10=]5;D[=10=][=10=][=10=][=10=]\r[=10=][=10=]\n"..., 42) = 42 <0.000012>
21401 14:58:11 stat("fleeg.ext.i", {st_mode=S_IFREG|0600, st_size=42, ...}) = 0 <0.000011>
21401 14:58:11 fchmod(4, 0100600) = 0 <0.002517>
21401 14:58:11 fstat(4, {st_mode=S_IFREG|0600, st_size=42, ...}) = 0 <0.000008>
21401 14:58:11 close(4) = 0 <0.000011>
21401 14:58:11 rename("fleeg.ext.i.tmp", "fleeg.pax.i") = 0 <0.001201>
21401 14:58:11 close(3) = 0 <0.000795>
21401 14:58:11 munmap(0x7f1475cce000, 4198400) = 0 <0.000177>
21401 14:58:11 munmap(0x7f14760cf000, 4198400) = 0 <0.000173>
21401 14:58:11 futex(0x7f147cbcb908, FUTEX_WAKE_PRIVATE, 2147483647) = 0 <0.000010>
21401 14:58:11 exit_group(0) = ?
21401 14:58:11 +++ exited with 0 +++
NB - 为保持一致性,在上面重命名的路径和文件。 fleeg.ext
是数据文件,fleeg.ext.i
是索引。在此过程中 - fleeg.ext.i
文件被覆盖(由 .tmp
文件),这就是为什么人们相信该路径应该始终有一个文件(旧文件或新文件)那只是覆盖了它)。
在 reading 客户端上,PCAP 看起来像 LOOKUP
NFS 调用失败了:
124 1.375777 10.10.41.35 -> 10.10.41.9 NFS 226 LOOKUP fleeg.ext.i V3 LOOKUP Call, DH: 0x6fbbff3a/fleeg.ext.i
125 1.375951 10.10.41.9 -> 10.10.41.35 NFS 186 5347 LOOKUP 0775 Directory V3 LOOKUP Reply (Call In 124) Error: NFS3ERR_NOENT
126 1.375975 10.10.41.35 -> 10.10.41.9 NFS 226 LOOKUP fleeg.ext.i V3 LOOKUP Call, DH: 0x6fbbff3a/fleeg.ext.i
127 1.376142 10.10.41.9 -> 10.10.41.35 NFS 186 5347 LOOKUP 0775 Directory V3 LOOKUP Reply (Call In 126) Error: NFS3ERR_NOENT
Should it actually be impossible to get ENOENT
in this scenario?
很有可能。 RFC 3530 表示:
The operation is required to be atomic to the client.
这很可能意味着它必须是原子的 调用此操作的客户端,而不是所有客户端。
上面还写着:
If the target directory already contains an entry with the name... the existing target is removed before the rename occurs.
这就是 其他 客户有时会 ENOENT
的原因。
换句话说,rename
在 NFS 上不是原子的。
我认为问题不在于重命名不是原子的,而在于通过 NFS 打开文件不是原子的。
NFS 使用文件句柄;为了对文件做一些事情,客户端首先通过LOOKUP获得一个Filehandle,然后使用获得的Filehandle来执行其他请求。至少需要两个数据报,在特定情况下,它们之间的时间可以相当 "large".
我想,您遇到的情况是客户端 (client1) 执行了 LOOKUP;紧接着,LOOKUPed 文件由于重命名(由 client2)而被删除; client1 的文件句柄不再有效,因为它指的是 inode,而不是命名路径。
这一切的原因是 NFS 旨在成为无状态的。此 PDF 中的更多信息:http://pages.cs.wisc.edu/~remzi/OSTEP/dist-nfs.pdf
第 6 页和第 8 页对此行为进行了很好的解释。
我想我现在知道发生了什么事了。我在这里添加它,因为虽然其他人在到达那里非常有帮助,但问题的实际根源是:
阅读主持人:
79542 10.643148 10.0.0.52 -> 10.0.0.24 NFS 222 ACCESS allowed testfile V3 ACCESS Call, FH: 0x76a9a83d, [Check: RD MD XT XE]
79543 10.643286 10.0.0.24 -> 10.0.0.52 NFS 194 0 ACCESS allowed 0600 Regular File testfile NFS3_OK V3 ACCESS Reply (Call In 79542), [Allowed: RD MD XT XE]
79544 10.643335 10.0.0.52 -> 10.0.0.24 NFS 222 ACCESS allowed V3 ACCESS Call, FH: 0xe0e7db45, [Check: RD LU MD XT DL]
79545 10.643456 10.0.0.24 -> 10.0.0.52 NFS 194 0 ACCESS allowed 0755 Directory NFS3_OK V3 ACCESS Reply (Call In 79544), [Allowed: RD LU MD XT DL]
79546 10.643487 10.0.0.52 -> 10.0.0.24 NFS 230 LOOKUP testfile V3 LOOKUP Call, DH: 0xe0e7db45/testfile
79547 10.643632 10.0.0.24 -> 10.0.0.52 NFS 190 0 LOOKUP 0755 Directory NFS3ERR_NOENT V3 LOOKUP Reply (Call In 79546) Error: NFS3ERR_NOENT
79548 10.643662 10.0.0.52 -> 10.0.0.24 NFS 230 LOOKUP testfile V3 LOOKUP Call, DH: 0xe0e7db45/testfile
79549 10.643814 10.0.0.24 -> 10.0.0.52 NFS 190 0 LOOKUP 0755 Directory NFS3ERR_NOENT V3 LOOKUP Reply (Call In 79548) Error: NFS3ERR_NOENT
写主机:
203306 13.805489 10.0.0.6 -> 10.0.0.24 NFS 246 LOOKUP .nfs00000000d59701e500001030 V3 LOOKUP Call, DH: 0xe0e7db45/.nfs00000000d59701e500001030
203307 13.805687 10.0.0.24 -> 10.0.0.6 NFS 186 0 LOOKUP 0755 Directory NFS3ERR_NOENT V3 LOOKUP Reply (Call In 203306) Error: NFS3ERR_NOENT
203308 13.805711 10.0.0.6 -> 10.0.0.24 NFS 306 RENAME testfile,.nfs00000000d59701e500001030 V3 RENAME Call, From DH: 0xe0e7db45/testfile To DH: 0xe0e7db45/.nfs00000000d59701e500001030
203309 13.805982 10.0.0.24 -> 10.0.0.6 NFS 330 0,0 RENAME 0755,0755 Directory,Directory NFS3_OK V3 RENAME Reply (Call In 203308)
203310 13.806008 10.0.0.6 -> 10.0.0.24 NFS 294 RENAME testfile_temp,testfile V3 RENAME Call, From DH: 0xe0e7db45/testfile_temp To DH: 0xe0e7db45/testfile
203311 13.806254 10.0.0.24 -> 10.0.0.6 NFS 330 0,0 RENAME 0755,0755 Directory,Directory NFS3_OK V3 RENAME Reply (Call In 203310)
203312 13.806297 10.0.0.6 -> 10.0.0.24 NFS 246 CREATE testfile_temp V3 CREATE Call, DH: 0xe0e7db45/testfile_temp Mode: EXCLUSIVE
203313 13.806538 10.0.0.24 -> 10.0.0.6 NFS 354 0,0 CREATE 0755,0755 Regular File,Directory testfile_temp NFS3_OK V3 CREATE Reply (Call In 203312)
203314 13.806560 10.0.0.6 -> 10.0.0.24 NFS 246 SETATTR 0600 testfile_temp V3 SETATTR Call, FH: 0x4b69a46a
203315 13.806767 10.0.0.24 -> 10.0.0.6 NFS 214 0 SETATTR 0600 Regular File testfile_temp NFS3_OK V3 SETATTR Reply (Call In 203314)
如果您打开同一个文件进行读取,这仅可重现 - 所以除了一个简单的 C 写重命名循环之外:
#!/usr/bin/env perl
use strict;
use warnings;
while ( 1 ) {
open ( my $input, '<', 'testfile' ) or warn $!;
print ".";
sleep 1;
}
这似乎导致我的测试用例很快(几分钟)失败,而不是根本没有失败。它取决于打开文件句柄然后删除(或被 RENAME
覆盖)时创建的“.nfsXXX”文件。
因为 NFS 是无状态的,它必须为客户端提供一些持久性,因此它仍然可以 read/write 该文件,就像它在 open/unlink 上执行 open/unlink 一样本地文件系统。为此 - 我们得到一个双 RENAME
和一个非常短的(亚毫秒)间隔,我们的目标文件 不会 出现 LOOKUP
NFS RPC 查找。
参考:Is rename() atomic?
我问的是类似的问题,但 完全 不一样,因为我想知道的是,在什么时候依赖 rename()
的原子性是否安全使用 NFS?
这是我正在处理的场景 - 我有一个必须始终存在的 'index' 文件。
所以:
- 客户端创建一个新文件
- 客户端在 'old' 索引文件上重命名新文件。
独立客户端:
- 读取索引文件
- 指基于索引的磁盘结构。
这是假设 rename()
是原子意味着 - 总会有一个 'index' 文件(尽管它可能是一个过时的版本,因为缓存和计时)
但是我遇到的问题是这个 - 这发生在 NFS 上 - 并且正在工作 - 但我的几个 NFS 客户端 偶尔 报告 "ENOENT" -无此文件或目录。 (例如,在以 5 米为间隔发生的数百次操作中,我们每隔几天就会收到此错误)。
所以我希望有人能启发我 - 在这种情况下实际上不可能获得 'ENOENT' 吗?
我问的原因是 RFC 3530 中的这个条目:
The RENAME operation must be atomic to the client.
我想知道这是否意味着 只是 发出重命名的客户端,而不是查看目录的客户端? (我可以接受 cached/out 的日期目录结构,但此操作的要点是此文件将始终以某种形式 'present')
操作顺序(从执行写操作的客户端开始)是:
21401 14:58:11 open("fleeg.ext", O_RDWR|O_CREAT|O_EXCL, 0666) = -1 EEXIST (File exists) <0.000443>
21401 14:58:11 open("fleeg.ext", O_RDWR) = 3 <0.000547>
21401 14:58:11 fstat(3, {st_mode=S_IFREG|0600, st_size=572, ...}) = 0 <0.000012>
21401 14:58:11 fadvise64(3, 0, 572, POSIX_FADV_RANDOM) = 0 <0.000008>
21401 14:58:11 fcntl(3, F_SETLKW, {type=F_WRLCK, whence=SEEK_SET, start=1, len=1}) = 0 <0.001994>
21401 14:58:11 open("fleeg.ext.i", O_RDWR|O_CREAT, 0666) = 4 <0.000538>
21401 14:58:11 fstat(4, {st_mode=S_IFREG|0600, st_size=42, ...}) = 0 <0.000008>
21401 14:58:11 fadvise64(4, 0, 42, POSIX_FADV_RANDOM) = 0 <0.000006>
21401 14:58:11 close(4) = 0 <0.000011>
21401 14:58:11 fstat(3, {st_mode=S_IFREG|0600, st_size=572, ...}) = 0 <0.000007>
21401 14:58:11 open("fleeg.ext.i", O_RDONLY) = 4 <0.000577>
21401 14:58:11 fstat(4, {st_mode=S_IFREG|0600, st_size=42, ...}) = 0 <0.000007>
21401 14:58:11 fadvise64(4, 0, 42, POSIX_FADV_RANDOM) = 0 <0.000006>
21401 14:58:11 fstat(4, {st_mode=S_IFREG|0600, st_size=42, ...}) = 0 <0.000007>
21401 14:58:11 fstat(4, {st_mode=S_IFREG|0600, st_size=42, ...}) = 0 <0.000007>
21401 14:58:11 read(4, "PAX[=10=][=10=]O}0065\t[=10=]3RD[=10=][=10=][=10=][=10=]\r[=10=][=10=]\n"..., 42) = 42 <0.000552>
21401 14:58:11 close(4) = 0 <0.000013>
21401 14:58:11 fcntl(3, F_SETLKW, {type=F_RDLCK, whence=SEEK_SET, start=466, len=68}) = 0 <0.001418>
21401 14:58:11 pread(3, "@34I0322d61701#2034&J347-6LA53"..., 38, 534) = 38 <0.000010>
21401 14:58:11 pread(3, "@34I0322d61701#2034&J347-6LA53"..., 38, 534) = 38 <0.000010>
21401 14:58:11 pread(3, "\"113167232F6]01-x7b756261.64"..., 68, 466) = 68 <0.000010>
21401 14:58:11 pread(3, "2d47O7C]MxxM740196k1N225R23SH"..., 62, 300) = 62 <0.000011>
21401 14:58:11 pread(3, "2cv'4]7q2N2/255006037>7i`61Cy0"..., 104, 362) = 104 <0.000010>
21401 14:58:11 pwrite(3, "27423.\v7347C2P3\n~1Foh/0a5\n16"..., 127, 572) = 127 <0.000012>
21401 14:58:11 pwrite(3, "2Q5135657\WT$75[\63205[=10=]49A;2U"..., 68, 699) = 68 <0.000009>
21401 14:58:11 pwrite(3, "2Kc(!.07i3hkl~45H0.d[=10=]36\r2\v254"..., 38, 767) = 38 <0.000009>
21401 14:58:11 fsync(3) = 0 <0.001007>
21401 14:58:11 fstat(3, {st_mode=S_IFREG|0600, st_size=805, ...}) = 0 <0.000009>
21401 14:58:11 open("fleeg.ext.i.tmp", O_RDWR|O_CREAT|O_TRUNC, 0666) = 4 <0.001813>
21401 14:58:11 fstat(4, {st_mode=S_IFREG|0600, st_size=0, ...}) = 0 <0.000007>
21401 14:58:11 fadvise64(4, 0, 0, POSIX_FADV_RANDOM) = 0 <0.000007>
21401 14:58:11 write(4, "PAX[=10=][=10=]qT2565\t[=10=]5;D[=10=][=10=][=10=][=10=]\r[=10=][=10=]\n"..., 42) = 42 <0.000012>
21401 14:58:11 stat("fleeg.ext.i", {st_mode=S_IFREG|0600, st_size=42, ...}) = 0 <0.000011>
21401 14:58:11 fchmod(4, 0100600) = 0 <0.002517>
21401 14:58:11 fstat(4, {st_mode=S_IFREG|0600, st_size=42, ...}) = 0 <0.000008>
21401 14:58:11 close(4) = 0 <0.000011>
21401 14:58:11 rename("fleeg.ext.i.tmp", "fleeg.pax.i") = 0 <0.001201>
21401 14:58:11 close(3) = 0 <0.000795>
21401 14:58:11 munmap(0x7f1475cce000, 4198400) = 0 <0.000177>
21401 14:58:11 munmap(0x7f14760cf000, 4198400) = 0 <0.000173>
21401 14:58:11 futex(0x7f147cbcb908, FUTEX_WAKE_PRIVATE, 2147483647) = 0 <0.000010>
21401 14:58:11 exit_group(0) = ?
21401 14:58:11 +++ exited with 0 +++
NB - 为保持一致性,在上面重命名的路径和文件。 fleeg.ext
是数据文件,fleeg.ext.i
是索引。在此过程中 - fleeg.ext.i
文件被覆盖(由 .tmp
文件),这就是为什么人们相信该路径应该始终有一个文件(旧文件或新文件)那只是覆盖了它)。
在 reading 客户端上,PCAP 看起来像 LOOKUP
NFS 调用失败了:
124 1.375777 10.10.41.35 -> 10.10.41.9 NFS 226 LOOKUP fleeg.ext.i V3 LOOKUP Call, DH: 0x6fbbff3a/fleeg.ext.i
125 1.375951 10.10.41.9 -> 10.10.41.35 NFS 186 5347 LOOKUP 0775 Directory V3 LOOKUP Reply (Call In 124) Error: NFS3ERR_NOENT
126 1.375975 10.10.41.35 -> 10.10.41.9 NFS 226 LOOKUP fleeg.ext.i V3 LOOKUP Call, DH: 0x6fbbff3a/fleeg.ext.i
127 1.376142 10.10.41.9 -> 10.10.41.35 NFS 186 5347 LOOKUP 0775 Directory V3 LOOKUP Reply (Call In 126) Error: NFS3ERR_NOENT
Should it actually be impossible to get
ENOENT
in this scenario?
很有可能。 RFC 3530 表示:
The operation is required to be atomic to the client.
这很可能意味着它必须是原子的 调用此操作的客户端,而不是所有客户端。
上面还写着:
If the target directory already contains an entry with the name... the existing target is removed before the rename occurs.
这就是 其他 客户有时会 ENOENT
的原因。
换句话说,rename
在 NFS 上不是原子的。
我认为问题不在于重命名不是原子的,而在于通过 NFS 打开文件不是原子的。
NFS 使用文件句柄;为了对文件做一些事情,客户端首先通过LOOKUP获得一个Filehandle,然后使用获得的Filehandle来执行其他请求。至少需要两个数据报,在特定情况下,它们之间的时间可以相当 "large".
我想,您遇到的情况是客户端 (client1) 执行了 LOOKUP;紧接着,LOOKUPed 文件由于重命名(由 client2)而被删除; client1 的文件句柄不再有效,因为它指的是 inode,而不是命名路径。
这一切的原因是 NFS 旨在成为无状态的。此 PDF 中的更多信息:http://pages.cs.wisc.edu/~remzi/OSTEP/dist-nfs.pdf
第 6 页和第 8 页对此行为进行了很好的解释。
我想我现在知道发生了什么事了。我在这里添加它,因为虽然其他人在到达那里非常有帮助,但问题的实际根源是:
阅读主持人:
79542 10.643148 10.0.0.52 -> 10.0.0.24 NFS 222 ACCESS allowed testfile V3 ACCESS Call, FH: 0x76a9a83d, [Check: RD MD XT XE]
79543 10.643286 10.0.0.24 -> 10.0.0.52 NFS 194 0 ACCESS allowed 0600 Regular File testfile NFS3_OK V3 ACCESS Reply (Call In 79542), [Allowed: RD MD XT XE]
79544 10.643335 10.0.0.52 -> 10.0.0.24 NFS 222 ACCESS allowed V3 ACCESS Call, FH: 0xe0e7db45, [Check: RD LU MD XT DL]
79545 10.643456 10.0.0.24 -> 10.0.0.52 NFS 194 0 ACCESS allowed 0755 Directory NFS3_OK V3 ACCESS Reply (Call In 79544), [Allowed: RD LU MD XT DL]
79546 10.643487 10.0.0.52 -> 10.0.0.24 NFS 230 LOOKUP testfile V3 LOOKUP Call, DH: 0xe0e7db45/testfile
79547 10.643632 10.0.0.24 -> 10.0.0.52 NFS 190 0 LOOKUP 0755 Directory NFS3ERR_NOENT V3 LOOKUP Reply (Call In 79546) Error: NFS3ERR_NOENT
79548 10.643662 10.0.0.52 -> 10.0.0.24 NFS 230 LOOKUP testfile V3 LOOKUP Call, DH: 0xe0e7db45/testfile
79549 10.643814 10.0.0.24 -> 10.0.0.52 NFS 190 0 LOOKUP 0755 Directory NFS3ERR_NOENT V3 LOOKUP Reply (Call In 79548) Error: NFS3ERR_NOENT
写主机:
203306 13.805489 10.0.0.6 -> 10.0.0.24 NFS 246 LOOKUP .nfs00000000d59701e500001030 V3 LOOKUP Call, DH: 0xe0e7db45/.nfs00000000d59701e500001030
203307 13.805687 10.0.0.24 -> 10.0.0.6 NFS 186 0 LOOKUP 0755 Directory NFS3ERR_NOENT V3 LOOKUP Reply (Call In 203306) Error: NFS3ERR_NOENT
203308 13.805711 10.0.0.6 -> 10.0.0.24 NFS 306 RENAME testfile,.nfs00000000d59701e500001030 V3 RENAME Call, From DH: 0xe0e7db45/testfile To DH: 0xe0e7db45/.nfs00000000d59701e500001030
203309 13.805982 10.0.0.24 -> 10.0.0.6 NFS 330 0,0 RENAME 0755,0755 Directory,Directory NFS3_OK V3 RENAME Reply (Call In 203308)
203310 13.806008 10.0.0.6 -> 10.0.0.24 NFS 294 RENAME testfile_temp,testfile V3 RENAME Call, From DH: 0xe0e7db45/testfile_temp To DH: 0xe0e7db45/testfile
203311 13.806254 10.0.0.24 -> 10.0.0.6 NFS 330 0,0 RENAME 0755,0755 Directory,Directory NFS3_OK V3 RENAME Reply (Call In 203310)
203312 13.806297 10.0.0.6 -> 10.0.0.24 NFS 246 CREATE testfile_temp V3 CREATE Call, DH: 0xe0e7db45/testfile_temp Mode: EXCLUSIVE
203313 13.806538 10.0.0.24 -> 10.0.0.6 NFS 354 0,0 CREATE 0755,0755 Regular File,Directory testfile_temp NFS3_OK V3 CREATE Reply (Call In 203312)
203314 13.806560 10.0.0.6 -> 10.0.0.24 NFS 246 SETATTR 0600 testfile_temp V3 SETATTR Call, FH: 0x4b69a46a
203315 13.806767 10.0.0.24 -> 10.0.0.6 NFS 214 0 SETATTR 0600 Regular File testfile_temp NFS3_OK V3 SETATTR Reply (Call In 203314)
如果您打开同一个文件进行读取,这仅可重现 - 所以除了一个简单的 C 写重命名循环之外:
#!/usr/bin/env perl
use strict;
use warnings;
while ( 1 ) {
open ( my $input, '<', 'testfile' ) or warn $!;
print ".";
sleep 1;
}
这似乎导致我的测试用例很快(几分钟)失败,而不是根本没有失败。它取决于打开文件句柄然后删除(或被 RENAME
覆盖)时创建的“.nfsXXX”文件。
因为 NFS 是无状态的,它必须为客户端提供一些持久性,因此它仍然可以 read/write 该文件,就像它在 open/unlink 上执行 open/unlink 一样本地文件系统。为此 - 我们得到一个双 RENAME
和一个非常短的(亚毫秒)间隔,我们的目标文件 不会 出现 LOOKUP
NFS RPC 查找。