Skip to content

Commit 486c737

Browse files
adam900710kdave
authored andcommitted
btrfs: raid56: always verify the P/Q contents for scrub
[REGRESSION] Commit 75b4703 ("btrfs: raid56: migrate recovery and scrub recovery path to use error_bitmap") changed the behavior of scrub_rbio(). Initially if we have no error reading the raid bio, we will assign @need_check to true, then finish_parity_scrub() would later verify the content of P/Q stripes before writeback. But after that commit we never verify the content of P/Q stripes and just writeback them. This can lead to unrepaired P/Q stripes during scrub, or already corrupted P/Q copied to the dev-replace target. [FIX] The situation is more complex than the regression, in fact the initial behavior is not 100% correct either. If we have the following rare case, it can still lead to the same problem using the old behavior: 0 16K 32K 48K 64K Data 1: |IIIIIII| | Data 2: | | Parity: | |CCCCCCC| | Where "I" means IO error, "C" means corruption. In the above case, we're scrubbing the parity stripe, then read out all the contents of Data 1, Data 2, Parity stripes. But found IO error in Data 1, which leads to rebuild using Data 2 and Parity and got the correct data. In that case, we would not verify if the Parity is correct for range [16K, 32K). So here we have to always verify the content of Parity no matter if we did recovery or not. This patch would remove the @need_check parameter of finish_parity_scrub() completely, and would always do the P/Q verification before writeback. Fixes: 75b4703 ("btrfs: raid56: migrate recovery and scrub recovery path to use error_bitmap") CC: stable@vger.kernel.org # 6.2+ Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 866e98a commit 486c737

File tree

1 file changed

+3
-8
lines changed

1 file changed

+3
-8
lines changed

fs/btrfs/raid56.c

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ static void rmw_rbio_work_locked(struct work_struct *work);
7171
static void index_rbio_pages(struct btrfs_raid_bio *rbio);
7272
static int alloc_rbio_pages(struct btrfs_raid_bio *rbio);
7373

74-
static int finish_parity_scrub(struct btrfs_raid_bio *rbio, int need_check);
74+
static int finish_parity_scrub(struct btrfs_raid_bio *rbio);
7575
static void scrub_rbio_work_locked(struct work_struct *work);
7676

7777
static void free_raid_bio_pointers(struct btrfs_raid_bio *rbio)
@@ -2404,7 +2404,7 @@ static int alloc_rbio_essential_pages(struct btrfs_raid_bio *rbio)
24042404
return 0;
24052405
}
24062406

2407-
static int finish_parity_scrub(struct btrfs_raid_bio *rbio, int need_check)
2407+
static int finish_parity_scrub(struct btrfs_raid_bio *rbio)
24082408
{
24092409
struct btrfs_io_context *bioc = rbio->bioc;
24102410
const u32 sectorsize = bioc->fs_info->sectorsize;
@@ -2445,9 +2445,6 @@ static int finish_parity_scrub(struct btrfs_raid_bio *rbio, int need_check)
24452445
*/
24462446
clear_bit(RBIO_CACHE_READY_BIT, &rbio->flags);
24472447

2448-
if (!need_check)
2449-
goto writeback;
2450-
24512448
p_sector.page = alloc_page(GFP_NOFS);
24522449
if (!p_sector.page)
24532450
return -ENOMEM;
@@ -2516,7 +2513,6 @@ static int finish_parity_scrub(struct btrfs_raid_bio *rbio, int need_check)
25162513
q_sector.page = NULL;
25172514
}
25182515

2519-
writeback:
25202516
/*
25212517
* time to start writing. Make bios for everything from the
25222518
* higher layers (the bio_list in our rbio) and our p/q. Ignore
@@ -2699,7 +2695,6 @@ static int scrub_assemble_read_bios(struct btrfs_raid_bio *rbio)
26992695

27002696
static void scrub_rbio(struct btrfs_raid_bio *rbio)
27012697
{
2702-
bool need_check = false;
27032698
int sector_nr;
27042699
int ret;
27052700

@@ -2722,7 +2717,7 @@ static void scrub_rbio(struct btrfs_raid_bio *rbio)
27222717
* We have every sector properly prepared. Can finish the scrub
27232718
* and writeback the good content.
27242719
*/
2725-
ret = finish_parity_scrub(rbio, need_check);
2720+
ret = finish_parity_scrub(rbio);
27262721
wait_event(rbio->io_wait, atomic_read(&rbio->stripes_pending) == 0);
27272722
for (sector_nr = 0; sector_nr < rbio->stripe_nsectors; sector_nr++) {
27282723
int found_errors;

0 commit comments

Comments
 (0)