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

btrfs: scan but don't register device on single device filesystem

After the commit 5f58d783fd78 ("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 <anand.jain@oracle.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>

authored by

Anand Jain and committed by
David Sterba
bc27d6f0 ed164802

+54 -15
+18 -5
fs/btrfs/super.c
··· 846 846 error = -ENOMEM; 847 847 goto out; 848 848 } 849 - device = btrfs_scan_one_device(device_name, flags); 849 + device = btrfs_scan_one_device(device_name, flags, false); 850 850 kfree(device_name); 851 851 if (IS_ERR(device)) { 852 852 error = PTR_ERR(device); ··· 1432 1432 goto error_fs_info; 1433 1433 } 1434 1434 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); 1436 1441 if (IS_ERR(device)) { 1437 1442 mutex_unlock(&uuid_mutex); 1438 1443 error = PTR_ERR(device); ··· 2149 2144 switch (cmd) { 2150 2145 case BTRFS_IOC_SCAN_DEV: 2151 2146 mutex_lock(&uuid_mutex); 2152 - device = btrfs_scan_one_device(vol->name, BLK_OPEN_READ); 2147 + /* 2148 + * Scanning outside of mount can return NULL which would turn 2149 + * into 0 error code. 2150 + */ 2151 + device = btrfs_scan_one_device(vol->name, BLK_OPEN_READ, false); 2153 2152 ret = PTR_ERR_OR_ZERO(device); 2154 2153 mutex_unlock(&uuid_mutex); 2155 2154 break; ··· 2167 2158 break; 2168 2159 case BTRFS_IOC_DEVICES_READY: 2169 2160 mutex_lock(&uuid_mutex); 2170 - device = btrfs_scan_one_device(vol->name, BLK_OPEN_READ); 2171 - if (IS_ERR(device)) { 2161 + /* 2162 + * Scanning outside of mount can return NULL which would turn 2163 + * into 0 error code. 2164 + */ 2165 + device = btrfs_scan_one_device(vol->name, BLK_OPEN_READ, false); 2166 + if (IS_ERR_OR_NULL(device)) { 2172 2167 mutex_unlock(&uuid_mutex); 2173 2168 ret = PTR_ERR(device); 2174 2169 break;
+34 -9
fs/btrfs/volumes.c
··· 559 559 { 560 560 struct btrfs_fs_devices *fs_devices, *tmp_fs_devices; 561 561 struct btrfs_device *device, *tmp_device; 562 - int ret = 0; 562 + int ret; 563 + bool freed = false; 563 564 564 565 lockdep_assert_held(&uuid_mutex); 565 566 566 - if (devt) 567 - ret = -ENOENT; 568 - 567 + /* Return good status if there is no instance of devt. */ 568 + ret = 0; 569 569 list_for_each_entry_safe(fs_devices, tmp_fs_devices, &fs_uuids, fs_list) { 570 570 571 571 mutex_lock(&fs_devices->device_list_mutex); ··· 576 576 if (devt && devt != device->devt) 577 577 continue; 578 578 if (fs_devices->opened) { 579 - /* for an already deleted device return 0 */ 580 - if (devt && ret != 0) 579 + if (devt) 581 580 ret = -EBUSY; 582 581 break; 583 582 } ··· 586 587 list_del(&device->dev_list); 587 588 btrfs_free_device(device); 588 589 589 - ret = 0; 590 + freed = true; 590 591 } 591 592 mutex_unlock(&fs_devices->device_list_mutex); 592 593 ··· 596 597 free_fs_devices(fs_devices); 597 598 } 598 599 } 600 + 601 + /* If there is at least one freed device return 0. */ 602 + if (freed) 603 + return 0; 599 604 600 605 return ret; 601 606 } ··· 1359 1356 /* 1360 1357 * Look for a btrfs signature on a device. This may be called out of the mount path 1361 1358 * and we are not allowed to call set_blocksize during the scan. The superblock 1362 - * is read via pagecache 1359 + * is read via pagecache. 1360 + * 1361 + * With @mount_arg_dev it's a scan during mount time that will always register 1362 + * the device or return an error. Multi-device and seeding devices are registered 1363 + * in both cases. 1363 1364 */ 1364 - struct btrfs_device *btrfs_scan_one_device(const char *path, blk_mode_t flags) 1365 + struct btrfs_device *btrfs_scan_one_device(const char *path, blk_mode_t flags, 1366 + bool mount_arg_dev) 1365 1367 { 1366 1368 struct btrfs_super_block *disk_super; 1367 1369 bool new_device_added = false; ··· 1411 1403 goto error_bdev_put; 1412 1404 } 1413 1405 1406 + if (!mount_arg_dev && btrfs_super_num_devices(disk_super) == 1 && 1407 + !(btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_SEEDING)) { 1408 + dev_t devt; 1409 + 1410 + ret = lookup_bdev(path, &devt); 1411 + if (ret) 1412 + btrfs_warn(NULL, "lookup bdev failed for path %s: %d", 1413 + path, ret); 1414 + else 1415 + btrfs_free_stale_devices(devt, NULL); 1416 + 1417 + pr_debug("BTRFS: skip registering single non-seed device %s\n", path); 1418 + device = NULL; 1419 + goto free_disk_super; 1420 + } 1421 + 1414 1422 device = device_list_add(path, disk_super, &new_device_added); 1415 1423 if (!IS_ERR(device) && new_device_added) 1416 1424 btrfs_free_stale_devices(device->devt, device); 1417 1425 1426 + free_disk_super: 1418 1427 btrfs_release_disk_super(disk_super); 1419 1428 1420 1429 error_bdev_put:
+2 -1
fs/btrfs/volumes.h
··· 619 619 void btrfs_mapping_tree_free(struct extent_map_tree *tree); 620 620 int btrfs_open_devices(struct btrfs_fs_devices *fs_devices, 621 621 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); 623 624 int btrfs_forget_devices(dev_t devt); 624 625 void btrfs_close_devices(struct btrfs_fs_devices *fs_devices); 625 626 void btrfs_free_extra_devids(struct btrfs_fs_devices *fs_devices);