mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-25 05:34:00 +08:00
btrfs: clean the old superblocks before freeing the device
btrfs_rm_device frees the block device but then re-opens it using the saved device name. A race exists between the close and the re-open that allows the block size to be changed. The result is getting stuck forever in the reclaim loop in __getblk_slow. This patch moves the superblock cleanup before closing the block device, which is also consistent with other callers. We also don't need a private copy of dev_name as the whole routine operates under the uuid_mutex. Signed-off-by: Jeff Mahoney <jeffm@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
02794222c4
commit
cea67ab92d
@ -1846,7 +1846,6 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path, u64 devid)
|
|||||||
u64 num_devices;
|
u64 num_devices;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
bool clear_super = false;
|
bool clear_super = false;
|
||||||
char *dev_name = NULL;
|
|
||||||
|
|
||||||
mutex_lock(&uuid_mutex);
|
mutex_lock(&uuid_mutex);
|
||||||
|
|
||||||
@ -1882,11 +1881,6 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path, u64 devid)
|
|||||||
list_del_init(&device->dev_alloc_list);
|
list_del_init(&device->dev_alloc_list);
|
||||||
device->fs_devices->rw_devices--;
|
device->fs_devices->rw_devices--;
|
||||||
unlock_chunks(root);
|
unlock_chunks(root);
|
||||||
dev_name = kstrdup(device->name->str, GFP_KERNEL);
|
|
||||||
if (!dev_name) {
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto error_undo;
|
|
||||||
}
|
|
||||||
clear_super = true;
|
clear_super = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1936,14 +1930,21 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path, u64 devid)
|
|||||||
btrfs_sysfs_rm_device_link(root->fs_info->fs_devices, device);
|
btrfs_sysfs_rm_device_link(root->fs_info->fs_devices, device);
|
||||||
}
|
}
|
||||||
|
|
||||||
btrfs_close_bdev(device);
|
|
||||||
|
|
||||||
call_rcu(&device->rcu, free_device);
|
|
||||||
|
|
||||||
num_devices = btrfs_super_num_devices(root->fs_info->super_copy) - 1;
|
num_devices = btrfs_super_num_devices(root->fs_info->super_copy) - 1;
|
||||||
btrfs_set_super_num_devices(root->fs_info->super_copy, num_devices);
|
btrfs_set_super_num_devices(root->fs_info->super_copy, num_devices);
|
||||||
mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
|
mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* at this point, the device is zero sized and detached from
|
||||||
|
* the devices list. All that's left is to zero out the old
|
||||||
|
* supers and free the device.
|
||||||
|
*/
|
||||||
|
if (device->writeable)
|
||||||
|
btrfs_scratch_superblocks(device->bdev, device->name->str);
|
||||||
|
|
||||||
|
btrfs_close_bdev(device);
|
||||||
|
call_rcu(&device->rcu, free_device);
|
||||||
|
|
||||||
if (cur_devices->open_devices == 0) {
|
if (cur_devices->open_devices == 0) {
|
||||||
struct btrfs_fs_devices *fs_devices;
|
struct btrfs_fs_devices *fs_devices;
|
||||||
fs_devices = root->fs_info->fs_devices;
|
fs_devices = root->fs_info->fs_devices;
|
||||||
@ -1962,24 +1963,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path, u64 devid)
|
|||||||
root->fs_info->num_tolerated_disk_barrier_failures =
|
root->fs_info->num_tolerated_disk_barrier_failures =
|
||||||
btrfs_calc_num_tolerated_disk_barrier_failures(root->fs_info);
|
btrfs_calc_num_tolerated_disk_barrier_failures(root->fs_info);
|
||||||
|
|
||||||
/*
|
|
||||||
* at this point, the device is zero sized. We want to
|
|
||||||
* remove it from the devices list and zero out the old super
|
|
||||||
*/
|
|
||||||
if (clear_super) {
|
|
||||||
struct block_device *bdev;
|
|
||||||
|
|
||||||
bdev = blkdev_get_by_path(dev_name, FMODE_READ | FMODE_EXCL,
|
|
||||||
root->fs_info->bdev_holder);
|
|
||||||
if (!IS_ERR(bdev)) {
|
|
||||||
btrfs_scratch_superblocks(bdev, dev_name);
|
|
||||||
blkdev_put(bdev, FMODE_READ | FMODE_EXCL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
kfree(dev_name);
|
|
||||||
|
|
||||||
mutex_unlock(&uuid_mutex);
|
mutex_unlock(&uuid_mutex);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user