2015-07-03 05:23:24

by Yuanhan Liu

[permalink] [raw]
Subject: [PATCH] async_tx: replace page_address with kmap_atomic

As a page might belong to highmem.

Strictly nested kmap_atomic() order is followed according to doc
Documentation/vm/highmem.txt

CC: Dan Williams <[email protected]>
CC: Shaohua Li <[email protected]>
Signed-off-by: Yuanhan Liu <[email protected]>
---
crypto/async_tx/async_pq.c | 18 +++++++++++++-----
crypto/async_tx/async_raid6_recov.c | 31 ++++++++++++++++++++++++-------
crypto/async_tx/async_xor.c | 17 ++++++++++++++---
3 files changed, 51 insertions(+), 15 deletions(-)

diff --git a/crypto/async_tx/async_pq.c b/crypto/async_tx/async_pq.c
index 5d355e0..a408b7e 100644
--- a/crypto/async_tx/async_pq.c
+++ b/crypto/async_tx/async_pq.c
@@ -136,7 +136,7 @@ do_sync_gen_syndrome(struct page **blocks, unsigned int offset, int disks,
BUG_ON(i > disks - 3); /* P or Q can't be zero */
srcs[i] = (void*)raid6_empty_zero_page;
} else {
- srcs[i] = page_address(blocks[i]) + offset;
+ srcs[i] = kmap_atomic(blocks[i]) + offset;
if (i < disks - 2) {
stop = i;
if (start == -1)
@@ -150,6 +150,12 @@ do_sync_gen_syndrome(struct page **blocks, unsigned int offset, int disks,
raid6_call.xor_syndrome(disks, start, stop, len, srcs);
} else
raid6_call.gen_syndrome(disks, len, srcs);
+
+ for (i = disks; i--; ) {
+ if (blocks[i])
+ kunmap_atomic(srcs[i]);
+ }
+
async_tx_sync_epilog(submit);
}

@@ -395,14 +401,15 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int disks,
*/
tx = NULL;
*pqres = 0;
+ s = kmap_atomic(spare) + offset;
if (p_src) {
init_async_submit(submit, ASYNC_TX_XOR_ZERO_DST, NULL,
NULL, NULL, scribble);
tx = async_xor(spare, blocks, offset, disks-2, len, submit);
async_tx_quiesce(&tx);
- p = page_address(p_src) + offset;
- s = page_address(spare) + offset;
+ p = kmap_atomic(p_src) + offset;
*pqres |= !!memcmp(p, s, len) << SUM_CHECK_P;
+ kunmap_atomic(p);
}

if (q_src) {
@@ -411,10 +418,11 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int disks,
init_async_submit(submit, 0, NULL, NULL, NULL, scribble);
tx = async_gen_syndrome(blocks, offset, disks, len, submit);
async_tx_quiesce(&tx);
- q = page_address(q_src) + offset;
- s = page_address(spare) + offset;
+ q = kmap_atomic(q_src) + offset;
*pqres |= !!memcmp(q, s, len) << SUM_CHECK_Q;
+ kunmap_atomic(q);
}
+ kunmap_atomic(s);

/* restore P, Q and submit */
P(blocks, disks) = p_src;
diff --git a/crypto/async_tx/async_raid6_recov.c b/crypto/async_tx/async_raid6_recov.c
index 934a849..abcacb0 100644
--- a/crypto/async_tx/async_raid6_recov.c
+++ b/crypto/async_tx/async_raid6_recov.c
@@ -80,9 +80,9 @@ async_sum_product(struct page *dest, struct page **srcs, unsigned char *coef,
async_tx_quiesce(&submit->depend_tx);
amul = raid6_gfmul[coef[0]];
bmul = raid6_gfmul[coef[1]];
- a = page_address(srcs[0]);
- b = page_address(srcs[1]);
- c = page_address(dest);
+ a = kmap_atomic(srcs[0]);
+ b = kmap_atomic(srcs[1]);
+ c = kmap_atomic(dest);

while (len--) {
ax = amul[*a++];
@@ -90,6 +90,10 @@ async_sum_product(struct page *dest, struct page **srcs, unsigned char *coef,
*c++ = ax ^ bx;
}

+ kunmap_atomic(c);
+ kunmap_atomic(b);
+ kunmap_atomic(a);
+
return NULL;
}

@@ -147,12 +151,15 @@ async_mult(struct page *dest, struct page *src, u8 coef, size_t len,
*/
async_tx_quiesce(&submit->depend_tx);
qmul = raid6_gfmul[coef];
- d = page_address(dest);
- s = page_address(src);
+ d = kmap_atomic(dest);
+ s = kmap_atomic(src);

while (len--)
*d++ = qmul[*s++];

+ kunmap_atomic(s);
+ kunmap_atomic(d);
+
return NULL;
}

@@ -372,10 +379,15 @@ async_raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
if (blocks[i] == NULL)
ptrs[i] = (void *) raid6_empty_zero_page;
else
- ptrs[i] = page_address(blocks[i]);
+ ptrs[i] = kmap_atomic(blocks[i]);

raid6_2data_recov(disks, bytes, faila, failb, ptrs);

+ for (i = disks; i--; ) {
+ if (blocks[i])
+ kunmap_atomic(ptrs[i]);
+ }
+
async_tx_sync_epilog(submit);

return NULL;
@@ -448,10 +460,15 @@ async_raid6_datap_recov(int disks, size_t bytes, int faila,
if (blocks[i] == NULL)
ptrs[i] = (void*)raid6_empty_zero_page;
else
- ptrs[i] = page_address(blocks[i]);
+ ptrs[i] = kmap_atomic(blocks[i]);

raid6_datap_recov(disks, bytes, faila, ptrs);

+ for (i = disks; i--; ) {
+ if (blocks[i])
+ kunmap_atomic(ptrs[i]);
+ }
+
async_tx_sync_epilog(submit);

return NULL;
diff --git a/crypto/async_tx/async_xor.c b/crypto/async_tx/async_xor.c
index e1bce26..e26a0cd 100644
--- a/crypto/async_tx/async_xor.c
+++ b/crypto/async_tx/async_xor.c
@@ -30,6 +30,7 @@
#include <linux/dma-mapping.h>
#include <linux/raid/xor.h>
#include <linux/async_tx.h>
+#include <linux/highmem.h>

/* do_async_xor - dma map the pages and perform the xor with an engine */
static __async_inline struct dma_async_tx_descriptor *
@@ -127,10 +128,10 @@ do_sync_xor(struct page *dest, struct page **src_list, unsigned int offset,
/* convert to buffer pointers */
for (i = 0; i < src_cnt; i++)
if (src_list[i])
- srcs[xor_src_cnt++] = page_address(src_list[i]) + offset;
+ srcs[xor_src_cnt++] = kmap_atomic(src_list[i]) + offset;
src_cnt = xor_src_cnt;
/* set destination address */
- dest_buf = page_address(dest) + offset;
+ dest_buf = kmap_atomic(dest) + offset;

if (submit->flags & ASYNC_TX_XOR_ZERO_DST)
memset(dest_buf, 0, len);
@@ -144,6 +145,9 @@ do_sync_xor(struct page *dest, struct page **src_list, unsigned int offset,
src_cnt -= xor_src_cnt;
src_off += xor_src_cnt;
}
+ kunmap_atomic(dest_buf);
+ for (i = src_off; i--; )
+ kunmap_atomic(srcs[i]);

async_tx_sync_epilog(submit);
}
@@ -235,7 +239,14 @@ EXPORT_SYMBOL_GPL(async_xor);

static int page_is_zero(struct page *p, unsigned int offset, size_t len)
{
- return !memchr_inv(page_address(p) + offset, 0, len);
+ void *addr;
+ int ret;
+
+ addr = kmap_atomic(p);
+ ret = !memchr_inv(addr + offset, 0, len);
+ kunmap_atomic(addr);
+
+ return ret;
}

static inline struct dma_chan *
--
1.9.0