19 #include <linux/kernel.h>
20 #include <linux/slab.h>
24 #include <linux/sched.h>
39 static void lzo_free_workspace(
struct list_head *
ws)
49 static struct list_head *lzo_alloc_workspace(
void)
53 workspace = kzalloc(
sizeof(*workspace),
GFP_NOFS);
60 if (!workspace->
mem || !workspace->
buf || !workspace->
cbuf)
63 INIT_LIST_HEAD(&workspace->
list);
65 return &workspace->
list;
67 lzo_free_workspace(&workspace->
list);
71 static inline void write_compress_length(
char *
buf,
size_t len)
79 static inline size_t read_compress_length(
char *
buf)
91 unsigned long nr_dest_pages,
92 unsigned long *out_pages,
93 unsigned long *total_in,
94 unsigned long *total_out,
95 unsigned long max_out)
97 struct workspace *workspace =
list_entry(ws,
struct workspace,
list);
104 unsigned long bytes_left;
109 unsigned long tot_in = 0;
110 unsigned long tot_out = 0;
111 unsigned long pg_bytes_left;
112 unsigned long out_offset;
120 data_in =
kmap(in_page);
127 if (out_page ==
NULL) {
131 cpage_out =
kmap(out_page);
140 while (tot_in < len) {
142 &out_len, workspace->
mem);
151 write_compress_length(cpage_out + out_offset, out_len);
160 buf = workspace->
cbuf;
162 bytes =
min_t(
unsigned long, pg_bytes_left, out_len);
164 memcpy(cpage_out + out_offset, buf, bytes);
167 pg_bytes_left -=
bytes;
177 if ((out_len == 0 && pg_bytes_left < LZO_LEN) ||
178 pg_bytes_left == 0) {
180 memset(cpage_out + out_offset, 0,
182 tot_out += pg_bytes_left;
186 if (out_len == 0 && tot_in >= len)
190 if (nr_pages == nr_dest_pages) {
197 if (out_page ==
NULL) {
201 cpage_out =
kmap(out_page);
202 pages[nr_pages++] = out_page;
210 if (tot_in > 8192 && tot_in < tot_out)
217 if (tot_out > max_out)
220 bytes_left = len - tot_in;
226 data_in =
kmap(in_page);
230 if (tot_out > tot_in)
234 cpage_out =
kmap(pages[0]);
235 write_compress_length(cpage_out, tot_out);
240 *total_out = tot_out;
243 *out_pages = nr_pages;
255 static int lzo_decompress_biovec(
struct list_head *ws,
256 struct page **pages_in,
258 struct bio_vec *bvec,
262 struct workspace *workspace =
list_entry(ws,
struct workspace,
list);
265 unsigned long page_in_index = 0;
266 unsigned long page_out_index = 0;
269 unsigned long buf_start;
270 unsigned long buf_offset = 0;
272 unsigned long working_bytes;
273 unsigned long pg_offset;
277 unsigned long in_offset;
278 unsigned long in_page_bytes_left;
279 unsigned long tot_in;
280 unsigned long tot_out;
281 unsigned long tot_len;
283 bool may_late_unmap, need_unmap;
285 data_in =
kmap(pages_in[0]);
286 tot_len = read_compress_length(data_in);
290 tot_len =
min_t(
size_t, srclen, tot_len);
296 while (tot_in < tot_len) {
297 in_len = read_compress_length(data_in + in_offset);
304 may_late_unmap = need_unmap =
false;
307 if (in_page_bytes_left >= in_len) {
308 buf = data_in + in_offset;
310 may_late_unmap =
true;
315 buf = workspace->
cbuf;
317 while (working_bytes) {
318 bytes =
min(working_bytes, in_page_bytes_left);
320 memcpy(buf + buf_offset, data_in + in_offset, bytes);
323 working_bytes -=
bytes;
324 in_page_bytes_left -=
bytes;
328 if ((working_bytes == 0 && in_page_bytes_left < LZO_LEN)
329 || in_page_bytes_left == 0) {
330 tot_in += in_page_bytes_left;
332 if (working_bytes == 0 && tot_in >= tot_len)
335 if (page_in_index + 1 >= total_pages_in) {
343 kunmap(pages_in[page_in_index]);
345 data_in =
kmap(pages_in[++page_in_index]);
356 kunmap(pages_in[page_in_index - 1]);
369 &page_out_index, &pg_offset);
374 kunmap(pages_in[page_in_index]);
378 static int lzo_decompress(
struct list_head *ws,
unsigned char *data_in,
379 struct page *dest_page,
380 unsigned long start_byte,
381 size_t srclen,
size_t destlen)
383 struct workspace *workspace =
list_entry(ws,
struct workspace,
list);
393 tot_len = read_compress_length(data_in);
396 in_len = read_compress_length(data_in);
407 if (out_len < start_byte) {
412 bytes =
min_t(
unsigned long, destlen, out_len - start_byte);
415 memcpy(kaddr, workspace->
buf + start_byte, bytes);
422 .alloc_workspace = lzo_alloc_workspace,
423 .free_workspace = lzo_free_workspace,
424 .compress_pages = lzo_compress_pages,
425 .decompress_biovec = lzo_decompress_biovec,
426 .decompress = lzo_decompress,