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