diff options
author | Jeff Mahoney <jeffm@suse.com> | 2016-09-20 08:50:21 -0400 |
---|---|---|
committer | David Sterba <dsterba@suse.com> | 2016-09-26 12:08:44 -0400 |
commit | cea67ab92d3d4da9f2b4141d87cb8664757daca0 (patch) | |
tree | 75f6575c0d9aecef3d981ff0083222b2c4932be9 | |
parent | 02794222c4132ac003e7281fb71f4ec1645ffc87 (diff) |
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>
-rw-r--r-- | fs/btrfs/volumes.c | 38 |
1 files changed, 11 insertions, 27 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index c356ce332229..be2c8b35c3ae 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -1846,7 +1846,6 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path, u64 devid) | |||
1846 | u64 num_devices; | 1846 | u64 num_devices; |
1847 | int ret = 0; | 1847 | int ret = 0; |
1848 | bool clear_super = false; | 1848 | bool clear_super = false; |
1849 | char *dev_name = NULL; | ||
1850 | 1849 | ||
1851 | mutex_lock(&uuid_mutex); | 1850 | mutex_lock(&uuid_mutex); |
1852 | 1851 | ||
@@ -1882,11 +1881,6 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path, u64 devid) | |||
1882 | list_del_init(&device->dev_alloc_list); | 1881 | list_del_init(&device->dev_alloc_list); |
1883 | device->fs_devices->rw_devices--; | 1882 | device->fs_devices->rw_devices--; |
1884 | unlock_chunks(root); | 1883 | unlock_chunks(root); |
1885 | dev_name = kstrdup(device->name->str, GFP_KERNEL); | ||
1886 | if (!dev_name) { | ||
1887 | ret = -ENOMEM; | ||
1888 | goto error_undo; | ||
1889 | } | ||
1890 | clear_super = true; | 1884 | clear_super = true; |
1891 | } | 1885 | } |
1892 | 1886 | ||
@@ -1936,14 +1930,21 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path, u64 devid) | |||
1936 | btrfs_sysfs_rm_device_link(root->fs_info->fs_devices, device); | 1930 | btrfs_sysfs_rm_device_link(root->fs_info->fs_devices, device); |
1937 | } | 1931 | } |
1938 | 1932 | ||
1939 | btrfs_close_bdev(device); | ||
1940 | |||
1941 | call_rcu(&device->rcu, free_device); | ||
1942 | |||
1943 | num_devices = btrfs_super_num_devices(root->fs_info->super_copy) - 1; | 1933 | num_devices = btrfs_super_num_devices(root->fs_info->super_copy) - 1; |
1944 | btrfs_set_super_num_devices(root->fs_info->super_copy, num_devices); | 1934 | btrfs_set_super_num_devices(root->fs_info->super_copy, num_devices); |
1945 | mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); | 1935 | mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); |
1946 | 1936 | ||
1937 | /* | ||
1938 | * at this point, the device is zero sized and detached from | ||
1939 | * the devices list. All that's left is to zero out the old | ||
1940 | * supers and free the device. | ||
1941 | */ | ||
1942 | if (device->writeable) | ||
1943 | btrfs_scratch_superblocks(device->bdev, device->name->str); | ||
1944 | |||
1945 | btrfs_close_bdev(device); | ||
1946 | call_rcu(&device->rcu, free_device); | ||
1947 | |||
1947 | if (cur_devices->open_devices == 0) { | 1948 | if (cur_devices->open_devices == 0) { |
1948 | struct btrfs_fs_devices *fs_devices; | 1949 | struct btrfs_fs_devices *fs_devices; |
1949 | fs_devices = root->fs_info->fs_devices; | 1950 | fs_devices = root->fs_info->fs_devices; |
@@ -1962,24 +1963,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path, u64 devid) | |||
1962 | root->fs_info->num_tolerated_disk_barrier_failures = | 1963 | root->fs_info->num_tolerated_disk_barrier_failures = |
1963 | btrfs_calc_num_tolerated_disk_barrier_failures(root->fs_info); | 1964 | btrfs_calc_num_tolerated_disk_barrier_failures(root->fs_info); |
1964 | 1965 | ||
1965 | /* | ||
1966 | * at this point, the device is zero sized. We want to | ||
1967 | * remove it from the devices list and zero out the old super | ||
1968 | */ | ||
1969 | if (clear_super) { | ||
1970 | struct block_device *bdev; | ||
1971 | |||
1972 | bdev = blkdev_get_by_path(dev_name, FMODE_READ | FMODE_EXCL, | ||
1973 | root->fs_info->bdev_holder); | ||
1974 | if (!IS_ERR(bdev)) { | ||
1975 | btrfs_scratch_superblocks(bdev, dev_name); | ||
1976 | blkdev_put(bdev, FMODE_READ | FMODE_EXCL); | ||
1977 | } | ||
1978 | } | ||
1979 | |||
1980 | out: | 1966 | out: |
1981 | kfree(dev_name); | ||
1982 | |||
1983 | mutex_unlock(&uuid_mutex); | 1967 | mutex_unlock(&uuid_mutex); |
1984 | return ret; | 1968 | return ret; |
1985 | 1969 | ||