问题
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
回答1:
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:
- Found the filesystem hosting my file's block size using
stat()
and accessing thest_blksize
attribute. - Allocated
align
more bytes than I need. I then added those extraalign
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 ofalign
which isblksize
-1), and voila- your buffer isblksize
-aligned.
Also note that the amount you write also has to be aligned to block size (at least in my case).
-LD
回答2:
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.
来源:https://stackoverflow.com/questions/34182535/write-error-invalid-argument-when-file-is-opened-with-o-direct