X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=crypto%2Fscatterwalk.c;h=0f76175f623fe9172566568f63124407225ce55e;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=f6a5c9e5b2e096b5d5e955c3744c221d208ecff1;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/crypto/scatterwalk.c b/crypto/scatterwalk.c index f6a5c9e5b..0f76175f6 100644 --- a/crypto/scatterwalk.c +++ b/crypto/scatterwalk.c @@ -15,9 +15,11 @@ */ #include #include +#include #include #include -#include +#include + #include "internal.h" #include "scatterwalk.h" @@ -27,98 +29,77 @@ enum km_type crypto_km_types[] = { KM_SOFTIRQ0, KM_SOFTIRQ1, }; +EXPORT_SYMBOL_GPL(crypto_km_types); -void *scatterwalk_whichbuf(struct scatter_walk *walk, unsigned int nbytes, void *scratch) +static inline void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out) { - if (nbytes <= walk->len_this_page && - (((unsigned long)walk->data) & (PAGE_CACHE_SIZE - 1)) + nbytes <= - PAGE_CACHE_SIZE) - return walk->data; - else - return scratch; -} + void *src = out ? buf : sgdata; + void *dst = out ? sgdata : buf; -static void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out) -{ - if (out) - memcpy(sgdata, buf, nbytes); - else - memcpy(buf, sgdata, nbytes); + memcpy(dst, src, nbytes); } void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg) { - unsigned int rest_of_page; - walk->sg = sg; - walk->page = sg->page; - walk->len_this_segment = sg->length; + BUG_ON(!sg->length); - rest_of_page = PAGE_CACHE_SIZE - (sg->offset & (PAGE_CACHE_SIZE - 1)); - walk->len_this_page = min(sg->length, rest_of_page); walk->offset = sg->offset; } +EXPORT_SYMBOL_GPL(scatterwalk_start); -void scatterwalk_map(struct scatter_walk *walk, int out) +void *scatterwalk_map(struct scatter_walk *walk, int out) { - walk->data = crypto_kmap(walk->page, out) + walk->offset; + return crypto_kmap(scatterwalk_page(walk), out) + + offset_in_page(walk->offset); } +EXPORT_SYMBOL_GPL(scatterwalk_map); static void scatterwalk_pagedone(struct scatter_walk *walk, int out, unsigned int more) { - /* walk->data may be pointing the first byte of the next page; - however, we know we transfered at least one byte. So, - walk->data - 1 will be a virtual address in the mapped page. */ - if (out) - flush_dcache_page(walk->page); + flush_dcache_page(scatterwalk_page(walk)); if (more) { - walk->len_this_segment -= walk->len_this_page; - - if (walk->len_this_segment) { - walk->page++; - walk->len_this_page = min(walk->len_this_segment, - (unsigned)PAGE_CACHE_SIZE); - walk->offset = 0; - } - else + walk->offset += PAGE_SIZE - 1; + walk->offset &= PAGE_MASK; + if (walk->offset >= walk->sg->offset + walk->sg->length) scatterwalk_start(walk, sg_next(walk->sg)); } } void scatterwalk_done(struct scatter_walk *walk, int out, int more) { - crypto_kunmap(walk->data, out); - if (walk->len_this_page == 0 || !more) + if (!offset_in_page(walk->offset) || !more) scatterwalk_pagedone(walk, out, more); } +EXPORT_SYMBOL_GPL(scatterwalk_done); -/* - * Do not call this unless the total length of all of the fragments - * has been verified as multiple of the block size. - */ -int scatterwalk_copychunks(void *buf, struct scatter_walk *walk, - size_t nbytes, int out) +void scatterwalk_copychunks(void *buf, struct scatter_walk *walk, + size_t nbytes, int out) { - if (buf != walk->data) { - while (nbytes > walk->len_this_page) { - memcpy_dir(buf, walk->data, walk->len_this_page, out); - buf += walk->len_this_page; - nbytes -= walk->len_this_page; - - crypto_kunmap(walk->data, out); - scatterwalk_pagedone(walk, out, 1); - scatterwalk_map(walk, out); - } - - memcpy_dir(buf, walk->data, nbytes, out); - } + for (;;) { + unsigned int len_this_page = scatterwalk_pagelen(walk); + u8 *vaddr; + + if (len_this_page > nbytes) + len_this_page = nbytes; + + vaddr = scatterwalk_map(walk, out); + memcpy_dir(buf, vaddr, len_this_page, out); + scatterwalk_unmap(vaddr, out); + + scatterwalk_advance(walk, len_this_page); - walk->offset += nbytes; - walk->len_this_page -= nbytes; - walk->len_this_segment -= nbytes; - return 0; + if (nbytes == len_this_page) + break; + + buf += len_this_page; + nbytes -= len_this_page; + + scatterwalk_pagedone(walk, out, 1); + } } +EXPORT_SYMBOL_GPL(scatterwalk_copychunks);