Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

David Howells and committed by
Al Viro
43ce4c1f 0f071004

+32 -7
+28 -7
fs/super.c
··· 1160 1160 { 1161 1161 int (*test)(struct super_block *, struct fs_context *); 1162 1162 struct super_block *sb; 1163 + int err; 1163 1164 1164 1165 switch (keying) { 1165 1166 case vfs_get_single_super: 1167 + case vfs_get_single_reconf_super: 1166 1168 test = test_single_super; 1167 1169 break; 1168 1170 case vfs_get_keyed_super: ··· 1182 1180 return PTR_ERR(sb); 1183 1181 1184 1182 if (!sb->s_root) { 1185 - int err = fill_super(sb, fc); 1186 - if (err) { 1187 - deactivate_locked_super(sb); 1188 - return err; 1189 - } 1183 + err = fill_super(sb, fc); 1184 + if (err) 1185 + goto error; 1190 1186 1191 1187 sb->s_flags |= SB_ACTIVE; 1188 + fc->root = dget(sb->s_root); 1189 + } else { 1190 + fc->root = dget(sb->s_root); 1191 + if (keying == vfs_get_single_reconf_super) { 1192 + err = reconfigure_super(fc); 1193 + if (err < 0) { 1194 + dput(fc->root); 1195 + fc->root = NULL; 1196 + goto error; 1197 + } 1198 + } 1192 1199 } 1193 1200 1194 - BUG_ON(fc->root); 1195 - fc->root = dget(sb->s_root); 1196 1201 return 0; 1202 + 1203 + error: 1204 + deactivate_locked_super(sb); 1205 + return err; 1197 1206 } 1198 1207 EXPORT_SYMBOL(vfs_get_super); 1199 1208 ··· 1223 1210 return vfs_get_super(fc, vfs_get_single_super, fill_super); 1224 1211 } 1225 1212 EXPORT_SYMBOL(get_tree_single); 1213 + 1214 + int get_tree_single_reconf(struct fs_context *fc, 1215 + int (*fill_super)(struct super_block *sb, 1216 + struct fs_context *fc)) 1217 + { 1218 + return vfs_get_super(fc, vfs_get_single_reconf_super, fill_super); 1219 + } 1220 + EXPORT_SYMBOL(get_tree_single_reconf); 1226 1221 1227 1222 int get_tree_keyed(struct fs_context *fc, 1228 1223 int (*fill_super)(struct super_block *sb,
+4
include/linux/fs_context.h
··· 141 141 */ 142 142 enum vfs_get_super_keying { 143 143 vfs_get_single_super, /* Only one such superblock may exist */ 144 + vfs_get_single_reconf_super, /* As above, but reconfigure if it exists */ 144 145 vfs_get_keyed_super, /* Superblocks with different s_fs_info keys may exist */ 145 146 vfs_get_independent_super, /* Multiple independent superblocks may exist */ 146 147 }; ··· 154 153 int (*fill_super)(struct super_block *sb, 155 154 struct fs_context *fc)); 156 155 extern int get_tree_single(struct fs_context *fc, 156 + int (*fill_super)(struct super_block *sb, 157 + struct fs_context *fc)); 158 + extern int get_tree_single_reconf(struct fs_context *fc, 157 159 int (*fill_super)(struct super_block *sb, 158 160 struct fs_context *fc)); 159 161 extern int get_tree_keyed(struct fs_context *fc,