Merge tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck...
[linux-drm-fsl-dcu.git] / fs / btrfs / scrub.c
index a18e0e23f6a6742cd21277702ed6599df84c32c3..561e2f16ba3e3ff3b0be72b12b4a052b86082d2a 100644 (file)
@@ -938,8 +938,10 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
                                BTRFS_DEV_STAT_CORRUPTION_ERRS);
        }
 
-       if (sctx->readonly && !sctx->is_dev_replace)
-               goto did_not_correct_error;
+       if (sctx->readonly) {
+               ASSERT(!sctx->is_dev_replace);
+               goto out;
+       }
 
        if (!is_metadata && !have_csum) {
                struct scrub_fixup_nodatasum *fixup_nodatasum;
@@ -2717,8 +2719,6 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
                mutex_unlock(&fs_info->scrub_lock);
                wake_up(&fs_info->scrub_pause_wait);
 
-               dev_replace->cursor_left = dev_replace->cursor_right;
-               dev_replace->item_needs_writeback = 1;
                btrfs_put_block_group(cache);
                if (ret)
                        break;
@@ -2732,6 +2732,9 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
                        break;
                }
 
+               dev_replace->cursor_left = dev_replace->cursor_right;
+               dev_replace->item_needs_writeback = 1;
+
                key.offset = found_key.offset + length;
                btrfs_release_path(path);
        }
@@ -2783,7 +2786,6 @@ static noinline_for_stack int scrub_workers_get(struct btrfs_fs_info *fs_info,
 {
        int ret = 0;
 
-       mutex_lock(&fs_info->scrub_lock);
        if (fs_info->scrub_workers_refcnt == 0) {
                if (is_dev_replace)
                        btrfs_init_workers(&fs_info->scrub_workers, "scrub", 1,
@@ -2813,21 +2815,17 @@ static noinline_for_stack int scrub_workers_get(struct btrfs_fs_info *fs_info,
        }
        ++fs_info->scrub_workers_refcnt;
 out:
-       mutex_unlock(&fs_info->scrub_lock);
-
        return ret;
 }
 
 static noinline_for_stack void scrub_workers_put(struct btrfs_fs_info *fs_info)
 {
-       mutex_lock(&fs_info->scrub_lock);
        if (--fs_info->scrub_workers_refcnt == 0) {
                btrfs_stop_workers(&fs_info->scrub_workers);
                btrfs_stop_workers(&fs_info->scrub_wr_completion_workers);
                btrfs_stop_workers(&fs_info->scrub_nocow_workers);
        }
        WARN_ON(fs_info->scrub_workers_refcnt < 0);
-       mutex_unlock(&fs_info->scrub_lock);
 }
 
 int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
@@ -2888,23 +2886,18 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
                return -EINVAL;
        }
 
-       ret = scrub_workers_get(fs_info, is_dev_replace);
-       if (ret)
-               return ret;
 
        mutex_lock(&fs_info->fs_devices->device_list_mutex);
        dev = btrfs_find_device(fs_info, devid, NULL, NULL);
        if (!dev || (dev->missing && !is_dev_replace)) {
                mutex_unlock(&fs_info->fs_devices->device_list_mutex);
-               scrub_workers_put(fs_info);
                return -ENODEV;
        }
-       mutex_lock(&fs_info->scrub_lock);
 
+       mutex_lock(&fs_info->scrub_lock);
        if (!dev->in_fs_metadata || dev->is_tgtdev_for_dev_replace) {
                mutex_unlock(&fs_info->scrub_lock);
                mutex_unlock(&fs_info->fs_devices->device_list_mutex);
-               scrub_workers_put(fs_info);
                return -EIO;
        }
 
@@ -2915,10 +2908,17 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
                btrfs_dev_replace_unlock(&fs_info->dev_replace);
                mutex_unlock(&fs_info->scrub_lock);
                mutex_unlock(&fs_info->fs_devices->device_list_mutex);
-               scrub_workers_put(fs_info);
                return -EINPROGRESS;
        }
        btrfs_dev_replace_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);
+               return ret;
+       }
+
        sctx = scrub_setup_ctx(dev, is_dev_replace);
        if (IS_ERR(sctx)) {
                mutex_unlock(&fs_info->scrub_lock);
@@ -2931,13 +2931,15 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
 
        atomic_inc(&fs_info->scrubs_running);
        mutex_unlock(&fs_info->scrub_lock);
-       mutex_unlock(&fs_info->fs_devices->device_list_mutex);
 
        if (!is_dev_replace) {
-               down_read(&fs_info->scrub_super_lock);
+               /*
+                * by holding device list mutex, we can
+                * kick off writing super in log tree sync.
+                */
                ret = scrub_supers(sctx, dev);
-               up_read(&fs_info->scrub_super_lock);
        }
+       mutex_unlock(&fs_info->fs_devices->device_list_mutex);
 
        if (!ret)
                ret = scrub_enumerate_chunks(sctx, dev, start, end,
@@ -2954,10 +2956,10 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
 
        mutex_lock(&fs_info->scrub_lock);
        dev->scrub_device = NULL;
+       scrub_workers_put(fs_info);
        mutex_unlock(&fs_info->scrub_lock);
 
        scrub_free_ctx(sctx);
-       scrub_workers_put(fs_info);
 
        return ret;
 }
@@ -2987,16 +2989,6 @@ void btrfs_scrub_continue(struct btrfs_root *root)
        wake_up(&fs_info->scrub_pause_wait);
 }
 
-void btrfs_scrub_pause_super(struct btrfs_root *root)
-{
-       down_write(&root->fs_info->scrub_super_lock);
-}
-
-void btrfs_scrub_continue_super(struct btrfs_root *root)
-{
-       up_write(&root->fs_info->scrub_super_lock);
-}
-
 int btrfs_scrub_cancel(struct btrfs_fs_info *fs_info)
 {
        mutex_lock(&fs_info->scrub_lock);