TL; DR:LinuxカーネルがバッファリングされたI / O書き込みを失った場合、アプリケーションがそれを見つける方法はありますか?
fsync()
耐久性のためにファイル(およびその親ディレクトリ)を使用する必要があることを知っています。問題は、I / Oエラーが原因で書き込み保留中のダーティバッファーがカーネルで失われた場合、アプリケーションはこれをどのように検出して回復または中止できるでしょうか。
書き込みの順序と書き込みの持続性が重要になるデータベースアプリケーションなどを考えてください。
書き込みを忘れましたか?どうやって?
Linuxカーネルのブロックレイヤーは、状況によっては、などによって正常に送信されたバッファリングされたI / O要求を失う可能性があり、次のようなエラーが発生します。write()
pwrite()
Buffer I/O error on device dm-0, logical block 12345
lost page write due to I/O error on dm-0
(end_buffer_write_sync(...)
およびend_buffer_async_write(...)
をfs/buffer.c
参照)。
新しいカーネルでは、エラーには代わりに「失われた非同期ページ書き込み」が含まれます。
Buffer I/O error on dev dm-0, logical block 12345, lost async page write
アプリケーションwrite()
は既にエラーなしで返されているので、アプリケーションにエラーを報告する方法はないようです。
それらを検出しますか?
私はカーネルソースにそれほど精通していませんが、非同期書き込みを行っている場合、書き出されなかったバッファーに設定されると思いますAS_EIO
。
set_bit(AS_EIO, &page->mapping->flags);
set_buffer_write_io_error(bh);
clear_buffer_uptodate(bh);
SetPageError(page);
しかし、アプリケーションが後でfsync()
ディスク上にあることを確認するためにファイルを処理するときに、アプリケーションがこれを見つけることができるかどうか、またはどのようにそれを見つけることができるかは不明です。
それはのように見えるwait_on_page_writeback_range(...)
中mm/filemap.c
でかもしれないdo_sync_mapping_range(...)
中fs/sync.c
で呼び出される順番ですsys_sync_file_range(...)
。-EIO
1つ以上のバッファに書き込めなかった場合に返されます。
私が推測しているように、これがfsync()
の結果に反映される場合、アプリがパニックに陥り、I / Oエラーが発生しfsync()
、再起動時に作業をやり直す方法を知っている場合は、それで十分です。
おそらくアプリがファイル内のどのバイトオフセットが失われたページに対応しているかを知る方法はないので、アプリがその方法を知っている場合はそれらを書き換えることができますが、アプリがfsync()
ファイルの最後の成功以降に保留中の作業をすべて繰り返し、それが書き換えられる場合ファイルに対する失われた書き込みに対応するダーティカーネルバッファー。失われたページのI / Oエラーフラグをクリアし、次のページfsync()
を完了できるようにする必要があります。
それから、救済とやり直し作業があまりにも劇的でfsync()
ある、戻ってくるかもしれない他の無害な状況はあり-EIO
ますか?
どうして?
もちろん、そのようなエラーは発生しません。この場合、エラーは、dm-multipath
ドライバーのデフォルトと、SANがシンプロビジョニングされたストレージの割り当ての失敗を報告するために使用するセンスコードとの間の不幸な相互作用から発生しました。しかし、これが発生する可能性があるのはこれだけではありません。たとえば、libvirtやDockerなどで使用されているシンプロビジョニングされたLVMからの報告も見ました。データベースのような重要なアプリケーションは、あたかもすべてが順調であるかのように盲目的に実行するのではなく、そのようなエラーに対処しようとする必要があります。
場合は、カーネルはカーネルパニックで死なずに失うの書き込みにそれはOKだと思っ、アプリケーションが対処する方法を見つける必要があります。
実際的な影響は、DBMSが書き込みが失敗したことを知らなかったために、SANのマルチパスの問題が原因で書き込みが失われ、データベースが破損するケースを見つけたことです。楽しくない。