linux – rename()原子性和NFS?

参考: Is rename() atomic?

我问的是类似的东西,但不完全相同,因为我想知道的是在使用NFS时依赖于rename()的原子性是否安全?

这是我正在处理的一个场景 – 我有一个必须始终存在的’索引’文件.

所以:

>客户端创建一个新文件
>客户端通过“旧”索引文件重命名新文件.

独立客户:

>读取索引文件
>指基于索引的磁盘结构.

这假设rename()是原子意味着 – 总会有一个’索引’文件(尽管它可能是一个过时的版本,因为缓存和时间)

但是我遇到的问题是 – 这发生在NFS上 – 并且正在工作 – 但我的几个NFS客户端偶尔会报告“ENOENT” – 没有这样的文件或目录. (例如,在每隔5米发生的数百次操作中,我们每隔几天就会收到此错误).

所以我希望是否有人能够启发我 – 在这种情况下,实际上是否真的不可能获得’ENOENT’?

我问的原因是RFC 3530这个条目:

The RENAME operation must be atomic to the client.

我想知道这是否只是发出重命名的客户端,而不是查看目录的客户端? (我对缓存/过时的目录结构没问题,但是这个操作的重点是这个文件总是以某种形式“存在”)

操作顺序(来自执行写操作的客户端)是:

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,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_size=42,...}) = 0 <0.000008>
21401 14:58:11 fadvise64(4,42,POSIX_FADV_RANDOM) = 0 <0.000006>
21401 14:58:11 close(4)                 = 0 <0.000011>
21401 14:58:11 fstat(3,...}) = 0 <0.000007>
21401 14:58:11 open("fleeg.ext.i",O_RDONLY) = 4 <0.000577>
21401 14:58:11 fstat(4,...}) = 0 <0.000007>
21401 14:58:11 fadvise64(4,POSIX_FADV_RANDOM) = 0 <0.000006>
21401 14:58:11 fstat(4,...}) = 0 <0.000007>
21401 14:58:11 fstat(4,...}) = 0 <0.000007>
21401 14:58:11 read(4,"\3PAX\1\0\0O}\270\370\206\20\225\24\22\t\2\0\203RD\0\0\0\0\17\r\0\2\0\n"...,42) = 42 <0.000552>
21401 14:58:11 close(4)                 = 0 <0.000013>
21401 14:58:11 fcntl(3,{type=F_RDLCK,start=466,len=68}) = 0 <0.001418>
21401 14:58:11 pread(3,"\21@\203\244I\240\333\272\252d\316\261\3770\361#\222\200\313\224&J\253\5\354\217-\256LA\345\253"...,38,534) = 38 <0.000010>
21401 14:58:11 pread(3,"\21\"\30\361\241\223\271\256\317\302\363\262F\276]\260\241-x\227b\377\205\356\252\236\211\37\17.\216\364"...,68,466) = 68 <0.000010>
21401 14:58:11 pread(3,"\21\302d\344\327O\207C]M\10xxM\377\2340\0319\206k\201N\372\332\265R\242\313S\24H"...,62,300) = 62 <0.000011>
21401 14:58:11 pread(3,"\21\362cv'\37\204]\377q\362N\302/\212\255\255\370\200\236\350\2237>7i`\346\271Cy\370"...,104,362) = 104 <0.000010>
21401 14:58:11 pwrite(3,"\21\302\3174\252\273.\17\v\247\313\324\267C\222P\303\n~\341F\24oh/\300a\315\n\321\31\256"...,127,572) = 127 <0.000012>
21401 14:58:11 pwrite(3,"\21\212Q\325\371\223\235\256\245\247\\WT$\4\227\375[\\\3263\222\0305\0\34\2049A;2U"...,699) = 68 <0.000009>
21401 14:58:11 pwrite(3,"\21\262\20Kc(!.\350\367i\253hkl~\254\335H\250.d\0036\r\342\v\242\7\255\214\31"...,767) = 38 <0.000009>
21401 14:58:11 fsync(3)                 = 0 <0.001007>
21401 14:58:11 fstat(3,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_size=0,POSIX_FADV_RANDOM) = 0 <0.000007>
21401 14:58:11 write(4,"\3PAX\1\0\0qT2\225\226\20\225\24\22\t\2\0\205;D\0\0\0\0\17\r\0\2\0\n"...,42) = 42 <0.000012>
21401 14:58:11 stat("fleeg.ext.i",...}) = 0 <0.000011>
21401 14:58:11 fchmod(4,0100600)       = 0 <0.002517>
21401 14:58:11 fstat(4,...}) = 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 +++

注意 – 上面重命名的路径和文件是为了保持一致性. fleeg.ext是数据文件,fleeg.ext.i是索引.在此过程中 – fleeg.ext.i文件被覆盖(由.tmp文件),这就是为什么相信该路径上应该始终存在一个文件(旧文件或刚被覆盖的新文件)它).

在阅读客户端上,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

解决方法

我认为问题不在于RENAME不是原子的,而是因为通过NFS打开文件不是原子的.

NFS使用Filehandles;为了对文件做某事,客户端首先通过LOOKUP获取Filehandle,然后使用获得的Filehandle来执行其他请求.至少需要两个数据报,并且在特定情况下,它们之间的时间可能非常“大”.

我想,你发生的事情是客户端(client1)执行LOOKUP;之后,LOOKUP文件被RENAME(by client2)删除; Filehandle client1不再有效,因为它引用的是inode,而不是指向命名的路径.

所有这一切的原因是NFS旨在成为无国籍人.更多信息在此PDF:http://pages.cs.wisc.edu/~remzi/OSTEP/dist-nfs.pdf

在第6和第8页中,这种行为得到了很好的解释.

相关文章

linux常用进程通信方式包括管道(pipe)、有名管道(FIFO)、...
Linux性能观测工具按类别可分为系统级别和进程级别,系统级别...
本文详细介绍了curl命令基础和高级用法,包括跳过https的证书...
本文包含作者工作中常用到的一些命令,用于诊断网络、磁盘占满...
linux的平均负载表示运行态和就绪态及不可中断状态(正在io)的...
CPU上下文频繁切换会导致系统性能下降,切换分为进程切换、线...