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 викликала втрачені записи, які приземлилися, викликаючи пошкодження бази даних, тому що СУБД не знала, що її запис провалився. Не смішно.