Skip to content

Commit ac0b414

Browse files
adam900710kdave
authored andcommitted
btrfs: scrub: Don't use inode pages for device replace
[BUG] Btrfs can create compressed extent without checksum (even though it shouldn't), and if we then try to replace device containing such extent, the result device will contain all the uncompressed data instead of the compressed one. Test case already submitted to fstests: https://patchwork.kernel.org/patch/10442353/ [CAUSE] When handling compressed extent without checksum, device replace will goe into copy_nocow_pages() function. In that function, btrfs will get all inodes referring to this data extents and then use find_or_create_page() to get pages direct from that inode. The problem here is, pages directly from inode are always uncompressed. And for compressed data extent, they mismatch with on-disk data. Thus this leads to corrupted compressed data extent written to replace device. [FIX] In this attempt, we could just remove the "optimization" branch, and let unified scrub_pages() to handle it. Although scrub_pages() won't bother reusing page cache, it will be a little slower, but it does the correct csum checking and won't cause such data corruption caused by "optimization". Note about the fix: this is the minimal fix that can be backported to older stable trees without conflicts. The whole callchain from copy_nocow_pages() can be deleted, and will be in followup patches. Fixes: ff023aa ("Btrfs: add code to scrub to copy read data to another disk") CC: [email protected] # 4.4+ Reported-by: James Harvey <[email protected]> Reviewed-by: James Harvey <[email protected]> Signed-off-by: Qu Wenruo <[email protected]> [ remove code removal, add note why ] Signed-off-by: David Sterba <[email protected]>
1 parent a528a24 commit ac0b414

File tree

1 file changed

+1
-1
lines changed

1 file changed

+1
-1
lines changed

fs/btrfs/scrub.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2799,7 +2799,7 @@ static int scrub_extent(struct scrub_ctx *sctx, struct map_lookup *map,
27992799
have_csum = scrub_find_csum(sctx, logical, csum);
28002800
if (have_csum == 0)
28012801
++sctx->stat.no_csum;
2802-
if (sctx->is_dev_replace && !have_csum) {
2802+
if (0 && sctx->is_dev_replace && !have_csum) {
28032803
ret = copy_nocow_pages(sctx, logical, l,
28042804
mirror_num,
28052805
physical_for_dev_replace);

0 commit comments

Comments
 (0)