目录
有参考 -- FUSE介绍 | 成长录-知行合一
fuse
引入
内核态文件系统存在的问题
早期的文件系统是内核的一个模块,它位于vfs之下,块设备之上
- 其调用流程为:
- 它将上层请求一层层转发,最终到达物理层,然后进行操作;操作完后通过原路径,将响应返回给yon
作为内核模块,它开发最难的就是调试和排障
- 用户态的程序你可以随意 debug,最多就是程序崩溃
- 而内核态的程序出了问题就是死机,只能重启机器,然后通过dmesg命令看日志信息
- (我之前想要将一个程序改写成内核模块,结果程序没有按照我预想的打印出信息,所以也不知道它到底执行了没,卸载也卸不掉,只能重启,可麻烦)
需求
因为用户空间的需求多样,而内核提供的功能固定单一,所以为了迎合用户的需求,就需要引入用户空间驱动的概念
- 开发者可以通过编写用户空间驱动来支持需要的特性
介绍
框架组件
fuse是一个用户空间文件系统的框架
该框架包括以下组件:
- 这三个组件帮助我们在用户态实现文件系统,并且让io可以在内核态/用户态文件系统之间自由穿梭
和内核模块的对比
通过fuse实现出的文件系统的核心逻辑是在用户空间实现的,而不依赖于内核模块的形式
- fuse是基于用户空间驱动实现的,编写和运行都类似于普通的用户程序
而传统的文件系统是内核驱动式
- 内核驱动是使用了内核中的函数和头文件,以内核模块的形式,编译到内核空间中,然后通过insmod和rmmod手动加载和卸载
- 所以,使用用户空间驱动,可以更灵活地编写和运行底层功能,它允许开发人员创建自定义文件系统而无需修改内核代码
但会损耗一部分性能,毕竟增加了内核态和用户态之间的切换
机制
远端服务的文件系统挂载到本地
如果我们想要让远端的某个服务挂在到本地的文件系统里,想像访问本地文件一样访问远端存储文件
- 我们可以实现一个用户空间的fuse驱动,将远端文件系统挂载到本地某个目录下
- 就可以在该目录里,访问远端文件了
自定义文件系统
也可以自主实现一个fuse用户空间驱动,来满足业务上的需求
- 这种自定义文件系统可以根据业务需求实现各种特定功能,如加密、压缩、版本控制等。
- 这个fuse驱动程序可以通过与用户态应用程序的交互,实现对文件系统的各种操作,并将这些操作转换为对底层存储的相应操作
调用流程
利用原本内核中的vfs文件系统框架
- 将针对fuse文件系统的请求发给fuse驱动
- 然后内核驱动发给基于fuse library实现的fuse用户空间驱动(fuse守护进程),该驱动来实际处理用户请求
- 最后将结果通过原路径返回给用户
简化版的流程:
总之,我觉得和内核态文件系统的逻辑差别不大
- 都是让vfs作为中转站
- 都是由具体文件系统完成文件操作
只是用户态文件系统在处理时,可能会多出一些步骤
fuse内核驱动
fuse.ko是这个内核模块的名字
- 也就是图中的fuse driver模块
- 它会接收VFS下来的IO请求,然后封装成 FUSE 数据包(这个数据包的封装和解析基于libfuse库完成),通过/dev/fuse这个管道(设备节点)转发给用户态
- 在此之前有守护进程监听这个管道,看到有消息出来之后,立马读出来,然后利用libfuse库解析协议
- 之后就是用户文件系统的代码逻辑了
图解如下:
用户态文件系统
指文件内容和文件属性都是由用户态的进程提供的(守护进程),也就是这里的fuse用户空间驱动
挂载卸载操作
挂载
- 二进制文件名 + 挂载目录名
可以查看挂载后的目录的文件系统类型
卸载
fusermount -u 挂载目录名
注意卸载时,一定要保证没有进程访问该目录及其子文件
梳理
普通的访问本地文件系统,步骤很少
- 只需要经历vfs的转发,去访问实际的文件系统类型
- 然后实际的文件系统类型(如EXT4、NTFS等)收到请求后,会执行相应的操作
但如果要访问用户态文件系统,需要经历更多的路径,以及更多的内核态和用户态之间的切换
- 它虽然也同样被vfs转发到fuse的内核驱动中,但它的下一步并不是交给他就行了,而是需要转发给用户态的fuse驱动,它去进行实际的操作
- 而它的操作相当于就是一次访问本地文件系统
- 所以,它多了很多中间步骤
- 虽然增加了文件操作的自由性(因为是由我们去自主定义文件操作)
- 但因此失去的性能也不容小觑: