Как я могу иметь два файла с одинаковым именем в каталоге при монтировании с NFS?

8

У меня есть тест приложения C ++, который создает 10000 файлов в смонтированном каталоге 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приводит к появлению двойной записи, но это происходит только в две директории, где эта двойная запись была замечена.

WilliamKF
источник
AFAIK, невозможно для двух файлов с одинаковым именем и расширением сосуществовать в одном каталоге в любой файловой системе. Вы можете использовать какой-то механизм исключения в своей программе для предотвращения сбоев, кроме этого ...
Doktoro Reichard
Какую файловую систему вы используете?
Доктор Рейхард
Они точно такие же? Например, нет начальных или конечных пробелов? нет UTF-16 символов, ...
Хенн
Какие еще тесты я могу выполнить, чтобы подтвердить, что они точно такие же?
WilliamKF
Похоже, вы узнали, как выполнить конечную проверку жизненно важной ОС.
Fiasco Labs

Ответы:

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, если требуемая информация отсутствует в его кэше атрибутов. Это приводит к путанице, так как клиент считает, что сервер не может этого сделать.

WilliamKF
источник
Это происходит и со мной, с ядром 3.18.17-13.el6.x86_64 (CentOS 6). Я почти уверен, что это ошибка базовой системы NFS NAS-сервера QNAP TS-212, на которой смонтирован каталог, может кто-нибудь подтвердит?
Годзилланте
6

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

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

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

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

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

LawrenceC
источник
Я собирался предположить, что объем записи в файловой системе в конечном итоге что-то сломал и позволил существование двух идентичных файлов.
Доктор Рейхард,
Бег не fsckнашел проблем. Перезагружал и хост и клиентские машины, проблема все еще показывает.
WilliamKF
Я должен был быть более ясным - fsckвероятно, будет работать только на локальной файловой системе, а не на смонтированной NFS. Возможно, вам нужно обновить / исправить ваши пакеты nfs и, возможно, ваше ядро. Как упоминает @somequixotic, ваш CentOS устарел, и проблемы, с которыми вы столкнулись, могли быть решены в будущих обновлениях.
LawrenceC
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");}'
боб
источник