TL; DR : 리눅스 커널이 버퍼 된 I / O 쓰기를 잃어버린 경우 , 응용 프로그램을 찾을 수있는 방법이 있습니까?
fsync()
내구성 을 위해 파일 (및 상위 디렉토리)에 있어야한다는 것을 알고 있습니다 . 문제는 커널이 I / O 오류로 인해 쓰기 보류중인 더티 버퍼를 잃어 버린 경우 응용 프로그램이 어떻게이를 감지하고 복구하거나 중단 할 수 있습니까?
쓰기 순서와 쓰기 내구성이 중요한 데이터베이스 응용 프로그램 등을 생각하십시오.
글을 잃어 버렸습니까? 어떻게?
어떤 상황에서 리눅스 커널의 블록 층 캔은 잃을 성공적으로 제출 한 I / O 요청 버퍼 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
).
최신 커널에서는 오류에 "lost async page write"가 포함됩니다 .
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()
결과에 전파 되면 응용 프로그램이 패닉 상태에서 I / O 오류가 발생하고 응용 프로그램 fsync()
을 다시 시작할 때 작업을 다시 수행하는 방법을 알면 구제되는 경우 충분한 보호 조치가 필요합니까?
앱 이 파일의 어떤 바이트 오프셋이 손실 된 페이지에 해당 하는지 알 수 있는 방법은 없을 것이므로 어떻게 알면 다시 작성할 수는 있지만 앱 fsync()
이 파일 의 마지막 성공 이후에 보류중인 모든 작업을 반복 하고 다시 쓰는 경우 파일에 대한 쓰기 손실에 해당하는 더티 커널 버퍼, 손실 된 페이지에서 I / O 오류 플래그를 지우고 다음 fsync()
을 완료해야합니다.
그런 다음 창백하고 재 작업하는 것이 너무 과감한 곳으로 fsync()
돌아올 수 있는 다른 무해한 상황이 -EIO
있습니까?
왜?
물론 이러한 오류는 발생하지 않아야합니다. 이 경우 오류는 dm-multipath
드라이버 기본값과 SAN에서 씬 프로비저닝 된 스토리지 할당 실패를보고하기 위해 사용하는 감지 코드 간의 불행한 상호 작용으로 인해 발생했습니다. 그러나 이것이 일어날 수 있는 유일한 상황은 아닙니다. 예를 들어 libvirt, Docker 등에서 사용되는 씬 프로비저닝 된 LVM에서 보고서를 보았습니다. 데이터베이스와 같은 중요한 응용 프로그램은 모든 것이 제대로 된 것처럼 맹목적으로 수행하기보다는 이러한 오류에 대처해야합니다.
커널 이 커널 패닉으로 죽지 않고 쓰기를 잃어도 좋다고 생각 한다면 , 응용 프로그램은 대처할 방법을 찾아야합니다.
실질적인 영향은 SAN의 다중 경로 문제로 인해 쓰기 손실이 발생하여 DBMS가 쓰기 실패를 알지 못하여 데이터베이스 손상을 일으키는 기록을 잃어버린 경우를 발견했습니다. 재미 없어.