aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/zlib.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/zlib.c')
-rw-r--r--fs/btrfs/zlib.c253
1 files changed, 50 insertions, 203 deletions
diff --git a/fs/btrfs/zlib.c b/fs/btrfs/zlib.c
index b01558661e3b..9a3e693917f2 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,155 +39,51 @@ 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); 43{
53static unsigned long num_workspace; 44 struct workspace *workspace = list_entry(ws, struct workspace, list);
54static atomic_t alloc_workspace = ATOMIC_INIT(0);
55static DECLARE_WAIT_QUEUE_HEAD(workspace_wait);
56 45
57/* 46 vfree(workspace->def_strm.workspace);
58 * this finds an available zlib workspace or allocates a new one 47 vfree(workspace->inf_strm.workspace);
59 * NULL or an ERR_PTR is returned if things go bad. 48 kfree(workspace->buf);
60 */ 49 kfree(workspace);
61static struct workspace *find_zlib_workspace(void) 50}
51
52static struct list_head *zlib_alloc_workspace(void)
62{ 53{
63 struct workspace *workspace; 54 struct workspace *workspace;
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 if (atomic_read(&alloc_workspace) > cpus) {
79 DEFINE_WAIT(wait);
80
81 spin_unlock(&workspace_lock);
82 prepare_to_wait(&workspace_wait, &wait, TASK_UNINTERRUPTIBLE);
83 if (atomic_read(&alloc_workspace) > cpus && !num_workspace)
84 schedule();
85 finish_wait(&workspace_wait, &wait);
86 goto again;
87 }
88 atomic_inc(&alloc_workspace);
89 spin_unlock(&workspace_lock);
90 55
91 workspace = kzalloc(sizeof(*workspace), GFP_NOFS); 56 workspace = kzalloc(sizeof(*workspace), GFP_NOFS);
92 if (!workspace) { 57 if (!workspace)
93 ret = -ENOMEM; 58 return ERR_PTR(-ENOMEM);
94 goto fail;
95 }
96 59
97 workspace->def_strm.workspace = vmalloc(zlib_deflate_workspacesize()); 60 workspace->def_strm.workspace = vmalloc(zlib_deflate_workspacesize());
98 if (!workspace->def_strm.workspace) {
99 ret = -ENOMEM;
100 goto fail;
101 }
102 workspace->inf_strm.workspace = vmalloc(zlib_inflate_workspacesize()); 61 workspace->inf_strm.workspace = vmalloc(zlib_inflate_workspacesize());
103 if (!workspace->inf_strm.workspace) {
104 ret = -ENOMEM;
105 goto fail_inflate;
106 }
107 workspace->buf = kmalloc(PAGE_CACHE_SIZE, GFP_NOFS); 62 workspace->buf = kmalloc(PAGE_CACHE_SIZE, GFP_NOFS);
108 if (!workspace->buf) { 63 if (!workspace->def_strm.workspace ||
109 ret = -ENOMEM; 64 !workspace->inf_strm.workspace || !workspace->buf)
110 goto fail_kmalloc; 65 goto fail;
111 }
112 return workspace;
113
114fail_kmalloc:
115 vfree(workspace->inf_strm.workspace);
116fail_inflate:
117 vfree(workspace->def_strm.workspace);
118fail:
119 kfree(workspace);
120 atomic_dec(&alloc_workspace);
121 wake_up(&workspace_wait);
122 return ERR_PTR(ret);
123}
124
125/*
126 * put a workspace struct back on the list or free it if we have enough
127 * idle ones sitting around
128 */
129static int free_workspace(struct workspace *workspace)
130{
131 spin_lock(&workspace_lock);
132 if (num_workspace < num_online_cpus()) {
133 list_add_tail(&workspace->list, &idle_workspace);
134 num_workspace++;
135 spin_unlock(&workspace_lock);
136 if (waitqueue_active(&workspace_wait))
137 wake_up(&workspace_wait);
138 return 0;
139 }
140 spin_unlock(&workspace_lock);
141 vfree(workspace->def_strm.workspace);
142 vfree(workspace->inf_strm.workspace);
143 kfree(workspace->buf);
144 kfree(workspace);
145 66
146 atomic_dec(&alloc_workspace); 67 INIT_LIST_HEAD(&workspace->list);
147 if (waitqueue_active(&workspace_wait))
148 wake_up(&workspace_wait);
149 return 0;
150}
151 68
152/* 69 return &workspace->list;
153 * cleanup function for module exit 70fail:
154 */ 71 zlib_free_workspace(&workspace->list);
155static void free_workspaces(void) 72 return ERR_PTR(-ENOMEM);
156{
157 struct workspace *workspace;
158 while (!list_empty(&idle_workspace)) {
159 workspace = list_entry(idle_workspace.next, struct workspace,
160 list);
161 list_del(&workspace->list);
162 vfree(workspace->def_strm.workspace);
163 vfree(workspace->inf_strm.workspace);
164 kfree(workspace->buf);
165 kfree(workspace);
166 atomic_dec(&alloc_workspace);
167 }
168} 73}
169 74
170/* 75static int zlib_compress_pages(struct list_head *ws,
171 * given an address space and start/len, compress the bytes. 76 struct address_space *mapping,
172 * 77 u64 start, unsigned long len,
173 * pages are allocated to hold the compressed result and stored 78 struct page **pages,
174 * in 'pages' 79 unsigned long nr_dest_pages,
175 * 80 unsigned long *out_pages,
176 * out_pages is used to return the number of pages allocated. There 81 unsigned long *total_in,
177 * may be pages allocated even if we return an error 82 unsigned long *total_out,
178 * 83 unsigned long max_out)
179 * total_in is used to return the number of bytes actually read. It
180 * may be smaller then len if we had to exit early because we
181 * ran out of room in the pages array or because we cross the
182 * max_out threshold.
183 *
184 * total_out is used to return the total number of compressed bytes
185 *
186 * max_out tells us the max number of bytes that we're allowed to
187 * stuff into pages
188 */
189int btrfs_zlib_compress_pages(struct address_space *mapping,
190 u64 start, unsigned long len,
191 struct page **pages,
192 unsigned long nr_dest_pages,
193 unsigned long *out_pages,
194 unsigned long *total_in,
195 unsigned long *total_out,
196 unsigned long max_out)
197{ 84{
85 struct workspace *workspace = list_entry(ws, struct workspace, list);
198 int ret; 86 int ret;
199 struct workspace *workspace;
200 char *data_in; 87 char *data_in;
201 char *cpage_out; 88 char *cpage_out;
202 int nr_pages = 0; 89 int nr_pages = 0;
@@ -208,10 +95,6 @@ int btrfs_zlib_compress_pages(struct address_space *mapping,
208 *total_out = 0; 95 *total_out = 0;
209 *total_in = 0; 96 *total_in = 0;
210 97
211 workspace = find_zlib_workspace();
212 if (IS_ERR(workspace))
213 return -1;
214
215 if (Z_OK != zlib_deflateInit(&workspace->def_strm, 3)) { 98 if (Z_OK != zlib_deflateInit(&workspace->def_strm, 3)) {
216 printk(KERN_WARNING "deflateInit failed\n"); 99 printk(KERN_WARNING "deflateInit failed\n");
217 ret = -1; 100 ret = -1;
@@ -325,35 +208,18 @@ out:
325 kunmap(in_page); 208 kunmap(in_page);
326 page_cache_release(in_page); 209 page_cache_release(in_page);
327 } 210 }
328 free_workspace(workspace);
329 return ret; 211 return ret;
330} 212}
331 213
332/* 214static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in,
333 * pages_in is an array of pages with compressed data. 215 u64 disk_start,
334 * 216 struct bio_vec *bvec,
335 * disk_start is the starting logical offset of this array in the file 217 int vcnt,
336 * 218 size_t srclen)
337 * bvec is a bio_vec of pages from the file that we want to decompress into
338 *
339 * vcnt is the count of pages in the biovec
340 *
341 * srclen is the number of bytes in pages_in
342 *
343 * The basic idea is that we have a bio that was created by readpages.
344 * The pages in the bio are for the uncompressed data, and they may not
345 * be contiguous. They all correspond to the range of bytes covered by
346 * the compressed extent.
347 */
348int btrfs_zlib_decompress_biovec(struct page **pages_in,
349 u64 disk_start,
350 struct bio_vec *bvec,
351 int vcnt,
352 size_t srclen)
353{ 219{
220 struct workspace *workspace = list_entry(ws, struct workspace, list);
354 int ret = 0; 221 int ret = 0;
355 int wbits = MAX_WBITS; 222 int wbits = MAX_WBITS;
356 struct workspace *workspace;
357 char *data_in; 223 char *data_in;
358 size_t total_out = 0; 224 size_t total_out = 0;
359 unsigned long page_bytes_left; 225 unsigned long page_bytes_left;
@@ -371,10 +237,6 @@ int btrfs_zlib_decompress_biovec(struct page **pages_in,
371 unsigned long current_buf_start; 237 unsigned long current_buf_start;
372 char *kaddr; 238 char *kaddr;
373 239
374 workspace = find_zlib_workspace();
375 if (IS_ERR(workspace))
376 return -ENOMEM;
377
378 data_in = kmap(pages_in[page_in_index]); 240 data_in = kmap(pages_in[page_in_index]);
379 workspace->inf_strm.next_in = data_in; 241 workspace->inf_strm.next_in = data_in;
380 workspace->inf_strm.avail_in = min_t(size_t, srclen, PAGE_CACHE_SIZE); 242 workspace->inf_strm.avail_in = min_t(size_t, srclen, PAGE_CACHE_SIZE);
@@ -400,8 +262,7 @@ int btrfs_zlib_decompress_biovec(struct page **pages_in,
400 262
401 if (Z_OK != zlib_inflateInit2(&workspace->inf_strm, wbits)) { 263 if (Z_OK != zlib_inflateInit2(&workspace->inf_strm, wbits)) {
402 printk(KERN_WARNING "inflateInit failed\n"); 264 printk(KERN_WARNING "inflateInit failed\n");
403 ret = -1; 265 return -1;
404 goto out;
405 } 266 }
406 while (workspace->inf_strm.total_in < srclen) { 267 while (workspace->inf_strm.total_in < srclen) {
407 ret = zlib_inflate(&workspace->inf_strm, Z_NO_FLUSH); 268 ret = zlib_inflate(&workspace->inf_strm, Z_NO_FLUSH);
@@ -527,35 +388,21 @@ done:
527 zlib_inflateEnd(&workspace->inf_strm); 388 zlib_inflateEnd(&workspace->inf_strm);
528 if (data_in) 389 if (data_in)
529 kunmap(pages_in[page_in_index]); 390 kunmap(pages_in[page_in_index]);
530out:
531 free_workspace(workspace);
532 return ret; 391 return ret;
533} 392}
534 393
535/* 394static int zlib_decompress(struct list_head *ws, unsigned char *data_in,
536 * a less complex decompression routine. Our compressed data fits in a 395 struct page *dest_page,
537 * single page, and we want to read a single page out of it. 396 unsigned long start_byte,
538 * start_byte tells us the offset into the compressed data we're interested in 397 size_t srclen, size_t destlen)
539 */
540int btrfs_zlib_decompress(unsigned char *data_in,
541 struct page *dest_page,
542 unsigned long start_byte,
543 size_t srclen, size_t destlen)
544{ 398{
399 struct workspace *workspace = list_entry(ws, struct workspace, list);
545 int ret = 0; 400 int ret = 0;
546 int wbits = MAX_WBITS; 401 int wbits = MAX_WBITS;
547 struct workspace *workspace;
548 unsigned long bytes_left = destlen; 402 unsigned long bytes_left = destlen;
549 unsigned long total_out = 0; 403 unsigned long total_out = 0;
550 char *kaddr; 404 char *kaddr;
551 405
552 if (destlen > PAGE_CACHE_SIZE)
553 return -ENOMEM;
554
555 workspace = find_zlib_workspace();
556 if (IS_ERR(workspace))
557 return -ENOMEM;
558
559 workspace->inf_strm.next_in = data_in; 406 workspace->inf_strm.next_in = data_in;
560 workspace->inf_strm.avail_in = srclen; 407 workspace->inf_strm.avail_in = srclen;
561 workspace->inf_strm.total_in = 0; 408 workspace->inf_strm.total_in = 0;
@@ -576,8 +423,7 @@ int btrfs_zlib_decompress(unsigned char *data_in,
576 423
577 if (Z_OK != zlib_inflateInit2(&workspace->inf_strm, wbits)) { 424 if (Z_OK != zlib_inflateInit2(&workspace->inf_strm, wbits)) {
578 printk(KERN_WARNING "inflateInit failed\n"); 425 printk(KERN_WARNING "inflateInit failed\n");
579 ret = -1; 426 return -1;
580 goto out;
581 } 427 }
582 428
583 while (bytes_left > 0) { 429 while (bytes_left > 0) {
@@ -627,12 +473,13 @@ next:
627 ret = 0; 473 ret = 0;
628 474
629 zlib_inflateEnd(&workspace->inf_strm); 475 zlib_inflateEnd(&workspace->inf_strm);
630out:
631 free_workspace(workspace);
632 return ret; 476 return ret;
633} 477}
634 478
635void btrfs_zlib_exit(void) 479struct btrfs_compress_op btrfs_zlib_compress = {
636{ 480 .alloc_workspace = zlib_alloc_workspace,
637 free_workspaces(); 481 .free_workspace = zlib_free_workspace,
638} 482 .compress_pages = zlib_compress_pages,
483 .decompress_biovec = zlib_decompress_biovec,
484 .decompress = zlib_decompress,
485};