Fuse 是 filesystem in user space,一个用户空间的文件系统框架,fuse包含包含一个内核模块和一个用户空间守护进程。fuse 两种开发模式:
一种是 high-level 模式,入口函数为 fuse_main,封装了一系列初始化操作,使用简单,但不灵活
另一种是low-level模式,可以利用 fuse 提供的底层函数灵活开发应用程序
FUSE分为三大模块:
- FUSE内核模块(内核态)
- LibFUSE模块(用户态)
- 用户程序模块(用户态)
LibFUSE 实现文件系统主要框架、对实现的文件系统操作进行封装、mount管理、通过设备/dev/fuse与内核模块通信
FUSE 内核模块实现 VFS 接口(fuse文件驱动注册、supper block、dentry、inode的维护),接收请求传递给LibFUSE,LibFUSE 再传递给用户程序的接口进行操作
FUSE需要把VFS层的请求传到用户态的fuseapp,在用户态处理,然后再返回到内核态,把结果返回给VFS层。
代码地址: https://github.com/libfuse/libfuse
fuse_operations 结构体
定义文件路径 libfuse/include/fuse.h,在fuse_operations中所有的方法都是可选的,
struct fuse_operations {
int (*getattr) (const char *, struct stat *); //类似stat()
int (*readlink) (const char *, char *, size_t); //读取链接文件的真实文件路径
int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t); //使用readdir()替代
int (*mknod) (const char *, mode_t, dev_t); //创建一个文件节点
int (*mkdir) (const char *, mode_t); //创建一个目录,获得目录类型bit位,mode|S_IFDIR
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);
unsigned int flag_nullpath_ok:1;
unsigned int flag_nopath:1;
unsigned int flag_utime_omit_ok:1;
unsigned int flag_reserved:29;
int (*ioctl) (const char *, int cmd, void *arg,
struct fuse_file_info *, unsigned int flags, void *data);
int (*poll) (const char *, struct fuse_file_info *,
struct fuse_pollhandle *ph, unsigned *reventsp);
int (*write_buf) (const char *, struct fuse_bufvec *buf, off_t off,
struct fuse_file_info *);
int (*read_buf) (const char *, struct fuse_bufvec **bufp,
size_t size, off_t off, struct fuse_file_info *);
int (*flock) (const char *, struct fuse_file_info *, int op);
int (*fallocate) (const char *, int, off_t, off_t,
struct fuse_file_info *);
};
libfuse的核心数据结构,还有没有完全画出,需要时间
- fuse_session:客户端管理会话的结构体
- fuse_chan: 客户端与fuse内核模块连接隧道的结构体,客户端通过fuse设备驱动来读写设备缓存
fuse_main 入口开始,注册定义的文件操作方法来实现自定义的文件系统。在 libfuse 模块,当调用 fuse_main() 函数时(lib/helper.c),分析参数,然后调用 fuse_mount() 函数(lib/mount.c)
fuse_main_real (1)
--> fuse_main_common
--> fuse_setup_common
--> fuse_parse_cmdline
--> fuse_mount_common (1.1)
--> fuse_mount_compat25
--> fuse_kern_mount
--> fuse_mount_sys (1.1.1)
--> fuse_kern_chan_new (1.2)
--> fuse_chan_new 中介
--> fuse_chan_new_common
--> fuse_new_common (2)
--> fuse_lowlevel_new_common (2.1)
--> fuse_daemonize
--> fuse_set_signal_handlers
--> fuse_loop_mt
--> fuse_loop
--> fuse_session_loop
1. 函数 fuse_main_real
根据 include/fuse.h 中定义,fuse_main_real 是主要入口函数,主要功能包括如下:
#define fuse_main(argc, argv, op, user_data) \ fuse_main_real(argc, argv, op, sizeof(*(op)), user_data)
- fuse_parse_cmdline 函数分析命令行参数,-d -s -h
- 传入相关参数给 fuse_mount 函数
1.1 fuse_mount_common 函数
fuse_mount_common 里的函数 fuse_mount_compat25 最终调用文件 mount.c 中的 fuse_kern_mount 函数,这个函数调用主要函数 fuse_mount_sys 函数,
static struct fuse_chan *fuse_mount_common(const char *mountpoint,
struct fuse_args *args)
{
fd = fuse_mount_compat25(mountpoint, args);
if (fd == -1)
return NULL;
ch = fuse_kern_chan_new(fd);
if (!ch)
fuse_kern_unmount(mountpoint, fd);
return ch;
}
1.1.1 fuse_mount_sys 函数
open(devname, O_RDWR) 打开设备文件 /dev/fuse
调用 mount 函数进行挂载
1.1.2 fuse_kern_chan_new 函数
实例化 fuse_chan_ops 有 recive send destroy
fuse_chan_new 最终调用函数 fuse_chan_new_common,实例化 fuse_chan 对象,包括操作 fuse_chan_ops bufsize
struct fuse_chan *fuse_kern_chan_new(int fd)
{
struct fuse_chan_ops op = {
.receive = fuse_kern_chan_receive,
.send = fuse_kern_chan_send,
.destroy = fuse_kern_chan_destroy,
};
size_t bufsize = getpagesize() + 0x1000;
bufsize = bufsize < MIN_BUFSIZE ? MIN_BUFSIZE : bufsize;
return fuse_chan_new(&op, fd, bufsize, NULL);
}
1.1.2.1 fuse_kern_chan_receive 函数
可以看到 read,fuse_chan_fd 其实就是打开的 /dev/fuse,直接读取 size 长度数据
static int fuse_kern_chan_receive(struct fuse_chan **chp, char *buf,
size_t size)
{
struct fuse_chan *ch = *chp;
int err;
ssize_t res;
struct fuse_session *se = fuse_chan_session(ch);
assert(se != NULL);
restart:
res = read(fuse_chan_fd(ch), buf, size);
err = errno;
return res;
}
2. fuse_new_common 函数
分配 fuse 数据结构,存储以及维护着文件系统数据结构。
(struct fuse *) calloc(1, sizeof(struct fuse)) 分配 fuse 结构
fuse_fs_new 分配 fuse_fs 结构
struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
const struct fuse_operations *op,
size_t op_size, void *user_data, int compat)
{
f = (struct fuse *) calloc(1, sizeof(struct fuse));
if (f == NULL) {
fprintf(stderr, "fuse: failed to allocate fuse object\n");
goto out_delete_context_key;
}
2.1 fuse_lowlevel_new_common 函数
fuse_lowlevel_ops 定义了一大堆操作函数,开发者实现的 fuse_lowlevel_ops 接口
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,
2.1.1 定义 fuse_session_ops
process 处理函数为 fuse_ll_process
struct fuse_session_ops sop = {
.process = fuse_ll_process,
.destroy = fuse_ll_destroy,
};
2.1.2 创建新的 fuse_session
设置 receive_buf 与 process_buf
se = fuse_session_new(&sop, f);
if (!se)
goto out_key_destroy;
se->receive_buf = fuse_ll_receive_buf;
se->process_buf = fuse_ll_process_buf;
fuse_ll_process_buf
--> fuse_ll_copy_from_pipe
--> fuse_ll_alloc_req
2.1.2.1 fuse_ll_process_buf 函数
首先看看数据结构 fuse_ll,定义在 fuse_i.h 中
struct fuse_ll {
int debug;
int allow_root;
int atomic_o_trunc;
int no_remote_posix_lock;
int no_remote_flock;
int big_writes;
int splice_write;
int splice_move;
int splice_read;
int no_splice_write;
int no_splice_move;
int no_splice_read;
struct fuse_lowlevel_ops op;
int got_init;
struct cuse_data *cuse_data;
void *userdata;
uid_t owner;
struct fuse_conn_info conn;
struct fuse_req list;
struct fuse_req interrupts;
pthread_mutex_t lock;
int got_destroy;
pthread_key_t pipe_key;
int broken_splice_nonblock;
uint64_t notify_ctr;
struct fuse_notify_req notify_list;
};
头部字段 fuse_in_header,占用 40 字节
struct fuse_in_header {
__u32 len;
__u32 opcode;
__u64 unique;
__u64 nodeid;
__u32 uid;
__u32 gid;
__u32 pid;
__u32 padding;
};
fuse_req 结构体,发往用户空间
struct fuse_req {
struct fuse_ll *f;
uint64_t unique;
int ctr;
pthread_mutex_t lock;
struct fuse_ctx ctx;
struct fuse_chan *ch;
int interrupted;
unsigned int ioctl_64bit : 1;
union {
struct {
uint64_t unique;
} i;
struct {
fuse_interrupt_func_t func;
void *data;
} ni;
} u;
struct fuse_req *next;
struct fuse_req *prev;
};
3. fuse_loop 函数
通过函数 fuse_session_next_chan 获取,分配缓冲 buf,调用 fuse_session_receive_buf 获取数据,以及调用 fuse_session_process_buf 处理数据
int fuse_session_loop(struct fuse_session *se)
{
int res = 0;
struct fuse_chan *ch = fuse_session_next_chan(se, NULL);
size_t bufsize = fuse_chan_bufsize(ch);
char *buf = (char *) malloc(bufsize);
while (!fuse_session_exited(se)) {
struct fuse_chan *tmpch = ch;
struct fuse_buf fbuf = {
.mem = buf,
.size = bufsize,
};
res = fuse_session_receive_buf(se, &fbuf, &tmpch);
fuse_session_process_buf(se, &fbuf, tmpch);
}
}
3.1 fuse_session_receive_buf 函数
如果定义了 receive_buf 操作函数,否则调用 fuse_chan_revc,巴拉巴拉,最后可以得到直接调用注册的 receive 操作函数(1.1.2.1 fuse_kern_chan_receive 函数),直接从 /dev/fuse 读取数据
int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf,
struct fuse_chan **chp)
{
int res;
if (se->receive_buf) {
res = se->receive_buf(se, buf, chp);
} else {
res = fuse_chan_recv(chp, buf->mem, buf->size);
if (res > 0)
buf->size = res;
}
return res;
}
3.2 fuse_session_process_buf 函数
根据注册的函数 process_buf 为 fuse_ll_process_buf
void fuse_session_process_buf(struct fuse_session *se,
const struct fuse_buf *buf, struct fuse_chan *ch)
{
if (se->process_buf) {
se->process_buf(se->data, buf, ch);
} else {
assert(!(buf->flags & FUSE_BUF_IS_FD));
fuse_session_process(se->data, buf->mem, buf->size, ch);
}
}