2016-12-28 26 views
7

Со ссылкой на: Is rename() atomic?переименовать() атомарность и NFS?

я что-то подобное с просьбой, но не совсем то же самое, потому что я хочу знать, это безопасно полагаться на atomicty из rename() при использовании NFS?

Вот сценарий, с которым я имею дело - у меня есть файл индекса, который должен всегда присутствовать.

Итак:

  • Клиент создает новый файл
  • Client переименовывает новый файл через 'старый' файл индекса.

Отдельный клиент:

  • Читает индексный файл
  • относится к структуре на диске на основе индекса.

Это делает предположение о том, что rename() будучи атомные средства - всегда будет файл «индекс» (хотя, это может быть устаревшей версия, так как кэширование и синхронизация)

Однако проблемы Я нахожусь в этом, что это происходит на NFS - и работает, но некоторые из моих клиентов NFS: иногда сообщение «ENOENT» - нет такого файла или каталога. (например, в сотнях операций, выполняемых с интервалом 5 м, мы получаем эту ошибку каждые пару дней).

Так что я надеюсь, сможет ли кто-нибудь просветить меня - неужели на самом деле невозможно получить «ENOENT» в этом сценарии?

Причина, почему я спрашиваю, эта запись в RFC 3530:

Операция ПЕРЕИМЕНОВАТЬ должна быть атомарной клиенту.

мне интересно, если это означает, что только клиента, выдавшее переименование, а не просмотр клиента каталога? (Я в порядке с структурой кэшированной/устаревшей каталогов, но суть этой операции в том, что этот файл всегда будет «присутствовать» в той или иной форме)

Последовательность операций (от клиента, выполняющего операцию записи):

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, "\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, F_SETLKW, {type=F_RDLCK, whence=SEEK_SET, start=466, len=68}) = 0 <0.001418> 
21401 14:58:11 pread(3, "\[email protected]\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, "\[email protected]\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"..., 68, 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"..., 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, "\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", {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), поэтому вера в то, что на этом пути всегда должен быть файл (либо старый, либо новый, который просто перезаписывается).

На чтение клиента 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 
+2

Вы закрываете файл перед переименованием? Важно, чтобы он был закрыт первым. –

+0

Хмм, глядя на «strace», похоже, это не так - «новый» файл создается вызовом 'open', а затем' rename'ed while open. Я проведу еще один след, чтобы подтвердить. – Sobrique

+0

@MaximEgorushkin - повторили трассировку и добавили его к вопросу - файл был закрыт до переименования. – Sobrique

ответ

0

Думаю, теперь у меня есть ответ о том, что происходит.Я добавляю его здесь, потому что в то время как другие были очень полезны в получении там, фактический корень этой проблемы заключается в следующем:

Чтение хост:

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) 

Это только воспроизводимым, если открыть тот же файл для чтения - поэтому в дополнение к тривиальному с записью переименовать цикл:

#!/usr/bin/env perl 

use strict; 
use warnings; 

while (1) { 
    open (my $input, '<', 'testfile') or warn $!; 
    print "."; 
    sleep 1; 
} 

Это, по-видимому, приводит к тому, что мой тестовый чехол завершится быстро (минут), а не вообще. Это файл «.nfsXXX», который создается, когда дескриптор файла открыт, а затем удален (или перезаписан RENAME).

Поскольку NFS не имеет гражданства, он должен иметь некоторые постоянные для клиента, поэтому он все равно может читать и записывать этот файл так же, как если бы он выполнял открытую/развязку в локальной файловой системе. И для этого - мы получаем двойной RENAME и очень короткий интервал (субмиллисекунда), в котором файл, на который мы нацеливаем , не является для LOOKUP NFS RPC для поиска.

+0

Есть что-то странное, или я чего-то не хватает. NFS File Handle должен «настойчиво» ссылаться на один и тот же объект (более или менее, «inode»). Первое переименование в вашей трассе - «0xe0e7db45/testfile To DH: 0xe0e7db45/.nfs000», где я вижу, что Filehandle остается неизменным. После этого первого переименования дескриптор по-прежнему относится к одному и тому же объекту, поэтому я не понимаю, почему потребуются два переименования вместо простого, простого, атомного переименования. – linuxfan

+0

Это происходит только в том случае, если на хосте «writer» есть открытая дескриптор чтения. Переименование является атомарным клиенту _that_, но поскольку происходит два переименования, клиент _remote_ видит директорию, которая очень коротко - пустая между двумя событиями. – Sobrique

+0

Я все еще думаю, что двойное переименование ошибочно. Даже с открытым файлом, продолжающим работать, должно работать одно переименование, которое действительно сохраняет Filehandle. Я все еще что-то упускаю. – linuxfan

3

Если это на самом деле невозможно получить ENOENT в этом сценарии?

Это вполне возможно. RFC 3530 говорит:

Операция должна быть атомарной для клиента.

Это скорее всего означает, что он должен быть атомарным в клиент вызова этой операции, не все клиенты.

И далее он говорит:

Если целевой каталог уже содержит запись с именем ... существующая цель удаляется прежде, чем произойдет переименование.

Это причина другие клиенты получают ENOENT иногда.

Иными словами, rename не является атомарным на NFS.

5

Я думаю, что проблема не в том, что RENAME не является атомарным, а в том, что ОТКРЫТИЕ файла через NFS не является атомарным.

NFS использует дескрипторы файлов; для того, чтобы что-то сделать в файл, клиент сначала получает Filehandle через LOOKUP, тогда полученный File Handle используется для выполнения других запросов. Требуется не менее двух дейтаграмм, и время между ними может, в конкретных обстоятельствах, быть довольно «большим».

Что происходит с вами, я полагаю, что клиент (client1) выполняет LOOKUP; сразу после этого файл LOOKUPed стирается в результате RENAME (по клиенту2); клиент1 файла Filehandle уже недействителен, поскольку он относится к inode, а не к именованному пути.

Причина в том, что NFS стремится быть апатридом. Дополнительная информация в этом PDF-формате: http://pages.cs.wisc.edu/~remzi/OSTEP/dist-nfs.pdf

На страницах 6 и 8 это поведение хорошо объяснено.

 Смежные вопросы

  • Нет связанных вопросов^_^