TL; DR: Якщо ядро Linux втрачає захищене записування вводу / виводу , чи є програма, як це дізнатись?
Я знаю, що ви повинні мати fsync()
файл (і його батьківський каталог) для довговічності . Питання полягає в тому, якщо ядро втрачає брудні буфери, які очікують на запит через помилку вводу / виводу, як програма може виявити це і відновити або перервати?
Подумайте про додатки для баз даних тощо, де порядок стійкості запису та запису може мати вирішальне значення.
Втрачено пише? Як?
Блок шар чи ядро в деяких обставинах втрачають буферном запити введення / виведення , які були успішно представлені 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
якщо один або більше буферів не вдалося записати.
Якщо, як я здогадуюсь, це поширюється на fsync()
результат, то якщо додаток панікує і не виходить, якщо воно отримує помилку вводу / виводу fsync()
і знає, як виконати свою роботу при перезапуску, це повинно бути достатньою гарантією?
Імовірно, додаток не може знати, які байтові зрушення у файлі відповідають загубленим сторінкам, щоб він міг переписати їх, якщо знає як, але якщо додаток повторює всі очікувані роботи з останнього успішного fsync()
файлу, і це переписує будь-які буфери брудного ядра, що відповідають втраченому запису у файл, які повинні очистити будь-які прапор помилок вводу / виводу на загублених сторінках і дозволити fsync()
завершити наступне - так?
Чи є тоді якісь інші, нешкідливі обставини, коли fsync()
можуть повернутися, -EIO
коли випуск і переробка робіт були б занадто різкими?
Чому?
Звичайно, таких помилок не повинно бути. У цьому випадку помилка виникла через нещасну взаємодію за dm-multipath
замовчуванням драйвера та сенсорного коду, який використовує SAN для повідомлення про відмову у виділенні місця з обмеженим зберіганням. Але це не єдина обставина, коли вони можуть трапитися - я також бачив повідомлення про це, наприклад, з тонкого розміщеного LVM, як його використовують libvirt, Docker тощо. Такий критичний додаток, як база даних, повинен намагатися впоратися з такими помилками, а не сліпо продовжувати, як ніби все добре.
Якщо ядро вважає, що нормально втрачати записи, не вмираючи з панікою ядра, додатки повинні знайти спосіб впоратися.
Практичний вплив полягає в тому, що я виявив випадок, коли проблема з багатостороннім зв'язком з SAN викликала втрачені записи, які приземлилися, викликаючи пошкодження бази даних, тому що СУБД не знала, що її запис провалився. Не смішно.