使用fuse实现一个控制接口文件,先写入命令,然后读取结果。读取的时候发现一直返回0。
控制命令如下:
1 2 3 4 5 | fd = open(NAS_MNT "/album/control" , O_RDWR); write(fd, "reload\n" , 7); lseek(fd, 0, SEEK_SET); ret = read(fd, buf, sizeof (buf)-1); close(fd); |
结果read总是返回0。
经过一番分析,发现跟fuse的io mode有关系【1】。fuse有2种模式:
1 direct io模式
direct io模式会完全bypass掉page cache。读写请求会直接发给fuse程序。此时shared map默认会关掉。
2 cached模式
有 write-through 和 write-back两种。默认是write-through模式。
cached mode 读会从page cache满足。写跟上述两种子模式有关。
write-through会直接写到fuse 程序。write-back会先写到page cache。
fuse默认是write-through cached mode。所以,在读的时候,会:
[ 127679.2808] FUSE: lookup ino 1 name control
[ 127679.2809] RPLY: lookup ino 1 name control return ino 2
[ 127679.2809] FUSE: open fh 1 ino 2 flags RDWR
[ 127679.2810] RPLY: open fh 1 ino 2
[ 127679.2811] FUSE: write fh 1 ino 2 size 7 off 0
[ 127679.2835] RPLY: write fh 1 ino 2 done 7
[ 127679.2836] FUSE: getattr fh 1 ino 2
[ 127679.2837] RPLY: getattr fh 1 ino 2
[ 127679.2837] FUSE: read fh 1 ino 2 size 4096 off 0
[ 127679.2837] RPLY: read fh 1 ino 2 len 16
[ 127679.2839] FUSE: flush fh 1 ino 2
[ 127679.2839] RPLY: flush fh 1 ino 2
[ 127679.2839] FUSE: release fh 1 ino 2
[ 127679.2840] RPLY: release fh 1 ino 2
可以看到 read之前有一个getattr请求,这个接口返回的文件大小是0。导致内核构建的page cache大小是0,即使read返回了16个字节。
getattr返回一个大的长度后,read可以读取到数据。
但是我们开启direct io后。
[ 127816.9747] FUSE: getattr ino 1
[ 127816.9748] RPLY: getattr ino 1
[ 127816.9749] FUSE: lookup ino 1 name control
[ 127816.9749] RPLY: lookup ino 1 name control return ino 2
[ 127816.9750] FUSE: open fh 1 ino 2 flags RDWR
[ 127816.9751] RPLY: open fh 1 ino 2 direct io
[ 127816.9751] FUSE: write fh 1 ino 2 size 7 off 0
[ 127816.9778] RPLY: write fh 1 ino 2 done 7
[ 127816.9780] FUSE: read fh 1 ino 2 size 127 off 0
[ 127816.9780] RPLY: read fh 1 ino 2 len 16
[ 127816.9781] FUSE: flush fh 1 ino 2
[ 127816.9781] RPLY: flush fh 1 ino 2
[ 127816.9781] FUSE: release fh 1 ino 2
[ 127816.9782] RPLY: release fh 1 ino 2
fuse没有使用getattr来获取文件信息。read请求直接跳过了page cache。此时用户可以读取到内容。
开启direct io的方法,是在open的时候,回复FOPEN_DIRECT_IO标志。
libfuse只要设置
struct fuse_file_info *fi
fi.direct_io = 1
即可。
参考
https://docs.kernel.org/filesystems/fuse-io.html