The device_list_mutex and scrub_lock creates a nested locks in btrfs_scrub_dev().
During lock the order is device_list_mutex and then scrub_lock, and during unlock, the order is device_list_mutex and then scrub_lock. Fix this to the lock order of scrub_lock and then device_list_mutex. Signed-off-by: Anand Jain <anand.j...@oracle.com> --- v1->v2: change the order of lock acquire first scrub_lock and then device_list_mutex, which matches with the order of unlock. The extra line which are now in the scrub_lock are ok to be under the scrub_lock. fs/btrfs/scrub.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 902819d3cf41..a9d6fc3b01d4 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -3813,28 +3813,29 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start, return -EINVAL; } - + mutex_lock(&fs_info->scrub_lock); mutex_lock(&fs_info->fs_devices->device_list_mutex); dev = btrfs_find_device(fs_info, devid, NULL, NULL); if (!dev || (test_bit(BTRFS_DEV_STATE_MISSING, &dev->dev_state) && !is_dev_replace)) { mutex_unlock(&fs_info->fs_devices->device_list_mutex); + mutex_unlock(&fs_info->scrub_lock); return -ENODEV; } if (!is_dev_replace && !readonly && !test_bit(BTRFS_DEV_STATE_WRITEABLE, &dev->dev_state)) { mutex_unlock(&fs_info->fs_devices->device_list_mutex); + mutex_unlock(&fs_info->scrub_lock); btrfs_err_in_rcu(fs_info, "scrub: device %s is not writable", rcu_str_deref(dev->name)); return -EROFS; } - mutex_lock(&fs_info->scrub_lock); if (!test_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &dev->dev_state) || test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &dev->dev_state)) { - mutex_unlock(&fs_info->scrub_lock); mutex_unlock(&fs_info->fs_devices->device_list_mutex); + mutex_unlock(&fs_info->scrub_lock); return -EIO; } @@ -3843,23 +3844,23 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start, (!is_dev_replace && btrfs_dev_replace_is_ongoing(&fs_info->dev_replace))) { btrfs_dev_replace_read_unlock(&fs_info->dev_replace); - mutex_unlock(&fs_info->scrub_lock); mutex_unlock(&fs_info->fs_devices->device_list_mutex); + mutex_unlock(&fs_info->scrub_lock); return -EINPROGRESS; } btrfs_dev_replace_read_unlock(&fs_info->dev_replace); ret = scrub_workers_get(fs_info, is_dev_replace); if (ret) { - mutex_unlock(&fs_info->scrub_lock); mutex_unlock(&fs_info->fs_devices->device_list_mutex); + mutex_unlock(&fs_info->scrub_lock); return ret; } sctx = scrub_setup_ctx(dev, is_dev_replace); if (IS_ERR(sctx)) { - mutex_unlock(&fs_info->scrub_lock); mutex_unlock(&fs_info->fs_devices->device_list_mutex); + mutex_unlock(&fs_info->scrub_lock); scrub_workers_put(fs_info); return PTR_ERR(sctx); } -- 1.8.3.1