어제 누군가 내 대답 의 논리 및 / 또는 진실성에 관해 약간의 토론에 들어갔습니다 . 합리적인 시간 (년과 년)으로 반론의 핵심은 SD 카드를 착용하는 사람들에 대한 많은 이야기가 온라인에 있기 때문에 내가 틀렸다는 것 같았습니다.
24/7에 남아있는 rw 루트 파일 시스템을 포함하는 SD 카드가있는 장치가 있기 때문에 전제 조건을 만족스럽게 테스트했습니다. 이 테스트를 약간 조정하고 (실제로 동일한 카드를 사용하여) 반복하여 여기에 제시했습니다. 내가 가지고있는 두 가지 주요 질문은 다음과 같습니다.
- 나는 쓰기를 다시 계속의 효과를 재현하는 의도 염두에두고, 카드가 가능한 난파 시도에 사용하는 방법입니다 작은 양의 데이터는?
- 카드를 확인하는 데 사용한 방법이 여전히 유효합니까?
첫 번째 부분에 대한 이의 제기는 아마도 내 테스트가 실제로 내가하는 방식대로 카드에 쓰지 않았다고 주장해야하기 때문에 아마도 여기에 SO 또는 SuperUser 대신 질문을하고 있습니다. 리눅스에 대한 특별한 지식.
[SD 카드는 같은 종류의 스마트 버퍼링 또는 캐시를 사용하여 같은 장소에 반복해서 쓰는 것이 마모가 덜 발생하는 곳에서 버퍼링 / 캐시 될 수 있습니다. 어디에서나 이것에 대한 징후를 찾지 못했지만 SU 에 대해 묻고 있습니다. ]
테스트의 기본 개념은 카드의 동일한 작은 블록에 수백만 번 쓰는 것입니다. 이는 이러한 디바이스가 유지할 수있는 쓰기주기 수에 대한 주장을 훨씬 넘어서는 것이지만 , 카드의 크기가 적당한 경우 마모 레벨링 이 효과적이라고 가정 하면 "같은 블록"과 같이 수백만 개의 쓰기는 여전히 중요하지 않습니다. 말 그대로 동일한 물리적 블록이 아닙니다. 이를 위해 모든 쓰기 작업이 하드웨어 및 동일한 겉보기 영역 으로 완전히 비워 졌는지 확인해야했습니다 .
하드웨어로 플러시하기 위해 POSIX 라이브러리 호출에 의존했습니다 fdatasync()
.
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
// Compile std=gnu99
#define BLOCK 1 << 16
int main (void) {
int in = open ("/dev/urandom", O_RDONLY);
if (in < 0) {
fprintf(stderr,"open in %s", strerror(errno));
exit(0);
}
int out = open("/dev/sdb1", O_WRONLY);
if (out < 0) {
fprintf(stderr,"open out %s", strerror(errno));
exit(0);
}
fprintf(stderr,"BEGIN\n");
char buffer[BLOCK];
unsigned int count = 0;
int thousands = 0;
for (unsigned int i = 1; i !=0; i++) {
ssize_t r = read(in, buffer, BLOCK);
ssize_t w = write(out, buffer, BLOCK);
if (r != w) {
fprintf(stderr, "r %d w %d\n", r, w);
if (errno) {
fprintf(stderr,"%s\n", strerror(errno));
break;
}
}
if (fdatasync(out) != 0) {
fprintf(stderr,"Sync failed: %s\n", strerror(errno));
break;
}
count++;
if (!(count % 1000)) {
thousands++;
fprintf(stderr,"%d000...\n", thousands);
}
lseek(out, 0, SEEK_SET);
}
fprintf(stderr,"TOTAL %lu\n", count);
close(in);
close(out);
return 0;
}
나는 파티션 의 시작 부분에 2 백만 회 이상의 쓰기 를 축적 할 때까지 ~ 8 시간 동안 이것을 실행했습니다 /dev/sdb1
. 1/dev/sdb
(파티션이 아닌 원시 장치)를 쉽게 사용할 수 있었지만 이것이 어떻게 다른지 알 수 없습니다.
그런 다음 파일 시스템을 만들고 마운트하여 카드를 확인했습니다 /dev/sdb1
. 이것은 밤새도록 쓰던 특정 블록이 실현 가능하다는 것을 나타냅니다. 그러나 이는 카드의 일부 영역이 마모 레벨링으로 마모 및 교체되지 않았지만 접근 가능한 상태로 남아 있음을 의미하지는 않습니다.
이를 테스트하기 badblocks -v -w
위해 파티션에서 사용 했습니다. 이 테스트 는 파괴적인 읽기 / 쓰기 테스트이지만 마모 레벨링 여부는 각 롤링 쓰기를위한 공간을 제공해야하므로 카드의 실행 가능성을 강력하게 나타냅니다. 다시 말해, 카드를 완전히 채우고 문자가 모두 맞는지 확인하는 것은 문자 그대로입니다. 불량 블록이 몇 가지 패턴을 통해 작동하게했기 때문에 여러 번.
[아래 Jason C의 의견에 따르면, 이런 방식으로 불량 블록을 사용하는 것에 대해 잘못된 점은 없습니다. SD 카드의 특성으로 인해 실제로 불량 블록을 식별하는 데 유용하지는 않지만 개정 된 테스트가 진행된 -b
and -c
스위치를 사용하여 임의 크기의 파괴적인 읽기-쓰기 테스트를 수행 하는 것이 좋습니다 (나의 답변 참조). ). 카드 컨트롤러에 의한 마법이나 캐싱의 양은 몇 메가 바이트의 데이터를 하드웨어에 쓰고 올바르게 다시 읽을 수있는 테스트를 속일 수 없습니다. Jason의 다른 의견은 오해- 의도적 인 IMO에 근거한 것 같습니다. 그래서 내가 논쟁하지 않아도됩니다. 머리가 위로 올라가면 독자에게 맡겨서 무엇이 합리적이고 무엇이 아닌지 를 결정하게 됩니다.]
1 이 카드는 내가 거의 사용하지 않은 오래된 4GB Sandisk 카드 ( "클래스"번호가 없음)였습니다. 다시 한 번, 이것은 문자 그대로 동일한 물리적 장소에 2 백만 쓰기가 아니라는 점을 명심하십시오. 마모 레벨링으로 인해 "첫 번째 블록"은 테스트 중에 컨트롤러에 의해 지속적으로 움직였으며 상태 는 마모 상태를 레벨 아웃했습니다.
/dev/sdb1
대 /dev/sdb
그것은 당신의 프로그램에 대한 차이가 없습니다,하지만 않습니다 (아래 설명 참조) 차이를 만드는 장치에 사용되지 않은 블록의 상태가 테스트에 대한 미지의 행방 불명, 그리고 것입니다 당신이 전체 장치를 기입하지 않는 한 (예를 들어, /dev/sdb
) 먼저 데이터를 사용하면 공간 마모 레벨링이 작동해야하는 양이 주요 변수입니다. 따라서 장치 대 파티션은 테스트와 관련이 없지만 장치에 데이터를 올바르게 채운 후에는 파티션별로 사용 가능한 옵션이 아니므로 결함이있는 테스트의 결과입니다.
badblocks
플래시 드라이브에서 페이지 오류를 표시 하는 데 사용할 수 없으며 오해의 소지가 있다고 주장 할 수 없습니다 . 이들은 컨트롤러에 의해 처리되고 감지 될 때 공간을 확보하도록 매핑됩니다. 드라이브에서 데이터의 물리적 레이아웃은 I / O를 수행 할 때 표시되는 물리적 레이아웃과 동일하지 않으므로웨어 레벨링이 투명성을 유지하는 방식입니다. I / O 중에이 중 어느 것도 보이지 않습니다. 드라이브가 SMART를 지원하는 경우, 컨트롤러에서 장애 및 예약 된 공간에 대한 정보를 얻을 수 있습니다.