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 once
direct_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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#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);
}