From 266eb3f2fae488fd19ee5acfc01ba9d483715699 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 4 Jun 2021 18:11:54 +0200 Subject: fuse: Call vfs_get_tree() for submounts We recently fixed an infinite loop by setting the SB_BORN flag on submounts along with the write barrier needed by super_cache_count(). This is the job of vfs_get_tree() and FUSE shouldn't have to care about the barrier at all. Split out some code from fuse_dentry_automount() to the dedicated fuse_get_tree_submount() handler for submounts and call vfs_get_tree(). Signed-off-by: Greg Kurz Reviewed-by: Max Reitz Signed-off-by: Miklos Szeredi --- fs/fuse/dir.c | 53 +++++------------------------------------------------ 1 file changed, 5 insertions(+), 48 deletions(-) (limited to 'fs/fuse/dir.c') diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 3fa8604c21d5..b88e5785a3dd 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -309,12 +309,8 @@ static int fuse_dentry_delete(const struct dentry *dentry) static struct vfsmount *fuse_dentry_automount(struct path *path) { struct fs_context *fsc; - struct fuse_mount *parent_fm = get_fuse_mount_super(path->mnt->mnt_sb); - struct fuse_conn *fc = parent_fm->fc; - struct fuse_mount *fm; struct vfsmount *mnt; struct fuse_inode *mp_fi = get_fuse_inode(d_inode(path->dentry)); - struct super_block *sb; int err; fsc = fs_context_for_submount(path->mnt->mnt_sb->s_type, path->dentry); @@ -323,48 +319,15 @@ static struct vfsmount *fuse_dentry_automount(struct path *path) goto out; } - err = -ENOMEM; - fm = kzalloc(sizeof(struct fuse_mount), GFP_KERNEL); - if (!fm) - goto out_put_fsc; + /* Pass the FUSE inode of the mount for fuse_get_tree_submount() */ + fsc->fs_private = mp_fi; - fsc->s_fs_info = fm; - sb = sget_fc(fsc, NULL, set_anon_super_fc); - if (IS_ERR(sb)) { - err = PTR_ERR(sb); - kfree(fm); + err = vfs_get_tree(fsc); + if (err) goto out_put_fsc; - } - fm->fc = fuse_conn_get(fc); - - /* Initialize superblock, making @mp_fi its root */ - err = fuse_fill_super_submount(sb, mp_fi); - if (err) { - fuse_conn_put(fc); - kfree(fm); - sb->s_fs_info = NULL; - goto out_put_sb; - } - - down_write(&fc->killsb); - list_add_tail(&fm->fc_entry, &fc->mounts); - up_write(&fc->killsb); - - sb->s_flags |= SB_ACTIVE; - fsc->root = dget(sb->s_root); - - /* - * FIXME: setting SB_BORN requires a write barrier for - * super_cache_count(). We should actually come - * up with a proper ->get_tree() implementation - * for submounts and call vfs_get_tree() to take - * care of the write barrier. - */ - smp_wmb(); - sb->s_flags |= SB_BORN; /* We are done configuring the superblock, so unlock it */ - up_write(&sb->s_umount); + up_write(&fsc->root->d_sb->s_umount); /* Create the submount */ mnt = vfs_create_mount(fsc); @@ -376,12 +339,6 @@ static struct vfsmount *fuse_dentry_automount(struct path *path) put_fs_context(fsc); return mnt; -out_put_sb: - /* - * Only jump here when fsc->root is NULL and sb is still locked - * (otherwise put_fs_context() will put the superblock) - */ - deactivate_locked_super(sb); out_put_fsc: put_fs_context(fsc); out: -- cgit v1.2.3-59-g8ed1b