提交 85188b76 编写于 作者: I Ira Weiny 提交者: Zheng Zengkai

btrfs: fix raid6 qstripe kmap

stable inclusion
from stable-5.10.22
commit b2a48761321893e07721d8a2528c6db0b8ac75bf
bugzilla: 50796

--------------------------------

commit d70cef0d 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: 5a6ac9ea ("Btrfs, raid56: support parity scrub on raid56")
CC: stable@vger.kernel.org # 4.4.x: c17af965: btrfs: raid56: simplify tracking of Q stripe presence
CC: stable@vger.kernel.org # 4.4.x
Signed-off-by: NIra Weiny <ira.weiny@intel.com>
Reviewed-by: NDavid Sterba <dsterba@suse.com>
Signed-off-by: NDavid Sterba <dsterba@suse.com>
Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: NChen Jun <chenjun102@huawei.com>
Acked-by: N  Weilong Chen <chenweilong@huawei.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 4549e55f
...@@ -2363,16 +2363,21 @@ static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio, ...@@ -2363,16 +2363,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;
...@@ -2382,16 +2387,8 @@ static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio, ...@@ -2382,16 +2387,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 {
...@@ -2412,12 +2409,14 @@ static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio, ...@@ -2412,12 +2409,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:
/* /*
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册