FUSE-用户空间文件系统(Filesystem in Usese Space)
2009-11-22 11:26:16 阿炯

用户空间文件系统(Filesystem in Usese Space,简称FUSE)是操作系统中的概念,指完全在用户态实现的文件系统,FUSE提供了在用户空间的程序中实现文件系统的接口。目前Linux通过内核模块对此进行支持。一些文件系统如ZFS,glusterfs和luster使用FUSE实现。

Linux用于支持用户空间文件系统的内核模块名叫FUSE,FUSE一词有时特指Linux下的用户空间文件系统。

文件系统是一个通用操作系统重要的组成部分。传统上操作系统在内核层面上对文件系统提供支持;而通常内核态的代码难以调试,生产率较低。

FUSE结构
FUSE主要是由以下的三部分构成。
* 内核模块fuse
* 用户空间库libfuse
* mount/umount程序fusermount

用户空间进程在实行操作文件的系统调用的时候,在内核空间,VFS就会调用各文件系统定义的对应操作函数。FUSE内核模块中被定义的操作函数是把,和它对应的请求送到实现文件系统的用户空间进程(FUSE文件系统.后台程序),并等待回应。FUSE内核模块和FUSE文件系统.后台程序间的通信是通过设备文件/dev/fuse进行的。FUSE文件系统.后台程序把定义的FUSE操作函数群的地址登录到fuse_operations结构体中,并通过把fuse_operations的地址作为参数,调用fuse_main()函数。

在库函数fuse_main()中,实行以下的动作。
1. 打开设备文件/dev/fuse

2. 挂载FUSE文件系统

3. 做成FUSE文件系统句柄

4. 登录FUSE操作函数到FUSE文件系统句柄中

5. 登录信号处理器

6. 实行事件循环
A) 从设备文件/dev/fuse中读取来自内核模块的请求
B) 实行和这个请求对应的操作函数
C) 写入返回给内核模块的应答到设备文件/dev/fuse中

7. 卸载FUSE文件系统
现在,API库里已经定义了31个接口(getattr,readlink,getdir,mknod,mkdir,unlink,rmdir,symlink,rename,link,chmod,chown,truncate,utime,open,
read,write,statfs,flush,release,fsync,setxattr,getxattr,listxattr,removexattr,opendir,readdir,releasedir,
fsyncdir,init,destroy),它们可以被任意使用,FUSE文件系统,后台程序实际上是否真的实现是自由的。并且它们的大部分是把文件的路径作为第一个参数。

Linux从2.6.14版本开始通过FUSE模块支持在用户空间实现文件系统。在用户空间实现文件系统能够大幅提高生产率,简化了为操作系统提供新的文件系统的工作量,特别适用于各种虚拟文件系统和网络文件系统,ZFS和glusterfs都属于网络文件系统。但在用户态实现文件系统必然会引入额外的内核态/用户态切换带来的开销,对性能会产生一定影响。

Linux中FUSE的运行机制

目前Linux,FreeBSD,NetBSD,OpenSolaris和Mac OSX支持用户空间态文件系统,比较知名的用户空间文件系统
* ExpanDrive: 商业文件系统,实现了SFTP/FTP/FTPS协议;
* GlusterFS: 用于集群的分布式文件系统,可以扩展到PB级;
* SSHFS: 通过SSH协议访问远程文件系统;
* GmailFS: 通过文件系统方式访问GMail;
* EncFS: 加密的虚拟文件系统
* NTFS-3G和Captive NTFS, 在非Windows中对NTFS文件系统提供支持;
* WikipediaFS : 支持通过文件系统接口访问Wikipedia上的文章;
* Sun公司的Lustre: 和GlusterFS类似但更早的一个集群文件系统
* ZFS: Luster的Linux版;
* archivemount:
* HDFS: Hadoop提供的分布式文件系统。HDFS可以通过一系列命令访问,并不一定经过Linux FUSE;

With FUSE it is possible to implement a fully functional filesystem in a userspace program.  Features include:
* Simple library API
* Simple installation (no need to patch or recompile the kernel)
* Secure implementation
* Userspace - kernel interface is very efficient
* Usable by non privileged users
* Runs on Linux kernels 2.4.X and 2.6.X
* Has proven very stable over time

How does it work?
The following figure shows the path of a filesystem call  (e.g. stat) in the above hello world example:

The FUSE kernel module and the FUSE library communicate via a special file descriptor which is obtained by opening /dev/fuse.  This file can be opened multiple times, and the obtained file descriptor is passed to the mount syscall, to match up the descriptor with the mounted filesystem.

在centos下对其的安装分体系架构而不同,先看x64的安装过程:
[root@smail ~]# rpm -aq|grep kernel
kernel-module-openafs-2.6.18-92.1.6.el5-1.4.7-68.2.SL5.i686
kernel-headers-2.6.18-92.1.6.el5.i386
kernel-module-fuse-2.6.18-92.1.6.el5-2.6.3-1.sl5.i686
kernel-devel-2.6.18-92.1.6.el5.i686
kernel-2.6.18-92.1.6.el5.i686

查看所安装的kernel包中,有没有安装kernel-devel这个包,没有则安装之;其次还要注意的是其版本一定要和主kernel版本完全一致(2.6.18-92.1.6.el5)。否则即使安装成功了fuse相关包后亦不能正常加载fuse模块。

如果通过yum查找不到,则可到rpm 相关下载站上进行搜索下载。在x64的机器上可能通过安装如下的软件包来实现fuse的加载:
#yum install fuse fuse-libs.x86_64 fuse-devel.x86_64 dkms-fuse.noarch

而在x86的机器上操作如下:
#yum install fuse.i386 fuse-devel.i386 fuse-libs.i386

当然debian系列的操作系统就更好安装了,安装其基本包及开发包就可以了。

FAQ
---------------------
关于这两个模块(FUSE、LUFS)的不同和为什么又开始了新的工程,说明一下好吗?

从SourceForge 上发布的日期来看,FUSE的最初发布比LUFS还要早一年。但在相当长的时间内,它们之前都没有相互注意。

在LUFS里,文件系统是根据lufsmount被载入的共享对象(.so),而在FUSE里,文件系统是使用fuse库的各自实行可能的对象,这就是他们之间所谓的区别。实际的API都非常相似,都是载入LUFS模块/使用FUSE内核模块,然后能实行API(参照FUSE页的lufis)。并且,LUFS在缓存目录和文件属性这一点上有一些不同。FUSE不是那样做的,但它提供了简单的接口。

---------------------
fuse_operations结构体里没有close()函数?

close()函数没有包含在fuse_operations结构体里有理由吗?大概得有必要知道什么时候文件被关闭吧。

这并不简单。请考虑一下mmap()函数。把文件映射到内存里后,即使关闭了文件,那通过内存地址也能对这个文件进行读写操作。然而,close()相似的函数还有flush和release函数。flush是 调用close(),release是包含内存映射的文件不再使用的时候在被调用的。

---------------------
FUSE为什么不支持ioctl。

因为对于规则文件实行ioctl没有什么意义,对于设备文件,文件系统的实现基本上不关心ioctl,所以怎么样使用它还不是很清楚。例如,为了支持设备ioctl即使做了一些改良,因为它们包含任意的结构化的数据(不是读/写场合的那些长度),对于它们好像什么也不能做。

使用getxattr()和setxattr()的话,跟ioctl()比起来也是没有问题,这些都在fuse-2.0里已经实现了。

该文章最后由 阿炯 于 2022-10-11 22:27:24 更新,目前是第 4 版。