Windows Subsystem for Linux (WSL)のreaddirはバグっている?


Windows Subsystem for Linux (WSL)のファイルシステムのベンチマークをBonnie++で取ろうとしたら、以下のようなエラーで中断してしまった。/homeの下でも/mnt/cの下でも同じ結果になる。

$ bonnie++
Writing a byte at a time...done
Writing intelligently...done
Rewriting...done
Reading a byte at a time...done
Reading intelligently...done
start 'em...done...done...done...done...done...
Create files in sequential order...done.
Stat files in sequential order...done.
Delete files in sequential order...Bonnie: drastic I/O error (rmdir): Directory not empty
Cleaning up test directory after error.

テストディレクトリを見ると、確かにファイルがたくさん残っている。Bonnie++はファイルのメタデータ操作の性能を測るために、16384(16*1024)個のファイルを作成するが、その半分くらいを消しそこねている。ファイルが何個残るかは試行によって微妙に変わる。

原因を調べてみたところ、Bonnie++がファイルを全部削除するときのロジックがbuggyであるというコメントをNFS-Ganeshaのissueで見つけた。Bonnie++は以下のロジックでファイルをすべて削除しているが、これがまずいとのこと。

opendir()
while (readdir())
    unlink();
closedir()

さらに調べると、macOSのHFSでも同じ問題が生じることがわかった。この記事では、ディレクトリに変更が加えられたあとにreaddirが何を返すかは未定義なので、このロジックではすべてのファイルを削除できないとしている。WSLのreaddirも同様に、ディレクトリに変更が加えられた場合に、すべてのエントリを読み出せるとは限らない実装になっているのだろう。

SUSv4のreaddirの仕様は、opendirのあとにファイルを追加や削除した場合、そのファイルをreaddirが返すかどうかを未定義としている。readdirの返値が未定義になるわけではない。追加・削除されたエントリを除くか含めるかは別として、readdirはすべてのエントリを読み出せなければならない。このロジックでファイルを全部削除できないreaddirの実装は、バグってるのではないだろうか。