]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/btrfs/scrub.c
Btrfs: fix BUG() in scrub when first superblock reading gives EIO
[karo-tx-linux.git] / fs / btrfs / scrub.c
index 61157a26cf2a6774293d50cd0b53c75742080357..bdbb94f245c9070802c65acb6eba392ba1a4c932 100644 (file)
@@ -785,6 +785,17 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
 
        BUG_ON(sblock_to_check->page_count < 1);
        fs_info = sctx->dev_root->fs_info;
+       if (sblock_to_check->pagev[0]->flags & BTRFS_EXTENT_FLAG_SUPER) {
+               /*
+                * if we find an error in a super block, we just report it.
+                * They will get written with the next transaction commit
+                * anyway
+                */
+               spin_lock(&sctx->stat_lock);
+               ++sctx->stat.super_errors;
+               spin_unlock(&sctx->stat_lock);
+               return 0;
+       }
        length = sblock_to_check->page_count * PAGE_SIZE;
        logical = sblock_to_check->pagev[0]->logical;
        generation = sblock_to_check->pagev[0]->generation;
@@ -1193,8 +1204,8 @@ static int scrub_setup_recheck_block(struct scrub_ctx *sctx,
                 * with a length of PAGE_SIZE, each returned stripe
                 * represents one mirror
                 */
-               ret = btrfs_map_block(fs_info, WRITE, logical, &mapped_length,
-                                     &bbio, 0);
+               ret = btrfs_map_block(fs_info, REQ_GET_READ_MIRRORS, logical,
+                                     &mapped_length, &bbio, 0);
                if (ret || !bbio || mapped_length < sublen) {
                        kfree(bbio);
                        return -EIO;
@@ -2657,7 +2668,8 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
                btrfs_put_block_group(cache);
                if (ret)
                        break;
-               if (atomic64_read(&dev_replace->num_write_errors) > 0) {
+               if (is_dev_replace &&
+                   atomic64_read(&dev_replace->num_write_errors) > 0) {
                        ret = -EIO;
                        break;
                }
@@ -2843,12 +2855,17 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
                return -EIO;
        }
 
-       if (dev->scrub_device) {
+       btrfs_dev_replace_lock(&fs_info->dev_replace);
+       if (dev->scrub_device ||
+           (!is_dev_replace &&
+            btrfs_dev_replace_is_ongoing(&fs_info->dev_replace))) {
+               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);
        sctx = scrub_setup_ctx(dev, is_dev_replace);
        if (IS_ERR(sctx)) {
                mutex_unlock(&fs_info->scrub_lock);