Linux direct io使用
在linux 2.6内核上使用direct io不难,只需按照如下几点来做即可:
1,在open文件时加上O_DIRECT旗标,这样以通告内核我们想对该文件进行直接io操作。
2,在源文件的最顶端加上_GNU_SOURCE宏定义,或在编译时加在命令行上也可以,否则将提示:
direct_io_write_file.c: In function 'main':direct_io_write_file.c:25: error: 'O_DIRECT' undeclared (first use in this function)direct_io_write_file.c:25: error: (Each undeclared identifier is reported only oncedirect_io_write_file.c:25: error: for each function it appears in.)
3,存放文件数据的缓存区起始位置以及每一次读写数据长度必须是磁盘逻辑块大小的整数倍,一般也就是512字节(也有可能是一内存页大小,4096),否则将导致read/write失败,perror将提示:read failed: Invalid argument或write failed: Invalid argument。
1和2很容易做到,而第3点,要满足缓存区起始位置与512对齐,这可以在进行缓存区空间申请时使用posix_memalign这样的函数指定512对齐:ret = posix_memalign((void **)&buf, 512, BUF_SIZE);
或者进行手动调节对齐:
real_buf = malloc(BUF_SIZE + 512);aligned_buf = ((((unsigned int)real_buf + 512 - 1) / 512) * 512);
由于要满足每一次读写数据长度必须是磁盘逻辑块大小的整数倍,所以最后一次文件操作可能无法满足,此时只能重新以cached io模式打开文件后,fseek到对应位置进行剩余数据的读写。
为什么要使用direct io?因为direct io不过文件系统缓冲,也就是说对文件进行direct io操作不会减少系统的free内存数量,这对于自己本身带有缓存的应用程序(比如数据库)比较有用。 示例:/** * gcc cached_io_read_file.c -o cached_io_read_file -D_GNU_SOURCE */#include#include #include #include #include #include #include #define BUF_SIZE 1024 int main(){ int fd; int ret; unsigned char *buf; ret = posix_memalign((void **)&buf, 512, BUF_SIZE); if (ret) { perror("posix_memalign failed"); exit(1); } fd = open("./direct_io.data", O_RDONLY, 0755); if (fd < 0){ perror("open ./direct_io.data failed"); free(buf); exit(1); } do { ret = read(fd, buf, BUF_SIZE); if (ret < 0) { perror("read ./direct_io.data failed"); } } while (ret > 0); free(buf); close(fd);}
/** * gcc cached_io_write_file.c -o cached_io_write_file -D_GNU_SOURCE */#include#include #include #include #include #include #include #define BUF_SIZE 1024 int main(int argc, char * argv[]){ int fd; int ret; unsigned char *buf; ret = posix_memalign((void **)&buf, 512, BUF_SIZE); if (ret) { perror("posix_memalign failed"); exit(1); } memset(buf, 'c', BUF_SIZE); fd = open("./direct_io.data", O_WRONLY | O_CREAT, 0755); if (fd < 0){ perror("open ./direct_io.data failed"); free(buf); exit(1); } do { ret = write(fd, buf, BUF_SIZE); if (ret < 0) { perror("write ./direct_io.data failed"); } } while (1); free(buf); close(fd);}
/** * gcc direct_io_read_file.c -o direct_io_read_file -D_GNU_SOURCE */#include#include #include #include #include #include #include #define BUF_SIZE 1024 int main(){ int fd; int ret; unsigned char *buf; ret = posix_memalign((void **)&buf, 512, BUF_SIZE); if (ret) { perror("posix_memalign failed"); exit(1); } fd = open("./direct_io.data", O_RDONLY | O_DIRECT, 0755); if (fd < 0){ perror("open ./direct_io.data failed"); exit(1); } do { ret = read(fd, buf, BUF_SIZE); if (ret < 0) { perror("write ./direct_io.data failed"); } } while (ret > 0); free(buf); close(fd);}
/** * gcc direct_io_write_file.c -o direct_io_write_file -D_GNU_SOURCE */#include#include #include #include #include #include #include #define BUF_SIZE 1024 int main(int argc, char * argv[]){ int fd; int ret; unsigned char *buf; ret = posix_memalign((void **)&buf, 512, BUF_SIZE); if (ret) { perror("posix_memalign failed"); exit(1); } memset(buf, 'c', BUF_SIZE); fd = open("./direct_io.data", O_WRONLY | O_DIRECT | O_CREAT, 0755); if (fd < 0){ perror("open ./direct_io.data failed"); exit(1); } do { ret = write(fd, buf, BUF_SIZE); if (ret < 0) { perror("write ./direct_io.data failed"); } } while (1); free(buf); close(fd);}
/** * gcc direct_io_read_write_file.c -o direct_io_read_write_file -D_GNU_SOURCE */#include#include #include #include #include #include #include #define BUF_SIZE 1024 int main(int argc, char * argv[]){ int fd, fd1; int ret; unsigned char *buf; ret = posix_memalign((void **)&buf, 512, BUF_SIZE); if (ret) { perror("posix_memalign failed"); exit(1); } memset(buf, 'c', BUF_SIZE); fd = open("/dev/sda", O_RDONLY | O_DIRECT | O_LARGEFILE, 0755); if (fd < 0){ perror("open /dev/sda failed"); exit(1); } fd1 = open("./direct_io.data", O_WRONLY | O_DIRECT | O_CREAT, 0755); if (fd1 < 0){ perror("open ./direct_io.data failed"); close(fd); exit(1); } do { ret = read(fd, buf, BUF_SIZE); if (ret < 0) { perror("read /dev/sda failed"); } ret = write(fd1, buf, BUF_SIZE); if (ret < 0) { perror("write ./direct_io.data failed"); } } while (1); free(buf); close(fd); close(fd1);}