8

У меня есть тест приложения C++, который создает 10 000 файлов в смонтированном каталоге NFS, но недавно мой тест не прошел один раз из-за того, что один файл дважды появился с тем же именем в этом каталоге со всеми остальными 10000 файлами. Это можно увидеть в Linux Centos v4 или v5, где каталог смонтирован по NFS, но не на главном компьютере, где находится диск.

Как вообще возможно иметь два файла с одинаковым именем в одном каталоге?

[centos4x32 destination] ls -al ./testfile03373
-rwx------  1 user root 3373 Sep  3 03:23 ./testfile03373*
[centos4x32 destination] ls -al ./testfile03373*
-rwx------  1 user root 3373 Sep  3 03:23 ./testfile03373*
-rwx------  1 user root 3373 Sep  3 03:23 ./testfile03373*
[centos4x32 destination] ls -al *testfile03373
-rwx------  1 user root 3373 Sep  3 03:23 testfile03373*
-rwx------  1 user root 3373 Sep  3 03:23 testfile03373*
[centos4x32 destination] ls -alb test*file03373
-rwx------  1 user root 3373 Sep  3 03:23 testfile03373*
-rwx------  1 user root 3373 Sep  3 03:23 testfile03373*

Запуск сценария Perl, предложенного в одном из ответов ниже:

ls -la *03373* | perl -e 'while(<>){chomp();while(/(.)/g){$c=$1;if($c=~/[!-~]/){print("$c");}else{printf("\\x%.2x",ord($c));}}print("\n");}'

дает:

-rwx------\x20\x201\x20user\x20root\x203373\x20Sep\x20\x203\x2003:23\x20testfile03373*
-rwx------\x20\x201\x20user\x20root\x203373\x20Sep\x20\x203\x2003:23\x20testfile03373*

Печать со значениями inode (-i) показывает, что две копии имеют одинаковую запись inode (36733444):

[h3-centos4x32 destination] ls -alib te*stfile03373
36733444 -rwx------  1 user root 3373 Sep  3 03:23 testfile03373*
36733444 -rwx------  1 user root 3373 Sep  3 03:23 testfile03373*

Казалось бы, запись каталога как-то повреждена.

Может ли мое приложение законно создать такую ситуацию, или это ошибка в операционной системе? Могу ли я что-нибудь сделать для защиты от этого в моей программе, которая создает файлы?

Я думаю, что есть какая-то ошибка в программе монтирования NFS. Также «umount» и затем «mount» диска NFS, в котором возникла проблема, не решает ее, повторная запись остается после перемонтирования.


Обновление 1: теперь я столкнулся с этой проблемой второй раз, несколько часов спустя, и действительно странно то, что это произошло с точно таким же файлом, testfile03373 , хотя на этот раз он получил другой инод, 213352984, для дублированных файлов , Я также добавлю, что файл создается на компьютере Centos 5, где размещается диск, поэтому он создается локально и показывает правильное локально, но все остальные машины, которые его монтируют в NFS, видят двойную запись.


Обновление 2: я смонтировал диск на компьютере Centos v6 и обнаружил следующее в /var/log/messages после перечисления и просмотра двойной записи:

[root@c6x64 double3373file]# ls -laiB testfile03373* ; tail -3 /var/log/messages
36733444 -rwx------. 1 user root 3373 Sep  3 03:23 testfile03373
36733444 -rwx------. 1 user root 3373 Sep  3 03:23 testfile03373
...
Sep  4 14:59:46 c6x64 kernel: NFS: directory user/double3373file contains a readdir loop.Please contact your server vendor.  The file: testfile03373 has duplicate cookie 7675190874049154909
Sep  4 14:59:46 c6x64 kernel: NFS: directory user/double3373file contains a readdir loop.Please contact your server vendor.  The file: testfile03373 has duplicate cookie 7675190874049154909

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

3 ответа3

8

Друг помог мне отследить это и обнаружил, что это ошибка, записанная в Bugzilla 38572 для ядра Linux здесь. Ошибка предположительно исправлена в версии 3.0.0 ядра, но присутствует по крайней мере в версии 2.6.38.

Проблема заключается в том, что RPC-вызов сервера ReadDIR() возвращает неверные результаты. Это происходит из-за следующего:

Когда клиент читает каталог, он указывает максимальный размер буфера и обнуляет cookie. Если каталог слишком большой, ответ указывает, что ответ является только частичным, и обновляет cookie. Затем клиент может повторно выполнить RPC с обновленным файлом cookie, чтобы получить следующий фрагмент данных. (Данные представляют собой наборы файловых дескрипторов и имен. В случае ReadDirPlus () также есть данные stat/inode/vnode.) В документации не указано, что это ошибка в ReadDirPlus (), но, вероятно, она также присутствует.

Фактическая проблема заключается в том, что последний файл в каждом чанке (имя, дескриптор кортежа) иногда возвращается как первый файл в следующем чанке.

Плохое взаимодействие с базовыми файловыми системами. Ext4 показывает это, XFS нет.

Вот почему проблема возникает в некоторых ситуациях, но не в других, и редко возникает в небольших каталогах. Как видно из описания вопроса, файлы показывают одинаковый номер инода, а имена идентичны (не повреждены). Поскольку ядро Linux вызывает операции vnode для базовых операций, таких как open () и т.д., Базовые процедуры файловой системы решают, что произойдет. В этом случае клиент NFS3 просто переводит операцию vnode в RPC, если требуемая информация отсутствует в его кэше атрибутов. Это приводит к путанице, так как клиент считает, что сервер не может этого сделать.

6

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

Возможно, ошибка, проблема или состояние гонки в NFS.

Возможно иметь два файла с одинаковым именем, если вы напрямую редактируете структуры файловой системы с помощью шестнадцатеричного редактора. Однако я не уверен, что произойдет, если вы попытаетесь удалить или открыть файлы. Я не уверен, какие инструменты существуют в Linux для доступа к файлу по номеру инода (который не может быть дублирован), но это может сработать.

Повторяющиеся имена файлов - это то, что fsck , вероятно, поймает и попытается исправить.

Убедитесь, что ни один из файлов не имеет разный конечный пробел.

4

Существует вероятность того, что у вас есть скрытый непечатаемый символ или пробел в одном из имен файлов. Вы можете проверить с помощью опции -b для ls , например:

user@server:~/test$ ls -lab
total 8
drwxr-xr-x 2 user user 4096 Sep  3 12:20 .
drwx------ 8 user user 4096 Sep  3 12:20 ..
-rw-r--r-- 1 user user    0 Sep  3 12:19 hello
-rw-r--r-- 1 user user    0 Sep  3 12:19 hello\

Обратите внимание на \ обозначающий пробел в конце этого имени файла.

   -b, --escape
          print C-style escapes for nongraphic characters

В качестве альтернативы (хотя вышеприведенное должно работать), вы можете передать вывод через этот сценарий perl, чтобы заменить все, что не является печатным символом ASCII, его шестнадцатеричным кодом. Например, пробел становится \x20 .

while (<>) {
    chomp();
    while (/(.)/g) {
        $c = $1;
        if ($c=~/[!-~]/) {
            print("$c");
        } else {
            printf("\\x%.2x", ord($c));
        }
    }
    print("\n");
}

Использование:

ls -la | perl -e 'while(<>){chomp();while(/(.)/g){$c=$1;if($c=~/[!-~]/){print("$c");}else{printf("\\x%.2x",ord($c));}}print("\n");}'

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .