Skip to content
isdnetworks
Go back

디스크에 안 쓰고 성공을 돌려준다

현장에 나간 장비에서 설정이 초기값으로 돌아가는 일이 생겼다. 값을 바꾸고 저장했는데 전원을 껐다 켜면 없다.

코드를 봤다. 쓰고 나서 flush까지 부르고 있었다.

fwrite(buf, 1, len, fp);
fflush(fp);
fsync(fileno(fp));
close(...)

fsync 는 디스크에 실제로 기록될 때까지 기다린다는 뜻이다. 이것이 성공을 돌려줬으면 저장된 것이어야 한다.

Table of contents

Open Table of contents

시간을 재 봤다

fsync 가 실제로 무엇을 하는지 재 봤다.

clock_gettime(CLOCK_MONOTONIC, &t1);
fsync(fd);
clock_gettime(CLOCK_MONOTONIC, &t2);

clock_gettime 으로 앞뒤를 찍으니 수 마이크로초가 나왔다.

플래시 메모리에 한 페이지를 실제로 쓰면 밀리초 단위가 걸린다. 마이크로초면 아무 데도 안 다녀온 것이다.

fsync 가 성공을 돌려주는데 자료는 아직 버퍼에 있다. 그 상태에서 전원이 끊기면 통째로 날아간다.

어디서 흉내를 내나

계층이 여럿이라 어디서 막히는지 봐야 했다. 커널 페이지 캐시를 비우는 것은 fsync 본래 역할이고 여기는 정상이었다.

다음은 장치의 쓰기 캐시다. 저장 매체 안에는 자체 버퍼가 있다. 커널이 비우라는 명령을 내려도 장치가 그것을 무시하고 성공을 돌려줄 수 있다.

fsync 맨페이지에도 이 자리가 적혀 있다. 오래된 커널이나 덜 쓰이는 파일시스템은 디스크 캐시를 비우는 법을 모른다고 적혀 있다. 안전하게 하려면 hdparm 으로 캐시를 끄라고 나온다.

중간에 캐시를 두는 컨트롤러가 있으면 거기서도 막히는데 이 장비는 두 번째 경우였다.

매체마다 달랐다

같은 코드를 다른 매체에서 돌려 봤다.

매체fsync 레이턴시판정
내장 eMMC수 µs흉내
SD 카드수 µs흉내
USB 저장장치 (쓰기 캐시 켜짐)수 µs흉내
USB 저장장치 (쓰기 캐시 끔)수 ms실제

같은 코드이고 같은 커널인데 매체에 따라 갈렸고 쓰기 캐시를 끈 경우에만 밀리초가 나왔다.

그러면 개발 보드에서는 안 나타나고 현장 장비에서만 나타나므로 개발 중에 한 번도 안 걸렸다.

선택지 — 세 가지 방향

방향이 셋이었다. 매체를 바꾸는 것이 가장 확실한데 하드웨어 결정이라 늦게 나오고 이미 나간 장비에는 못 쓴다.

둘째는 쓰기 캐시를 끄는 것이다.

hdparm -W0 /dev/sdX

hdparm -W0 로 끄면 밀리초가 나오는데 성능이 떨어지지만 설정 파일처럼 자주 안 쓰는 자료면 감수할 만하다.

셋째는 전원이 끊겨도 되게 만드는 것인데 매체를 못 바꾸는 상황이라 이것이 실질적인 답이었다.

두 파일을 번갈아 쓴다

설정 저장을 이렇게 바꿨다.

config.a   ← 유효한 설정
config.b   ← 다음 저장 대상
config.cur ← 어느 쪽이 유효한지 가리킴

저장할 때 비활성 쪽에 쓰고 다 쓴 뒤에 config.cur 를 바꾼다. 쓰는 도중에 끊기면 config.cur 가 아직 옛것을 가리키므로 옛 설정으로 뜬다.

포인터를 바꾸는 도중에 끊겨도 둘 중 하나로 복구할 수 있으니 전원이 어디서 끊겨도 한쪽은 온전하다.

flush가 안 되는 것을 전제로 설계한 것이고 매체를 믿는 대신 거짓말을 해도 되게 만들었다.

조치 — 체크섬

config.cur 만으로는 부족했는데 파일 자체가 반쯤 써진 상태일 수 있다.

[설정 내용]
CRC32: a3f2c1d4

각 파일 끝에 CRC32 를 넣고 읽을 때 확인한다. 안 맞으면 반대쪽을 읽고 둘 다 깨졌으면 기본값으로 간다.

이래도 설정이 초기값으로 돌아가는 일은 생긴다. 다만 그때는 체크섬 불일치로 기본값을 적용했다는 줄이 남는다.

왜 그렇게 됐는지를 아는 것과 모르는 것이 다르고 같은 증상이라도 로그가 있으면 다음 판단이 정해진다.

검증 — 판정 방법

새 매체를 쓸 때 확인할 절차를 적어 뒀는데 먼저 fsync 레이턴시를 잰다.

마이크로초면 흉내이므로 4KB 단위로 여러 번 반복해 평균을 본다.

그다음 전원을 실제로 끊어 본다. 쓰는 도중에 뽑고 복구되는지를 보는데 손이 가도 이것만이 진짜 확인이다.

자료에 전원 손실 보호라고 적혀 있어도 재 보는데 그 문구가 어느 계층을 말하는지가 제품마다 다르다.

정리


Share this post on:

Previous Post
시험 환경이 살아 있는 동안 확인했다
Next Post
장비에 두 번 보내면