ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

用户态文件系统fuse学习

2021-04-16 13:52:10  阅读:280  来源: 互联网

标签:调用 函数 文件系统 用户 fuse 内核 dir


FUSE概述

FUSE(用户态文件系统)是一个实现在用户空间的文件系统框架,通过FUSE内核模块的支持,使用者只需要根据fuse提供的接口实现具体的文件操作就可以实现一个文件系统。
在fuse出现以前,Linux中的文件系统都是完全实现在内核态,编写一个特定功能的文件系统,不管是代码编写还是调试都不太方便,就算是仅仅在现有传统文件系统上添加一个小小的功能,因为是在内核中实现仍需要做很大的工作量。在用户态文件系统FUSE出现后(2.6内核以后都支持fuse),就会大大的减少工作量,也会很方便的进行调试。编写FUSE文件系统时,只需要内核加载了fuse内核模块即可,不需要重新编译内核。
FUSE 特点

  1.     用户空间文件系统——类Unix OS的框架
  2.     允许非超户在用户空间开发文件系统
  3.     内核的API接口,使用fs-type操作
  4.     支持多种编程语言( c、c++、perl、java 等)
  5.     普通用户也可以挂载FUSE
  6.     不用重新编译内核

FUSE组成

fuse主要由三部分组成:FUSE内核模块、用户空间库libfuse以及挂载工具fusermount。

  1.     fuse内核模块:实现了和VFS的对接,实现了一个能被用户空间进程打开的设备,当VFS发来文件操作请求之后,将请求转化为特定格式,并通过设备传递给用户空间进程,用户空间进程在处理完请求后,将结果返回给fuse内核模块,内核模块再将其还原为Linux kernel需要的格式,并返回给VFS;
  2.     fuse库libfuse:负责和内核空间通信,接收来自/dev/fuse的请求,并将其转化为一系列的函数调用,将结果写回到/dev/fuse;提供的函数可以对fuse文件系统进行挂载卸载、从linux内核读取请求以及发送响应到内核。libfuse提供了两个APIs:一个“high-level”同步API 和一个“low-level” 异步API 。这两种API 都从内核接收请求传递到主程序(fuse_main函数),主程序使用相应的回调函数进行处理。当使用high-level API时,回调函数使用文件名(file names)和路径(paths)工作,而不是索引节点inodes,回调函数返回时也就是一个请求处理的完成。使用low-level API 时,回调函数必须使用索引节点inode工作,响应发送必须显示的使用一套单独的API函数。
  3.     挂载工具:实现对用户态文件系统的挂载

FUSE主要代码文件
in kernel:

  1.     kernel/inode.c —> 主要完成fuse文件驱动模块的注册,提供对supper block的维护函数以及其它(驱动的组织开始文件)
  2.     kernel/dev.c —> fuse 的(虚拟)设备驱动
  3.     kernel/control.c —> 提供对于dentry的维护及其它
  4.     kernel/dir.c —> 主要提供对于目录inode索引节点的维护
  5.     kernel/file.c —> 主要提供对于文件inode索引节点的维护

in userspace:

  1.     lib/helper.c —> “fuse_main()”调用的主入口
  2.     lib/fuse_kern_chan.c—>主要实现fuse应用层访问(读写)fuse driver的功能
  3.     lib/fuse_mt.c —> fuse 的mount管理
  4.     lib/fuse.c —> lib库主框架文件,实现了主要框架及对”用户实现的文件系统操作代码”的封装
  5.     lib/fuse_lowlevel.c –> 实现比较底层的函数封装,供fuse.c等使用
  6.     lib/fuse_loop.c —> fuse lib循环监视”fuse driver”的通信缓存
  7.     lib/fuse_loop_mt.c —> 同fuse_loop.c
  8.     lib/fuse_session.c —> fuse会话管理

Fuse是怎么工作的(fuse-2.9)?
1. fuse库

    1.在用户态程序调用fuse_main() (lib/helper.c)时,先调用fuse_setup_common()该函数先解析用户态程序传递过来的参数,然后调用fuse_mount_common()(该函数是fuse_kern_mount()函数的封装,lib/mount.c)。
    fuse_main()是一个宏定义(include/fuse.h),如下:

 

#define fuse_main(argc, argv, op, user_data)                            \

        fuse_main_real(argc, argv, op, sizeof(*(op)), user_data)

 

    2.fuse_kern_mount()函数中调用fuse_mount_fusermount()使用socketpair()创建一个UNIX域套接字,然后使用创建子进程执行fusermount程序,将FUSE_COMMFD_ENV环境变量中套接字的一端传递给它。
    3.fusermount(util/fusermount.c)确保fuse 模块已经被加载,然后打开/dev/fuse并通过一个UNIX套接字发送文件处理句柄。父进程等待子进程执行完毕回收,然后返回fuse_mount_fusermount()函数。
    4.fuse_kern_mount()通过/dev/fuse返回文件句柄给fuse_kern_chan_new()负责处理内核数据,然后返回到fuse_mount_common()函数。
    5.fuse_setup_common()函数调用fuse_new_common(lib/fuse.c),fuse_new_common()函数分配fuse数据结构,存储并维护一个文件系统数据镜像缓存cached,返回到fuse_main()。
    6.最后,fuse_main()调用fuse_loop(lib/fuse.c)或者fuse_loop_mt()(lib/fuse_mt.c),这两个函数都可以从设备/dev/fuse读取文件系统调用,调用fuse_main()之前调用存储在fuse_operations结构体中的用户态函数。这些调用的结果回写到/dev/fuse设备(这个设备可以转发给系统调用)。


