summaryrefslogtreecommitdiffstats
path: root/fs/super.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2019-03-27 10:15:16 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2019-09-05 14:34:22 -0400
commitfe62c3a4e17ddfe672710425ab6eba2ba7203526 (patch)
tree4b8bfb4bbfbeb53c75b14f4522233ed3216749aa /fs/super.c
parent533770cc0ae84890624dc129609f3d75855c8982 (diff)
vfs: Create fs_context-aware mount_bdev() replacement
Create a function, get_tree_bdev(), that is fs_context-aware and a ->get_tree() counterpart of mount_bdev(). It caches the block device pointer in the fs_context struct so that this information can be passed into sget_fc()'s test and set functions. Signed-off-by: David Howells <dhowells@redhat.com> cc: Jens Axboe <axboe@kernel.dk> cc: linux-block@vger.kernel.org Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/super.c')
-rw-r--r--fs/super.c94
1 files changed, 94 insertions, 0 deletions
diff --git a/fs/super.c b/fs/super.c
index 0220def9baba..da223b4cfbca 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -1222,6 +1222,7 @@ int get_tree_keyed(struct fs_context *fc,
1222EXPORT_SYMBOL(get_tree_keyed); 1222EXPORT_SYMBOL(get_tree_keyed);
1223 1223
1224#ifdef CONFIG_BLOCK 1224#ifdef CONFIG_BLOCK
1225
1225static int set_bdev_super(struct super_block *s, void *data) 1226static int set_bdev_super(struct super_block *s, void *data)
1226{ 1227{
1227 s->s_bdev = data; 1228 s->s_bdev = data;
@@ -1231,6 +1232,99 @@ static int set_bdev_super(struct super_block *s, void *data)
1231 return 0; 1232 return 0;
1232} 1233}
1233 1234
1235static int set_bdev_super_fc(struct super_block *s, struct fs_context *fc)
1236{
1237 return set_bdev_super(s, fc->sget_key);
1238}
1239
1240static int test_bdev_super_fc(struct super_block *s, struct fs_context *fc)
1241{
1242 return s->s_bdev == fc->sget_key;
1243}
1244
1245/**
1246 * get_tree_bdev - Get a superblock based on a single block device
1247 * @fc: The filesystem context holding the parameters
1248 * @fill_super: Helper to initialise a new superblock
1249 */
1250int get_tree_bdev(struct fs_context *fc,
1251 int (*fill_super)(struct super_block *,
1252 struct fs_context *))
1253{
1254 struct block_device *bdev;
1255 struct super_block *s;
1256 fmode_t mode = FMODE_READ | FMODE_EXCL;
1257 int error = 0;
1258
1259 if (!(fc->sb_flags & SB_RDONLY))
1260 mode |= FMODE_WRITE;
1261
1262 if (!fc->source)
1263 return invalf(fc, "No source specified");
1264
1265 bdev = blkdev_get_by_path(fc->source, mode, fc->fs_type);
1266 if (IS_ERR(bdev)) {
1267 errorf(fc, "%s: Can't open blockdev", fc->source);
1268 return PTR_ERR(bdev);
1269 }
1270
1271 /* Once the superblock is inserted into the list by sget_fc(), s_umount
1272 * will protect the lockfs code from trying to start a snapshot while
1273 * we are mounting
1274 */
1275 mutex_lock(&bdev->bd_fsfreeze_mutex);
1276 if (bdev->bd_fsfreeze_count > 0) {
1277 mutex_unlock(&bdev->bd_fsfreeze_mutex);
1278 warnf(fc, "%pg: Can't mount, blockdev is frozen", bdev);
1279 return -EBUSY;
1280 }
1281
1282 fc->sb_flags |= SB_NOSEC;
1283 fc->sget_key = bdev;
1284 s = sget_fc(fc, test_bdev_super_fc, set_bdev_super_fc);
1285 mutex_unlock(&bdev->bd_fsfreeze_mutex);
1286 if (IS_ERR(s))
1287 return PTR_ERR(s);
1288
1289 if (s->s_root) {
1290 /* Don't summarily change the RO/RW state. */
1291 if ((fc->sb_flags ^ s->s_flags) & SB_RDONLY) {
1292 warnf(fc, "%pg: Can't mount, would change RO state", bdev);
1293 deactivate_locked_super(s);
1294 blkdev_put(bdev, mode);
1295 return -EBUSY;
1296 }
1297
1298 /*
1299 * s_umount nests inside bd_mutex during
1300 * __invalidate_device(). blkdev_put() acquires
1301 * bd_mutex and can't be called under s_umount. Drop
1302 * s_umount temporarily. This is safe as we're
1303 * holding an active reference.
1304 */
1305 up_write(&s->s_umount);
1306 blkdev_put(bdev, mode);
1307 down_write(&s->s_umount);
1308 } else {
1309 s->s_mode = mode;
1310 snprintf(s->s_id, sizeof(s->s_id), "%pg", bdev);
1311 sb_set_blocksize(s, block_size(bdev));
1312 error = fill_super(s, fc);
1313 if (error) {
1314 deactivate_locked_super(s);
1315 return error;
1316 }
1317
1318 s->s_flags |= SB_ACTIVE;
1319 bdev->bd_super = s;
1320 }
1321
1322 BUG_ON(fc->root);
1323 fc->root = dget(s->s_root);
1324 return 0;
1325}
1326EXPORT_SYMBOL(get_tree_bdev);
1327
1234static int test_bdev_super(struct super_block *s, void *data) 1328static int test_bdev_super(struct super_block *s, void *data)
1235{ 1329{
1236 return (void *)s->s_bdev == data; 1330 return (void *)s->s_bdev == data;