用户空间文件系统(FUSE)

简介:

转载自:http://blog.chinaunix.net/uid-8350672-id-2031702.html

 

一、FUSE简介


FUSE(用户空间文件系统)是这样一个框架,它使得FUSE用户在用户态下编写文件系统成为可能,而不必和内核打交道。FUSE由三个部分组成,linux内核模块、FUSE库以及mount 工具。用户关心的只是FUSE库和mount工具,内核模块仅仅提供kernel的接入口,给了文件系统一个框架,而文件系统本身的主要实现代码位于用户空间中。 FUSE库给用户提供了编程的接口,而mount工具则用于挂在用户编写的文件系统。

 

FUSE起初是为了研究AVFS(A Virtual Filesystem)而设计的,而现在已经成为SourceForge的一个独立项目,目前适用的平台有Linux, FreeBSD, NetBSD, OpenSolaris和Mac OS X。官方的linux kernel版本到2.6.14才添加了FUSE模块,因此2.4的内核模块下,用户如果要在FUSE中创建一个文件系统,需要先安装一个FUSE内核模块,然后使用FUSE库和API来创建。

 

二、FUSE特性


? 库文件和 API简单,极大地方便了用户的使用

? 安装简便,不需要加补丁或者重新编译 kernel

? 执行安全,使用稳定

? 高效,相对于其它用户态文件系统实例

? 非特权用户可以使用

? 基于 linux2.4.x 和 2.6.x 内核,现在可以支持JavaTM 绑定,不必限定使用C和C++来编 写文件系统

 

三、源代码目录


? ./doc 包含FUSE相关文档

? ./include 包含了FUSE API头,对创建文件系统有用,主要用fuse.h

? ./lib 存放FUSE库的源代码

? ./util 包含了FUSE工具库的源代码

? ./example 参考的例子

 

四、安装


FUSE的源码安装类似于其他软件,只需要在FUSE的源码目录下执行如下命令即可:

1
2
3
. /configure
make
make  install (以root身份执行)

 

五、FUSE operations


FUSE使用fuse_operations来给用户提供编程结构,让用户通过注册自己编写的函数到该结构体来实现自己的文件系统。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
struct  fuse_operations {
int  (*getattr) ( const  char  *,  struct  stat *);
int  (*readlink) ( const  char  *,  char  *,  size_t );
int  (*mknod) ( const  char  *, mode_t, dev_t);
int  (*mkdir) ( const  char  *, mode_t);
int  (*unlink) ( const  char  *);
int  (*rmdir) ( const  char  *);
int  (*symlink) ( const  char  *,  const  char  *);
int  (* rename ) ( const  char  *,  const  char  *);
int  (*link) ( const  char  *,  const  char  *);
int  (*chmod) ( const  char  *, mode_t);
int  (*chown) ( const  char  *, uid_t, gid_t);
int  (*truncate) ( const  char  *, off_t);
int  (*utime) ( const  char  *,  struct  utimbuf *);
int  (*open) ( const  char  *,  struct  fuse_file_info *);
int  (*read) ( const  char  *,  char  *,  size_t , off_t,  struct  fuse_file_info *);
int  (*write) ( const  char  *,  const  char  *,  size_t , off_t,  struct  fuse_file_info *);
int  (*statfs) ( const  char  *,  struct  statvfs *);
int  (*flush) ( const  char  *,  struct  fuse_file_info *);
int  (*release) ( const  char  *,  struct  fuse_file_info *);
int  (*fsync) ( const  char  *,  int struct  fuse_file_info *);
int  (*setxattr) ( const  char  *,  const  char  *,  const  char  *,  size_t int );
int  (*getxattr) ( const  char  *,  const  char  *,  char  *,  size_t );
int  (*listxattr) ( const  char  *,  char  *,  size_t );
int  (*removexattr) ( const  char  *,  const  char  *);
int  (*opendir) ( const  char  *,  struct  fuse_file_info *);
int  (*readdir) ( const  char  *,  void  *, fuse_fill_dir_t, off_t,  struct  fuse_file_info *);
int  (*releasedir) ( const  char  *,  struct  fuse_file_info *);
int  (*fsyncdir) ( const  char  *,  int struct  fuse_file_info *);
void  *(*init) ( struct  fuse_conn_info *conn);
void  (*destroy) ( void  *);
int  (*access) ( const  char  *,  int );
int  (*create) ( const  char  *, mode_t,  struct  fuse_file_info *);
int  (*ftruncate) ( const  char  *, off_t,  struct  fuse_file_info *);
int  (*fgetattr) ( const  char  *,  struct  stat *,  struct  fuse_file_info *);
int  (*lock) ( const  char  *,  struct  fuse_file_info *,  int  cmd,  struct  flock *);
int  (*utimens) ( const  char  *,  const  struct  timespec tv[2]);
int  (*bmap) ( const  char  *,  size_t  blocksize, uint64_t *idx);
};

 

六、hello示例文件系统源码分析


