diff options
author | David Howells <dhowells@redhat.com> | 2019-03-27 10:15:16 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2019-09-05 14:34:22 -0400 |
commit | fe62c3a4e17ddfe672710425ab6eba2ba7203526 (patch) | |
tree | 4b8bfb4bbfbeb53c75b14f4522233ed3216749aa /fs/super.c | |
parent | 533770cc0ae84890624dc129609f3d75855c8982 (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.c | 94 |
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, | |||
1222 | EXPORT_SYMBOL(get_tree_keyed); | 1222 | EXPORT_SYMBOL(get_tree_keyed); |
1223 | 1223 | ||
1224 | #ifdef CONFIG_BLOCK | 1224 | #ifdef CONFIG_BLOCK |
1225 | |||
1225 | static int set_bdev_super(struct super_block *s, void *data) | 1226 | static 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 | ||
1235 | static 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 | |||
1240 | static 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 | */ | ||
1250 | int 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 | } | ||
1326 | EXPORT_SYMBOL(get_tree_bdev); | ||
1327 | |||
1234 | static int test_bdev_super(struct super_block *s, void *data) | 1328 | static 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; |