TL; DR: Jika kernel Linux kehilangan tulis I / O yang disangga , apakah ada cara bagi aplikasi untuk mengetahuinya?
Saya tahu Anda harus ke fsync()
file (dan direktori induknya) untuk daya tahan . Pertanyaannya adalah jika kernel kehilangan buffer kotor yang tertunda tulis karena kesalahan I / O, bagaimana aplikasi dapat mendeteksi ini dan memulihkan atau membatalkan?
Pikirkan aplikasi basis data, dll, di mana urutan ketahanan menulis dan menulis bisa menjadi sangat penting.
Hilang menulis? Bagaimana?
Lapisan blok kernel Linux dalam beberapa keadaan kehilangan permintaan I / O buffered yang telah berhasil dikirim oleh write()
, pwrite()
dll, dengan kesalahan seperti:
Buffer I/O error on device dm-0, logical block 12345
lost page write due to I/O error on dm-0
(Lihat end_buffer_write_sync(...)
dan end_buffer_async_write(...)
dalamfs/buffer.c
).
Pada kernel yang lebih baru kesalahannya malah akan mengandung "lost async page write" , seperti:
Buffer I/O error on dev dm-0, logical block 12345, lost async page write
Karena aplikasi write()
sudah kembali tanpa kesalahan, sepertinya tidak ada cara untuk melaporkan kesalahan kembali ke aplikasi.
Mendeteksi mereka?
Saya tidak begitu familiar dengan sumber kernel, tetapi saya pikir itu menetapkan AS_EIO
pada buffer yang gagal dituliskan jika itu melakukan penulisan async:
set_bit(AS_EIO, &page->mapping->flags);
set_buffer_write_io_error(bh);
clear_buffer_uptodate(bh);
SetPageError(page);
tetapi tidak jelas bagi saya apakah atau bagaimana aplikasi dapat mengetahui tentang hal ini ketika nanti fsync()
file untuk mengkonfirmasi itu pada disk.
Sepertinya wait_on_page_writeback_range(...)
dimm/filemap.c
kekuatan oleh do_sync_mapping_range(...)
difs/sync.c
yang belok disebut oleh sys_sync_file_range(...)
. Itu kembali -EIO
jika satu atau lebih buffer tidak bisa ditulis.
Jika, seperti yang saya tebak, ini menyebar ke fsync()
hasil, maka jika panik dan menalangi aplikasi jika mendapat kesalahan I / O fsync()
dan tahu bagaimana melakukan kembali pekerjaannya ketika dihidupkan ulang, apakah itu cukup perlindungan?
Mungkin tidak ada cara bagi aplikasi untuk mengetahui offset byte mana dalam file yang sesuai dengan halaman yang hilang sehingga dapat menulis ulang mereka jika mengetahui caranya, tetapi jika aplikasi mengulangi semua pekerjaan yang tertunda sejak keberhasilan terakhir fsync()
file, dan yang menulis ulang setiap buffer kernel kotor yang terkait dengan penulisan yang hilang terhadap file, yang seharusnya menghapus semua flag kesalahan I / O pada halaman yang hilang dan memungkinkan berikutnya fsync()
untuk menyelesaikan - benar?
Apakah ada keadaan lain yang tidak berbahaya di mana fsync()
mungkin kembali di -EIO
mana bailing out dan mengulang pekerjaan akan terlalu drastis?
Mengapa?
Tentu saja kesalahan seperti itu seharusnya tidak terjadi. Dalam hal ini kesalahan muncul dari interaksi yang tidak menguntungkan antara dm-multipath
default pengemudi dan kode akal yang digunakan oleh SAN untuk melaporkan kegagalan untuk mengalokasikan penyimpanan yang disediakan secara tipis. Tapi ini bukan satu-satunya keadaan di mana mereka bisa terjadi - saya juga melihat laporan dari LVM yang disediakan misalnya, seperti yang digunakan oleh libvirt, Docker, dan banyak lagi. Aplikasi kritis seperti basis data harus berusaha mengatasi kesalahan semacam itu, alih-alih membabi buta seolah-olah semuanya baik-baik saja.
Jika kernel berpikir tidak masalah untuk kehilangan penulisan tanpa mati karena kernel panik, aplikasi harus menemukan cara untuk mengatasinya.
Dampak praktisnya adalah saya menemukan kasus di mana masalah multipath dengan SAN menyebabkan penulisan hilang yang menyebabkan korupsi basis data karena DBMS tidak tahu bahwa penulisan gagal. Tidak menyenangkan.