c - 我正在测试 SOLID STATE 写入失败时间(c 代码)并且设备没有失败

标签 c linux io

原来我误解了磨损均衡,我最初认为通过以 RAW 方式访问驱动器我会失去这个功能,但作为 Controller 上的一个功能,这解释了为什么我对“逻辑扇区”进行了数百万次写入我正在测试

我正在编写一个应用程序,我将在其中使用像循环缓冲区一样的 RAW 磁盘分区,即没有文件系统。

我需要某个地方来跟踪我的读/写缓冲区头,该缓冲区头在整个启动过程中都是持久的,我想我可以创建另一个分区来存储这 2 个指针。

但我担心在扇区消失之前我可以写入设备 SOLID 状态驱动器中的扇区多少次,因此我编写了下面的代码来敲打单个扇区并查看它失败的速度。

  1. 创建随机 block (512 字节)
  2. 使用 pwrite 写入扇区 0
  3. 使用 pread 从扇区 0 读取 block
  4. 比较每个字节
  5. 发现差异时退出。

但它现在已经运行了数百万个扇区写入!!

我本以为它会在某个标准的地方失败,比如 10,000-100,000 次?

我使用如下所示的 pread/pwrite,每个循环都有一个随机缓冲区,然后比较两个缓冲区。

void WriteBlock(const char* device, unsigned char* dataBlock, size_t sector, int size)
{
    int fd = open(device, O_WRONLY);
    if(fd <= 0)
    {
        std::cout << "error opening " << device << " '" << strerror(errno) << "'\r\n";
        exit(EXIT_FAILURE);
    }

    ssize_t r = pwrite(fd, dataBlock, size, sector*SECTOR_SIZE);
    if (r<=0 || r<size)
    {
        std::cout << "failure writing '" << strerror(errno) << "'\r\n";
        exit(EXIT_FAILURE);
    }
    close(fd);
}

void ReadBlock(const char* device, unsigned char* dataBlock, size_t sector, int size)
{
    int fd = open(device, O_RDONLY);
    if(fd <= 0)
    {
        std::cout << "error opening " << device << "\r\n";
        exit(EXIT_FAILURE);
    }

    ssize_t r = pread(fd, dataBlock, size, sector*SECTOR_SIZE);
    if (r<=0 || r<size)
    {
        std::cout << "failure writing '" << strerror(errno) << "'\r\n";
        exit(EXIT_FAILURE);
    }

    close(fd);
}

代码只是继续运行,每次写入缓冲区都等于读取缓冲区。

仅供引用,我没有将写入缓冲区与自身进行比较!如果我将一个值硬编码到读取缓冲区中,它会捕获并解释为失败。

最佳答案

I would have expected it to fail somewhere standard like between 10,000-100,000 times?

大多数固态硬盘都具有磨损均衡功能。这意味着当您写入逻辑 block 0 时,设备会说“嘿,逻辑 block 0 中的旧数据正在被覆盖,所以我可以假装一个完全不同的物理 block 现在是逻辑 block 0”。通过不断写入同一逻辑 block ,您可以写入许多完全不同的物理 block 。

要击败磨损均衡(并实际写入同一个物理 block ),您必须让设备相信所有其他 block 都在使用中。这是不可能的,因为有备用容量。例如,对于一个 1 TiB 的设备,您可以用数据填充所有 1 TiB 的逻辑 block (无需执行任何“修剪”等),但可能会有额外的 512 GiB 空闲空间,并且您对同一逻辑 block 的写入将分布在 512 GiB 的备用空间中;当您实际看到错误时,这可能意味着 512 GiB 备用空间中的每个 block 都发生了故障(而不仅仅是一个 block )。

如果您知道实际有多少空闲空间,那么您也许可以基于此进行计算 - 例如如果有 1000 个备用 block 并且您在看到错误之前进行了 10 亿次写入,那么您可能会说“10 亿次写入/1000 个 block = 每个物理 block 100 万次写入”。

现在,假设您是一家制造商,您有一个 1000 GiB 的驱动器。您决定将其作为消费者驱动器出售(假设该驱动器大部分是空的并且磨损均衡能够正常工作)并且您可以说它是一个 900 GiB 驱动器(带有 100 GiB 备用 block ) 10000 次写入后失败。然后您决定也出售与企业驱动器完全相同的驱动器(假设驱动器可能已满并且磨损均衡不会那么有效)并且您可以说它是 900 GiB 驱动器(100 GiB备用 block )将在 2000 次写入后失败。然后您决定可以增加备用空间量,并将“基本相同”的驱动器作为 500 GiB 企业驱动器(具有 500 GiB 备用 block )出售,该驱动器将在 20000 次写入后发生故障。

下一步;想象一下,您测试 1000 个相同的驱动器(使用您正在编写的软件)并测量“在用于测试的特定条件下(例如,其余逻辑 block 全部空闲/空),平均失败前 20000 次写入”。此信息大多无用 - 如果有人在不同条件下使用相同的驱动器(例如,空闲/空逻辑 block 较少),那么它会比您说的更早(或更晚)发生故障。

(可能更好的)替代方案;您或许可以使用从“S.M.A.R.T.”获得的信息。 (参见 https://en.wikipedia.org/wiki/S.M.A.R.T . )。不幸的是,您可以获得的一些最有用的信息是特定于制造商的(例如,已使用的保留 block 总数、未使用的保留 block 总数),并且某些设备(USB 闪存)根本不支持它。

关于c - 我正在测试 SOLID STATE 写入失败时间(c 代码)并且设备没有失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54180391/

相关文章:

linux - 为 CentOS 移植一个 debian 包到 YUM

java io捕获异常

c - 从文件中读取配置

c - Arduino Due C 定时器编码(中断计数)

linux - 将 ttyUSB* 设备存储在数组中的 C 程序

c - 运行时生成的printf参数

c - 打印大写/小写字母

java - 使用 go 管理 Java 进程

linux - awk 更新到 txt

c++ - 如何使用 fgets 获取文本并保存 std::string