Skip to content

Commit a075f23

Browse files
committed
Merge tag 'for-5.5-rc8-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs fix from David Sterba: "Here's a last minute fix for a regression introduced in this development cycle. There's a small chance of a silent corruption when device replace and NOCOW data writes happen at the same time in one block group. Metadata or COW data writes are unaffected. The extra fixup patch is there to silence an unnecessary warning" * tag 'for-5.5-rc8-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: dev-replace: remove warning for unknown return codes when finished btrfs: scrub: Require mandatory block group RO for dev-replace
2 parents 93d1a05 + 4cea903 commit a075f23

File tree

2 files changed

+29
-9
lines changed

2 files changed

+29
-9
lines changed

fs/btrfs/dev-replace.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -500,11 +500,8 @@ static int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info,
500500
&dev_replace->scrub_progress, 0, 1);
501501

502502
ret = btrfs_dev_replace_finishing(fs_info, ret);
503-
if (ret == -EINPROGRESS) {
503+
if (ret == -EINPROGRESS)
504504
ret = BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS;
505-
} else if (ret != -ECANCELED) {
506-
WARN_ON(ret);
507-
}
508505

509506
return ret;
510507

fs/btrfs/scrub.c

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3577,17 +3577,27 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
35773577
* This can easily boost the amount of SYSTEM chunks if cleaner
35783578
* thread can't be triggered fast enough, and use up all space
35793579
* of btrfs_super_block::sys_chunk_array
3580+
*
3581+
* While for dev replace, we need to try our best to mark block
3582+
* group RO, to prevent race between:
3583+
* - Write duplication
3584+
* Contains latest data
3585+
* - Scrub copy
3586+
* Contains data from commit tree
3587+
*
3588+
* If target block group is not marked RO, nocow writes can
3589+
* be overwritten by scrub copy, causing data corruption.
3590+
* So for dev-replace, it's not allowed to continue if a block
3591+
* group is not RO.
35803592
*/
3581-
ret = btrfs_inc_block_group_ro(cache, false);
3582-
scrub_pause_off(fs_info);
3583-
3593+
ret = btrfs_inc_block_group_ro(cache, sctx->is_dev_replace);
35843594
if (ret == 0) {
35853595
ro_set = 1;
3586-
} else if (ret == -ENOSPC) {
3596+
} else if (ret == -ENOSPC && !sctx->is_dev_replace) {
35873597
/*
35883598
* btrfs_inc_block_group_ro return -ENOSPC when it
35893599
* failed in creating new chunk for metadata.
3590-
* It is not a problem for scrub/replace, because
3600+
* It is not a problem for scrub, because
35913601
* metadata are always cowed, and our scrub paused
35923602
* commit_transactions.
35933603
*/
@@ -3596,9 +3606,22 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
35963606
btrfs_warn(fs_info,
35973607
"failed setting block group ro: %d", ret);
35983608
btrfs_put_block_group(cache);
3609+
scrub_pause_off(fs_info);
35993610
break;
36003611
}
36013612

3613+
/*
3614+
* Now the target block is marked RO, wait for nocow writes to
3615+
* finish before dev-replace.
3616+
* COW is fine, as COW never overwrites extents in commit tree.
3617+
*/
3618+
if (sctx->is_dev_replace) {
3619+
btrfs_wait_nocow_writers(cache);
3620+
btrfs_wait_ordered_roots(fs_info, U64_MAX, cache->start,
3621+
cache->length);
3622+
}
3623+
3624+
scrub_pause_off(fs_info);
36023625
down_write(&dev_replace->rwsem);
36033626
dev_replace->cursor_right = found_key.offset + length;
36043627
dev_replace->cursor_left = found_key.offset;

0 commit comments

Comments
 (0)