NFSマウントされたディレクトリに10,000個のファイルを作成するC++アプリケーションテストがありますが、最近、1つのファイルが他のすべての10,000ファイルと同じ名前でそのディレクトリに2回表示されたため、テストが1回失敗しました。これは、ディレクトリがNFSマウントされているLinux Centos v4またはv5で見られますが、ディスクが存在するホストマシンでは見られません。
同じディレクトリに同じ名前の2つのファイルを置くことさえ可能ですか?
[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*
以下の回答の1つで提案されている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*
Iノード(-i)値を使用して印刷すると、2つのコピーに同じiノードエントリ(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マウントソフトウェアになんらかのバグがあると思います。また、問題のあるNFSドライブの「umount」と「mount」の順に解決されないため、再マウント後も繰り返しエントリが残ります。
更新1:数時間後、この問題が2回発生しました。本当に奇妙なことに、まったく同じファイルtestfile03373
で発生しましたが、今回は、2倍のファイル用に別のiノード213352984を使用します。また、ファイルはディスクがホストされているCentos 5マシンで作成されているため、ローカルで作成され、ローカルで正しく表示されますが、NFSがマウントする他のすべてのマシンではエントリが2倍になっています。
更新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
という名前の新しいファイルに触れるだけで複式簿記が表示されますが、これは、この二重エントリが確認された2つのディレクトリでのみ発生します。
友人が私がこれを追跡するのを手伝ってくれて、これが LinuxカーネルのBugzilla 38572はこちら に記録されているバグであることがわかりました。このバグはカーネルのバージョン3.0.0で修正されていると思われますが、少なくともバージョン2.6.38には存在します。
問題は、サーバーのReadDIR()RPC呼び出しが誤った結果を返すことです。これは、次の理由で発生します。
クライアントがディレクトリを読み取るとき、最大バッファサイズを指定し、Cookieをゼロにします。ディレクトリが大きすぎる場合、応答は応答が部分的であることを示し、Cookieを更新します。次に、クライアントは更新されたCookieを使用してRPCを再実行し、次のデータチャンクを取得できます。 (データはファイルハンドルと名前のセットです。ReadDirPlus()の場合、stat/inode/vnodeデータもあります。)ドキュメントには、これがReadDirPlus()のバグであることが示されていませんが、おそらく存在します。同様に。
実際の問題は、各チャンク(名前、ハンドルタプル)の最後のファイルが時々次のチャンクの最初のファイルとして返されることです。
基盤となるファイルシステムとの相互作用が悪い。 Ext4はこれを示しますが、XFSは示しません。
これが、問題が一部の状況では発生するが他の状況では発生せず、小さなディレクトリではめったに発生しない理由です。質問の説明に見られるように、ファイルは同じiノード番号を示し、名前は同じです(破損していません)。 Linuxカーネルはopen()などの基礎となる操作のためにvnode操作を呼び出すため、ファイルシステムの基礎となるルーチンが何が起こるかを決定します。この場合、必要な情報が属性キャッシュにない場合、NFS3クライアントはvnode操作をRPCに変換するだけです。クライアントはサーバーがこれを実行できないと信じているため、これは混乱を招きます。
ディスクはNFSマウントされたディスクです。ドライブを公開しているホストコンピューターに移動すると、ファイルは1回だけリストされます。
おそらく、NFSのバグ、問題、または競合状態です。
16進エディタを使用してファイルシステム構造を直接編集すると、同じ名前の2つのファイルを持つことができます。ただし、ファイルを削除または開こうとするとどうなるかわかりません。 Linuxにiノード番号(複製できない)でファイルにアクセスするためのツールが存在するかどうかはわかりませんが、機能する可能性があります。
重複するファイル名は、fsck
がキャッチして修正しようとする可能性が高いものです。
ただし、どのファイルにも異なる末尾のスペースがないことを確認してください。
ファイル名の1つに、印刷できない文字または空白が隠されている可能性があります。 ls
に-b
オプションを指定することで確認できます。例:
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文字ではないものを16進コードに置き換えることができます。たとえば、スペース\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");}'