aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/zlib.c
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /fs/btrfs/zlib.c
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (diff)
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts: litmus/sched_cedf.c
Diffstat (limited to 'fs/btrfs/zlib.c')
-rw-r--r--fs/btrfs/zlib.c377
1 files changed, 72 insertions, 305 deletions
diff --git a/fs/btrfs/zlib.c b/fs/btrfs/zlib.c
index 3e2b90eaa239..faccd47c6c46 100644
--- a/fs/btrfs/zlib.c
+++ b/fs/btrfs/zlib.c
@@ -32,15 +32,6 @@
32#include <linux/bio.h> 32#include <linux/bio.h>
33#include "compression.h" 33#include "compression.h"
34 34
35/* Plan: call deflate() with avail_in == *sourcelen,
36 avail_out = *dstlen - 12 and flush == Z_FINISH.
37 If it doesn't manage to finish, call it again with
38 avail_in == 0 and avail_out set to the remaining 12
39 bytes for it to clean up.
40 Q: Is 12 bytes sufficient?
41*/
42#define STREAM_END_SPACE 12
43
44struct workspace { 35struct workspace {
45 z_stream inf_strm; 36 z_stream inf_strm;
46 z_stream def_strm; 37 z_stream def_strm;
@@ -48,169 +39,63 @@ struct workspace {
48 struct list_head list; 39 struct list_head list;
49}; 40};
50 41
51static LIST_HEAD(idle_workspace); 42static void zlib_free_workspace(struct list_head *ws)
52static DEFINE_SPINLOCK(workspace_lock);
53static unsigned long num_workspace;
54static atomic_t alloc_workspace = ATOMIC_INIT(0);
55static DECLARE_WAIT_QUEUE_HEAD(workspace_wait);
56
57/*
58 * this finds an available zlib workspace or allocates a new one
59 * NULL or an ERR_PTR is returned if things go bad.
60 */
61static struct workspace *find_zlib_workspace(void)
62{ 43{
63 struct workspace *workspace; 44 struct workspace *workspace = list_entry(ws, struct workspace, list);
64 int ret;
65 int cpus = num_online_cpus();
66
67again:
68 spin_lock(&workspace_lock);
69 if (!list_empty(&idle_workspace)) {
70 workspace = list_entry(idle_workspace.next, struct workspace,
71 list);
72 list_del(&workspace->list);
73 num_workspace--;
74 spin_unlock(&workspace_lock);
75 return workspace;
76
77 }
78 spin_unlock(&workspace_lock);
79 if (atomic_read(&alloc_workspace) > cpus) {
80 DEFINE_WAIT(wait);
81 prepare_to_wait(&workspace_wait, &wait, TASK_UNINTERRUPTIBLE);
82 if (atomic_read(&alloc_workspace) > cpus)
83 schedule();
84 finish_wait(&workspace_wait, &wait);
85 goto again;
86 }
87 atomic_inc(&alloc_workspace);
88 workspace = kzalloc(sizeof(*workspace), GFP_NOFS);
89 if (!workspace) {
90 ret = -ENOMEM;
91 goto fail;
92 }
93
94 workspace->def_strm.workspace = vmalloc(zlib_deflate_workspacesize());
95 if (!workspace->def_strm.workspace) {
96 ret = -ENOMEM;
97 goto fail;
98 }
99 workspace->inf_strm.workspace = vmalloc(zlib_inflate_workspacesize());
100 if (!workspace->inf_strm.workspace) {
101 ret = -ENOMEM;
102 goto fail_inflate;
103 }
104 workspace->buf = kmalloc(PAGE_CACHE_SIZE, GFP_NOFS);
105 if (!workspace->buf) {
106 ret = -ENOMEM;
107 goto fail_kmalloc;
108 }
109 return workspace;
110 45
111fail_kmalloc:
112 vfree(workspace->inf_strm.workspace);
113fail_inflate:
114 vfree(workspace->def_strm.workspace);
115fail:
116 kfree(workspace);
117 atomic_dec(&alloc_workspace);
118 wake_up(&workspace_wait);
119 return ERR_PTR(ret);
120}
121
122/*
123 * put a workspace struct back on the list or free it if we have enough
124 * idle ones sitting around
125 */
126static int free_workspace(struct workspace *workspace)
127{
128 spin_lock(&workspace_lock);
129 if (num_workspace < num_online_cpus()) {
130 list_add_tail(&workspace->list, &idle_workspace);
131 num_workspace++;
132 spin_unlock(&workspace_lock);
133 if (waitqueue_active(&workspace_wait))
134 wake_up(&workspace_wait);
135 return 0;
136 }
137 spin_unlock(&workspace_lock);
138 vfree(workspace->def_strm.workspace); 46 vfree(workspace->def_strm.workspace);
139 vfree(workspace->inf_strm.workspace); 47 vfree(workspace->inf_strm.workspace);
140 kfree(workspace->buf); 48 kfree(workspace->buf);
141 kfree(workspace); 49 kfree(workspace);
142
143 atomic_dec(&alloc_workspace);
144 if (waitqueue_active(&workspace_wait))
145 wake_up(&workspace_wait);
146 return 0;
147} 50}
148 51
149/* 52static struct list_head *zlib_alloc_workspace(void)
150 * cleanup function for module exit
151 */
152static void free_workspaces(void)
153{ 53{
154 struct workspace *workspace; 54 struct workspace *workspace;
155 while (!list_empty(&idle_workspace)) { 55
156 workspace = list_entry(idle_workspace.next, struct workspace, 56 workspace = kzalloc(sizeof(*workspace), GFP_NOFS);
157 list); 57 if (!workspace)
158 list_del(&workspace->list); 58 return ERR_PTR(-ENOMEM);
159 vfree(workspace->def_strm.workspace); 59
160 vfree(workspace->inf_strm.workspace); 60 workspace->def_strm.workspace = vmalloc(zlib_deflate_workspacesize(
161 kfree(workspace->buf); 61 MAX_WBITS, MAX_MEM_LEVEL));
162 kfree(workspace); 62 workspace->inf_strm.workspace = vmalloc(zlib_inflate_workspacesize());
163 atomic_dec(&alloc_workspace); 63 workspace->buf = kmalloc(PAGE_CACHE_SIZE, GFP_NOFS);
164 } 64 if (!workspace->def_strm.workspace ||
65 !workspace->inf_strm.workspace || !workspace->buf)
66 goto fail;
67
68 INIT_LIST_HEAD(&workspace->list);
69
70 return &workspace->list;
71fail:
72 zlib_free_workspace(&workspace->list);
73 return ERR_PTR(-ENOMEM);
165} 74}
166 75
167/* 76static int zlib_compress_pages(struct list_head *ws,
168 * given an address space and start/len, compress the bytes. 77 struct address_space *mapping,
169 * 78 u64 start, unsigned long len,
170 * pages are allocated to hold the compressed result and stored 79 struct page **pages,
171 * in 'pages' 80 unsigned long nr_dest_pages,
172 * 81 unsigned long *out_pages,
173 * out_pages is used to return the number of pages allocated. There 82 unsigned long *total_in,
174 * may be pages allocated even if we return an error 83 unsigned long *total_out,
175 * 84 unsigned long max_out)
176 * total_in is used to return the number of bytes actually read. It
177 * may be smaller then len if we had to exit early because we
178 * ran out of room in the pages array or because we cross the
179 * max_out threshold.
180 *
181 * total_out is used to return the total number of compressed bytes
182 *
183 * max_out tells us the max number of bytes that we're allowed to
184 * stuff into pages
185 */
186int btrfs_zlib_compress_pages(struct address_space *mapping,
187 u64 start, unsigned long len,
188 struct page **pages,
189 unsigned long nr_dest_pages,
190 unsigned long *out_pages,
191 unsigned long *total_in,
192 unsigned long *total_out,
193 unsigned long max_out)
194{ 85{
86 struct workspace *workspace = list_entry(ws, struct workspace, list);
195 int ret; 87 int ret;
196 struct workspace *workspace;
197 char *data_in; 88 char *data_in;
198 char *cpage_out; 89 char *cpage_out;
199 int nr_pages = 0; 90 int nr_pages = 0;
200 struct page *in_page = NULL; 91 struct page *in_page = NULL;
201 struct page *out_page = NULL; 92 struct page *out_page = NULL;
202 int out_written = 0;
203 int in_read = 0;
204 unsigned long bytes_left; 93 unsigned long bytes_left;
205 94
206 *out_pages = 0; 95 *out_pages = 0;
207 *total_out = 0; 96 *total_out = 0;
208 *total_in = 0; 97 *total_in = 0;
209 98
210 workspace = find_zlib_workspace();
211 if (IS_ERR(workspace))
212 return -1;
213
214 if (Z_OK != zlib_deflateInit(&workspace->def_strm, 3)) { 99 if (Z_OK != zlib_deflateInit(&workspace->def_strm, 3)) {
215 printk(KERN_WARNING "deflateInit failed\n"); 100 printk(KERN_WARNING "deflateInit failed\n");
216 ret = -1; 101 ret = -1;
@@ -224,6 +109,10 @@ int btrfs_zlib_compress_pages(struct address_space *mapping,
224 data_in = kmap(in_page); 109 data_in = kmap(in_page);
225 110
226 out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM); 111 out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
112 if (out_page == NULL) {
113 ret = -1;
114 goto out;
115 }
227 cpage_out = kmap(out_page); 116 cpage_out = kmap(out_page);
228 pages[0] = out_page; 117 pages[0] = out_page;
229 nr_pages = 1; 118 nr_pages = 1;
@@ -233,9 +122,6 @@ int btrfs_zlib_compress_pages(struct address_space *mapping,
233 workspace->def_strm.avail_out = PAGE_CACHE_SIZE; 122 workspace->def_strm.avail_out = PAGE_CACHE_SIZE;
234 workspace->def_strm.avail_in = min(len, PAGE_CACHE_SIZE); 123 workspace->def_strm.avail_in = min(len, PAGE_CACHE_SIZE);
235 124
236 out_written = 0;
237 in_read = 0;
238
239 while (workspace->def_strm.total_in < len) { 125 while (workspace->def_strm.total_in < len) {
240 ret = zlib_deflate(&workspace->def_strm, Z_SYNC_FLUSH); 126 ret = zlib_deflate(&workspace->def_strm, Z_SYNC_FLUSH);
241 if (ret != Z_OK) { 127 if (ret != Z_OK) {
@@ -265,6 +151,10 @@ int btrfs_zlib_compress_pages(struct address_space *mapping,
265 goto out; 151 goto out;
266 } 152 }
267 out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM); 153 out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
154 if (out_page == NULL) {
155 ret = -1;
156 goto out;
157 }
268 cpage_out = kmap(out_page); 158 cpage_out = kmap(out_page);
269 pages[nr_pages] = out_page; 159 pages[nr_pages] = out_page;
270 nr_pages++; 160 nr_pages++;
@@ -319,55 +209,26 @@ out:
319 kunmap(in_page); 209 kunmap(in_page);
320 page_cache_release(in_page); 210 page_cache_release(in_page);
321 } 211 }
322 free_workspace(workspace);
323 return ret; 212 return ret;
324} 213}
325 214
326/* 215static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in,
327 * pages_in is an array of pages with compressed data. 216 u64 disk_start,
328 * 217 struct bio_vec *bvec,
329 * disk_start is the starting logical offset of this array in the file 218 int vcnt,
330 * 219 size_t srclen)
331 * bvec is a bio_vec of pages from the file that we want to decompress into
332 *
333 * vcnt is the count of pages in the biovec
334 *
335 * srclen is the number of bytes in pages_in
336 *
337 * The basic idea is that we have a bio that was created by readpages.
338 * The pages in the bio are for the uncompressed data, and they may not
339 * be contiguous. They all correspond to the range of bytes covered by
340 * the compressed extent.
341 */
342int btrfs_zlib_decompress_biovec(struct page **pages_in,
343 u64 disk_start,
344 struct bio_vec *bvec,
345 int vcnt,
346 size_t srclen)
347{ 220{
348 int ret = 0; 221 struct workspace *workspace = list_entry(ws, struct workspace, list);
222 int ret = 0, ret2;
349 int wbits = MAX_WBITS; 223 int wbits = MAX_WBITS;
350 struct workspace *workspace;
351 char *data_in; 224 char *data_in;
352 size_t total_out = 0; 225 size_t total_out = 0;
353 unsigned long page_bytes_left;
354 unsigned long page_in_index = 0; 226 unsigned long page_in_index = 0;
355 unsigned long page_out_index = 0; 227 unsigned long page_out_index = 0;
356 struct page *page_out;
357 unsigned long total_pages_in = (srclen + PAGE_CACHE_SIZE - 1) / 228 unsigned long total_pages_in = (srclen + PAGE_CACHE_SIZE - 1) /
358 PAGE_CACHE_SIZE; 229 PAGE_CACHE_SIZE;
359 unsigned long buf_start; 230 unsigned long buf_start;
360 unsigned long buf_offset;
361 unsigned long bytes;
362 unsigned long working_bytes;
363 unsigned long pg_offset; 231 unsigned long pg_offset;
364 unsigned long start_byte;
365 unsigned long current_buf_start;
366 char *kaddr;
367
368 workspace = find_zlib_workspace();
369 if (IS_ERR(workspace))
370 return -ENOMEM;
371 232
372 data_in = kmap(pages_in[page_in_index]); 233 data_in = kmap(pages_in[page_in_index]);
373 workspace->inf_strm.next_in = data_in; 234 workspace->inf_strm.next_in = data_in;
@@ -377,8 +238,6 @@ int btrfs_zlib_decompress_biovec(struct page **pages_in,
377 workspace->inf_strm.total_out = 0; 238 workspace->inf_strm.total_out = 0;
378 workspace->inf_strm.next_out = workspace->buf; 239 workspace->inf_strm.next_out = workspace->buf;
379 workspace->inf_strm.avail_out = PAGE_CACHE_SIZE; 240 workspace->inf_strm.avail_out = PAGE_CACHE_SIZE;
380 page_out = bvec[page_out_index].bv_page;
381 page_bytes_left = PAGE_CACHE_SIZE;
382 pg_offset = 0; 241 pg_offset = 0;
383 242
384 /* If it's deflate, and it's got no preset dictionary, then 243 /* If it's deflate, and it's got no preset dictionary, then
@@ -394,107 +253,29 @@ int btrfs_zlib_decompress_biovec(struct page **pages_in,
394 253
395 if (Z_OK != zlib_inflateInit2(&workspace->inf_strm, wbits)) { 254 if (Z_OK != zlib_inflateInit2(&workspace->inf_strm, wbits)) {
396 printk(KERN_WARNING "inflateInit failed\n"); 255 printk(KERN_WARNING "inflateInit failed\n");
397 ret = -1; 256 return -1;
398 goto out;
399 } 257 }
400 while (workspace->inf_strm.total_in < srclen) { 258 while (workspace->inf_strm.total_in < srclen) {
401 ret = zlib_inflate(&workspace->inf_strm, Z_NO_FLUSH); 259 ret = zlib_inflate(&workspace->inf_strm, Z_NO_FLUSH);
402 if (ret != Z_OK && ret != Z_STREAM_END) 260 if (ret != Z_OK && ret != Z_STREAM_END)
403 break; 261 break;
404 /*
405 * buf start is the byte offset we're of the start of
406 * our workspace buffer
407 */
408 buf_start = total_out;
409 262
410 /* total_out is the last byte of the workspace buffer */ 263 buf_start = total_out;
411 total_out = workspace->inf_strm.total_out; 264 total_out = workspace->inf_strm.total_out;
412 265
413 working_bytes = total_out - buf_start; 266 /* we didn't make progress in this inflate call, we're done */
414 267 if (buf_start == total_out)
415 /*
416 * start byte is the first byte of the page we're currently
417 * copying into relative to the start of the compressed data.
418 */
419 start_byte = page_offset(page_out) - disk_start;
420
421 if (working_bytes == 0) {
422 /* we didn't make progress in this inflate
423 * call, we're done
424 */
425 if (ret != Z_STREAM_END)
426 ret = -1;
427 break; 268 break;
428 }
429 269
430 /* we haven't yet hit data corresponding to this page */ 270 ret2 = btrfs_decompress_buf2page(workspace->buf, buf_start,
431 if (total_out <= start_byte) 271 total_out, disk_start,
432 goto next; 272 bvec, vcnt,
433 273 &page_out_index, &pg_offset);
434 /* 274 if (ret2 == 0) {
435 * the start of the data we care about is offset into 275 ret = 0;
436 * the middle of our working buffer 276 goto done;
437 */
438 if (total_out > start_byte && buf_start < start_byte) {
439 buf_offset = start_byte - buf_start;
440 working_bytes -= buf_offset;
441 } else {
442 buf_offset = 0;
443 }
444 current_buf_start = buf_start;
445
446 /* copy bytes from the working buffer into the pages */
447 while (working_bytes > 0) {
448 bytes = min(PAGE_CACHE_SIZE - pg_offset,
449 PAGE_CACHE_SIZE - buf_offset);
450 bytes = min(bytes, working_bytes);
451 kaddr = kmap_atomic(page_out, KM_USER0);
452 memcpy(kaddr + pg_offset, workspace->buf + buf_offset,
453 bytes);
454 kunmap_atomic(kaddr, KM_USER0);
455 flush_dcache_page(page_out);
456
457 pg_offset += bytes;
458 page_bytes_left -= bytes;
459 buf_offset += bytes;
460 working_bytes -= bytes;
461 current_buf_start += bytes;
462
463 /* check if we need to pick another page */
464 if (page_bytes_left == 0) {
465 page_out_index++;
466 if (page_out_index >= vcnt) {
467 ret = 0;
468 goto done;
469 }
470
471 page_out = bvec[page_out_index].bv_page;
472 pg_offset = 0;
473 page_bytes_left = PAGE_CACHE_SIZE;
474 start_byte = page_offset(page_out) - disk_start;
475
476 /*
477 * make sure our new page is covered by this
478 * working buffer
479 */
480 if (total_out <= start_byte)
481 goto next;
482
483 /* the next page in the biovec might not
484 * be adjacent to the last page, but it
485 * might still be found inside this working
486 * buffer. bump our offset pointer
487 */
488 if (total_out > start_byte &&
489 current_buf_start < start_byte) {
490 buf_offset = start_byte - buf_start;
491 working_bytes = total_out - start_byte;
492 current_buf_start = buf_start +
493 buf_offset;
494 }
495 }
496 } 277 }
497next: 278
498 workspace->inf_strm.next_out = workspace->buf; 279 workspace->inf_strm.next_out = workspace->buf;
499 workspace->inf_strm.avail_out = PAGE_CACHE_SIZE; 280 workspace->inf_strm.avail_out = PAGE_CACHE_SIZE;
500 281
@@ -521,35 +302,21 @@ done:
521 zlib_inflateEnd(&workspace->inf_strm); 302 zlib_inflateEnd(&workspace->inf_strm);
522 if (data_in) 303 if (data_in)
523 kunmap(pages_in[page_in_index]); 304 kunmap(pages_in[page_in_index]);
524out:
525 free_workspace(workspace);
526 return ret; 305 return ret;
527} 306}
528 307
529/* 308static int zlib_decompress(struct list_head *ws, unsigned char *data_in,
530 * a less complex decompression routine. Our compressed data fits in a 309 struct page *dest_page,
531 * single page, and we want to read a single page out of it. 310 unsigned long start_byte,
532 * start_byte tells us the offset into the compressed data we're interested in 311 size_t srclen, size_t destlen)
533 */
534int btrfs_zlib_decompress(unsigned char *data_in,
535 struct page *dest_page,
536 unsigned long start_byte,
537 size_t srclen, size_t destlen)
538{ 312{
313 struct workspace *workspace = list_entry(ws, struct workspace, list);
539 int ret = 0; 314 int ret = 0;
540 int wbits = MAX_WBITS; 315 int wbits = MAX_WBITS;
541 struct workspace *workspace;
542 unsigned long bytes_left = destlen; 316 unsigned long bytes_left = destlen;
543 unsigned long total_out = 0; 317 unsigned long total_out = 0;
544 char *kaddr; 318 char *kaddr;
545 319
546 if (destlen > PAGE_CACHE_SIZE)
547 return -ENOMEM;
548
549 workspace = find_zlib_workspace();
550 if (IS_ERR(workspace))
551 return -ENOMEM;
552
553 workspace->inf_strm.next_in = data_in; 320 workspace->inf_strm.next_in = data_in;
554 workspace->inf_strm.avail_in = srclen; 321 workspace->inf_strm.avail_in = srclen;
555 workspace->inf_strm.total_in = 0; 322 workspace->inf_strm.total_in = 0;
@@ -570,8 +337,7 @@ int btrfs_zlib_decompress(unsigned char *data_in,
570 337
571 if (Z_OK != zlib_inflateInit2(&workspace->inf_strm, wbits)) { 338 if (Z_OK != zlib_inflateInit2(&workspace->inf_strm, wbits)) {
572 printk(KERN_WARNING "inflateInit failed\n"); 339 printk(KERN_WARNING "inflateInit failed\n");
573 ret = -1; 340 return -1;
574 goto out;
575 } 341 }
576 342
577 while (bytes_left > 0) { 343 while (bytes_left > 0) {
@@ -621,12 +387,13 @@ next:
621 ret = 0; 387 ret = 0;
622 388
623 zlib_inflateEnd(&workspace->inf_strm); 389 zlib_inflateEnd(&workspace->inf_strm);
624out:
625 free_workspace(workspace);
626 return ret; 390 return ret;
627} 391}
628 392
629void btrfs_zlib_exit(void) 393struct btrfs_compress_op btrfs_zlib_compress = {
630{ 394 .alloc_workspace = zlib_alloc_workspace,
631 free_workspaces(); 395 .free_workspace = zlib_free_workspace,
632} 396 .compress_pages = zlib_compress_pages,
397 .decompress_biovec = zlib_decompress_biovec,
398 .decompress = zlib_decompress,
399};