用户空间文件系统(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,如需转载请自行联系原作者








相关文章
|
存储 负载均衡 算法
p2p的文件系统
p2p的文件系统
139 4
|
7天前
|
存储 Unix PHP
31 文件系统
路老师分享PHP文件处理技术,涵盖文件的打开、关闭、读取及写入操作,帮助初学者深入了解PHP语言。
20 2
|
存储 数据可视化 Linux
文件系统-
文件系统-
72 0
|
存储 缓存 算法
文件系统(下)
文件系统(下)
170 0
|
存储 缓存 算法
文件系统(上)
文件系统(上)
183 0
|
存储 Linux Windows
【文件系统】
【文件系统】
99 0
|
存储 Unix Linux
|
存储 缓存 安全
基于FUSE的简单文件系统
基于FUSE的简单文件系统
548 0
|
存储 Linux 内存技术
文件系统
文件系统
133 0
|
缓存 Linux Shell
虚拟文件系统
Linux内核中的虚拟文件系统用来管理挂接各种具体文件系统。具体的文件系统可设计成可加载模块,在系统需要时进行加载。 挂载具体文件系统时,VFS读取它的超级块,得到具体文件系统的拓扑结构,并将这些信息映射到VFS超级块结构中。
1011 1