Reputation: 1872
it is very important to me to write to a file with the O_DIRECT
flag.
This is how I open the file:
//Open the file
int fd;
if((fd = open(inFilepath, O_WRONLY | O_CREAT |O_SYNC |O_DIRECT,S_IRUSR|S_IWUSR))<0) {
//Error handling
return;
}
I know about O_DIRECT's alignment restrictions. This is why I initialize my buffer with calloc:
char *buff = (char *) calloc((size_t) 1,sizeof(char));
if(write(fd,buff,(size_t)1)<1) {
//Error logging
free(buff);
return -1;
}
And I get the write: Invalid argument
error.
I even tried to use more extreme measures such as memalign and posix_memalign, but had issues with them (memalign got stuck, and posix_memalign is missing for the ARM processor).
When I comment out the O_DIRECT
flag, everything works as it should (but I/O is not direct, which is what I need).
Anyone has any insight as to why this is happening? If O_DIRECT
was not implemented in Android, then it should've failed at open()
, not at write()
; so I must be doing something wrong!
Thanks -LD
Upvotes: 7
Views: 7447
Reputation: 1872
I solved it (with your guidance)- and wanted to post my solution in case anyone in the future has similar problems.
The trick was that with the O_DIRECT
flag you need to align both the memory address and your buffer to the filesystem's block size (or at least, block size worked for me; sector didn't).
struct stat fstat;
stat(filepath, &fstat);
int blksize = (int)fstat.st_blksize;
int align = blksize-1;
const char *buff = (char *) malloc((int)blksize+align);
buff = (char *)(((uintptr_t)buff+align)&~((uintptr_t)align));
if(write(fd,buff,(size_t)blksize)<1) {
//Error handling
free((char *)buff);
return -1;
}
I did two main things:
stat()
and accessing the st_blksize
attribute.align
more bytes than I need. I then added those extra align
bytes to the pointer address so that masking off the bits to the lower block size alignment wouldn't leave me with less memory allocated than I wanted. Then of course you AND the bits with the mask (created by flipping the bits of align
which is blksize
-1), and voila- your buffer is blksize
-aligned.Also note that the amount you write also has to be aligned to block size (at least in my case).
-LD
Upvotes: 13
Reputation: 392
Calloc will not align the memory good enough in this case. Allocate more memory than you need, and round it up to the next 4k or so page. Also read the notes below in the manpage for open() with O_DIRECT.
Upvotes: 2