summaryrefslogtreecommitdiffstats
path: root/fs/super.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2019-03-21 10:22:36 +0100
committerAl Viro <viro@zeniv.linux.org.uk>2019-09-05 20:34:23 +0200
commit43ce4c1feadbc84c772518a2d1974f6ba1b15089 (patch)
treee3bc42b51b6c0ca84b4a7c99f676999ed0bf892f /fs/super.c
parentmtd: Provide fs_context-aware mount_mtd() replacement (diff)
downloadlinux-43ce4c1feadbc84c772518a2d1974f6ba1b15089.tar.xz
linux-43ce4c1feadbc84c772518a2d1974f6ba1b15089.zip
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>
Diffstat (limited to 'fs/super.c')
-rw-r--r--fs/super.c35
1 files changed, 28 insertions, 7 deletions
diff --git a/fs/super.c b/fs/super.c
index da223b4cfbca..beaf076d9733 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -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),