Skip to content

Commit

Permalink
btrfs: scan but don't register device on single device filesystem
Browse files Browse the repository at this point in the history
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 <anand.jain@oracle.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
  • Loading branch information
asj authored and kdave committed Oct 12, 2023
1 parent ed16480 commit bc27d6f
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 15 deletions.
23 changes: 18 additions & 5 deletions fs/btrfs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -846,7 +846,7 @@ static int btrfs_parse_device_options(const char *options, blk_mode_t flags)
error = -ENOMEM;
goto out;
}
device = btrfs_scan_one_device(device_name, flags);
device = btrfs_scan_one_device(device_name, flags, false);
kfree(device_name);
if (IS_ERR(device)) {
error = PTR_ERR(device);
Expand Down Expand Up @@ -1432,7 +1432,12 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
goto error_fs_info;
}

device = btrfs_scan_one_device(device_name, mode);
/*
* With 'true' passed to btrfs_scan_one_device() (mount time) we expect
* either a valid device or an error.
*/
device = btrfs_scan_one_device(device_name, mode, true);
ASSERT(device != NULL);
if (IS_ERR(device)) {
mutex_unlock(&uuid_mutex);
error = PTR_ERR(device);
Expand Down Expand Up @@ -2144,7 +2149,11 @@ static long btrfs_control_ioctl(struct file *file, unsigned int cmd,
switch (cmd) {
case BTRFS_IOC_SCAN_DEV:
mutex_lock(&uuid_mutex);
device = btrfs_scan_one_device(vol->name, BLK_OPEN_READ);
/*
* Scanning outside of mount can return NULL which would turn
* into 0 error code.
*/
device = btrfs_scan_one_device(vol->name, BLK_OPEN_READ, false);
ret = PTR_ERR_OR_ZERO(device);
mutex_unlock(&uuid_mutex);
break;
Expand All @@ -2158,8 +2167,12 @@ static long btrfs_control_ioctl(struct file *file, unsigned int cmd,
break;
case BTRFS_IOC_DEVICES_READY:
mutex_lock(&uuid_mutex);
device = btrfs_scan_one_device(vol->name, BLK_OPEN_READ);
if (IS_ERR(device)) {
/*
* Scanning outside of mount can return NULL which would turn
* into 0 error code.
*/
device = btrfs_scan_one_device(vol->name, BLK_OPEN_READ, false);
if (IS_ERR_OR_NULL(device)) {
mutex_unlock(&uuid_mutex);
ret = PTR_ERR(device);
break;
Expand Down
43 changes: 34 additions & 9 deletions fs/btrfs/volumes.c
Original file line number Diff line number Diff line change
Expand Up @@ -559,13 +559,13 @@ static int btrfs_free_stale_devices(dev_t devt, struct btrfs_device *skip_device
{
struct btrfs_fs_devices *fs_devices, *tmp_fs_devices;
struct btrfs_device *device, *tmp_device;
int ret = 0;
int ret;
bool freed = false;

lockdep_assert_held(&uuid_mutex);

if (devt)
ret = -ENOENT;

/* Return good status if there is no instance of devt. */
ret = 0;
list_for_each_entry_safe(fs_devices, tmp_fs_devices, &fs_uuids, fs_list) {

mutex_lock(&fs_devices->device_list_mutex);
Expand All @@ -576,8 +576,7 @@ static int btrfs_free_stale_devices(dev_t devt, struct btrfs_device *skip_device
if (devt && devt != device->devt)
continue;
if (fs_devices->opened) {
/* for an already deleted device return 0 */
if (devt && ret != 0)
if (devt)
ret = -EBUSY;
break;
}
Expand All @@ -587,7 +586,7 @@ static int btrfs_free_stale_devices(dev_t devt, struct btrfs_device *skip_device
list_del(&device->dev_list);
btrfs_free_device(device);

ret = 0;
freed = true;
}
mutex_unlock(&fs_devices->device_list_mutex);

Expand All @@ -598,6 +597,10 @@ static int btrfs_free_stale_devices(dev_t devt, struct btrfs_device *skip_device
}
}

/* If there is at least one freed device return 0. */
if (freed)
return 0;

return ret;
}

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

if (!mount_arg_dev && btrfs_super_num_devices(disk_super) == 1 &&
!(btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_SEEDING)) {
dev_t devt;

ret = lookup_bdev(path, &devt);
if (ret)
btrfs_warn(NULL, "lookup bdev failed for path %s: %d",
path, ret);
else
btrfs_free_stale_devices(devt, NULL);

pr_debug("BTRFS: skip registering single non-seed device %s\n", path);
device = NULL;
goto free_disk_super;
}

device = device_list_add(path, disk_super, &new_device_added);
if (!IS_ERR(device) && new_device_added)
btrfs_free_stale_devices(device->devt, device);

free_disk_super:
btrfs_release_disk_super(disk_super);

error_bdev_put:
Expand Down
3 changes: 2 additions & 1 deletion fs/btrfs/volumes.h
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,8 @@ struct btrfs_block_group *btrfs_create_chunk(struct btrfs_trans_handle *trans,
void btrfs_mapping_tree_free(struct extent_map_tree *tree);
int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
blk_mode_t flags, void *holder);
struct btrfs_device *btrfs_scan_one_device(const char *path, blk_mode_t flags);
struct btrfs_device *btrfs_scan_one_device(const char *path, blk_mode_t flags,
bool mount_arg_dev);
int btrfs_forget_devices(dev_t devt);
void btrfs_close_devices(struct btrfs_fs_devices *fs_devices);
void btrfs_free_extra_devids(struct btrfs_fs_devices *fs_devices);
Expand Down

0 comments on commit bc27d6f

Please sign in to comment.