Skip to content

Commit bc27d6f

Browse files
asjkdave
authored andcommitted
btrfs: scan but don't register device on single device filesystem
After the commit 5f58d78 ("btrfs: free device in btrfs_close_devices for a single device filesystem") we unregister the device from the kernel memory upon unmounting for a single device. So, device registration that was performed before mounting if any is no longer in the kernel memory. However, in fact, note that device registration is unnecessary for a single-device btrfs filesystem unless it's a seed device. So for commands like 'btrfs device scan' or 'btrfs device ready' with a non-seed single-device btrfs filesystem, they can return success just after superblock verification and without the actual device scan. When 'device scan --forget' is called on such device no error is returned. The seed device must remain in the kernel memory to allow the sprout device to mount without the need to specify the seed device explicitly. Signed-off-by: Anand Jain <[email protected]> Reviewed-by: David Sterba <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent ed16480 commit bc27d6f

File tree

3 files changed

+54
-15
lines changed

3 files changed

+54
-15
lines changed

fs/btrfs/super.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -846,7 +846,7 @@ static int btrfs_parse_device_options(const char *options, blk_mode_t flags)
846846
error = -ENOMEM;
847847
goto out;
848848
}
849-
device = btrfs_scan_one_device(device_name, flags);
849+
device = btrfs_scan_one_device(device_name, flags, false);
850850
kfree(device_name);
851851
if (IS_ERR(device)) {
852852
error = PTR_ERR(device);
@@ -1432,7 +1432,12 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
14321432
goto error_fs_info;
14331433
}
14341434