2.内核模块

内核模块由2个部分组成:

第一个是proc文件系统组件(在kernel/dev.c中);

第二个是文件系统调用(kernel/file.c、kernel/inode.c、kernel/dir.c)。
kernel/file.c、kernel/inode.c、kernel/dir.c中的所有系统调用要么调用request_send(),要么调用request_send_noreply()或者request_send_nonblock()。大部分都是调用request_send()函数,它添加请求到“list of request”结构体(fc->pending),然后等待一个响应。request_send_noreply()和request_send_nonblock()与request_send()函数相似,除了是非阻塞的和不响应一个回复。
kernel/dev.c中的proc文件系统组件响应文件IO请求,fuse_dev_read()处理文件读,并从请求列表结构体(list of requests)返回命令到调用程序。fuse_dev_write()处理文件写, 完成数据写并放入req->out结构体(它能返回系统调用通过请求列表结构体和request_send()函数),


用户进程和操作系统进行交互(read文件为例):

该fuse文件系统挂载在现有ext4文件系统之上.

1.一个用户进程发出read文件请求;
2.该请求被转换为一个内核系统调用,内核VFS层调用fuse文件系统内核模块;
3.fuse 内核模块通过/dev/fuse,将read请求传递到fuse 用户态进程;
4.fuse daemon根据用户实现的read接口,产生新的系统调用,最终调用ext4文件系统的read操作函数,从存储介质中提取读操作要求的数据(page cache中有,直接从其中获取,否则读磁盘);
5.内核将数据返回给fuse文件系统;
6.用户级文件系统再次调用内核操作,把数据返回给用户进程;
7.内核将数据传给用户进程完成操作。
库函数fuse_main()具体处理流程:

1.先打开设备文件/dev/fuse;
2.然后挂载FUSE文件系统;
3.产生FUSE文件系统指针;
4.初始化FUSE文件系统的操作函数集:
5.初始化信号处理函数集;
6.进入等待循环:
从设备文件/dev/fuse中读取来自内核模块的请求;
运行相应的操作函数,并获取返回结果;
将返回给内核的应答结果写入设备文件/dev/fuse中;
注意

fuse本质上(数据处理时)是处于现有文件系统之上的(具体实现是和现有文件系统处于同一个层次的),fuse不参与底层磁盘数据的存取,只负责处理对读取和写入的数据在逻辑上的操作而已。
安装使用fuse

软件包下载https://github.com/libfuse/libfuse/releases:
下载软件包,解压后,编译安装。

 

./configure
make
make install

 

解压后的目录中有名为example的目录,其中有fuse自带的几种fuse用户态实现例子,可以运行其进行测试。
fuse安装完后,该目录中的文件也已经编译成功,只需运行即可(目录dir为挂载点,挂载成功后,在该目录中对文件的操作就会调用fuse自己实现的操作函数):

 

   

    
//example/hello.c 部分代码,主要实现文件系统的取文件属性、打开目录、读文件、打开文件   

static struct fuse_operations hello_oper = {    //文件操作函数,为回调函数

        .getattr        = hello_getattr,
        .readdir        = hello_readdir,
        .open           = hello_open,
        .read           = hello_read,
};  
int main(int argc, char *argv[])
{
        return fuse_main(argc, argv, &hello_oper, NULL); //主函数,会调用文件操作结构体

}
 

ty@ubuntu:~/program/fuse/fuse-2.9.6/example/dir$ mkdir dir    //创建挂载点
ty@ubuntu:~/program/fuse/fuse-2.9.6/example/dir$ ./hello dir   //将hello fuse文件系统挂载在dir目录上

 

根据目前实现的四个功能进行测试如下:

ty@ubuntu:~/program/fuse/fuse-2.9.6/example/dir$ ls
hello 
ty@ubuntu:~/program/fuse/fuse-2.9.6/example/dir$ cat hello
Hello World!
ty@ubuntu:~/program/fuse/fuse-2.9.6/example/dir$ ls -l hello
-r--r--r-- 1 root root 13 12月 31  1969 hello
ty@ubuntu:~/program/fuse/fuse-2.9.6/example/dir$ rm -fr hello
rm: cannot remove ‘hello’: Function not implemented
    
ty@ubuntu:~/program/fuse/fuse-2.9.6/example/dir$ touch test
touch: cannot touch ‘test’: Function not implemented
ty@ubuntu:~/program/fuse/fuse-2.9.6/example/dir$ mkdir test
mkdir: cannot create directory ‘test’: Function not implemented

       

 

由测试可以发现在dir目录中只能对文件进行实现的四个功能的操作,其他的操作都无法完成,会提示用户函数没有实现。

ty@ubuntu:~/program/fuse/fuse-2.9.6/example/$ dirfusermount -u dir //卸载fuse文件系统dir



标签:调用,函数,文件系统,用户,fuse,内核,dir
来源: https://blog.51cto.com/u_15169172/2710908

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有