【linux内核】 libfuse 源码分析

 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);
	}
}
发布了242 篇原创文章 · 获赞 307 · 访问量 39万+

猜你喜欢

转载自blog.csdn.net/zhonglinzhang/article/details/104262658
今日推荐