@@ -2984,6 +2984,69 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
return ret;
}
+static int scrub_logical_chunks(struct scrub_ctx *sctx, u64 start, u64 end)
+{
+ struct btrfs_fs_info *fs_info = sctx->fs_info;
+ u64 cur = start;
+ int ret = 0;
+
+ while (cur < end) {
+ struct btrfs_block_group *bg;
+ bool ro_set = false;
+
+ bg = btrfs_lookup_first_block_group(fs_info, cur);
+
+ /* No more block groups. */
+ if (!bg)
+ break;
+ if (bg->start > end)
+ break;
+
+ ret = prepare_scrub_block_group(sctx, bg, &ro_set);
+ if (ret == -ETXTBSY) {
+ ret = 0;
+ goto next;
+ }
+ if (ret > 0)
+ goto next;
+ if (ret < 0) {
+ btrfs_put_block_group(bg);
+ break;
+ }
+
+ /* The real work starts here. */
+ ret = -EOPNOTSUPP;
+
+ if (ro_set)
+ btrfs_dec_block_group_ro(bg);
+ /*
+ * We might have prevented the cleaner kthread from deleting
+ * this block group if it was already unused because we raced
+ * and set it to RO mode first. So add it back to the unused
+ * list, otherwise it might not ever be deleted unless a manual
+ * balance is triggered or it becomes used and unused again.
+ */
+ spin_lock(&bg->lock);
+ if (!test_bit(BLOCK_GROUP_FLAG_REMOVED, &bg->runtime_flags) &&
+ !bg->ro && bg->reserved == 0 && bg->used == 0) {
+ spin_unlock(&bg->lock);
+ if (btrfs_test_opt(fs_info, DISCARD_ASYNC))
+ btrfs_discard_queue_work(&fs_info->discard_ctl, bg);
+ else
+ btrfs_mark_bg_unused(bg);
+ } else {
+ spin_unlock(&bg->lock);
+ }
+ btrfs_unfreeze_block_group(bg);
+next:
+ cur = bg->start + bg->length;
+ btrfs_put_block_group(bg);
+ if (ret < 0)
+ break;
+ }
+ return ret;
+}
+
int btrfs_scrub_logical(struct btrfs_fs_info *fs_info, u64 start, u64 end,
struct btrfs_scrub_progress *progress, bool readonly)
{
@@ -3030,8 +3093,7 @@ int btrfs_scrub_logical(struct btrfs_fs_info *fs_info, u64 start, u64 end,
atomic_inc(&fs_info->scrubs_logical_running);
mutex_unlock(&fs_info->scrub_lock);
- /* The main work would be implemented. */
- ret = -EOPNOTSUPP;
+ ret = scrub_logical_chunks(sctx, start, end);
atomic_dec(&fs_info->scrubs_running);
atomic_dec(&fs_info->scrubs_logical_running);
This patch implements the code to iterate chunks for scrub_logical feature. The differences between scrub_logical and scrub_dev are: - No need to lookup dev-extent tree As scrub_logical can directly grab the block group and check against the logical range. Thus we don't need to do the dev-extent lookup. - No dev-replace related work Scrub_logical would only be a feature to enhance full fs scrub, thus no need to do dev-replace related checks. For now only the block group iteration code is implemented, the real scrub part is not yet implemented. Signed-off-by: Qu Wenruo <wqu@suse.com> --- fs/btrfs/scrub.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-)