aboutsummaryrefslogtreecommitdiffstats
path: root/crypto/scatterwalk.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2006-08-12 07:56:17 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2006-09-20 21:41:52 -0400
commit5c64097aa0f6dc4f27718ef47ca9a12538d62860 (patch)
treed8c0cd3358464f589c9f2778b7be348f73db6950 /crypto/scatterwalk.c
parentf28776a369b12f9a03a822a8e1090ed670a41f4f (diff)
[CRYPTO] scatterwalk: Prepare for block ciphers
This patch prepares the scatterwalk code for use by the new block cipher type. Firstly it halves the size of scatter_walk on 32-bit platforms. This is important as we allocate at least two of these objects on the stack for each block cipher operation. It also exports the symbols since the block cipher code can be built as a module. Finally there is a hack in scatterwalk_unmap that relies on progress being made. Unfortunately, for hardware crypto we can't guarantee progress to be made since the hardware can fail. So this also gets rid of the hack by not advancing the address returned by scatterwalk_map. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/scatterwalk.c')
-rw-r--r--crypto/scatterwalk.c89
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};
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);