diff options
-rw-r--r-- | crypto/cipher.c | 27 | ||||
-rw-r--r-- | crypto/scatterwalk.c | 89 | ||||
-rw-r--r-- | crypto/scatterwalk.h | 48 | ||||
-rw-r--r-- | include/crypto/algapi.h | 5 |
4 files changed, 87 insertions, 82 deletions
diff --git a/crypto/cipher.c b/crypto/cipher.c index d8ca0ec8d0be..326461780673 100644 --- a/crypto/cipher.c +++ b/crypto/cipher.c | |||
@@ -45,15 +45,10 @@ static unsigned int crypt_slow(const struct cipher_desc *desc, | |||
45 | u8 buffer[bsize * 2 + alignmask]; | 45 | u8 buffer[bsize * 2 + alignmask]; |
46 | u8 *src = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); | 46 | u8 *src = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); |
47 | u8 *dst = src + bsize; | 47 | u8 *dst = src + bsize; |
48 | unsigned int n; | ||
49 | |||
50 | n = scatterwalk_copychunks(src, in, bsize, 0); | ||
51 | scatterwalk_advance(in, n); | ||
52 | 48 | ||
49 | scatterwalk_copychunks(src, in, bsize, 0); | ||
53 | desc->prfn(desc, dst, src, bsize); | 50 | desc->prfn(desc, dst, src, bsize); |
54 | 51 | scatterwalk_copychunks(dst, out, bsize, 1); | |
55 | n = scatterwalk_copychunks(dst, out, bsize, 1); | ||
56 | scatterwalk_advance(out, n); | ||
57 | 52 | ||
58 | return bsize; | 53 | return bsize; |
59 | } | 54 | } |
@@ -64,12 +59,16 @@ static inline unsigned int crypt_fast(const struct cipher_desc *desc, | |||
64 | unsigned int nbytes, u8 *tmp) | 59 | unsigned int nbytes, u8 *tmp) |
65 | { | 60 | { |
66 | u8 *src, *dst; | 61 | u8 *src, *dst; |
62 | u8 *real_src, *real_dst; | ||
63 | |||
64 | real_src = scatterwalk_map(in, 0); | ||
65 | real_dst = scatterwalk_map(out, 1); | ||
67 | 66 | ||
68 | src = in->data; | 67 | src = real_src; |
69 | dst = scatterwalk_samebuf(in, out) ? src : out->data; | 68 | dst = scatterwalk_samebuf(in, out) ? src : real_dst; |
70 | 69 | ||
71 | if (tmp) { | 70 | if (tmp) { |
72 | memcpy(tmp, in->data, nbytes); | 71 | memcpy(tmp, src, nbytes); |
73 | src = tmp; | 72 | src = tmp; |
74 | dst = tmp; | 73 | dst = tmp; |
75 | } | 74 | } |
@@ -77,7 +76,10 @@ static inline unsigned int crypt_fast(const struct cipher_desc *desc, | |||
77 | nbytes = desc->prfn(desc, dst, src, nbytes); | 76 | nbytes = desc->prfn(desc, dst, src, nbytes); |
78 | 77 | ||
79 | if (tmp) | 78 | if (tmp) |
80 | memcpy(out->data, tmp, nbytes); | 79 | memcpy(real_dst, tmp, nbytes); |
80 | |||
81 | scatterwalk_unmap(real_src, 0); | ||
82 | scatterwalk_unmap(real_dst, 1); | ||
81 | 83 | ||
82 | scatterwalk_advance(in, nbytes); | 84 | scatterwalk_advance(in, nbytes); |
83 | scatterwalk_advance(out, nbytes); | 85 | scatterwalk_advance(out, nbytes); |
@@ -126,9 +128,6 @@ static int crypt(const struct cipher_desc *desc, | |||
126 | tmp = (u8 *)buffer; | 128 | tmp = (u8 *)buffer; |
127 | } | 129 | } |
128 | 130 | ||
129 | scatterwalk_map(&walk_in, 0); | ||
130 | scatterwalk_map(&walk_out, 1); | ||
131 | |||
132 | n = scatterwalk_clamp(&walk_in, n); | 131 | n = scatterwalk_clamp(&walk_in, n); |
133 | n = scatterwalk_clamp(&walk_out, n); | 132 | n = scatterwalk_clamp(&walk_out, n); |
134 | 133 | ||
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); | ||
diff --git a/crypto/scatterwalk.h b/crypto/scatterwalk.h index e79925c474a3..ace595a2e119 100644 --- a/crypto/scatterwalk.h +++ b/crypto/scatterwalk.h | |||
@@ -14,17 +14,11 @@ | |||
14 | 14 | ||
15 | #ifndef _CRYPTO_SCATTERWALK_H | 15 | #ifndef _CRYPTO_SCATTERWALK_H |
16 | #define _CRYPTO_SCATTERWALK_H | 16 | #define _CRYPTO_SCATTERWALK_H |
17 | |||
17 | #include <linux/mm.h> | 18 | #include <linux/mm.h> |
18 | #include <asm/scatterlist.h> | 19 | #include <linux/scatterlist.h> |
19 | 20 | ||
20 | struct scatter_walk { | 21 | #include "internal.h" |
21 | struct scatterlist *sg; | ||
22 | struct page *page; | ||
23 | void *data; | ||
24 | unsigned int len_this_page; | ||
25 | unsigned int len_this_segment; | ||
26 | unsigned int offset; | ||
27 | }; | ||
28 | 22 | ||
29 | /* Define sg_next is an inline routine now in case we want to change | 23 | /* Define sg_next is an inline routine now in case we want to change |
30 | scatterlist to a linked list later. */ | 24 | scatterlist to a linked list later. */ |
@@ -33,26 +27,31 @@ static inline struct scatterlist *sg_next(struct scatterlist *sg) | |||
33 | return sg + 1; | 27 | return sg + 1; |
34 | } | 28 | } |
35 | 29 | ||
36 | static inline int scatterwalk_samebuf(struct scatter_walk *walk_in, | 30 | static inline unsigned long scatterwalk_samebuf(struct scatter_walk *walk_in, |
37 | struct scatter_walk *walk_out) | 31 | struct scatter_walk *walk_out) |
38 | { | 32 | { |
39 | return walk_in->page == walk_out->page && | 33 | return !(((walk_in->sg->page - walk_out->sg->page) << PAGE_SHIFT) + |
40 | walk_in->offset == walk_out->offset; | 34 | (int)(walk_in->offset - walk_out->offset)); |
35 | } | ||
36 | |||
37 | static inline unsigned int scatterwalk_pagelen(struct scatter_walk *walk) | ||
38 | { | ||
39 | unsigned int len = walk->sg->offset + walk->sg->length - walk->offset; | ||
40 | unsigned int len_this_page = offset_in_page(~walk->offset) + 1; | ||
41 | return len_this_page > len ? len : len_this_page; | ||
41 | } | 42 | } |
42 | 43 | ||
43 | static inline unsigned int scatterwalk_clamp(struct scatter_walk *walk, | 44 | static inline unsigned int scatterwalk_clamp(struct scatter_walk *walk, |
44 | unsigned int nbytes) | 45 | unsigned int nbytes) |
45 | { | 46 | { |
46 | return nbytes > walk->len_this_page ? walk->len_this_page : nbytes; | 47 | unsigned int len_this_page = scatterwalk_pagelen(walk); |
48 | return nbytes > len_this_page ? len_this_page : nbytes; | ||
47 | } | 49 | } |
48 | 50 | ||
49 | static inline void scatterwalk_advance(struct scatter_walk *walk, | 51 | static inline void scatterwalk_advance(struct scatter_walk *walk, |
50 | unsigned int nbytes) | 52 | unsigned int nbytes) |
51 | { | 53 | { |
52 | walk->data += nbytes; | ||
53 | walk->offset += nbytes; | 54 | walk->offset += nbytes; |
54 | walk->len_this_page -= nbytes; | ||
55 | walk->len_this_segment -= nbytes; | ||
56 | } | 55 | } |
57 | 56 | ||
58 | static inline unsigned int scatterwalk_aligned(struct scatter_walk *walk, | 57 | static inline unsigned int scatterwalk_aligned(struct scatter_walk *walk, |
@@ -61,9 +60,20 @@ static inline unsigned int scatterwalk_aligned(struct scatter_walk *walk, | |||
61 | return !(walk->offset & alignmask); | 60 | return !(walk->offset & alignmask); |
62 | } | 61 | } |
63 | 62 | ||
63 | static inline struct page *scatterwalk_page(struct scatter_walk *walk) | ||
64 | { | ||
65 | return walk->sg->page + (walk->offset >> PAGE_SHIFT); | ||
66 | } | ||
67 | |||
68 | static inline void scatterwalk_unmap(void *vaddr, int out) | ||
69 | { | ||
70 | crypto_kunmap(vaddr, out); | ||
71 | } | ||
72 | |||
64 | void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg); | 73 | void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg); |
65 | int scatterwalk_copychunks(void *buf, struct scatter_walk *walk, size_t nbytes, int out); | 74 | void scatterwalk_copychunks(void *buf, struct scatter_walk *walk, |
66 | void scatterwalk_map(struct scatter_walk *walk, int out); | 75 | size_t nbytes, int out); |
76 | void *scatterwalk_map(struct scatter_walk *walk, int out); | ||
67 | void scatterwalk_done(struct scatter_walk *walk, int out, int more); | 77 | void scatterwalk_done(struct scatter_walk *walk, int out, int more); |
68 | 78 | ||
69 | #endif /* _CRYPTO_SCATTERWALK_H */ | 79 | #endif /* _CRYPTO_SCATTERWALK_H */ |
diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h index 6f9fb27b2071..f21ae672e8a8 100644 --- a/include/crypto/algapi.h +++ b/include/crypto/algapi.h | |||
@@ -50,6 +50,11 @@ struct crypto_spawn { | |||
50 | struct crypto_instance *inst; | 50 | struct crypto_instance *inst; |
51 | }; | 51 | }; |
52 | 52 | ||
53 | struct scatter_walk { | ||
54 | struct scatterlist *sg; | ||
55 | unsigned int offset; | ||
56 | }; | ||
57 | |||
53 | int crypto_register_template(struct crypto_template *tmpl); | 58 | int crypto_register_template(struct crypto_template *tmpl); |
54 | void crypto_unregister_template(struct crypto_template *tmpl); | 59 | void crypto_unregister_template(struct crypto_template *tmpl); |
55 | struct crypto_template *crypto_lookup_template(const char *name); | 60 | struct crypto_template *crypto_lookup_template(const char *name); |