Message ID | 1543483513-16724-2-git-send-email-anand.jain@oracle.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | btrfs: scrub: fix scrub_lock | expand |
On Thu, Nov 29, 2018 at 9:27 AM Anand Jain <anand.jain@oracle.com> wrote: > > 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.jain@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. I don't get it. What problem does this patch fixes? Doesn't seem any functional fix to me, nor performance gain (by the contrary, the scrub_lock is now held for a longer time than needed), nor makes anything more readable or "beautiful". > 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
On 11/29/2018 06:36 PM, Filipe Manana wrote: > On Thu, Nov 29, 2018 at 9:27 AM Anand Jain <anand.jain@oracle.com> wrote: >> >> 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.jain@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. > > I don't get it. > What problem does this patch fixes? > Doesn't seem any functional fix to me, nor performance gain (by the > contrary, the scrub_lock is now held for a longer time than needed), > nor makes anything more readable or "beautiful". btrfs_scrub_dev() isn't following the lock and unlock FILO order. Such as lock-a lock-b .. unlock-b unlock-a. So this patch is trying to fix it. This patch fixes the order but I think you mean to say as __scrub_blocked_if_needed() calls unlock scrub_lock. oops my bad this patch is wrong. Scrub concurrency needs overhaul including the dependency on the user land btrfs-progs, which I was trying to avoid. but looks like its better to fix that as well. As of now I am NACK this patch. Thanks, Anand >> 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 > > >
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); }
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.jain@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(-)