btrfs: zoned: relocate block group to repair IO failure in zoned filesystems
[platform/kernel/linux-rpi.git] / fs / btrfs / volumes.c
index 1312b17..b8fab44 100644 (file)
@@ -7980,3 +7980,75 @@ bool btrfs_pinned_by_swapfile(struct btrfs_fs_info *fs_info, void *ptr)
        spin_unlock(&fs_info->swapfile_pins_lock);
        return node != NULL;
 }
+
+static int relocating_repair_kthread(void *data)
+{
+       struct btrfs_block_group *cache = (struct btrfs_block_group *)data;
+       struct btrfs_fs_info *fs_info = cache->fs_info;
+       u64 target;
+       int ret = 0;
+
+       target = cache->start;
+       btrfs_put_block_group(cache);
+
+       if (!btrfs_exclop_start(fs_info, BTRFS_EXCLOP_BALANCE)) {
+               btrfs_info(fs_info,
+                          "zoned: skip relocating block group %llu to repair: EBUSY",
+                          target);
+               return -EBUSY;
+       }
+
+       mutex_lock(&fs_info->delete_unused_bgs_mutex);
+
+       /* Ensure block group still exists */
+       cache = btrfs_lookup_block_group(fs_info, target);
+       if (!cache)
+               goto out;
+
+       if (!cache->relocating_repair)
+               goto out;
+
+       ret = btrfs_may_alloc_data_chunk(fs_info, target);
+       if (ret < 0)
+               goto out;
+
+       btrfs_info(fs_info,
+                  "zoned: relocating block group %llu to repair IO failure",
+                  target);
+       ret = btrfs_relocate_chunk(fs_info, target);
+
+out:
+       if (cache)
+               btrfs_put_block_group(cache);
+       mutex_unlock(&fs_info->delete_unused_bgs_mutex);
+       btrfs_exclop_finish(fs_info);
+
+       return ret;
+}
+
+int btrfs_repair_one_zone(struct btrfs_fs_info *fs_info, u64 logical)
+{
+       struct btrfs_block_group *cache;
+
+       /* Do not attempt to repair in degraded state */
+       if (btrfs_test_opt(fs_info, DEGRADED))
+               return 0;
+
+       cache = btrfs_lookup_block_group(fs_info, logical);
+       if (!cache)
+               return 0;
+
+       spin_lock(&cache->lock);
+       if (cache->relocating_repair) {
+               spin_unlock(&cache->lock);
+               btrfs_put_block_group(cache);
+               return 0;
+       }
+       cache->relocating_repair = 1;
+       spin_unlock(&cache->lock);
+
+       kthread_run(relocating_repair_kthread, cache,
+                   "btrfs-relocating-repair");
+
+       return 0;
+}