Submounts have their own superblock, which needs to be initialized. However, they do not have a fuse_fs_context associated with them, and the root node's attributes should be taken from the mountpoint's node.
Extend fuse_fill_super_common() to work for submounts by making the @ctx parameter optional, and by adding a @submount_finode parameter. Signed-off-by: Max Reitz <[email protected]> --- fs/fuse/fuse_i.h | 10 +++-- fs/fuse/inode.c | 89 +++++++++++++++++++++++++++++++++------------ fs/fuse/virtio_fs.c | 2 +- 3 files changed, 74 insertions(+), 27 deletions(-) diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 3b2b47e2e966..d8528aa97386 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1015,11 +1015,15 @@ void fuse_dev_free(struct fuse_dev *fud); void fuse_send_init(struct fuse_mount *fm); /** - * Fill in superblock and initialize fuse connection + * Fill in superblock and initialize fuse connection for root mounts. * @sb: partially-initialized superblock to fill in - * @ctx: mount context + * @ctx: mount context (for root mounts) + * @submount_finode: For submounts: The fuse_inode of the parent + * filesystem where this submount is mounted + * (NULL for root mounts) */ -int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx); +int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx, + struct fuse_inode *submount_finode); /** * Disassociate fuse connection from superblock and kill the superblock diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 596504321cc7..ff30d30b3faf 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -1140,9 +1140,32 @@ void fuse_dev_free(struct fuse_dev *fud) } EXPORT_SYMBOL_GPL(fuse_dev_free); -int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx) -{ - struct fuse_dev *fud; +static void fuse_fill_attr_from_inode(struct fuse_attr *attr, + const struct fuse_inode *fi) +{ + *attr = (struct fuse_attr){ + .ino = fi->inode.i_ino, + .size = fi->inode.i_size, + .blocks = fi->inode.i_blocks, + .atime = fi->inode.i_atime.tv_sec, + .mtime = fi->inode.i_mtime.tv_sec, + .ctime = fi->inode.i_ctime.tv_sec, + .atimensec = fi->inode.i_atime.tv_nsec, + .mtimensec = fi->inode.i_mtime.tv_nsec, + .ctimensec = fi->inode.i_ctime.tv_nsec, + .mode = fi->inode.i_mode, + .nlink = fi->inode.i_nlink, + .uid = fi->inode.i_uid.val, + .gid = fi->inode.i_gid.val, + .rdev = fi->inode.i_rdev, + .blksize = 1u << fi->inode.i_blkbits, + }; +} + +int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx, + struct fuse_inode *submount_finode) +{ + struct fuse_dev *fud = NULL; struct fuse_mount *fm = get_fuse_mount_super(sb); struct fuse_conn *fc = fm->fc; struct inode *root; @@ -1150,12 +1173,16 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx) int err; err = -EINVAL; + /* One must be NULL, the other must be non-NULL */ + if (!ctx == !submount_finode) + goto err; + if (sb->s_flags & SB_MANDLOCK) goto err; sb->s_flags &= ~(SB_NOSEC | SB_I_VERSION); - if (ctx->is_bdev) { + if (ctx && ctx->is_bdev) { #ifdef CONFIG_BLOCK err = -EINVAL; if (!sb_set_blocksize(sb, ctx->blksize)) @@ -1166,8 +1193,12 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx) sb->s_blocksize_bits = PAGE_SHIFT; } - sb->s_subtype = ctx->subtype; - ctx->subtype = NULL; + if (ctx) { + sb->s_subtype = ctx->subtype; + ctx->subtype = NULL; + } else + sb->s_subtype = NULL; + sb->s_magic = FUSE_SUPER_MAGIC; sb->s_op = &fuse_super_operations; sb->s_xattr = fuse_xattr_handlers; @@ -1185,9 +1216,11 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx) if (sb->s_user_ns != &init_user_ns) sb->s_xattr = fuse_no_acl_xattr_handlers; - fud = fuse_dev_alloc_install(fc); - if (!fud) - goto err; + if (ctx) { + fud = fuse_dev_alloc_install(fc); + if (!fud) + goto err; + } fm->dev = sb->s_dev; fm->sb = sb; @@ -1200,18 +1233,26 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx) fc->dont_mask = 1; sb->s_flags |= SB_POSIXACL; - fc->default_permissions = ctx->default_permissions; - fc->allow_other = ctx->allow_other; - fc->user_id = ctx->user_id; - fc->group_id = ctx->group_id; - fc->max_read = max_t(unsigned, 4096, ctx->max_read); - fc->destroy = ctx->destroy; - fc->no_control = ctx->no_control; - fc->no_force_umount = ctx->no_force_umount; - fc->no_mount_options = ctx->no_mount_options; + if (ctx) { + fc->default_permissions = ctx->default_permissions; + fc->allow_other = ctx->allow_other; + fc->user_id = ctx->user_id; + fc->group_id = ctx->group_id; + fc->max_read = max_t(unsigned, 4096, ctx->max_read); + fc->destroy = ctx->destroy; + fc->no_control = ctx->no_control; + fc->no_force_umount = ctx->no_force_umount; + fc->no_mount_options = ctx->no_mount_options; + } err = -ENOMEM; - root = fuse_get_root_inode(sb, ctx->rootmode); + if (ctx) { + root = fuse_get_root_inode(sb, ctx->rootmode); + } else { + struct fuse_attr root_attr; + fuse_fill_attr_from_inode(&root_attr, submount_finode); + root = fuse_iget(sb, submount_finode->nodeid, 0, &root_attr, 0, 0); + } sb->s_d_op = &fuse_root_dentry_operations; root_dentry = d_make_root(root); if (!root_dentry) @@ -1221,7 +1262,7 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx) mutex_lock(&fuse_mutex); err = -EINVAL; - if (*ctx->fudptr) + if (ctx && *ctx->fudptr) goto err_unlock; err = fuse_ctl_add_conn(fm); @@ -1230,7 +1271,8 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx) list_add_tail(&fm->entry, &fuse_mount_list); sb->s_root = root_dentry; - *ctx->fudptr = fud; + if (ctx) + *ctx->fudptr = fud; mutex_unlock(&fuse_mutex); return 0; @@ -1238,7 +1280,8 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx) mutex_unlock(&fuse_mutex); dput(root_dentry); err_dev_free: - fuse_dev_free(fud); + if (fud) + fuse_dev_free(fud); err: return err; } @@ -1284,7 +1327,7 @@ static int fuse_fill_super(struct super_block *sb, struct fs_context *fsc) fuse_conn_put(fc); sb->s_fs_info = fm; - err = fuse_fill_super_common(sb, ctx); + err = fuse_fill_super_common(sb, ctx, NULL); if (err) goto err_put_conn; /* diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c index 492ddd34ecd9..38100f096421 100644 --- a/fs/fuse/virtio_fs.c +++ b/fs/fuse/virtio_fs.c @@ -1075,7 +1075,7 @@ static int virtio_fs_fill_super(struct super_block *sb) } ctx.fudptr = (void **)&fs->vqs[VQ_REQUEST].fud; - err = fuse_fill_super_common(sb, &ctx); + err = fuse_fill_super_common(sb, &ctx, NULL); if (err < 0) goto err_free_fuse_devs; -- 2.26.2 _______________________________________________ Virtio-fs mailing list [email protected] https://www.redhat.com/mailman/listinfo/virtio-fs
