aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crypto/cipher.c27
-rw-r--r--crypto/scatterwalk.c89
-rw-r--r--crypto/scatterwalk.h48
-rw-r--r--include/crypto/algapi.h5
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};
32EXPORT_SYMBOL_GPL(crypto_km_types);
30 33
31static void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out) 34static 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
39void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg) 42void 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}
50EXPORT_SYMBOL_GPL(scatterwalk_start);
54 51
55void scatterwalk_map(struct scatter_walk *walk, int out) 52void *scatterwalk_map(struct scatter_walk *walk, int out)
56{
57 walk->data = crypto_kmap(walk->page, out) + walk->offset;
58}
59
60static 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}
57EXPORT_SYMBOL_GPL(scatterwalk_map);
67 58
68static void scatterwalk_pagedone(struct scatter_walk *walk, int out, 59static 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
88void scatterwalk_done(struct scatter_walk *walk, int out, int more) 73void 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}
78EXPORT_SYMBOL_GPL(scatterwalk_done);
94 79
95/* 80void 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 */
99int 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}
105EXPORT_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
20struct 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
36static inline int scatterwalk_samebuf(struct scatter_walk *walk_in, 30static 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
37static 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
43static inline unsigned int scatterwalk_clamp(struct scatter_walk *walk, 44static 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
49static inline void scatterwalk_advance(struct scatter_walk *walk, 51static 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
58static inline unsigned int scatterwalk_aligned(struct scatter_walk *walk, 57static 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
63static inline struct page *scatterwalk_page(struct scatter_walk *walk)
64{
65 return walk->sg->page + (walk->offset >> PAGE_SHIFT);
66}
67
68static inline void scatterwalk_unmap(void *vaddr, int out)
69{
70 crypto_kunmap(vaddr, out);
71}
72
64void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg); 73void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg);
65int scatterwalk_copychunks(void *buf, struct scatter_walk *walk, size_t nbytes, int out); 74void scatterwalk_copychunks(void *buf, struct scatter_walk *walk,
66void scatterwalk_map(struct scatter_walk *walk, int out); 75 size_t nbytes, int out);
76void *scatterwalk_map(struct scatter_walk *walk, int out);
67void scatterwalk_done(struct scatter_walk *walk, int out, int more); 77void 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
53struct scatter_walk {
54 struct scatterlist *sg;
55 unsigned int offset;
56};
57
53int crypto_register_template(struct crypto_template *tmpl); 58int crypto_register_template(struct crypto_template *tmpl);
54void crypto_unregister_template(struct crypto_template *tmpl); 59void crypto_unregister_template(struct crypto_template *tmpl);
55struct crypto_template *crypto_lookup_template(const char *name); 60struct crypto_template *crypto_lookup_template(const char *name);