0

ドライブにファイルを継続的に読み書きするアプリケーションを作成しています(ハードドライブでもSDカードでも何でも)。私は特定のパターンを書いて、それを検証として読み返しています。アプリが失敗するとすぐに、何らかのエラーをすぐに出力したいと考えています。基本的に、私たちはハードウェアに放射線を当てており、いつ故障したかを検出する必要があります。これまでのところ、アプリでファイルの読み取りと書き込みを正常に行っていますが、実行中に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のオープンコールと関連するコールを参照、stdio.hはありません)を使用し、O_RDWR|O_DIRECT|O_SYNCフラグを使用して読み取りと書き込みがハードウェアにヒットすることを確認し、rawメディアに直接アクセスする必要がありますマウントする代わりに、ブロックデバイスノードを介して。ウェアレベリングが放射抵抗チェックにあまり影響を与えないことを期待して、デバイス上のランダムな場所に対して読み取り/書き込みを行うこともできます。

(追加するために編集:テストされたメディアデバイスのネイティブ割り当てブロックのサイズとまったく同じサイズのブロックを書き込む場合、デバイスでの読み取り-変更-書き込みサイクルが遅くなるのを回避できます。デバイスは引き続きウェアレベリングを実行しますが、書き込みたブロックがフラッシュチップ内のランダムな物理的位置にあることを意味します。ネイティブブロックサイズはメディアデバイスによって異なります。読み取りと書き込みにかかる時間を観察することで、ネイティブブロックサイズを測定できます。異なるサイズのブロックですが、損傷テストでは、2の十分な大きさ(たとえば、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 に答える