GNU Tarでバグを見つけた方法

投稿者: Chris Siebenmann 、トロント大学Unixシステム管理者



時々、私の作品に奇妙なことが起こり、それが私を考えさせます。 どの結論が続くかがすぐに明確ではない場合でも。 先日、GNU Tarでバグを見つけたと述べましたが、これがどのように起こったかという話はそのようなケースの1つです。



バックアップファイルサーバーには、AmandaとGNU Tarを使用します。 時間が経つにつれて、 /var/mail



ディレクトリを使用してファイルシステムをバックアップするときにtarがクレイジーになり、大量の出力を生成するという、まれな問題が発生することがありました。 通常、このプロセスは無限になり、ダンプを強制終了しなければなりませんでした。 それ以外の場合、それはまだ終了し、テラバイトのデータが完全に圧縮されているように見えました。 再びそのような巨大なtarファイルに出会ったとき、私はそれをチェックしました-そして、 tar -t



テストチームが本当に嫌いな部分的にゼロバイトで構成されていることがわかりました。



(このため、メールボックスの人々にヌルバイトが自然に現れるのではないかと思っていました。 テキストファイルでヌルバイト見つけるのはそれほど簡単でなく、そうです。



最近、Ubuntu 18.04でファイルシステムを/var/mail



から新しいLinuxファイルサーバーに移動したため、OmniOSマシンよりも新しい標準バージョンのGNU Tarに切り替えました。 これで問題が解決することを期待していましたが、ほぼすぐに同じ事件が起こりました。 今回、GNU TarはUbuntuマシンで動作し、利用可能なすべてのデバッグツールに精通しているので、実行中のtar



プロセスをチェックしました。 テストでは、 tar



が0バイトを返すread()



無限ストリームを生成することが示されました。



 read(6, "", 512) = 0 read(6, "", 512) = 0 [...] read(6, "", 512) = 0 write(1, "\0\0\0\0\0"..., 10240) = 10240 read(6, "", 512) = 0 [...]
      
      





lsof



は、ファイル記述子6が他の誰かのメールボックスであると言いました。



apt-get source tar



を使用して、ソースコードをダウンロードし、ファイルの完了をチェックしないread()



システムコールを探し始めました。 間接的なアドレス指定のいくつかのレベルを調べたところ、このようなチェックが省略されているように見える明らかな場所、つまりsparse.csファイルのsparse_dump_region



関数が見つかりました 。 そして、私は何かを思い出しました。



数か月前、 AlpineでNFSの問題が発生しました 。 このバグに取り組んでいる間、私はAlpineプロセスをトレースし、とりわけftruncate()



を使用してメールボックスのサイズを変更することに気付きました。 時々それらを拡張し、一杯になるまで一時的にファイルのスパースセクションを作成し、場合によっては圧縮します。 これは現在の状況と一致しているように見えました:疎な領域が接続されており、 ftruncate()



を使用してファイルサイズを小さくすると、tarが予期せずファイルの完了を検出する状況が発生します。



(これは、tarが時々復元される理由を説明します;新しいメールが突然メールボックスに到着した場合、期待されるサイズに戻り、tarはもはや予期しないファイル終了に遭遇しません)。



Ubuntuのデバッグシンボルと受け取ったtarパッケージのソースコードでGDBを少し台無しにし、エラーを再現することができましたが、元の理論とは少し異なりました。 sparse_dump_region



はファイルのスパース領域をリセットせず、(もちろん)非スパース領域をリセットし、 --sparse



引数でtarを実行するとすべてのファイル(スパースまたは非スパース)に使用されることが--sparse



。 したがって、実際のエラーは、-- --sparse



引数を使用してGNU Tarを実行し、ファイルが読み込まれているときに圧縮されると、tarは予想よりも早く受信したファイルの終わりを正しく処理できないこと
です。 ファイルが再び大きくなると、tarが復元されます。



(ファイルが最後でのみ疎であり、この場所でのみ圧縮される場合を除きます。この場合、すべてが正常です。)



何年も前にOmniOSファイルサーバーでチェックできると思っていました。 プログラムおよびlsof



アナログのシステムコールをトレースする方法がありますlsof



バージョンのソースコードを見つけて調べ、OmniOSデバッガーで実行できます(GDBがインストールされていないようですが)。 しかし、私はしませんでした。 代わりに、私たちは肩をすくめて先に進みました。 Ubuntuでファイルシステムを移動して、指を動かして問題を把握することができました。



(ツールと環境だけではありません。OmniOSには、サポートされていない古いバージョンのGNU Tarがあると自動的に想定しました。問題は新しいバージョンで確実に解決されたため、調査する意味がありません)。



PS:おそらく、簡単な修正として、バックアップ時にAmandaがtar --sparse



を使用することを単に禁止します。 メールボックスはスパースであってはなりません。これが発生した場合、ファイルシステムバックアップを圧縮するため、これらのゼロバイトはすべて十分に圧縮されます。



PPS:バグをGNU Tar開発者に報告しようとはしませんでした。金曜日にしか見つからなかったため、大学は冬休み中です。 私の前でそれをしてください。



All Articles