LinuxでUSB大容量記憶装置の読み取りキャッシュ/バッファリングを無効にする

LinuxでUSB大容量記憶装置の読み取りキャッシュ/バッファリングを無効にする

大容量記憶装置としてUSBデバイスがあり、dmesgは次のようになります。

[    4.416584] scsi 0:0:0:0: Direct-Access     Adap ECU Modular ECU      1.0  PQ: 0 ANSI: 2
[    4.420186] sd 0:0:0:0: [sda] 131072 512-byte logical blocks: (67.1 MB/64.0 MiB)
[    4.421063] sd 0:0:0:0: [sda] Write Protect is off
[    4.421084] sd 0:0:0:0: [sda] Mode Sense: 03 00 00 00
[    4.422053] sd 0:0:0:0: [sda] No Caching mode page found
[    4.422067] sd 0:0:0:0: [sda] Assuming drive cache: write through
[    7.446823] sd 0:0:0:0: Attached scsi generic sg0 type 0

ファイルシステムを含めず、含めることはできません。インストールする必要はありません。 (この場合) /dev/sda を開いて読んでください。

問題は、デバイスを開いて読み込むときに最初に必要なものを取得し、その後のすべての読み取りからキャッシュされたデータを取得することです。デバイスのIOインジケータは、後続の読み取り後に点滅せず、最初の読み取りでのみ点滅するため、この仮定を行っています。もちろん、fread()最初の読み取りとまったく同じデータが含まれているからですfread()

私のコードはWindowsでコンパイルし、\.\X:を開くファイルとして指定し、呼び出すたびに新しいデータでデータをうまくポーリングするため、問題はありません。

だから私はLinuxが読み取りをキャッシュ/バッファしていると仮定します。

私のコードは次のとおりです

#define STARTBYTE 272384
#define ENDBYTE 274432
#define NUM_VARS 1024

int main() {
    FILE *input = fopen("/dev/sda", "r+");
    setbuf(input, NULL);
    int exit = 0;
    while (exit < 1) {
        signed short liveBuffer[NUM_VARS];
        fseek(input, STARTBYTE, SEEK_SET);
        fread(liveBuffer, 2, NUM_VARS, input);
        fflush(input);
        // do stuff with the now filled liveBuffer data
    }
    fclose(input);
    return 0;
}

私も使用してopen()指定してみましたO_DIRECTが、違いはありませんでした。

これを行うには、デバイス(/ dev / sda)を開き、272384バイトを見つけます。 2048バイトを読みます。同じ位置を再度見つけて2048バイトを読むなどの作業をします。

fclose()ファイルを再保存すると、open()新しいデータが得られます。非常に遅いのではない場合です。 Windowsでは、(オンまたはオフにせずに)毎秒約10のサンプルを取得します。毎秒約50を取得します。

私が気づいたことの1つは、コンパイルされたコードを数秒間実行してから終了したら(CTRL + C)、コードの実行中にデバイスのアクティビティインジケータが狂ったように点滅することを示していることです。

誰もが正しい方向に私を指すことができますか?

数日間、このような考えをして首を結ぶべきだと思いました。

答え1

介入を使用すると、問題が少し複雑になります。標準入出力呼び出している関数の戻りコードを無視してください。これを使用してO_DIRECTデバイスから新しいデータを取得できますが、それに応じた義務を遵守する必要があります。

具体的には、サーチオフセット、バッファアドレス、およびI / Oサイズはすべて4096の倍数(またはデバイスに応じて2の累乗)でなければなりません。

現在のliveBuffer宣言を削除し、最初に次のコードを含めるようにコードを変更すると、正しく機能することがわかります。

#define PAGE 4096
#define STARTBYTE (272384/PAGE*PAGE) // must align
#define OFFSET (272384-STARTBYTE)
#define ITEMSIZE (sizeof(*liveBuffer))
#define LIVEBUFSIZE ((OFFSET+NUM_VARS*ITEMSIZE+PAGE-1)/PAGE*PAGE)

signed short *liveBuffer;
if(posix_memalign((void**)&liveBuffer, PAGE, LIVEBUFSIZE)!=0)
   exit(5);
if (fcntl(fileno(input), F_SETFL, O_DIRECT) == -1)
   exit(6);

fread()代わりにNUM_VARSを使用する必要がありますLIVEBUFSIZE/ITEMSIZE。ソートが必要なので、必要なデータを見つけるには配列にSTARTBYTEさらに入る必要があります。また、すべての呼び出しを変更して戻りコードが正しいことを確認する必要があります。liveBufferOFFSET/ITEMSIZE

関連情報