FUSE在源码目录example下有一些示例文件系统,通过阅读这些示例文件系统可以掌握FUSE用户态文件系统的编写规范。下面以hello.c为例分析FUSE的编写规范:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#define FUSE_USE_VERSION 26
#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
static  const  char  *hello_str =  "Hello World!\n" ;
static  const  char  *hello_path =  "/hello" ;
/*该函数与stat()类似,用于得到文件的属性,将其存入到结构体struct stat中*/
static  int  hello_getattr( const  char  *path,  struct  stat *stbuf)
{
int  res = 0;
memset (stbuf, 0,  sizeof ( struct  stat));  //用于初始化结构体stat
if  ( strcmp (path,  "/" ) == 0) {
stbuf->st_mode = S_IFDIR | 0755;  //S_IFDIR 用于说明/为目录,详见S_IFDIR定义
stbuf->st_nlink = 2;  //文件链接数
else  if  ( strcmp (path, hello_path) == 0) {
stbuf->st_mode = S_IFREG | 0444;  //S_IFREG用于说明/hello为常规文件
stbuf->st_nlink = 1;
stbuf->st_size =  strlen (hello_str);  //设置文件长度为hello_str的长度
else
res = -ENOENT;  //返回错误信息,没有该文件或目录
return  res;  //执行成功返回0
}
/*该函数用于读取/目录中的内容,并在/目录下增加了. .. hello三个目录项*/
static  int  hello_readdir( const  char  *path,  void  *buf, fuse_fill_dir_t filler,
off_t offset,  struct  fuse_file_info *fi)
{
( void ) offset;
( void ) fi;
if  ( strcmp (path,  "/" ) != 0)
return  -ENOENT;
/*
fill的定义:
typedef int (*fuse_fill_dir_t) (void *buf, const char *name,
const struct stat *stbuf, off_t off);
其作用是在readdir函数中增加一个目录项
*/
filler(buf,  "." , NULL, 0);
//在/目录下增加. 这个目录项
filler(buf,  ".." , NULL, 0);
// 增加.. 目录项
filler(buf, hello_path + 1, NULL, 0);
//增加hello目录项
return  0;
}
/*用于打开hello文件*/
static  int  hello_open( const  char  *path,  struct  fuse_file_info *fi)
{
if  ( strcmp (path, hello_path) != 0)
return  -ENOENT;
if  ((fi->flags & 3) != O_RDONLY)
return  -EACCES;
return  0;
}
/*读取hello文件时的操作,它实际上读取的是字符串hello_str的内容*/
static  int  hello_read( const  char  *path,  char  *buf,  size_t  size, off_t offset,
struct  fuse_file_info *fi)
{
size_t  len;
( void ) fi;
if ( strcmp (path, hello_path) != 0)
return  -ENOENT;
len =  strlen (hello_str);
if  (offset < len) {
if  (offset + size > len)
size = len - offset;
memcpy (buf, hello_str + offset, size);
else
size = 0;
return  size;
}
/*注册上面定义的函数*/
static  struct  fuse_operations hello_oper = {
.getattr = hello_getattr,
.readdir = hello_readdir,
.open = hello_open,
.read = hello_read,
};
/*用户只需要调用fuse_main(),剩下的事就交给FUSE了*/
int  main( int  argc,  char  *argv[])
{
return  fuse_main(argc, argv, &hello_oper, NULL);
}

 

终端运行:

1
2
3
~ /fuse/example mkdir  /tmp/fuse  // /tmp 下建立fuse目录,用于挂载hello文件系统
~ /fuse/example $ . /hello  /tmp/fuse  // 挂载hello文件系统
~ /fuse/example ls  -l  /tmp/fuse  // 执行 ls 时,会调用到readdir函数,该函数会添加一个hello 文件
1
2
总用量 0
-r--r--r-- 1 root root 13 1970-01-01 07:00 hello

 

1
2
~ /fuse/example cat  /tmp/fuse/hello  // 执行 cat  hello时,会调用 open 以及 read 函数,将
Hello World! 字符串hello_str中的内容读出

 

1
~ /fuse/example $ fusermount -u  /tmp/fuse  // 卸载hello文件系统


通过上述的分析可以知道,使用FUSE必须要自己实现对文件或目录的操作,系统调用也会最终调用到用户自己实现的函数。用户实现的函数需要在结构体fuse_operations中注册。而在main()函数中,用户只需要调用fuse_main()函数就可以了,剩下的复杂工作可以交给FUSE。

 

wiki::FUSE::

project::FUSE::



















本文转自UltraSQL51CTO博客,原文链接: http://blog.51cto.com/ultrasql/1641974,如需转载请自行联系原作者








相关文章
|
4月前
|
存储 监控 Linux
|
存储 缓存 Linux
sysfs文件系统(1)
sysfs是一种虚拟文件系统,旨在提供一种访问内核数据结构的方法,从而允许用户空间程序查看和控制系统的设备和资源。sysfs文件系统通常被挂载在/sys目录下。sysfs提供了一种以树状结构组织的系统信息的方式,其中每个设备都有一个唯一的目录来表示它自己,其中包含有关设备的各种属性和状态信息的文件。这些文件通常是只读的,但有些也可以用于修改设备的某些设置。sysfs还提供了一个机制来通知用户空间程序有关设备状态更改的信息,从而使其能够对这些更改做出反应。sysfs文件系统被广泛用于Linux内核中,它为开发者提供了一种简单的方式来管理和控制系统中的各种设备和资源。
210 0
|
Linux Windows
7.1.8 其他Linux支持的文件系统与VFS
7.1.8 其他Linux支持的文件系统与VFS
78 0
|
Linux 程序员 Shell
sysfs文件系统与kobject
sysfs文件系统与kobject
177 0
|
Unix Linux 容器
sysfs文件系统(2)
每个内核设备直接或间接嵌入kobject属性。在添加到系统之前,必须使用kobject_ create()函数分配kobject,并将已经分配但尚未初始化的kob ject指针及其kobject_type 指针作为参数。kobject_add()函数用于添加kobject并将其链接到系统,同时根据其层次结构创建目录及其默认属性。功能与之相反的函数是kobject_ del(),将kobject删除链接
126 0
|
存储 缓存 安全
基于FUSE的简单文件系统
基于FUSE的简单文件系统
570 0
|
关系型数据库 Linux 数据库
linux 内存文件系统使用 - tmpfs, ramfs, shmfs
linux 内存文件系统使用 - tmpfs, ramfs, shmfs
2273 0