Magellan Linux

Annotation of /alx-src/tags/kernel26-2.6.12-alx-r9/crypto/scatterwalk.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 630 - (hide annotations) (download)
Wed Mar 4 11:03:09 2009 UTC (15 years, 3 months ago) by niro
File MIME type: text/plain
File size: 2898 byte(s)
Tag kernel26-2.6.12-alx-r9
1 niro 628 /*
2     * Cryptographic API.
3     *
4     * Cipher operations.
5     *
6     * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
7     * 2002 Adam J. Richter <adam@yggdrasil.com>
8     * 2004 Jean-Luc Cooke <jlcooke@certainkey.com>
9     *
10     * This program is free software; you can redistribute it and/or modify it
11     * under the terms of the GNU General Public License as published by the Free
12     * Software Foundation; either version 2 of the License, or (at your option)
13     * any later version.
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/bug.h>
21     #include <asm/scatterlist.h>
22     #include "internal.h"
23     #include "scatterwalk.h"
24    
25     enum km_type crypto_km_types[] = {
26     KM_USER0,
27     KM_USER1,
28     KM_SOFTIRQ0,
29     KM_SOFTIRQ1,
30     };
31    
32     static void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out)
33     {
34     if (out)
35     memcpy(sgdata, buf, nbytes);
36     else
37     memcpy(buf, sgdata, nbytes);
38     }
39    
40     void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg)
41     {
42     unsigned int rest_of_page;
43    
44     walk->sg = sg;
45    
46     walk->page = sg->page;
47     walk->len_this_segment = sg->length;
48    
49     BUG_ON(!sg->length);
50    
51     rest_of_page = PAGE_CACHE_SIZE - (sg->offset & (PAGE_CACHE_SIZE - 1));
52     walk->len_this_page = min(sg->length, rest_of_page);
53     walk->offset = sg->offset;
54     }
55    
56     void scatterwalk_map(struct scatter_walk *walk, int out)
57     {
58     walk->data = crypto_kmap(walk->page, out) + walk->offset;
59     }
60    
61     static inline void scatterwalk_unmap(struct scatter_walk *walk, int out)
62     {
63     /* walk->data may be pointing the first byte of the next page;
64     however, we know we transfered at least one byte. So,
65     walk->data - 1 will be a virtual address in the mapped page. */
66     crypto_kunmap(walk->data - 1, out);
67     }
68    
69     static void scatterwalk_pagedone(struct scatter_walk *walk, int out,
70     unsigned int more)
71     {
72     if (out)
73     flush_dcache_page(walk->page);
74    
75     if (more) {
76     walk->len_this_segment -= walk->len_this_page;
77    
78     if (walk->len_this_segment) {
79     walk->page++;
80     walk->len_this_page = min(walk->len_this_segment,
81     (unsigned)PAGE_CACHE_SIZE);
82     walk->offset = 0;
83     }
84     else
85     scatterwalk_start(walk, sg_next(walk->sg));
86     }
87     }
88    
89     void scatterwalk_done(struct scatter_walk *walk, int out, int more)
90     {
91     scatterwalk_unmap(walk, out);
92     if (walk->len_this_page == 0 || !more)
93     scatterwalk_pagedone(walk, out, more);
94     }
95    
96     /*
97     * Do not call this unless the total length of all of the fragments
98     * has been verified as multiple of the block size.
99     */
100     int scatterwalk_copychunks(void *buf, struct scatter_walk *walk,
101     size_t nbytes, int out)
102     {
103     do {
104     memcpy_dir(buf, walk->data, walk->len_this_page, out);
105     buf += walk->len_this_page;
106     nbytes -= walk->len_this_page;
107    
108     scatterwalk_unmap(walk, out);
109     scatterwalk_pagedone(walk, out, 1);
110     scatterwalk_map(walk, out);
111     } while (nbytes > walk->len_this_page);
112    
113     memcpy_dir(buf, walk->data, nbytes, out);
114     return nbytes;
115     }