diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index b26aa9169e83..636154861d7c 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -2052,7 +2052,7 @@ static int btrfs_get_tree_subvol(struct fs_context *fc) * then open_ctree will properly initialize the file system specific * settings later. btrfs_init_fs_info initializes the static elements * of the fs_info (locks and such) to make cleanup easier if we find a - * superblock with our given fs_devices later on at sget() time. + * superblock with our given fs_devices later on at sget_fc() time. */ fs_info = kvzalloc_obj(struct btrfs_fs_info); if (!fs_info) diff --git a/fs/ext4/extents-test.c b/fs/ext4/extents-test.c index 6b53a3f39fcd..bd7795a82607 100644 --- a/fs/ext4/extents-test.c +++ b/fs/ext4/extents-test.c @@ -37,6 +37,7 @@ #include #include +#include #include #include @@ -130,14 +131,20 @@ static void ext_kill_sb(struct super_block *sb) generic_shutdown_super(sb); } -static int ext_set(struct super_block *sb, void *data) +static int ext_init_fs_context(struct fs_context *fc) +{ + return 0; +} + +static int ext_set(struct super_block *sb, struct fs_context *fc) { return 0; } static struct file_system_type ext_fs_type = { - .name = "extents test", - .kill_sb = ext_kill_sb, + .name = "extents test", + .init_fs_context = ext_init_fs_context, + .kill_sb = ext_kill_sb, }; static void extents_kunit_exit(struct kunit *test) @@ -223,6 +230,7 @@ static int extents_kunit_init(struct kunit *test) struct ext4_inode_info *ei; struct inode *inode; struct super_block *sb; + struct fs_context *fc; struct ext4_sb_info *sbi = NULL; struct kunit_ext_test_param *param = (struct kunit_ext_test_param *)(test->param_value); @@ -232,7 +240,13 @@ static int extents_kunit_init(struct kunit *test) if (sbi == NULL) return -ENOMEM; - sb = sget(&ext_fs_type, NULL, ext_set, 0, NULL); + fc = fs_context_for_mount(&ext_fs_type, 0); + if (IS_ERR(fc)) { + kfree(sbi); + return PTR_ERR(fc); + } + sb = sget_fc(fc, NULL, ext_set); + put_fs_context(fc); if (IS_ERR(sb)) { kfree(sbi); return PTR_ERR(sb); diff --git a/fs/ext4/mballoc-test.c b/fs/ext4/mballoc-test.c index 90ed505fa4b1..d90da44aadbd 100644 --- a/fs/ext4/mballoc-test.c +++ b/fs/ext4/mballoc-test.c @@ -5,6 +5,7 @@ #include #include +#include #include #include "ext4.h" @@ -63,8 +64,14 @@ static void mbt_kill_sb(struct super_block *sb) generic_shutdown_super(sb); } +static int mbt_init_fs_context(struct fs_context *fc) +{ + return 0; +} + static struct file_system_type mbt_fs_type = { .name = "mballoc test", + .init_fs_context = mbt_init_fs_context, .kill_sb = mbt_kill_sb, }; @@ -127,7 +134,7 @@ static void mbt_mb_release(struct super_block *sb) kfree(sb->s_bdev); } -static int mbt_set(struct super_block *sb, void *data) +static int mbt_set(struct super_block *sb, struct fs_context *fc) { return 0; } @@ -136,13 +143,19 @@ static struct super_block *mbt_ext4_alloc_super_block(void) { struct mbt_ext4_super_block *fsb; struct super_block *sb; + struct fs_context *fc; struct ext4_sb_info *sbi; fsb = kzalloc_obj(*fsb); if (fsb == NULL) return NULL; - sb = sget(&mbt_fs_type, NULL, mbt_set, 0, NULL); + fc = fs_context_for_mount(&mbt_fs_type, 0); + if (IS_ERR(fc)) + goto out; + + sb = sget_fc(fc, NULL, mbt_set); + put_fs_context(fc); if (IS_ERR(sb)) goto out; diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c index b14ae3283553..834859fbd527 100644 --- a/fs/smb/client/cifsfs.c +++ b/fs/smb/client/cifsfs.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -970,26 +971,19 @@ cifs_get_root(struct smb3_fs_context *ctx, struct super_block *sb) return dentry; } -static int cifs_set_super(struct super_block *sb, void *data) -{ - struct cifs_mnt_data *mnt_data = data; - sb->s_fs_info = mnt_data->cifs_sb; - return set_anon_super(sb, NULL); -} - struct dentry * -cifs_smb3_do_mount(struct file_system_type *fs_type, - int flags, struct smb3_fs_context *old_ctx) +cifs_smb3_do_mount(struct fs_context *fc, struct smb3_fs_context *old_ctx) { struct cifs_mnt_data mnt_data; struct cifs_sb_info *cifs_sb; struct super_block *sb; struct dentry *root; + unsigned int saved_sb_flags; int rc; if (cifsFYI) { - cifs_dbg(FYI, "%s: devname=%s flags=0x%x\n", __func__, - old_ctx->source, flags); + cifs_dbg(FYI, "%s: devname=%s sb_flags=0x%x\n", __func__, + old_ctx->source, fc->sb_flags); } else { cifs_info("Attempting to mount %s\n", old_ctx->source); } @@ -1016,7 +1010,7 @@ cifs_smb3_do_mount(struct file_system_type *fs_type, rc = cifs_mount(cifs_sb, cifs_sb->ctx); if (rc) { - if (!(flags & SB_SILENT)) + if (!(fc->sb_flags & SB_SILENT)) cifs_dbg(VFS, "cifs_mount failed w/return code = %d\n", rc); root = ERR_PTR(rc); @@ -1025,12 +1019,27 @@ cifs_smb3_do_mount(struct file_system_type *fs_type, mnt_data.ctx = cifs_sb->ctx; mnt_data.cifs_sb = cifs_sb; - mnt_data.flags = flags; + mnt_data.flags = 0; - /* BB should we make this contingent on mount parm? */ - flags |= SB_NODIRATIME | SB_NOATIME; - - sb = sget(fs_type, cifs_match_super, cifs_set_super, flags, &mnt_data); + /* + * sb->s_flags is set from fc->sb_flags by alloc_super(). CIFS has + * historically forced SB_NODIRATIME | SB_NOATIME on every mount and + * ignored the caller-supplied SB_* flags. Preserve that behaviour by + * overriding fc->sb_flags around the sget_fc() call. + * + * Hand cifs_sb to sget_fc() via fc->s_fs_info; sget_fc() copies it + * onto sb->s_fs_info before running set() and clears fc->s_fs_info + * on successful publish. Pass the rest of the per-mount context to + * cifs_match_super() through fc->sget_key. + */ + saved_sb_flags = fc->sb_flags; + fc->sb_flags = SB_NODIRATIME | SB_NOATIME; + fc->s_fs_info = cifs_sb; + fc->sget_key = &mnt_data; + sb = sget_fc(fc, cifs_match_super, set_anon_super_fc); + fc->sget_key = NULL; + fc->s_fs_info = NULL; + fc->sb_flags = saved_sb_flags; if (IS_ERR(sb)) { cifs_umount(cifs_sb); return ERR_CAST(sb); diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h index 9d85224fafab..008b1d373245 100644 --- a/fs/smb/client/cifsfs.h +++ b/fs/smb/client/cifsfs.h @@ -147,8 +147,9 @@ ssize_t cifs_file_copychunk_range(unsigned int xid, struct file *src_file, long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg); void cifs_setsize(struct inode *inode, loff_t offset); +struct fs_context; struct smb3_fs_context; -struct dentry *cifs_smb3_do_mount(struct file_system_type *fs_type, int flags, +struct dentry *cifs_smb3_do_mount(struct fs_context *fc, struct smb3_fs_context *old_ctx); char *cifs_silly_fullpath(struct dentry *dentry); diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h index 79d891f7df1a..c4ababcb51a3 100644 --- a/fs/smb/client/cifsproto.h +++ b/fs/smb/client/cifsproto.h @@ -19,6 +19,7 @@ struct statfs; struct smb_rqst; struct smb3_fs_context; +struct fs_context; /* ***************************************************************** @@ -235,7 +236,7 @@ void cifs_mount_put_conns(struct cifs_mount_ctx *mnt_ctx); int cifs_mount_get_session(struct cifs_mount_ctx *mnt_ctx); int cifs_is_path_remote(struct cifs_mount_ctx *mnt_ctx); int cifs_mount_get_tcon(struct cifs_mount_ctx *mnt_ctx); -int cifs_match_super(struct super_block *sb, void *data); +int cifs_match_super(struct super_block *sb, struct fs_context *fc); int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx); void cifs_umount(struct cifs_sb_info *cifs_sb); void cifs_mark_open_files_invalid(struct cifs_tcon *tcon); diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index dcde25da468d..79762e6bbe50 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -6,6 +6,7 @@ * */ #include +#include #include #include #include @@ -2991,9 +2992,9 @@ static int match_prepath(struct super_block *sb, } int -cifs_match_super(struct super_block *sb, void *data) +cifs_match_super(struct super_block *sb, struct fs_context *fc) { - struct cifs_mnt_data *mnt_data = data; + struct cifs_mnt_data *mnt_data = fc->sget_key; struct smb3_fs_context *ctx; struct cifs_sb_info *cifs_sb; struct TCP_Server_Info *tcp_srv; diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c index 2f86158f85d7..9bb41114237f 100644 --- a/fs/smb/client/fs_context.c +++ b/fs/smb/client/fs_context.c @@ -889,7 +889,7 @@ static int smb3_get_tree_common(struct fs_context *fc) struct dentry *root; int rc = 0; - root = cifs_smb3_do_mount(fc->fs_type, 0, ctx); + root = cifs_smb3_do_mount(fc, ctx); if (IS_ERR(root)) return PTR_ERR(root); diff --git a/fs/super.c b/fs/super.c index 378e81efe643..5fe8cea9f8fe 100644 --- a/fs/super.c +++ b/fs/super.c @@ -328,7 +328,7 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags, init_rwsem(&s->s_umount); lockdep_set_class(&s->s_umount, &type->s_umount_key); /* - * sget() can have s_umount recursion. + * sget_fc() can have s_umount recursion. * * When it cannot find a suitable sb, it allocates a new * one (this one), and tries again to find a suitable old @@ -439,7 +439,7 @@ static void kill_super_notify(struct super_block *sb) /* * Remove it from @fs_supers so it isn't found by new - * sget{_fc}() walkers anymore. Any concurrent mounter still + * sget_fc() walkers anymore. Any concurrent mounter still * managing to grab a temporary reference is guaranteed to * already see SB_DYING and will wait until we notify them about * SB_DEAD. @@ -517,7 +517,7 @@ EXPORT_SYMBOL(deactivate_super); * @sb: superblock to acquire * * Acquire a temporary reference on a superblock and try to trade it for - * an active reference. This is used in sget{_fc}() to wait for a + * an active reference. This is used in sget_fc() to wait for a * superblock to either become SB_BORN or for it to pass through * sb->kill() and be marked as SB_DEAD. * @@ -673,11 +673,11 @@ void generic_shutdown_super(struct super_block *sb) /* * Broadcast to everyone that grabbed a temporary reference to this * superblock before we removed it from @fs_supers that the superblock - * is dying. Every walker of @fs_supers outside of sget{_fc}() will now + * is dying. Every walker of @fs_supers outside of sget_fc() will now * discard this superblock and treat it as dead. * * We leave the superblock on @fs_supers so it can be found by - * sget{_fc}() until we passed sb->kill_sb(). + * sget_fc() until we passed sb->kill_sb(). */ super_wake(sb, SB_DYING); super_unlock_excl(sb); @@ -808,67 +808,6 @@ struct super_block *sget_fc(struct fs_context *fc, } EXPORT_SYMBOL(sget_fc); -/** - * sget - find or create a superblock - * @type: filesystem type superblock should belong to - * @test: comparison callback - * @set: setup callback - * @flags: mount flags - * @data: argument to each of them - */ -struct super_block *sget(struct file_system_type *type, - int (*test)(struct super_block *,void *), - int (*set)(struct super_block *,void *), - int flags, - void *data) -{ - struct user_namespace *user_ns = current_user_ns(); - struct super_block *s = NULL; - struct super_block *old; - int err; - -retry: - spin_lock(&sb_lock); - if (test) { - hlist_for_each_entry(old, &type->fs_supers, s_instances) { - if (!test(old, data)) - continue; - if (user_ns != old->s_user_ns) { - spin_unlock(&sb_lock); - destroy_unused_super(s); - return ERR_PTR(-EBUSY); - } - if (!grab_super(old)) - goto retry; - destroy_unused_super(s); - return old; - } - } - if (!s) { - spin_unlock(&sb_lock); - s = alloc_super(type, flags, user_ns); - if (!s) - return ERR_PTR(-ENOMEM); - goto retry; - } - - err = set(s, data); - if (err) { - spin_unlock(&sb_lock); - destroy_unused_super(s); - return ERR_PTR(err); - } - s->s_type = type; - strscpy(s->s_id, type->name, sizeof(s->s_id)); - list_add_tail(&s->s_list, &super_blocks); - hlist_add_head(&s->s_instances, &type->fs_supers); - spin_unlock(&sb_lock); - get_filesystem(type); - shrinker_register(s->s_shrink); - return s; -} -EXPORT_SYMBOL(sget); - void drop_super(struct super_block *sb) { super_unlock_shared(sb); diff --git a/include/linux/fs.h b/include/linux/fs.h index c5c31a6f7ed5..a220d14b1f91 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2340,10 +2340,6 @@ void free_anon_bdev(dev_t); struct super_block *sget_fc(struct fs_context *fc, int (*test)(struct super_block *, struct fs_context *), int (*set)(struct super_block *, struct fs_context *)); -struct super_block *sget(struct file_system_type *type, - int (*test)(struct super_block *,void *), - int (*set)(struct super_block *,void *), - int flags, void *data); struct super_block *sget_dev(struct fs_context *fc, dev_t dev); /* Alas, no aliases. Too much hassle with bringing module.h everywhere */