1435-
device = btrfs_scan_one_device(device_name, mode);
1435+
/*
1436+
* With 'true' passed to btrfs_scan_one_device() (mount time) we expect
1437+
* either a valid device or an error.
1438+
*/
1439+
device = btrfs_scan_one_device(device_name, mode, true);
1440+
ASSERT(device != NULL);
14361441
if (IS_ERR(device)) {
14371442
mutex_unlock(&uuid_mutex);
14381443
error = PTR_ERR(device);
@@ -2144,7 +2149,11 @@ static long btrfs_control_ioctl(struct file *file, unsigned int cmd,
21442149
switch (cmd) {
21452150
case BTRFS_IOC_SCAN_DEV:
21462151
mutex_lock(&uuid_mutex);
2147-
device = btrfs_scan_one_device(vol->name, BLK_OPEN_READ);
2152+
/*
2153+
* Scanning outside of mount can return NULL which would turn
2154+
* into 0 error code.
2155+
*/
2156+
device = btrfs_scan_one_device(vol->name, BLK_OPEN_READ, false);
21482157
ret = PTR_ERR_OR_ZERO(device);
21492158
mutex_unlock(&uuid_mutex);
21502159
break;
@@ -2158,8 +2167,12 @@ static long btrfs_control_ioctl(struct file *file, unsigned int cmd,
21582167
break;
21592168
case BTRFS_IOC_DEVICES_READY:
21602169
mutex_lock(&uuid_mutex);
2161-
device = btrfs_scan_one_device(vol->name, BLK_OPEN_READ);
2162-
if (IS_ERR(device)) {
2170+
/*
2171+
* Scanning outside of mount can return NULL which would turn
2172+
* into 0 error code.
2173+
*/
2174+
device = btrfs_scan_one_device(vol->name, BLK_OPEN_READ, false);
2175+
if (IS_ERR_OR_NULL(device)) {
21632176
mutex_unlock(&uuid_mutex);
21642177
ret = PTR_ERR(device);
21652178
break;

fs/btrfs/volumes.c

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -559,13 +559,13 @@ static int btrfs_free_stale_devices(dev_t devt, struct btrfs_device *skip_device
559559
{
560560
struct btrfs_fs_devices *fs_devices, *tmp_fs_devices;
561561
struct btrfs_device *device, *tmp_device;
562-
int ret = 0;
562+
int ret;
563+
bool freed = false;
563564

564565
lockdep_assert_held(&uuid_mutex);
565566

566-
if (devt)
567-
ret = -ENOENT;
568-
567+
/* Return good status if there is no instance of devt. */
568+
ret = 0;
569569
list_for_each_entry_safe(fs_devices, tmp_fs_devices, &fs_uuids, fs_list) {
570570

571571
mutex_lock(&fs_devices->device_list_mutex);
@@ -576,8 +576,7 @@ static int btrfs_free_stale_devices(dev_t devt, struct btrfs_device *skip_device
576576
if (devt && devt != device->devt)
577577
continue;
578578
if (fs_devices->opened) {
579-
/* for an already deleted device return 0 */
580-
if (devt && ret != 0)
579+
if (devt)
581580
ret = -EBUSY;
582581
break;
583582
}
@@ -587,7 +586,7 @@ static int btrfs_free_stale_devices(dev_t devt, struct btrfs_device *skip_device
587586
list_del(&device->dev_list);
588587
btrfs_free_device(device);
589588

590-
ret = 0;
589+
freed = true;
591590
}
592591
mutex_unlock(&fs_devices->device_list_mutex);
593592

@@ -598,6 +597,10 @@ static int btrfs_free_stale_devices(dev_t devt, struct btrfs_device *skip_device
598597
}
599598
}
600599

600+
/* If there is at least one freed device return 0. */
601+
if (freed)
602+
return 0;
603+
601604
return ret;
602605
}
603606

@@ -1356,9 +1359,14 @@ int btrfs_forget_devices(dev_t devt)
13561359
/*
13571360
* Look for a btrfs signature on a device. This may be called out of the mount path
13581361
* and we are not allowed to call set_blocksize during the scan. The superblock
1359-
* is read via pagecache
1362+
* is read via pagecache.
1363+
*
1364+
* With @mount_arg_dev it's a scan during mount time that will always register
1365+
* the device or return an error. Multi-device and seeding devices are registered
1366+
* in both cases.
13601367
*/
1361-
struct btrfs_device *btrfs_scan_one_device(const char *path, blk_mode_t flags)
1368+
struct btrfs_device *btrfs_scan_one_device(const char *path, blk_mode_t flags,
1369+
bool mount_arg_dev)
13621370
{
13631371
struct btrfs_super_block *disk_super;
13641372
bool new_device_added = false;
@@ -1403,10 +1411,27 @@ struct btrfs_device *btrfs_scan_one_device(const char *path, blk_mode_t flags)
14031411
goto error_bdev_put;
14041412
}
14051413

1414+
if (!mount_arg_dev && btrfs_super_num_devices(disk_super) == 1 &&
1415+
!(btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_SEEDING)) {
1416+
dev_t devt;
1417+
1418+
ret = lookup_bdev(path, &devt);
1419+
if (ret)
1420+
btrfs_warn(NULL, "lookup bdev failed for path %s: %d",
1421+
path, ret);
1422+
else
1423+
btrfs_free_stale_devices(devt, NULL);
1424+
1425+
pr_debug("BTRFS: skip registering single non-seed device %s\n", path);
1426+
device = NULL;
1427+
goto free_disk_super;
1428+
}
1429+
14061430
device = device_list_add(path, disk_super, &new_device_added);
14071431
if (!IS_ERR(device) && new_device_added)
14081432
btrfs_free_stale_devices(device->devt, device);
14091433

1434+
free_disk_super:
14101435
btrfs_release_disk_super(disk_super);
14111436

14121437
error_bdev_put:

fs/btrfs/volumes.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,8 @@ struct btrfs_block_group *btrfs_create_chunk(struct btrfs_trans_handle *trans,
619619
void btrfs_mapping_tree_free(struct extent_map_tree *tree);
620620
int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
621621
blk_mode_t flags, void *holder);
622-
struct btrfs_device *btrfs_scan_one_device(const char *path, blk_mode_t flags);
622+
struct btrfs_device *btrfs_scan_one_device(const char *path, blk_mode_t flags,
623+
bool mount_arg_dev);
623624
int btrfs_forget_devices(dev_t devt);
624625
void btrfs_close_devices(struct btrfs_fs_devices *fs_devices);
625626
void btrfs_free_extra_devids(struct btrfs_fs_devices *fs_devices);

0 commit comments

Comments
 (0)