1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#include <linux/kernel.h>
17#include <linux/mm.h>
18#include <linux/pagemap.h>
19#include <linux/highmem.h>
20#include <asm/scatterlist.h>
21#include "internal.h"
22#include "scatterwalk.h"
23
24enum km_type crypto_km_types[] = {
25 KM_USER0,
26 KM_USER1,
27 KM_SOFTIRQ0,
28 KM_SOFTIRQ1,
29};
30
31static void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out)
32{
33 if (out)
34 memcpy(sgdata, buf, nbytes);
35 else
36 memcpy(buf, sgdata, nbytes);
37}
38
39void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg)
40{
41 unsigned int rest_of_page;
42
43 walk->sg = sg;
44
45 walk->page = sg->page;
46 walk->len_this_segment = sg->length;
47
48 BUG_ON(!sg->length);
49
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;
53}
54
55void 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{
62
63
64
65 crypto_kunmap(walk->data - 1, out);
66}
67
68static void scatterwalk_pagedone(struct scatter_walk *walk, int out,
69 unsigned int more)
70{
71 if (out)
72 flush_dcache_page(walk->page);
73
74 if (more) {
75 walk->len_this_segment -= walk->len_this_page;
76
77 if (walk->len_this_segment) {
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));
85 }
86}
87
88void scatterwalk_done(struct scatter_walk *walk, int out, int more)
89{
90 scatterwalk_unmap(walk, out);
91 if (walk->len_this_page == 0 || !more)
92 scatterwalk_pagedone(walk, out, more);
93}
94
95
96
97
98
99int scatterwalk_copychunks(void *buf, struct scatter_walk *walk,
100 size_t nbytes, int out)
101{
102 while (nbytes > walk->len_this_page) {
103 memcpy_dir(buf, walk->data, walk->len_this_page, out);
104 buf += walk->len_this_page;
105 nbytes -= walk->len_this_page;
106
107 scatterwalk_unmap(walk, out);
108 scatterwalk_pagedone(walk, out, 1);
109 scatterwalk_map(walk, out);
110 }
111
112 memcpy_dir(buf, walk->data, nbytes, out);
113 return nbytes;
114}
115