Linux下利用O_DIRECT标志绕过VFS cache Tweet

来源:互联网 发布:windows多用户同时登录 编辑:程序博客网 时间:2024/06/06 00:01

转载:http://passer-byb.com/blog/85.html


这个问题折腾了我有一个星期了,因为最近一直在搞有关磁盘的I/O的测试,因此需要绕过或者关闭VFS的cache直接对磁盘进行读写。Google过之后发现基本上想要关闭cache是不可能的,只有想办法绕过了。于是很自然的想到了write()和read()这两个东西,可是当时并没意识到buffer跟cache并不是一个东西。write()跟read()虽然叫直接I/O但事实上他们只是绕过了buffer,也就是说在读入跟输出的时候不进行任何的缓冲,但VFS本身的cache仍然存在,VFS仍然会选择在合适的时候将cache的数据写入磁盘。
于是找了很多方法,有的是通过drop cache的方法,就是"echo 1 > /proc/sys/vm/drop_caches"这样的方法,不过这种方法只能清除一次cache,读写一次,很是麻烦。于是果断放弃了这种不靠谱的方法。
后来想到了APUE上没有提到的一个O_DIRECT flag(因为APUE讲的是UNIX编程,当然没必要照顾到GNU Linux特有的东西)。具体怎么用呢,下面就来说说。
首先在文件头需要定义

#define _GNU_SOURCE

然后,这个东西用在open()获得文件描述符时所填写的第二个参数,也就是open(path,flag,mode)的第二个参数。比如你要以写方式创建一个路径为"/home/user/test.test"新文件,并且要直接I/O绕过cache,就可以这样写:

int fd=open("/home/user/test.test",O_WRONLY|O_CREAT|O_DIRECT,S_IRUSR|S_IWUSR);

之后在你需要read()或者write()的时候,传入的buffer的首地址,以及buffer的大小都必须跟文件系统的page size对齐。这个page size可以通过getpagesize()获得。所以这里要用到一个我的笨办法:

int buffersize = getpagesize()*page_num;
int pagesize=getpagesize();
char * t_buf = (char *) malloc(buffersize+pagesize);
char * buffer = (char *)(((unsigned int)buffersize+pagesize-1)/pagesize*pagesize);

之后你就可以用这个buffer来read()或者write()了。如:

read(fd,buffer,buffersize);

要注意的是这里的buffersize必须是页大小的整数倍,并且buffer指向的地址也必须是页大小的整数倍。用上面的简单计算就可以得到满足条件的buffer。之后的I/O便是完全绕过cache的direct I/O了。


原创粉丝点击