Linux mount(2)
매뉴얼 페이지에서 다음 발췌문을 발견했습니다.
다음 패턴을 통해 기존 파일을 교체할 때 손상된 많은 응용 프로그램은 fsync()를 사용하지 않습니다.
fd = open("foo.new")/write(fd,...)/close(fd)/ rename("foo.new", "foo")
또는 더 나쁘다
fd = open("foo", O_TRUNC)/write(fd,...)/close(fd).
auto_da_alloc이 활성화된 경우 ext4는 rename을 통한 교체 및 잘림을 통한 교체 모드를 감지하고 이름 바꾸기() 작업 후 기본 data=ordered 모드에서 다음 로그 커밋에 지연된 할당 블록이 강제로 할당되도록 합니다. 새 파일이 디스크에 강제로 저장됩니다. 이는 ext3과 거의 동일한 수준의 보장을 제공하며 지연 할당된 블록이 디스크에 강제로 기록되기 전에 시스템이 충돌할 경우 발생할 수 있는 "길이가 없는" 문제를 방지합니다.
이 코드는 어떤 의미에서 "깨졌습니까"? 코드가 불법이거나 비표준 규격(POSIX 등)이라고 말하고 있습니까?
fsync()
시스템이 충돌하면 어떻게 될지 걱정하는 사람들에게는 분명히 이것이 좋은 생각일 수 있습니다. 하지만 시스템이 충돌하지 않는다고 가정하면 두 버전의 예제 코드(없음)가 모두 fsync()
올바른 작업을 수행합니까?
답변1
rename
기대는 원자적입니다. 완전히 완료되거나 전혀 완료되지 않습니다. B 대신 A의 이름을 바꾸면 A와 B가 모두 그대로 유지되거나(전혀 발생하지 않음) A의 내용을 B의 이름 아래에 넣어야 합니다(완전히 완료됨).
이는 시스템이 충돌하지 않는 한 호출(등)에 관계없이 fsync
발생합니다 .
그러나 시스템이 충돌하는 경우 이름 바꾸기 자체가 디스크에 도달하여 완료되었음을 알 수 있습니다. 이름을 기억하세요! =파일. 파일/인덱스 노드는 여러 이름을 가질 수 있습니다. 이름을 바꾸면 기본 파일/데이터가 아닌 이름이 변경됩니다.
따라서 프로그램이 A를 쓰고 B를 대체하도록 이름을 바꾼 다음 전원이 꺼지는 상태가 있을 수 있습니다. 결과적으로 파일 시스템은 A의 실제 데이터 대신 디스크에 이름 바꾸기를 기록합니다. 아니요. fsync
따라서 길이가 0인 B 또는 0으로 채워진 B가 됩니다.
응용 프로그램이 파일을 덮어쓰는 대신 임시 파일에 쓰고 이름을 바꾸는 이유는 다음과 같습니다.~ 고 싶어요충돌 안전. 중요한 문서의 절반만 작성된 임시 복사본을 수정되지 않은 양호한 복사본 옆에 놓아도 사용자는 별로 기분이 상하지 않을 것입니다. 하지만 좋은 카피를 남기지 않으면 사용자는 만족하지 못할 것입니다.
답변2
코드는 합법적이지만 "순진"합니다. 문제는 충돌이 발생하면 정확히 어떻게 되는지입니다.
카탈로그가 업데이트될 때까지 새 데이터에 공간이 할당되지 않아 데이터가 손실될 위험이 있습니다.
좋은 애플리케이션은 호출하여 fflush()
데이터 fsync()
가 디스크에 플러시되었는지 확인합니다. 이러한 auto_da_alloc
루틴은 커널 내에서 경험적으로 이를 수행하려고 시도합니다.
https://bugzilla.kernel.org/show_bug.cgi?id=103111#c10일부 "문제"가 설명되었습니다.
답변3
완전히 합법적이라면 작동하겠지만 원하는 대로 되지는 않습니다.
두 번째는 분명합니다. 새 것을 저장하기 전에 원본을 파괴합니다.
첫 번째는 덜 명확합니다. 시스템이 실패하면(예: 정전) 아무것도 하지 않고(시작하지 않음) 두 개의 파일이 있는 것처럼 보입니다. 이전 파일과 새 파일, 성공 파일이 있습니다. 하지만 그 말대로 하지 않으면 그렇지 않습니다 fsync
.
그들은 당신의 주의를 끌기 위해 "손상된"이라는 단어를 사용합니다. 사용자가 데이터를 잃어 버리기 때문에 깨졌습니다. 오늘은 아닐 수도 있습니다. 어쩌면 내일이 아닐 수도 있지만 곧, 그리고 평생 동안.
이를 간헐적 오류라고 합니다. 증상이 나타나기 전까지 수년 동안 지속될 수 있는 오류입니다.
사용자의 데이터 무결성에 관심이 없다면 첫 번째 예를 수행하는 이유는 무엇입니까?