TL; DR: Se o kernel do Linux perder uma gravação de E / S em buffer , existe alguma maneira de o aplicativo descobrir?
Eu sei que você tem que fsync()
o arquivo (e seu diretório pai) para maior durabilidade . A questão é se o kernel perde buffers sujos com gravação pendente devido a um erro de E / S, como o aplicativo pode detectar isso e recuperar ou anular?
Pense em aplicativos de banco de dados, etc., onde a ordem de gravação e a durabilidade da gravação podem ser cruciais.
Gravações perdidas? Quão?
Pode camada do bloco do kernel Linux em algumas circunstâncias perdem solicitações de E / S que foram submetidos com sucesso por tamponada write()
, pwrite()
etc, com um erro como:
Buffer I/O error on device dm-0, logical block 12345
lost page write due to I/O error on dm-0
(Veja end_buffer_write_sync(...)
e end_buffer_async_write(...)
entrefs/buffer.c
).
Nos kernels mais recentes, o erro conterá "escrita de página assíncrona perdida" , como:
Buffer I/O error on dev dm-0, logical block 12345, lost async page write
Como o aplicativo write()
já retornou sem erro, parece não haver maneira de relatar um erro ao aplicativo.
Detectando-os?
Não estou familiarizado com as fontes do kernel, mas acho que ele define AS_EIO
o buffer que falhou ao ser gravado se estiver fazendo uma gravação assíncrona:
set_bit(AS_EIO, &page->mapping->flags);
set_buffer_write_io_error(bh);
clear_buffer_uptodate(bh);
SetPageError(page);
mas não está claro para mim se ou como o aplicativo pode descobrir isso quando mais tarde for fsync()
o arquivo para confirmar que está no disco.
Parece que wait_on_page_writeback_range(...)
nomm/filemap.c
poder por do_sync_mapping_range(...)
emfs/sync.c
que se vire chamado por sys_sync_file_range(...)
. Retorna -EIO
se um ou mais buffers não puderam ser gravados.
Se, como suponho, isso se propaga para fsync()
o resultado, se o aplicativo entrar em pânico e cair fora se receber um erro de E / S fsync()
e souber como refazer seu trabalho quando reiniciado, isso deve ser uma proteção suficiente?
Presumivelmente, não há como o aplicativo saber quais desvios de bytes em um arquivo correspondem às páginas perdidas, para poder reescrevê-las se souber, mas se o aplicativo repetir todo o seu trabalho pendente desde o último êxito fsync()
do arquivo e que reescreve quaisquer buffers de kernel sujos correspondentes a gravações perdidas no arquivo, que devem limpar os sinalizadores de erro de E / S nas páginas perdidas e permitir que o próximo fsync()
seja concluído - certo?
Existem outras circunstâncias inofensivas nas quais fsync()
pode voltar -EIO
onde o resgate e o refazer do trabalho seriam muito drásticos?
Por quê?
Claro que esses erros não deveriam acontecer. Nesse caso, o erro surgiu de uma interação infeliz entre os dm-multipath
padrões do driver e o código de detecção usado pela SAN para relatar falha na alocação de armazenamento thin-provisioned. Mas essa não é a única circunstância em que eles podem acontecer - eu também vi relatórios sobre LVM thin provisionado, por exemplo, conforme usado por libvirt, Docker e muito mais. Um aplicativo crítico como um banco de dados deve tentar lidar com esses erros, em vez de continuar cegamente como se tudo estivesse bem.
Se o kernel achar que não há problema em perder gravações sem morrer de pânico, os aplicativos precisam encontrar uma maneira de lidar com isso.
O impacto prático é que eu encontrei um caso em que um problema de caminhos múltiplos com uma SAN causava gravações perdidas que acabavam causando corrupção no banco de dados porque o DBMS não sabia que suas gravações haviam falhado. Não tem graça.