用户空间文件系统FUSE源码解析

FUSEsourceforge上的一个开源项目。包含一个内核的服务模块一个用于用户空间开发的lib。它完成和内核fuse模块通信的功能,并为开发者提供友好的接口。

 

http://fuse.sourceforge.net/

 

首先,从kernel模块说起,本文以2.7.4 版本为例

 

kernel/inode.c

 

1144: module_init(fuse_init);

1145: module_exit(fuse_exit)

 

这两行注册了模块fuse.ko的初始化和退出时的钩子函数。退出没什么好说的,来看看初始化fuse_init

 

主要流程:

fuse_fs_init(); //用于截获用户的文件系统调用,包括open/read/write等等

fuse_dev_init(); //创建设备文件/dev/fuse,这个文件主要是用来完成内核和用户空间的通信

fuse_sysfs_init(); //注册fuse的信息到sysfs

fuse_ctl_init(); //创建一个控制文件系统,用于查看某个连接的请求情况或者强制结束一个连接。

 

初始化函数给了我们一些基本的概念,下面介绍一下fuse实现的基本原理。

 

首先,我们用libfuse开发的用户空间文件实现,其实只是实现了一个文件系统调用的回调函数。(怎么使用libfuse开发用户空间文件系统可以参考其demo)

当我们运行我们的实现程序时,libfuse内部会进行mount操作,并且挂载的文件系统类型就是fuse,那么在挂载目录下的文件访问活动都会被fuse_fs_init函数中注册的fuse文件系统捕获并处理。

 

fuse文件系统是在内核空间捕获到这些文件调用的(事实上就是vfs根据挂载点信息找到并分派给它的)。它怎么把请求传递到用户空间,供我们的回调钩子函数处理呢?

这里fuse利用了fuse_dev_init这个函数注册的设备/dev/fuse。

首先,fuse fs捕获到文件操作请求后,直接将请求写入一个内核请求队列,然后在一个事件上等待,直到请求结束时wakeup。其次,我们重新考察libfuse的实现。在我们运行我们用户空间的自定义文件系统时,libfuse除了前面说的进行mount之外,还在用户空间打开了/dev/fuse这个设备文件,并启动一个线程循环地读取/dev/fuse设备的数据。而用户空间对/dev/fuse的read调用,转化为内核空间fuse dev的ops->read,即fuse_dev_read。这个函数直接从前面提到的fuse fs写入的请求队列读取请求,返回给用户空间即可。这时,libfuse在用户空间获得了请求,并通过回调调用用户实现的钩子函数来处理请求。

用户处理完请求之后的结果,又通过写入设备/dev/fuse的方式传入到内核空间,fuse_dev_write函数响应用户的反馈,将相应的数据交给原先等待的fuse fs请求,fuse fs再返回到vfs,最终反馈给用户空间的调用者。

 

后面的sysfs和ctlfs都是一些辅助功能原理类似,这里就不多做介绍了。

 

你可能感兴趣的:(用户空间文件系统FUSE源码解析)