学习完了fuse的内核实现,我们真实的来看怎么实现一个简单的fuse文件系统,我们还是以之前的例子,对于用户空间需要实现基于libfuse实现的应用程序hello,例子可以参考http://fuse.sourceforge.net/helloworld.html
首先,我们需要编译libfuse,其可以参考下面的github,里面有编译的相关方法
1 libfuse库测试
libfuse的仓库地址为:https://github.com/libfuse/libfuse
使用其方法编译安装完成如下图所示,表示libfuse库已经安装到我们的系统中
libfuse提供了两个APIs:
- 一个“high-level”同步API
- 一个“low-level” 异步API
这两种API 都从内核接收请求传递到主程序(fuse_main函数),主程序使用相应的回调函数进行处理。
- 当使用high-level API时,回调函数使用文件名(file names)和路径(paths)工作,而不是索引节点inodes,回调函数返回时也就是一个请求处理的完成。
- 使用low-level API 时,回调函数必须使用索引节点inode工作,响应发送必须显示的使用一套单独的API函数
low-level api 相对于 high-level api 来说,有更好的自由度;high-level相对于 low-level api 则有更简单的api使用,如果阅读过fuse源码过后,使用low-level api将使得可控性更强。
- 一种是high-level模式,此模式下fuse的入口函数为fuse_main,它封装了一系列初始化操作,使用简单,但是不灵活。
- 另一种是low-level模式,用户可以利用fuse提供的底层函数灵活开发应用程序。
libfuse的简单示例
刚才上面提到了两个API,一个high-level API
,一个是low-level API
,libfuse 提供了两个示例程序:
- High-Level API example: https://github.com/libfuse/libfuse/blob/fuse_2_9_bugfix/example/hello.c
- Low-Level API example: https://github.com/libfuse/libfuse/blob/fuse_2_9_bugfix/example/hello_ll.c
这里学习了解一下High-Level
,接下来进行一个简单的测试:
gcc -Wall hello.c `pkg-config fuse3 --cflags --libs` -o hello
然后进行挂载
cd /mnt
mkdir hello_test //建立挂载目录
cd libfuse/example
./hello /mnt/hello_test/ //挂载
若显示:
是因为没有配置ldconfig:
vim /etc/ld.so.conf.d/fuse.conf
输入:
/usr/local/lib
执行:
ldconfig
重新挂载:
./hello /mnt/hello_test/
/home/book/fuse/libfuse/example/hello on /home/book/fuse/hello_test type fuse.hello (rw,nosuid,nodev,relatime,user_id=1001,group_id=1001)
现在挂载成功啦!!!其挂载的属性为fuse.hello,这个在VFS分发中将会使用到,那么进入hello_test目录,可以看到hello文件:
cat hello hello
Hello World!
2. fuse用户空间工作原理
首先来看看hello.c中是如何启动fuse deman的,其入口为,重点是fuse_main接口
int main(int argc, char *argv[])
{
int ret;
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
/* Set defaults -- we have to use strdup so that
fuse_opt_parse can free the defaults if other
values are specified */
options.filename = strdup("hello");
options.contents = strdup("Hello World!\n");
/* Parse options */
if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1)
return 1;
/* When --help is specified, first print our own file-system
specific help text, then signal fuse_main to show
additional help (by adding `--help` to the options again)
without usage: line (by setting argv[0] to the empty
string) */
if (options.show_help) {
show_help(argv[0]);
assert(fuse_opt_add_arg(&args, "--help") == 0);
args.argv[0][0] = '\0';
}
ret = fuse_main(args.argc, args.argv, &hello_oper, NULL);
fuse_opt_free_args(&args);
return ret;
}
fuse为开发者提供了两组接口,分别是fuse_lowlevel_ops以及fuse_operations,开发者只需要实现
这两组接口的一种即可实现一个用户空间文件系统。
static struct fuse_lowlevel_ops fuse_path_ops = {
.init = fuse_lib_init,
.destroy = fuse_lib_destroy,
.lookup = fuse_lib_lookup,
.forget = fuse_lib_forget,
.forget_multi = fuse_lib_forget_multi,
...