昨天,我与某人就我的回答的逻辑和/或准确性进行了一次小辩论,即,在体面(GB +)大小的SD卡上记录和维护fs元数据可能永远不足以使卡磨损在合理的时间内(数年和数年)。反驳的理由似乎是我一定错了,因为网上有很多关于SD卡磨损的故事。
由于我的设备中确实装有SD卡,其中包含24/7保留的rw根文件系统,因此我之前对前提条件进行了测试,令我感到满意。我对测试进行了一些调整,重复了一下(实际上是使用同一张卡片),并在这里进行介绍。我有两个核心问题:
- 是我曾经试图破坏该卡可行的,记住它的目的是不断重现的影响,重新编写方法小数据量?
- 我用来验证卡的方法仍然可行吗?
我将问题而不是SO或SuperUser放在这里,因为对第一部分的异议可能必须断言我的测试并未真正按照我确定的方式写入卡,并且断言这需要一些时间linux的特殊知识。
[也可能是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;
}
我将其运行了大约8个小时,直到我对该分区的开头累积了200万次以上的写入/dev/sdb1
。1 我可以很容易地使用它/dev/sdb
(原始设备而不是分区),但是我看不到这会有什么用。
然后,我尝试通过在上创建并安装文件系统来检查卡/dev/sdb1
。这项工作奏效了,表明我整夜都在写的特定代码块是可行的。但是,这并不意味着该卡的某些区域没有因磨损平整而被磨损和移位,而是可以访问的。
为了测试这一点,我badblocks -v -w
在分区上使用了。这是一个破坏性的读写测试,但是无论是否磨损均衡,它都应强烈表明该卡的可行性,因为它仍必须为每次滚动写入提供空间。换句话说,这实际上是完全填充卡,然后检查所有这些都可以。几次,因为我让坏块通过几种模式工作。
[下面是Contra Jason C的评论,以这种方式使用Badblocks没有错是非。虽然由于SD卡的性质,它实际上不能识别坏块,但可以使用-b
和-c
开关进行任意大小的破坏性读写测试,这是很好的选择,这是修改后的测试的去向(请参阅我自己的回答) )。卡的控制器无法进行任何魔术或缓存操作,因此无法通过测试将几兆字节的数据写入硬件并正确地再次读取。杰森(Jason)的其他评论似乎是基于一种误读-国际海事组织(IMO)是有意为之的,这就是为什么我不愿意争论。抬起头来,我让读者来决定什么有意义,什么没有。]
1该卡是旧的4 GB Sandisk卡(上面没有“类”号),我几乎没用过。再次提醒您,实际上不是在同一物理位置写入200万个字;由于磨损平衡,在测试过程中,控制器将不断移动“第一个滑块”以平衡磨损。
/dev/sdb1
vs,/dev/sdb
这对您的程序没有影响,但确实有所不同(如下所述)的是,设备上未使用块的状态是未知的,并且在测试中无法解释,除非您填满整个设备(例如,/dev/sdb
)首先要获得数据,必须要处理的空间损耗平衡量是一个主要变量。因此,尽管设备与分区之间的关系与您的测试无关,这主要是测试有缺陷的结果,因为在用数据正确填充设备后,按分区将是不可用的选项(除非您格式化之后)。
badblocks
用来显示闪存驱动器上的页面失败(并声称这是非常误导的)。这些由控制器处理,并在检测到时映射为保留空间。驱动器上数据的物理布局与执行I / O时看到的物理布局不同,这就是损耗均衡保持透明性的方式。没有这个过程中I / O是对你可见。如果驱动器最多支持SMART,则可以从控制器获取有关故障和剩余保留空间的一些信息。