Skip to content

Commit

Permalink
btrfs: fix raid6 qstripe kmap
Browse files Browse the repository at this point in the history
commit d70cef0 upstream.

When a qstripe is required an extra page is allocated and mapped.  There
were 3 problems:

1) There is no corresponding call of kunmap() for the qstripe page.
2) There is no reason to map the qstripe page more than once if the
   number of bits set in rbio->dbitmap is greater than one.
3) There is no reason to map the parity page and unmap it each time
   through the loop.

The page memory can continue to be reused with a single mapping on each
iteration by raid6_call.gen_syndrome() without remapping.  So map the
page for the duration of the loop.

Similarly, improve the algorithm by mapping the parity page just 1 time.

Fixes: 5a6ac9e ("Btrfs, raid56: support parity scrub on raid56")
CC: stable@vger.kernel.org # 4.4.x: c17af96: btrfs: raid56: simplify tracking of Q stripe presence
CC: stable@vger.kernel.org # 4.4.x
Signed-off-by: Ira Weiny <ira.weiny@intel.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
weiny2 authored and gregkh committed Mar 9, 2021
1 parent a01415e commit b2a4876
Showing 1 changed file with 10 additions and 11 deletions.
21 changes: 10 additions & 11 deletions fs/btrfs/raid56.c
Expand Up @@ -2363,16 +2363,21 @@ static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio,
SetPageUptodate(p_page);

if (has_qstripe) {
/* RAID6, allocate and map temp space for the Q stripe */
q_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
if (!q_page) {
__free_page(p_page);
goto cleanup;
}
SetPageUptodate(q_page);
pointers[rbio->real_stripes - 1] = kmap(q_page);
}

atomic_set(&rbio->error, 0);

/* Map the parity stripe just once */
pointers[nr_data] = kmap(p_page);

for_each_set_bit(pagenr, rbio->dbitmap, rbio->stripe_npages) {
struct page *p;
void *parity;
Expand All @@ -2382,16 +2387,8 @@ static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio,
pointers[stripe] = kmap(p);
}

/* then add the parity stripe */
pointers[stripe++] = kmap(p_page);

if (has_qstripe) {
/*
* raid6, add the qstripe and call the
* library function to fill in our p/q
*/
pointers[stripe++] = kmap(q_page);

/* RAID6, call the library function to fill in our P/Q */
raid6_call.gen_syndrome(rbio->real_stripes, PAGE_SIZE,
pointers);
} else {
Expand All @@ -2412,12 +2409,14 @@ static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio,

for (stripe = 0; stripe < nr_data; stripe++)
kunmap(page_in_rbio(rbio, stripe, pagenr, 0));
kunmap(p_page);
}

kunmap(p_page);
__free_page(p_page);
if (q_page)
if (q_page) {
kunmap(q_page);
__free_page(q_page);
}

writeback:
/*
Expand Down

0 comments on commit b2a4876

Please sign in to comment.