FUSE需求
究竟什么样的需求才能用到用户文件系统?
来看一个小例子:
需求是这样的。在deepin的安装器中,安装器就会给多分出一个分区:数据盘。
数据盘的主要作用是让用户存放数据文件,也就是以前用Windows的时候D盘或者E盘等的作用,放点图片、视频资源等。用户重装系统的时候,也可以方便的做数据迁移。这个数据盘大概隐含隐性需求:
- 文件权限不要太严格;
$ setfacl -d -m "g:sudo:rwx" /xxx
$ setfacl -m "g:sudo:rwx" /xxx
主要差别体现在ACL规则的继承上面,上面一句默认继承
Linux(可能其他系统也是)对ACL的处理有点奇怪,假如在拥有ACL规则的对象(文件或者文件夹)上进行chmod操作,那么chmod 会对对象的ACL规则造成影响,影响的结果就是对象虽然有ACL规则,但是ACL的有效值会变成chmod要达成的效果。
$ getfacl testacl
# file: testacl
# owner: hualet
# group: hualet #chmod 700 testacl
user::rwx
group::r-- #effective:---
group:sudo:rwx #effective:---
mask::---
other::---
造成的问题:系统里面的A用户放在数据盘里面的文件B用户怎么无法访问
FUSE(Filesystem in Userspace)就是用户空间的文件系统,它的出现让非内核开发者开发自己的文件系统成为可能,非特权用户不需要获取特权就可以挂载自己的文件系统。对于开发者来说,FUSE更多是一个开发框架,用来开发和实现用户空间系统,这个框架主要分为三个部分:内核模块、libfuse和文件系统守护进程,它们之间的关系如下图所示:
图中的./hello就是文件系统守护进程,/tmp/fuse则是这个文件系统的挂载点。文件系统工作在用户空间,通过libfuse跟内核中的FUSE模块进程通信,代理所有用户对挂载点内文件的访问请求,从而实现特殊的文件系统功能需求。
举个例子,sshfs就是一种用户空间文件系统,用来将ssh服务器上的一个文件夹挂载到本地使用。它的使用方式特别简单,只需执行命令:sshfs [user@]host:[dir] mountpoint,这样你在mountpoint下看到的文件的文件就是你ssh服务器上相应文件夹的文件,你再本地做得修改也都会在你的ssh服务器上体现出来。
因为libfuse使用起来非常方便,所以有不少有意思的文件系统都是基于FUSE完成的(见FUSE Filesystems)。类似上面的sshfs可能更像是开发者的一个玩具,但是FUSE家族也不缺乏一些重量级的文件系统,像ZFS和NTFS等也是基于FUSE实现的。这么说并不是在FUSE完美无瑕,实际上很多人批评FUSE的性能比较差,据To FUSE or Not to FUSE: Performance of User-Space File Systems这篇论文测算,FUSE文件系统在吞吐量上比原生的文件系统要低83%,而CPU占用则要高31%。
资料直通车:Linux内核源码技术学习路线+视频教程内核源码
学习直通车:Linux内核源码内存调优文件系统进程管理设备驱动/网络协议栈
Extfuse提出背景
EXTFUSE与现有的用户文件系统框架协同工作,允许快速路径和现有的慢速路径共存,而不会对目标用户文件系统的设计进行重大更改
fuse 文件挂载的小例子:
Fuse 包含两个部分 - kernel 和用户态 daemon。内核部分是一个 Linux 的内核模块,它会在 Linux 的 VFS 上面注册一个 Fuse 的文件系统驱动。这个 Fuse 驱动可以认为是一个 proxy,会将请求给转发到后面的用户态 daemon 上面。
Fuse 内核模块也会注册一个 /dev/fuse 的块设备,这个就是 kernel 和用户态 daemon 交互的接口。通常 Daemon 会从 /dev/fuse 上面读取到 Fuse 的请求,处理并且将数据写回到 /dev/fuse。一个简单的 Fuse 流程如下:
- 应用程序在挂载的 Fuse 的文件系统上面进行操作。
- VFS 会将操作转发到 Fuse 的 kernel driver 上面。
- Fuse 的 kernel driver 分配一个 request,并且将这个 request 提交到 Fuse 的 queue 上面。
- Fuse 的用户态 daemon 会从 queue 里面通过读取 /dev/fuse 将这个 request 取出来并且处理。这里需要注意,处理 request 的时候仍然可能进入 kernel,譬如可能将 request 发到 Ext4 去实际处理。
- 当请求处理完毕,Daemon 会将结果写回到 /dev/fuse。
- Fuse 的 kernel 标记这个 request 结束,然后唤醒用户应用程序。
EXTFUSE由三个组件组成。首先是一个帮助器用户库,它提供了一组熟悉的文件系统API来注册扩展并实现C语言子集的定制快速路径功能。其次,包装器(no-op)插入驱动程序,该驱动程序与低级VFS接口连接,并提供必要的支持,以便根据需要将请求转发到已注册的内核扩展以及较低的文件系统。第三,安全地执行扩展的内核内的虚拟机(VM)运行时。
慢速路径:开销大,红色的切换
快速路径:开销小,迅速切换
工作流程:
1.挂载阶段:在挂载用户文件系统时,FUSE驱动程序向用户空间守护进程发送FUSE_INIT请求。(1&&4)
2.用户守护进程通过在请求参数中查找FUSE_CAP_EXTFUSE标志来检查操作系统内核是否支持EXTFUSE框架。如果支持,守护程序必须调用libExtFUSE init API将包含专用处理程序(扩展)的eBPF程序加载到内核中,并将其注册到EXTFUSE驱动程序。这是使用bpf_Load_prog系统调用来实现的,该系统调用eBPF验证器来检查扩展的完整性。
复现进度
extfuse已完成,开始SandFs
接下来的计划
全过程追踪(就是把extfuse的路程图与代码对应起来)
1.Extfuse Library:extfuse/src at master · extfuse/extfuse · GitHub
2.Modified:ExtFUSE: Extension Framework for FUSE · extfuse/linux@b7923d6 · GitHub
3.libfuse: Add support for detecting/enabling ExtFUSE · extfuse/libfuse@7c88efb · GitHub
Comparing libfuse:master...extfuse:ExtFUSE-1.0 · libfuse/libfuse · GitHub
性能分析(论文中提到了很多性能的对比)
1.可以尝试将eBPF开源项目中已有的文件性能测试相关的代码单独抽取出来做demo