diff options
Diffstat (limited to 'crypto/scatterwalk.c')
-rw-r--r-- | crypto/scatterwalk.c | 89 |
1 files changed, 40 insertions, 49 deletions
diff --git a/crypto/scatterwalk.c b/crypto/scatterwalk.c index 2953e2cc56f0..35172d3f043b 100644 --- a/crypto/scatterwalk.c +++ b/crypto/scatterwalk.c | |||
@@ -15,9 +15,11 @@ | |||
15 | */ | 15 | */ |
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/mm.h> | 17 | #include <linux/mm.h> |
18 | #include <linux/module.h> | ||
18 | #include <linux/pagemap.h> | 19 | #include <linux/pagemap.h> |
19 | #include <linux/highmem.h> | 20 | #include <linux/highmem.h> |
20 | #include <asm/scatterlist.h> | 21 | #include <linux/scatterlist.h> |
22 | |||
21 | #include "internal.h" | 23 | #include "internal.h" |
22 | #include "scatterwalk.h" | 24 | #include "scatterwalk.h" |
23 | 25 | ||
@@ -27,88 +29,77 @@ enum km_type crypto_km_types[] = { | |||
27 | KM_SOFTIRQ0, | 29 | KM_SOFTIRQ0, |
28 | KM_SOFTIRQ1, | 30 | KM_SOFTIRQ1, |
29 | }; | 31 | }; |
32 | EXPORT_SYMBOL_GPL(crypto_km_types); | ||
30 | 33 | ||
31 | static void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out) | 34 | static inline void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out) |
32 | { | 35 | { |
33 | if (out) | 36 | void *src = out ? buf : sgdata; |
34 | memcpy(sgdata, buf, nbytes); | 37 | void *dst = out ? sgdata : buf; |
35 | else | 38 | |
36 | memcpy(buf, sgdata, nbytes); | 39 | memcpy(dst, src, nbytes); |
37 | } | 40 | } |
38 | 41 | ||
39 | void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg) | 42 | void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg) |
40 | { | 43 | { |
41 | unsigned int rest_of_page; | ||
42 | |||
43 | walk->sg = sg; | 44 | walk->sg = sg; |
44 | 45 | ||
45 | walk->page = sg->page; | ||
46 | walk->len_this_segment = sg->length; | ||
47 | |||
48 | BUG_ON(!sg->length); | 46 | BUG_ON(!sg->length); |
49 | 47 | ||
50 | rest_of_page = PAGE_CACHE_SIZE - (sg->offset & (PAGE_CACHE_SIZE - 1)); | ||
51 | walk->len_this_page = min(sg->length, rest_of_page); | ||
52 | walk->offset = sg->offset; | 48 | walk->offset = sg->offset; |
53 | } | 49 | } |
50 | EXPORT_SYMBOL_GPL(scatterwalk_start); | ||
54 | 51 | ||
55 | void scatterwalk_map(struct scatter_walk *walk, int out) | 52 | void *scatterwalk_map(struct scatter_walk *walk, int out) |
56 | { | ||
57 | walk->data = crypto_kmap(walk->page, out) + walk->offset; | ||
58 | } | ||
59 | |||
60 | static inline void scatterwalk_unmap(struct scatter_walk *walk, int out) | ||
61 | { | 53 | { |
62 | /* walk->data may be pointing the first byte of the next page; | 54 | return crypto_kmap(scatterwalk_page(walk), out) + |
63 | however, we know we transfered at least one byte. So, | 55 | offset_in_page(walk->offset); |
64 | walk->data - 1 will be a virtual address in the mapped page. */ | ||
65 | crypto_kunmap(walk->data - 1, out); | ||
66 | } | 56 | } |
57 | EXPORT_SYMBOL_GPL(scatterwalk_map); | ||
67 | 58 | ||
68 | static void scatterwalk_pagedone(struct scatter_walk *walk, int out, | 59 | static void scatterwalk_pagedone(struct scatter_walk *walk, int out, |
69 | unsigned int more) | 60 | unsigned int more) |
70 | { | 61 | { |
71 | if (out) | 62 | if (out) |
72 | flush_dcache_page(walk->page); | 63 | flush_dcache_page(scatterwalk_page(walk)); |
73 | 64 | ||
74 | if (more) { | 65 | if (more) { |
75 | walk->len_this_segment -= walk->len_this_page; | 66 | walk->offset += PAGE_SIZE - 1; |
76 | 67 | walk->offset &= PAGE_MASK; | |
77 | if (walk->len_this_segment) { | 68 | if (walk->offset >= walk->sg->offset + walk->sg->length) |
78 | walk->page++; | ||
79 | walk->len_this_page = min(walk->len_this_segment, | ||
80 | (unsigned)PAGE_CACHE_SIZE); | ||
81 | walk->offset = 0; | ||
82 | } | ||
83 | else | ||
84 | scatterwalk_start(walk, sg_next(walk->sg)); | 69 | scatterwalk_start(walk, sg_next(walk->sg)); |
85 | } | 70 | } |
86 | } | 71 | } |
87 | 72 | ||
88 | void scatterwalk_done(struct scatter_walk *walk, int out, int more) | 73 | void scatterwalk_done(struct scatter_walk *walk, int out, int more) |
89 | { | 74 | { |
90 | scatterwalk_unmap(walk, out); | 75 | if (!offset_in_page(walk->offset) || !more) |
91 | if (walk->len_this_page == 0 || !more) | ||
92 | scatterwalk_pagedone(walk, out, more); | 76 | scatterwalk_pagedone(walk, out, more); |
93 | } | 77 | } |
78 | EXPORT_SYMBOL_GPL(scatterwalk_done); | ||
94 | 79 | ||
95 | /* | 80 | void scatterwalk_copychunks(void *buf, struct scatter_walk *walk, |
96 | * Do not call this unless the total length of all of the fragments | 81 | size_t nbytes, int out) |
97 | * has been verified as multiple of the block size. | ||
98 | */ | ||
99 | int scatterwalk_copychunks(void *buf, struct scatter_walk *walk, | ||
100 | size_t nbytes, int out) | ||
101 | { | 82 | { |
102 | while (nbytes > walk->len_this_page) { | 83 | for (;;) { |
103 | memcpy_dir(buf, walk->data, walk->len_this_page, out); | 84 | unsigned int len_this_page = scatterwalk_pagelen(walk); |
104 | buf += walk->len_this_page; | 85 | u8 *vaddr; |
105 | nbytes -= walk->len_this_page; | 86 | |
87 | if (len_this_page > nbytes) | ||
88 | len_this_page = nbytes; | ||
89 | |||
90 | vaddr = scatterwalk_map(walk, out); | ||
91 | memcpy_dir(buf, vaddr, len_this_page, out); | ||
92 | scatterwalk_unmap(vaddr, out); | ||
93 | |||
94 | if (nbytes == len_this_page) | ||
95 | break; | ||
96 | |||
97 | buf += len_this_page; | ||
98 | nbytes -= len_this_page; | ||
106 | 99 | ||
107 | scatterwalk_unmap(walk, out); | ||
108 | scatterwalk_pagedone(walk, out, 1); | 100 | scatterwalk_pagedone(walk, out, 1); |
109 | scatterwalk_map(walk, out); | ||
110 | } | 101 | } |
111 | 102 | ||
112 | memcpy_dir(buf, walk->data, nbytes, out); | 103 | scatterwalk_advance(walk, nbytes); |
113 | return nbytes; | ||
114 | } | 104 | } |
105 | EXPORT_SYMBOL_GPL(scatterwalk_copychunks); | ||