diff options
author | David Howells <dhowells@redhat.com> | 2019-03-21 05:22:36 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2019-09-05 14:34:23 -0400 |
commit | 43ce4c1feadbc84c772518a2d1974f6ba1b15089 (patch) | |
tree | e3bc42b51b6c0ca84b4a7c99f676999ed0bf892f /fs/super.c | |
parent | 0f071004109d9c8de7023b9a64fa2ba3fa87cbed (diff) |
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.c | 35 |
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, | |||
1160 | { | 1160 | { |
1161 | int (*test)(struct super_block *, struct fs_context *); | 1161 | int (*test)(struct super_block *, struct fs_context *); |
1162 | struct super_block *sb; | 1162 | struct super_block *sb; |
1163 | int err; | ||
1163 | 1164 | ||
1164 | switch (keying) { | 1165 | switch (keying) { |
1165 | case vfs_get_single_super: | 1166 | case vfs_get_single_super: |
1167 | case vfs_get_single_reconf_super: | ||
1166 | test = test_single_super; | 1168 | test = test_single_super; |
1167 | break; | 1169 | break; |
1168 | case vfs_get_keyed_super: | 1170 | case vfs_get_keyed_super: |
@@ -1180,18 +1182,29 @@ int vfs_get_super(struct fs_context *fc, | |||
1180 | return PTR_ERR(sb); | 1182 | return PTR_ERR(sb); |
1181 | 1183 | ||
1182 | if (!sb->s_root) { | 1184 | if (!sb->s_root) { |
1183 | int err = fill_super(sb, fc); | 1185 | err = fill_super(sb, fc); |
1184 | if (err) { | 1186 | if (err) |
1185 | deactivate_locked_super(sb); | 1187 | goto error; |
1186 | return err; | ||
1187 | } | ||
1188 | 1188 | ||
1189 | sb->s_flags |= SB_ACTIVE; | 1189 | sb->s_flags |= SB_ACTIVE; |
1190 | fc->root = dget(sb->s_root); | ||
1191 | } else { | ||
1192 | fc->root = dget(sb->s_root); | ||
1193 | if (keying == vfs_get_single_reconf_super) { | ||
1194 | err = reconfigure_super(fc); | ||
1195 | if (err < 0) { | ||
1196 | dput(fc->root); | ||
1197 | fc->root = NULL; | ||
1198 | goto error; | ||
1199 | } | ||
1200 | } | ||
1190 | } | 1201 | } |
1191 | 1202 | ||
1192 | BUG_ON(fc->root); | ||
1193 | fc->root = dget(sb->s_root); | ||
1194 | return 0; | 1203 | return 0; |
1204 | |||
1205 | error: | ||
1206 | deactivate_locked_super(sb); | ||
1207 | return err; | ||
1195 | } | 1208 | } |
1196 | EXPORT_SYMBOL(vfs_get_super); | 1209 | EXPORT_SYMBOL(vfs_get_super); |
1197 | 1210 | ||
@@ -1211,6 +1224,14 @@ int get_tree_single(struct fs_context *fc, | |||
1211 | } | 1224 | } |
1212 | EXPORT_SYMBOL(get_tree_single); | 1225 | EXPORT_SYMBOL(get_tree_single); |
1213 | 1226 | ||
1227 | int get_tree_single_reconf(struct fs_context *fc, | ||
1228 | int (*fill_super)(struct super_block *sb, | ||
1229 | struct fs_context *fc)) | ||
1230 | { | ||
1231 | return vfs_get_super(fc, vfs_get_single_reconf_super, fill_super); | ||
1232 | } | ||
1233 | EXPORT_SYMBOL(get_tree_single_reconf); | ||
1234 | |||
1214 | int get_tree_keyed(struct fs_context *fc, | 1235 | int get_tree_keyed(struct fs_context *fc, |
1215 | int (*fill_super)(struct super_block *sb, | 1236 | int (*fill_super)(struct super_block *sb, |
1216 | struct fs_context *fc), | 1237 | struct fs_context *fc), |