Fuse架构

Untitled

Untitled

Untitled

整体来看Fuse作为VFS的一种实现存在和其他的Filesystem是同一层,可以把他理解成一种特殊的文件系统,当我们在Fuse的挂载点上进行文件操作的时候,请求最终会进入到Fuse文件系统,Fuse文件系统进行各种处理后,将请求封装成一个fuse request,然后写入到/dev/fuse设备,

Untitled

核心数据结构

mount的时候触发fs_context的get_tree获取superblock,在get_tree中会初始化fuse_mount,一个mount对应一个fuse_mount,表示一个mount的fuse文件系统

/*
 * Represents a mounted filesystem, potentially a submount.
 *
 * This object allows sharing a fuse_conn between separate mounts to
 * allow submounts with dedicated superblocks and thus separate device
 * IDs.
 */
struct fuse_mount {
	/* Underlying (potentially shared) connection to the FUSE server */
	struct fuse_conn *fc;

	/*
	 * Super block for this connection (fc->killsb must be held when
	 * accessing this).
	 */
	struct super_block *sb;

	/* Entry on fc->mounts */
	struct list_head fc_entry;
};

static int fuse_get_tree(struct fs_context *fsc) 
{
	struct fuse_conn *fc;
	struct fuse_mount *fm;
	.....
  fuse_conn_init(fc, fm, fsc->user_ns, &fuse_dev_fiq_ops, NULL);
  ....
}

mount的时候会触发fs_context的get_tree获取superblock,初始化fuse_conn,并添加到fuse_conn_list链表中。多个mount可能指向同一个fuse server

static int fuse_get_tree(struct fs_context *fsc)
{
	struct fuse_fs_context *ctx = fsc->fs_private;
	struct fuse_dev *fud;
	struct fuse_conn *fc;
	struct fuse_mount *fm;
	struct super_block *sb;
	int err;
	......
	fuse_conn_init(fc, fm, fsc->user_ns, &fuse_dev_fiq_ops, NULL);
	fc->release = fuse_free_conn;
	fsc->s_fs_info = fm;
	// open打开的/dev/fuse会传递进来,被保存再ctx->file里面
	if (ctx->fd_present)
		ctx->file = fget(ctx->fd);
	.........
	err = -EINVAL;
	if (!ctx->file)
		goto out;

	/*
	 * Allow creating a fuse mount with an already initialized fuse
	 * connection
	 */
	......
	err = get_tree_nodev(fsc, fuse_fill_super);
out:
	if (fsc->s_fs_info)
		fuse_mount_destroy(fm);
	if (ctx->file)
		fput(ctx->file);
	return err;
}

Mount的时候,会调用fuse_init_fs_context来初始化fs_context,然后把fuse_fs_context放到fs_context的fs_private字段,然后给其指定fuse_context_ops,用来params解析、获取super block、fs_context释放等

static struct file_system_type fuse_fs_type = {
	.owner		= THIS_MODULE,
	.name		= "fuse",
	.fs_flags	= FS_HAS_SUBTYPE | FS_USERNS_MOUNT,
	.init_fs_context = fuse_init_fs_context,
	.parameters	= fuse_fs_parameters,
	.kill_sb	= fuse_kill_sb_anon,
};

/*
 * Set up the filesystem mount context.
 */
static int fuse_init_fs_context(struct fs_context *fsc)
{
	struct fuse_fs_context *ctx;

	ctx = kzalloc(sizeof(struct fuse_fs_context), GFP_KERNEL);
	if (!ctx)
		return -ENOMEM;

	ctx->max_read = ~0;
	ctx->blksize = FUSE_DEFAULT_BLKSIZE;
	ctx->legacy_opts_show = true;

#ifdef CONFIG_BLOCK
	if (fsc->fs_type == &fuseblk_fs_type) {
		ctx->is_bdev = true;
		ctx->destroy = true;
	}
#endif

	fsc->fs_private = ctx;
	fsc->ops = &fuse_context_ops;
	return 0;
}
// 会调用这个来初始化一个inode
// fuse_node的第一个字段就是struct inode,所以传递过来的实际上是fuse_node
// 但是可以当作是struct inode
static void fuse_inode_init_once(void *foo)
{
	struct inode *inode = foo;

	inode_init_once(inode);
}

// 先通过alloc_inode_sb来分配和初始化struct inode部分,然后再初始化fuse_inode其余字段
static struct inode *fuse_alloc_inode(struct super_block *sb)
{
	struct fuse_inode *fi;

	fi = alloc_inode_sb(sb, fuse_inode_cachep, GFP_KERNEL);
	if (!fi)
		return NULL;

	fi->i_time = 0;
	fi->inval_mask = 0;
	fi->nodeid = 0;
	fi->nlookup = 0;
	fi->attr_version = 0;
	fi->orig_ino = 0;
	fi->state = 0;
	mutex_init(&fi->mutex);
	spin_lock_init(&fi->lock);
	fi->forget = fuse_alloc_forget();
	if (!fi->forget)
		goto out_free;

	if (IS_ENABLED(CONFIG_FUSE_DAX) && !fuse_dax_inode_alloc(sb, fi))
		goto out_free_forget;

	return &fi->inode;

out_free_forget:
	kfree(fi->forget);
out_free:
	kmem_cache_free(fuse_inode_cachep, fi);
	return NULL;
}

mount的时候创建,然后存放在/dev/fuse的打开的文件handle中的private_data中,并且在fuse_fs_context中也会指向fuse_dev。