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개를 얻습니다.

제가 알아차린 한 가지는 컴파일된 코드를 몇 초 동안 실행한 다음 종료할 때(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

관련 정보