这个问题折腾了我有一个星期了,因为最近一直在搞有关磁盘的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()获得。memalign()可以用来得到这样一个buffer: int buffersize = getpagesize()*page_num; int pagesize=getpagesize(); char * buffer = memalign(pagesize, buffersize); 之后你就可以用这个buffer来read()或者write()了。如: read(fd,buffer,buffersize); 要注意的是,在2.4以前的kernel里,buffersize必须是页大小的整数倍,并且buffer指向的地址也必须是页大小的整数倍。用上面的简单计算就可以得到满足条件的buffer。之后的I/O便是完全绕过cache的direct I/O了。 PS:完成这个之后,周末就可以放心的回家了,很开心。