vfs: Add a single-or-reconfig keying to vfs_get_super()

Add an additional keying mode to vfs_get_super() to indicate that only a
single superblock should exist in the system, and that, if it does, further
mounts should invoke reconfiguration upon it.

This allows mount_single() to be replaced.

[Fix by Eric Biggers folded in]

Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
David Howells 2019-03-21 09:22:36 +00:00 committed by Al Viro
parent 0f07100410
commit 43ce4c1fea
2 changed files with 32 additions and 7 deletions

View File

@ -1160,9 +1160,11 @@ int vfs_get_super(struct fs_context *fc,
{
int (*test)(struct super_block *, struct fs_context *);
struct super_block *sb;
int err;
switch (keying) {
case vfs_get_single_super:
case vfs_get_single_reconf_super:
test = test_single_super;
break;
case vfs_get_keyed_super:
@ -1180,18 +1182,29 @@ int vfs_get_super(struct fs_context *fc,
return PTR_ERR(sb);
if (!sb->s_root) {
int err = fill_super(sb, fc);
if (err) {
deactivate_locked_super(sb);
return err;
}
err = fill_super(sb, fc);
if (err)
goto error;
sb->s_flags |= SB_ACTIVE;
fc->root = dget(sb->s_root);
} else {
fc->root = dget(sb->s_root);
if (keying == vfs_get_single_reconf_super) {
err = reconfigure_super(fc);
if (err < 0) {
dput(fc->root);
fc->root = NULL;
goto error;
}
}
}
BUG_ON(fc->root);
fc->root = dget(sb->s_root);
return 0;
error:
deactivate_locked_super(sb);
return err;
}
EXPORT_SYMBOL(vfs_get_super);
@ -1211,6 +1224,14 @@ int get_tree_single(struct fs_context *fc,
}
EXPORT_SYMBOL(get_tree_single);
int get_tree_single_reconf(struct fs_context *fc,
int (*fill_super)(struct super_block *sb,
struct fs_context *fc))
{
return vfs_get_super(fc, vfs_get_single_reconf_super, fill_super);
}
EXPORT_SYMBOL(get_tree_single_reconf);
int get_tree_keyed(struct fs_context *fc,
int (*fill_super)(struct super_block *sb,
struct fs_context *fc),

View File

@ -141,6 +141,7 @@ extern void put_fs_context(struct fs_context *fc);
*/
enum vfs_get_super_keying {
vfs_get_single_super, /* Only one such superblock may exist */
vfs_get_single_reconf_super, /* As above, but reconfigure if it exists */
vfs_get_keyed_super, /* Superblocks with different s_fs_info keys may exist */
vfs_get_independent_super, /* Multiple independent superblocks may exist */
};
@ -155,6 +156,9 @@ extern int get_tree_nodev(struct fs_context *fc,
extern int get_tree_single(struct fs_context *fc,
int (*fill_super)(struct super_block *sb,
struct fs_context *fc));
extern int get_tree_single_reconf(struct fs_context *fc,
int (*fill_super)(struct super_block *sb,
struct fs_context *fc));
extern int get_tree_keyed(struct fs_context *fc,
int (*fill_super)(struct super_block *sb,
struct fs_context *fc),