0

我正在编写一个应用程序来连续向驱动器写入和读取文件(无论是硬盘驱动器还是 SD 卡或其他)。我正在编写某种模式,然后将其读回作为验证。一旦应用程序失败,我想立即输出某种刺耳的错误。基本上,我们正在用辐射击中硬件,并且需要检测它何时发生故障。到目前为止,我的应用程序可以很好地读取和写入文件,但可以在执行过程中拉出 SD 卡,并且它会继续运行,就好像它还在那里一样。我真的需要检测 SD 卡被移除的那一刻。我看到一些建议使用libudev。我不能使用它,因为这是在没有它的嵌入式 linux 系统上。这是我到目前为止的代码:

#include <stdio.h>
#include <time.h>

const unsigned long long size = 16ULL*1024;
#define NANOS 1000000000LL
#define KB 1024

long long CreateFile(char* filename)
{
    struct timespec time_start;
    struct timespec time_stop;
    long long start, elapsed, microseconds;
    int timefail = 0;
    size_t stat;

    if(clock_gettime(CLOCK_REALTIME, &time_start) < 0)
        timefail = 1;
    start = time_start.tv_sec*NANOS + time_start.tv_nsec;

    int a[size];
    int i, j;

    for(i=0;i<size;i++)
        a[i] = i;

    FILE* pFile;
    pFile = fopen(filename, "wb");
    if(pFile < 0)
    {
        perror("fopen");
        return -1;
    }
    for(j=0; j < KB; j++)
    {
        stat = fwrite(a, sizeof(int), size, pFile);
        if(stat < 0)
            perror("fwrite");
        stat = fsync(pFile);
        //if(stat)
        //  perror("fysnc");
    }

fclose(pFile);

    if(clock_gettime(CLOCK_REALTIME, &time_stop) < 0)
        timefail = 1;

    elapsed = time_stop.tv_sec*NANOS + time_stop.tv_nsec - start;
    microseconds = elapsed / 1000 + (elapsed % 1000 >= 500);

    if(timefail)
        return -1;

    return microseconds / 1000;
}

long long ReadFile(char* filename)
{
    struct timespec time_start;
    struct timespec time_stop;
    long long start, elapsed, microseconds;
    int timefail = 0;

    if(clock_gettime(CLOCK_REALTIME, &time_start) < 0)
        timefail = 1;
    start = time_start.tv_sec*NANOS + time_start.tv_nsec;

    FILE* pFile;
    pFile = fopen(filename, "rb");

    int a[KB];
    int i=0, j=0;
    for(i=0; i<size; i++)
    {
        if(ferror(pFile) != 0)
        {
            fprintf(stderr, "**********************************************");
            fprintf(stderr, "READ FAILURE\n");
            fclose(pFile);
            return -1;
        }
        fread(a, sizeof(a), 1, pFile);
        for(j=0; j<KB;j++)
        {
            if(a[0] != a[1]-1)
            {
                fprintf(stderr, "**********************************************");
                fprintf(stderr, "DATA FAILURE, %d != %d\n", a[j], a[j+1]-1);
                fclose(pFile);
                return -1;
            }
        }
    }
    fclose(pFile);
    if(clock_gettime(CLOCK_REALTIME, &time_stop) < 0)
            timefail = 1;

    if(timefail)
        return -1;

    elapsed = time_stop.tv_sec*NANOS + time_stop.tv_nsec - start;
    microseconds = elapsed / 1000 + (elapsed % 1000 >= 500);

    return microseconds/1000;
}

