Josh Finlay
Josh Finlay

Reputation: 21

Disabling read buffering in Linux for USB mass storage device

Scenario:

I'm simply using fopen() to open /dev/sda for reading, I seek to the position I want to read and I read 2048 bytes. I then re-seek to the position I seek'ed before and read that data again.

On my first read, I get fresh, correct data. On each subsequent read I get the same data over and over again. It does not attempt to poll the device again (because it has an activity light) after the first read, however when I kill my app (ctrl+c) I see the activity light flashing madly and then stop.

I thought it was a buffering issue with my code (I started with ifstream, and have tried fopen() and open(), all the same) and tried the various different methods of disabling the buffing (ie. setvbuf()) but I'm still not getting fresh data.

If I close and open the file again then I get new data but this is a very slow process (I only get about 10-12 samples/sec).

Keep in mind, this is not a mounted device, it simply presents as a storage device and I read from its block device directly.

I ported the same code to Windows and it works, so I don't believe it is my code, but rather something within Linux.

Any help would be greatly appreciated.

Upvotes: 0

Views: 599

Answers (1)

Josh Finlay
Josh Finlay

Reputation: 21

This was solved in my question on the stackexchange site: unix.stackexchange.com/questions/372452/disable-read-cache-buffer-for-usb-mass-storage-device-in-linux

To summarise, the issue was that I needed to use O_DIRECT but ensure that I was reading (and seeking) full blocks of data. In my case, the device was in 512byte blocks so I needed to fetch that amount.

#define NUM_VARS 1024
#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;
FILE *input = fopen("/dev/sda", "r+");
if(posix_memalign((void**)&liveBuffer, PAGE, LIVEBUFSIZE)!=0)
   exit(5);
if (fcntl(fileno(input), F_SETFL, O_DIRECT) == -1)
   exit(6);
fseek(input, OFFSET, SEEK_SET);
fread(liveBuffer, ITEMSIZE, LIVEBUFSIZE, input);
fclose(input);

Upvotes: 2

Related Questions