1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#include "kmap_types.h"
17
18#include <linux/kernel.h>
19#include <linux/mm.h>
20#include <linux/pagemap.h>
21#include <linux/highmem.h>
22#include <asm/scatterlist.h>
23#include "internal.h"
24#include "scatterwalk.h"
25
26enum km_type crypto_km_types[] = {
27 KM_USER0,
28 KM_USER1,
29 KM_SOFTIRQ0,
30 KM_SOFTIRQ1,
31};
32
33void *scatterwalk_whichbuf(struct scatter_walk *walk, unsigned int nbytes, void *scratch)
34{
35 if (nbytes <= walk->len_this_page &&
36 (((unsigned long)walk->data) & (PAGE_CACHE_SIZE - 1)) + nbytes <=
37 PAGE_CACHE_SIZE)
38 return walk->data;
39 else
40 return scratch;
41}
42
43static void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out)
44{
45 if (out)
46 memcpy(sgdata, buf, nbytes);
47 else
48 memcpy(buf, sgdata, nbytes);
49}
50
51void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg)
52{
53 unsigned int rest_of_page;
54
55 walk->sg = sg;
56
57 walk->page = sg->page;
58 walk->len_this_segment = sg->length;
59
60 rest_of_page = PAGE_CACHE_SIZE - (sg->offset & (PAGE_CACHE_SIZE - 1));
61 walk->len_this_page = min(sg->length, rest_of_page);
62 walk->offset = sg->offset;
63}
64
65void scatterwalk_map(struct scatter_walk *walk, int out)
66{
67 walk->data = crypto_kmap(walk->page, out) + walk->offset;
68}
69
70static void scatterwalk_pagedone(struct scatter_walk *walk, int out,
71 unsigned int more)
72{
73
74
75
76
77 if (out)
78 flush_dcache_page(walk->page);
79
80 if (more) {
81 walk->len_this_segment -= walk->len_this_page;
82
83 if (walk->len_this_segment) {
84 walk->page++;
85 walk->len_this_page = min(walk->len_this_segment,
86 (unsigned)PAGE_CACHE_SIZE);
87 walk->offset = 0;
88 }
89 else
90 scatterwalk_start(walk, sg_next(walk->sg));
91 }
92}
93
94void scatterwalk_done(struct scatter_walk *walk, int out, int more)
95{
96 crypto_kunmap(walk->data, out);
97 if (walk->len_this_page == 0 || !more)
98 scatterwalk_pagedone(walk, out, more);
99}
100
101
102
103
104
105int scatterwalk_copychunks(void *buf, struct scatter_walk *walk,
106 size_t nbytes, int out)
107{
108 if (buf != walk->data) {
109 while (nbytes > walk->len_this_page) {
110 memcpy_dir(buf, walk->data, walk->len_this_page, out);
111 buf += walk->len_this_page;
112 nbytes -= walk->len_this_page;
113
114 crypto_kunmap(walk->data, out);
115 scatterwalk_pagedone(walk, out, 1);
116 scatterwalk_map(walk, out);
117 }
118
119 memcpy_dir(buf, walk->data, nbytes, out);
120 }
121
122 walk->offset += nbytes;
123 walk->len_this_page -= nbytes;
124 walk->len_this_segment -= nbytes;
125 return 0;
126}
127