int main(int argc, char* argv[])
{
    char* filenamebase = "/tmp/media/mmcblk0p1/test.file";
    char filename[100] = "";
    int i=0;
    long long tmpsec = 0;
    long long totalwritetime = 0;
    int totalreadtime = 0;
    int numfiles = 10;
    int totalwritten = 0;
    int totalread = 0;

    for(i=0;i<numfiles;i++)
    {
        sprintf(filename, "%s%d", filenamebase, i);
        fprintf(stderr, "Writing File: %s ...", filename);
        tmpsec = CreateFile(filename);
        if(tmpsec < 0)
            return 0;
        totalwritetime += tmpsec;
        totalwritten++;
        fprintf(stderr, "completed in %lld seconds\n", tmpsec);
        fprintf(stderr, "Reading File: %s ...", filename);
        tmpsec = ReadFile(filename);
        if(tmpsec < 0)
            return 0;
        totalreadtime += tmpsec;
        totalread++;
        fprintf(stderr, "completed in %lld seconds\n", tmpsec);
    }

    fprintf(stderr, "Test Complete\nTotal Files: %d written, %d read\n", totalwritten, totalread);
    fprintf(stderr, "File Size: %lld KB\n", size);
    fprintf(stderr, "Total KBytes Written: %lld\n", size*totalwritten);
    fprintf(stderr, "Average Write Speed: %0.2f KBps\n", (double)size*totalwritten/(totalwritetime/1000));
    fprintf(stderr, "Total KBytes Read: %lld\n", size*totalread);
    fprintf(stderr, "Average Read Speed: %0.2f KBps\n", (double)size*totalread/(totalreadtime/1000));

    return 0;
}
4

2 回答 2

2

你需要改变你的方法。

如果你拉出已经挂载的媒体,你可能会惊慌你的内核(因为它在内存中保留了代表挂载文件系统的复杂数据结构),并破坏了媒体本身。

我已经用这种方式销毁了很多 USB 记忆棒——它们处理分配和磨损均衡的内部小逻辑不喜欢在运行中断电,而且最便宜的似乎没有能够提供足够电力的电容器让它们运行足够长的时间以确保一致的状态——但 SD 卡和更昂贵的 USB 记忆棒可能会更好地生存。

根据使用的驱动程序,内核可能允许您读取和写入媒体,但只需将更改保存在页面缓存中。(此外,您的 stdio.h I/O 可能只进入页面缓存,而不是实际的媒体,这取决于安装选项(是否直接/同步安装)。您的方法根本不提供您的行为假设确实如此。)

相反,您应该使用低级 I/O(unistd.h,参见man 2 open和相关调用,没有 stdio.h),使用O_RDWR|O_DIRECT|O_SYNC标志来确保您的读写命中硬件,并直接访问原始媒体通过块设备节点,而不是安装它。您还可以读取/写入设备上的随机位置,希望磨损均衡不会过多影响您的抗辐射检查。

(编辑添加:如果您在块中写入与测试媒体设备的本机分配块大小完全相同的块,您将避免设备上缓慢的读取 - 修改 - 写入周期。设备仍然会进行磨损均衡,但是只是意味着你写入的块在闪存芯片中的随机物理位置。本机块大小取决于媒体设备。可以通过观察读取和写入需要多长时间来测量本机块大小一个不同大小的块,但我认为对于损坏测试,两个足够大的幂应该效果最好——比如 256k 或 262144 字节。最好让用户为每个设备单独设置它,并使用制造商提供的任何一个信息,或单独的测试程序来找出正确的值。)

您不想为此使用mmap(),因为由媒体错误和媒体变得不可用引起的 SIGBUS 信号很难正确处理。在我看来,低级 unistd.h I/O 最适合这个。

我相信,但尚未验证,将中间读/写的媒体拉出到未安装的低级设备,应该只会产生读/写错误。(不过,我现在没有任何愿意冒险检查的媒体:)

于 2013-02-15T21:54:51.610 回答
1

从我的评论中回答:

在您的写入功能中,您应该具有:

for(j=0; j < KB; j++)
{
    uint32_t bytes_written = fwrite(a, sizeof(int), size, pFile);
    if(bytes_written < size)
    {
        perror("fwrite");
        break;
    }
    stat = fsync(pFile);
    if(stat < 0)
    {
        perror("fysnc");
        break;
    }
}

并在您的阅读功能中:

uint32_t read_bytes_count = fread(a, sizeof(a), 1, pFile);
if(read_bytes_count < sizeof(a))
    break;

此外,如果您有 C99 编译器,请使用 中可用的固定大小类型stdint.h,例如:uint32_t,...

于 2013-02-15T22:06:42.390 回答