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