mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-13 22:25:03 +00:00
btrfs: fix raid6 qstripe kmap
commitd70cef0d46
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:5a6ac9eacb
("Btrfs, raid56: support parity scrub on raid56") CC: stable@vger.kernel.org # 4.4.x:c17af96554
: 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>
This commit is contained in:
parent
909a8d2b1e
commit
0c740d2b8c
1 changed files with 10 additions and 11 deletions
|
@ -2390,16 +2390,21 @@ static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio,
|
||||||
SetPageUptodate(p_page);
|
SetPageUptodate(p_page);
|
||||||
|
|
||||||
if (has_qstripe) {
|
if (has_qstripe) {
|
||||||
|
/* RAID6, allocate and map temp space for the Q stripe */
|
||||||
q_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
|
q_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
|
||||||
if (!q_page) {
|
if (!q_page) {
|
||||||
__free_page(p_page);
|
__free_page(p_page);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
SetPageUptodate(q_page);
|
SetPageUptodate(q_page);
|
||||||
|
pointers[rbio->real_stripes - 1] = kmap(q_page);
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_set(&rbio->error, 0);
|
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) {
|
for_each_set_bit(pagenr, rbio->dbitmap, rbio->stripe_npages) {
|
||||||
struct page *p;
|
struct page *p;
|
||||||
void *parity;
|
void *parity;
|
||||||
|
@ -2409,16 +2414,8 @@ static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio,
|
||||||
pointers[stripe] = kmap(p);
|
pointers[stripe] = kmap(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* then add the parity stripe */
|
|
||||||
pointers[stripe++] = kmap(p_page);
|
|
||||||
|
|
||||||
if (has_qstripe) {
|
if (has_qstripe) {
|
||||||
/*
|
/* RAID6, call the library function to fill in our P/Q */
|
||||||
* raid6, add the qstripe and call the
|
|
||||||
* library function to fill in our p/q
|
|
||||||
*/
|
|
||||||
pointers[stripe++] = kmap(q_page);
|
|
||||||
|
|
||||||
raid6_call.gen_syndrome(rbio->real_stripes, PAGE_SIZE,
|
raid6_call.gen_syndrome(rbio->real_stripes, PAGE_SIZE,
|
||||||
pointers);
|
pointers);
|
||||||
} else {
|
} else {
|
||||||
|
@ -2439,12 +2436,14 @@ static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio,
|
||||||
|
|
||||||
for (stripe = 0; stripe < nr_data; stripe++)
|
for (stripe = 0; stripe < nr_data; stripe++)
|
||||||
kunmap(page_in_rbio(rbio, stripe, pagenr, 0));
|
kunmap(page_in_rbio(rbio, stripe, pagenr, 0));
|
||||||
kunmap(p_page);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kunmap(p_page);
|
||||||
__free_page(p_page);
|
__free_page(p_page);
|
||||||
if (q_page)
|
if (q_page) {
|
||||||
|
kunmap(q_page);
|
||||||
__free_page(q_page);
|
__free_page(q_page);
|
||||||
|
}
|
||||||
|
|
||||||
writeback:
|
writeback:
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in a new issue