aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLi Zefan <lizf@cn.fujitsu.com>2010-10-25 03:12:26 -0400
committerLi Zefan <lizf@cn.fujitsu.com>2010-12-22 10:15:47 -0500
commita6fa6fae40ec336c7df6155255ae64ebef43a8bc (patch)
tree6cda8aa6a60967206614a941f034249e3017913e
parent261507a02ccba9afda919852263b6bc1581ce1ef (diff)
btrfs: Add lzo compression support
Lzo is a much faster compression algorithm than gzib, so would allow more users to enable transparent compression, and some users can choose from compression ratio and speed for different applications Usage: # mount -t btrfs -o compress[=<zlib,lzo>] dev /mnt or # mount -t btrfs -o compress-force[=<zlib,lzo>] dev /mnt "-o compress" without argument is still allowed for compatability. Compatibility: If we mount a filesystem with lzo compression, it will not be able be mounted in old kernels. One reason is, otherwise btrfs will directly dump compressed data, which sits in inline extent, to user. Performance: The test copied a linux source tarball (~400M) from an ext4 partition to the btrfs partition, and then extracted it. (time in second) lzo zlib nocompress copy: 10.6 21.7 14.9 extract: 70.1 94.4 66.6 (data size in MB) lzo zlib nocompress copy: 185.87 108.69 394.49 extract: 193.80 132.36 381.21 Changelog: v1 -> v2: - Select LZO_COMPRESS and LZO_DECOMPRESS in btrfs Kconfig. - Add incompability flag. - Fix error handling in compress code. Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
-rw-r--r--fs/btrfs/Kconfig2
-rw-r--r--fs/btrfs/Makefile2
-rw-r--r--fs/btrfs/compression.c1
-rw-r--r--fs/btrfs/compression.h1
-rw-r--r--fs/btrfs/ctree.h9
-rw-r--r--fs/btrfs/disk-io.c8
-rw-r--r--fs/btrfs/lzo.c509
-rw-r--r--fs/btrfs/super.c3
8 files changed, 527 insertions, 8 deletions
diff --git a/fs/btrfs/Kconfig b/fs/btrfs/Kconfig
index 7bb3c020e570..ecb9fd3be143 100644
--- a/fs/btrfs/Kconfig
+++ b/fs/btrfs/Kconfig
@@ -4,6 +4,8 @@ config BTRFS_FS
4 select LIBCRC32C 4 select LIBCRC32C
5 select ZLIB_INFLATE 5 select ZLIB_INFLATE
6 select ZLIB_DEFLATE 6 select ZLIB_DEFLATE
7 select LZO_COMPRESS
8 select LZO_DECOMPRESS
7 help 9 help
8 Btrfs is a new filesystem with extents, writable snapshotting, 10 Btrfs is a new filesystem with extents, writable snapshotting,
9 support for multiple devices and many more features. 11 support for multiple devices and many more features.
diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile
index a35eb36b32fd..31610ea73aec 100644
--- a/fs/btrfs/Makefile
+++ b/fs/btrfs/Makefile
@@ -6,5 +6,5 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
6 transaction.o inode.o file.o tree-defrag.o \ 6 transaction.o inode.o file.o tree-defrag.o \
7 extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \ 7 extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \
8 extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \ 8 extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
9 export.o tree-log.o acl.o free-space-cache.o zlib.o \ 9 export.o tree-log.o acl.o free-space-cache.o zlib.o lzo.o \
10 compression.o delayed-ref.o relocation.o 10 compression.o delayed-ref.o relocation.o
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
index 6638c9877720..8faa2df9e719 100644
--- a/fs/btrfs/compression.c
+++ b/fs/btrfs/compression.c
@@ -691,6 +691,7 @@ static wait_queue_head_t comp_workspace_wait[BTRFS_COMPRESS_TYPES];
691 691
692struct btrfs_compress_op *btrfs_compress_op[] = { 692struct btrfs_compress_op *btrfs_compress_op[] = {
693 &btrfs_zlib_compress, 693 &btrfs_zlib_compress,
694 &btrfs_lzo_compress,
694}; 695};
695 696
696int __init btrfs_init_compress(void) 697int __init btrfs_init_compress(void)
diff --git a/fs/btrfs/compression.h b/fs/btrfs/compression.h
index 9b5f2f365b79..f7ce217113fa 100644
--- a/fs/btrfs/compression.h
+++ b/fs/btrfs/compression.h
@@ -73,5 +73,6 @@ struct btrfs_compress_op {
73}; 73};
74 74
75extern struct btrfs_compress_op btrfs_zlib_compress; 75extern struct btrfs_compress_op btrfs_zlib_compress;
76extern struct btrfs_compress_op btrfs_lzo_compress;
76 77
77#endif 78#endif
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index e06534438592..53b984623983 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -398,13 +398,15 @@ struct btrfs_super_block {
398#define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF (1ULL << 0) 398#define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF (1ULL << 0)
399#define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (1ULL << 1) 399#define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (1ULL << 1)
400#define BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS (1ULL << 2) 400#define BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS (1ULL << 2)
401#define BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO (1ULL << 3)
401 402
402#define BTRFS_FEATURE_COMPAT_SUPP 0ULL 403#define BTRFS_FEATURE_COMPAT_SUPP 0ULL
403#define BTRFS_FEATURE_COMPAT_RO_SUPP 0ULL 404#define BTRFS_FEATURE_COMPAT_RO_SUPP 0ULL
404#define BTRFS_FEATURE_INCOMPAT_SUPP \ 405#define BTRFS_FEATURE_INCOMPAT_SUPP \
405 (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \ 406 (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \
406 BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL | \ 407 BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL | \
407 BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) 408 BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS | \
409 BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO)
408 410
409/* 411/*
410 * A leaf is full of items. offset and size tell us where to find 412 * A leaf is full of items. offset and size tell us where to find
@@ -553,8 +555,9 @@ struct btrfs_timespec {
553enum btrfs_compression_type { 555enum btrfs_compression_type {
554 BTRFS_COMPRESS_NONE = 0, 556 BTRFS_COMPRESS_NONE = 0,
555 BTRFS_COMPRESS_ZLIB = 1, 557 BTRFS_COMPRESS_ZLIB = 1,
556 BTRFS_COMPRESS_TYPES = 1, 558 BTRFS_COMPRESS_LZO = 2,
557 BTRFS_COMPRESS_LAST = 2, 559 BTRFS_COMPRESS_TYPES = 2,
560 BTRFS_COMPRESS_LAST = 3,
558}; 561};
559 562
560struct btrfs_inode_item { 563struct btrfs_inode_item {
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index a5d2249e6da5..f88eb2ce7919 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1744,10 +1744,10 @@ struct btrfs_root *open_ctree(struct super_block *sb,
1744 } 1744 }
1745 1745
1746 features = btrfs_super_incompat_flags(disk_super); 1746 features = btrfs_super_incompat_flags(disk_super);
1747 if (!(features & BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF)) { 1747 features |= BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF;
1748 features |= BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF; 1748 if (tree_root->fs_info->compress_type & BTRFS_COMPRESS_LZO)
1749 btrfs_set_super_incompat_flags(disk_super, features); 1749 features |= BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO;
1750 } 1750 btrfs_set_super_incompat_flags(disk_super, features);
1751 1751
1752 features = btrfs_super_compat_ro_flags(disk_super) & 1752 features = btrfs_super_compat_ro_flags(disk_super) &
1753 ~BTRFS_FEATURE_COMPAT_RO_SUPP; 1753 ~BTRFS_FEATURE_COMPAT_RO_SUPP;
diff --git a/fs/btrfs/lzo.c b/fs/btrfs/lzo.c
new file mode 100644
index 000000000000..523b144e2aec
--- /dev/null
+++ b/fs/btrfs/lzo.c
@@ -0,0 +1,509 @@
1/*
2 * Copyright (C) 2008 Oracle. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License v2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public
14 * License along with this program; if not, write to the
15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 * Boston, MA 021110-1307, USA.
17 */
18
19#include <linux/kernel.h>
20#include <linux/slab.h>
21#include <linux/vmalloc.h>
22#include <linux/init.h>
23#include <linux/err.h>
24#include <linux/sched.h>
25#include <linux/pagemap.h>
26#include <linux/bio.h>
27#include <linux/lzo.h>
28#include "compression.h"
29
30#define LZO_LEN 4
31
32struct workspace {
33 void *mem;
34 void *buf; /* where compressed data goes */
35 void *cbuf; /* where decompressed data goes */
36 struct list_head list;
37};
38
39static void lzo_free_workspace(struct list_head *ws)
40{
41 struct workspace *workspace = list_entry(ws, struct workspace, list);
42
43 vfree(workspace->buf);
44 vfree(workspace->cbuf);
45 vfree(workspace->mem);
46 kfree(workspace);
47}
48
49static struct list_head *lzo_alloc_workspace(void)
50{
51 struct workspace *workspace;
52
53 workspace = kzalloc(sizeof(*workspace), GFP_NOFS);
54 if (!workspace)
55 return ERR_PTR(-ENOMEM);
56
57 workspace->mem = vmalloc(LZO1X_MEM_COMPRESS);
58 workspace->buf = vmalloc(lzo1x_worst_compress(PAGE_CACHE_SIZE));
59 workspace->cbuf = vmalloc(lzo1x_worst_compress(PAGE_CACHE_SIZE));
60 if (!workspace->mem || !workspace->buf || !workspace->cbuf)
61 goto fail;
62
63 INIT_LIST_HEAD(&workspace->list);
64
65 return &workspace->list;
66fail:
67 lzo_free_workspace(&workspace->list);
68 return ERR_PTR(-ENOMEM);
69}
70
71static inline void write_compress_length(char *buf, size_t len)
72{
73 __le32 dlen;
74
75 dlen = cpu_to_le32(len);
76 memcpy(buf, &dlen, LZO_LEN);
77}
78
79static inline size_t read_compress_length(char *buf)
80{
81 __le32 dlen;
82
83 memcpy(&dlen, buf, LZO_LEN);
84 return le32_to_cpu(dlen);
85}
86
87static int lzo_compress_pages(struct list_head *ws,
88 struct address_space *mapping,
89 u64 start, unsigned long len,
90 struct page **pages,
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)
96{
97 struct workspace *workspace = list_entry(ws, struct workspace, list);
98 int ret = 0;
99 char *data_in;
100 char *cpage_out;
101 int nr_pages = 0;
102 struct page *in_page = NULL;
103 struct page *out_page = NULL;
104 unsigned long bytes_left;
105
106 size_t in_len;
107 size_t out_len;
108 char *buf;
109 unsigned long tot_in = 0;
110 unsigned long tot_out = 0;
111 unsigned long pg_bytes_left;
112 unsigned long out_offset;
113 unsigned long bytes;
114
115 *out_pages = 0;
116 *total_out = 0;
117 *total_in = 0;
118
119 in_page = find_get_page(mapping, start >> PAGE_CACHE_SHIFT);
120 data_in = kmap(in_page);
121
122 /*
123 * store the size of all chunks of compressed data in
124 * the first 4 bytes
125 */
126 out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
127 if (out_page == NULL) {
128 ret = -ENOMEM;
129 goto out;
130 }
131 cpage_out = kmap(out_page);
132 out_offset = LZO_LEN;
133 tot_out = LZO_LEN;
134 pages[0] = out_page;
135 nr_pages = 1;
136 pg_bytes_left = PAGE_CACHE_SIZE - LZO_LEN;
137
138 /* compress at most one page of data each time */
139 in_len = min(len, PAGE_CACHE_SIZE);
140 while (tot_in < len) {
141 ret = lzo1x_1_compress(data_in, in_len, workspace->cbuf,
142 &out_len, workspace->mem);
143 if (ret != LZO_E_OK) {
144 printk(KERN_DEBUG "btrfs deflate in loop returned %d\n",
145 ret);
146 ret = -1;
147 goto out;
148 }
149
150 /* store the size of this chunk of compressed data */
151 write_compress_length(cpage_out + out_offset, out_len);
152 tot_out += LZO_LEN;
153 out_offset += LZO_LEN;
154 pg_bytes_left -= LZO_LEN;
155
156 tot_in += in_len;
157 tot_out += out_len;
158
159 /* copy bytes from the working buffer into the pages */
160 buf = workspace->cbuf;
161 while (out_len) {
162 bytes = min_t(unsigned long, pg_bytes_left, out_len);
163
164 memcpy(cpage_out + out_offset, buf, bytes);
165
166 out_len -= bytes;
167 pg_bytes_left -= bytes;
168 buf += bytes;
169 out_offset += bytes;
170
171 /*
172 * we need another page for writing out.
173 *
174 * Note if there's less than 4 bytes left, we just
175 * skip to a new page.
176 */
177 if ((out_len == 0 && pg_bytes_left < LZO_LEN) ||
178 pg_bytes_left == 0) {
179 if (pg_bytes_left) {
180 memset(cpage_out + out_offset, 0,
181 pg_bytes_left);
182 tot_out += pg_bytes_left;
183 }
184
185 /* we're done, don't allocate new page */
186 if (out_len == 0 && tot_in >= len)
187 break;
188
189 kunmap(out_page);
190 if (nr_pages == nr_dest_pages) {
191 out_page = NULL;
192 ret = -1;
193 goto out;
194 }
195
196 out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
197 if (out_page == NULL) {
198 ret = -ENOMEM;
199 goto out;
200 }
201 cpage_out = kmap(out_page);
202 pages[nr_pages++] = out_page;
203
204 pg_bytes_left = PAGE_CACHE_SIZE;
205 out_offset = 0;
206 }
207 }
208
209 /* we're making it bigger, give up */
210 if (tot_in > 8192 && tot_in < tot_out)
211 goto out;
212
213 /* we're all done */
214 if (tot_in >= len)
215 break;
216
217 if (tot_out > max_out)
218 break;
219
220 bytes_left = len - tot_in;
221 kunmap(in_page);
222 page_cache_release(in_page);
223
224 start += PAGE_CACHE_SIZE;
225 in_page = find_get_page(mapping, start >> PAGE_CACHE_SHIFT);
226 data_in = kmap(in_page);
227 in_len = min(bytes_left, PAGE_CACHE_SIZE);
228 }
229
230 if (tot_out > tot_in)
231 goto out;
232
233 /* store the size of all chunks of compressed data */
234 cpage_out = kmap(pages[0]);
235 write_compress_length(cpage_out, tot_out);
236
237 kunmap(pages[0]);
238
239 ret = 0;
240 *total_out = tot_out;
241 *total_in = tot_in;
242out:
243 *out_pages = nr_pages;
244 if (out_page)
245 kunmap(out_page);
246
247 if (in_page) {
248 kunmap(in_page);
249 page_cache_release(in_page);
250 }
251
252 return ret;
253}
254
255static int lzo_decompress_biovec(struct list_head *ws,
256 struct page **pages_in,
257 u64 disk_start,
258 struct bio_vec *bvec,
259 int vcnt,
260 size_t srclen)
261{
262 struct workspace *workspace = list_entry(ws, struct workspace, list);
263 int ret = 0;
264 char *data_in;
265 unsigned long page_bytes_left;
266 unsigned long page_in_index = 0;
267 unsigned long page_out_index = 0;
268 struct page *page_out;
269 unsigned long total_pages_in = (srclen + PAGE_CACHE_SIZE - 1) /
270 PAGE_CACHE_SIZE;
271 unsigned long buf_start;
272 unsigned long buf_offset = 0;
273 unsigned long bytes;
274 unsigned long working_bytes;
275 unsigned long pg_offset;
276 unsigned long start_byte;
277 unsigned long current_buf_start;
278 char *kaddr;
279
280 size_t in_len;
281 size_t out_len;
282 unsigned long in_offset;
283 unsigned long in_page_bytes_left;
284 unsigned long tot_in;
285 unsigned long tot_out;
286 unsigned long tot_len;
287 char *buf;
288
289 data_in = kmap(pages_in[0]);
290 tot_len = read_compress_length(data_in);
291
292 tot_in = LZO_LEN;
293 in_offset = LZO_LEN;
294 tot_len = min_t(size_t, srclen, tot_len);
295 in_page_bytes_left = PAGE_CACHE_SIZE - LZO_LEN;
296
297 tot_out = 0;
298 page_out = bvec[0].bv_page;
299 page_bytes_left = PAGE_CACHE_SIZE;
300 pg_offset = 0;
301
302 while (tot_in < tot_len) {
303 in_len = read_compress_length(data_in + in_offset);
304 in_page_bytes_left -= LZO_LEN;
305 in_offset += LZO_LEN;
306 tot_in += LZO_LEN;
307
308 tot_in += in_len;
309 working_bytes = in_len;
310
311 /* fast path: avoid using the working buffer */
312 if (in_page_bytes_left >= in_len) {
313 buf = data_in + in_offset;
314 bytes = in_len;
315 goto cont;
316 }
317
318 /* copy bytes from the pages into the working buffer */
319 buf = workspace->cbuf;
320 buf_offset = 0;
321 while (working_bytes) {
322 bytes = min(working_bytes, in_page_bytes_left);
323
324 memcpy(buf + buf_offset, data_in + in_offset, bytes);
325 buf_offset += bytes;
326cont:
327 working_bytes -= bytes;
328 in_page_bytes_left -= bytes;
329 in_offset += bytes;
330
331 /* check if we need to pick another page */
332 if ((working_bytes == 0 && in_page_bytes_left < LZO_LEN)
333 || in_page_bytes_left == 0) {
334 tot_in += in_page_bytes_left;
335
336 if (working_bytes == 0 && tot_in >= tot_len)
337 break;
338
339 kunmap(pages_in[page_in_index]);
340 page_in_index++;
341 if (page_in_index >= total_pages_in) {
342 ret = -1;
343 data_in = NULL;
344 goto done;
345 }
346 data_in = kmap(pages_in[page_in_index]);
347
348 in_page_bytes_left = PAGE_CACHE_SIZE;
349 in_offset = 0;
350 }
351 }
352
353 out_len = lzo1x_worst_compress(PAGE_CACHE_SIZE);
354 ret = lzo1x_decompress_safe(buf, in_len, workspace->buf,
355 &out_len);
356 if (ret != LZO_E_OK) {
357 printk(KERN_WARNING "btrfs decompress failed\n");
358 ret = -1;
359 break;
360 }
361
362 /*
363 * buf start is the byte offset we're of the start of
364 * our workspace buffer
365 */
366 buf_start = tot_out;
367
368 /* tot_out is the last byte of the workspace buffer */
369 tot_out += out_len;
370
371 working_bytes = tot_out - buf_start;
372
373 /*
374 * start_byte is the first byte of the page we're currently
375 * copying into relative to the start of the compressed data.
376 */
377 start_byte = page_offset(page_out) - disk_start;
378
379 if (working_bytes == 0) {
380 /* we didn't make progress in this inflate
381 * call, we're done
382 */
383 break;
384 }
385
386 /* we haven't yet hit data corresponding to this page */
387 if (tot_out <= start_byte)
388 continue;
389
390 /*
391 * the start of the data we care about is offset into
392 * the middle of our working buffer
393 */
394 if (tot_out > start_byte && buf_start < start_byte) {
395 buf_offset = start_byte - buf_start;
396 working_bytes -= buf_offset;
397 } else {
398 buf_offset = 0;
399 }
400 current_buf_start = buf_start;
401
402 /* copy bytes from the working buffer into the pages */
403 while (working_bytes > 0) {
404 bytes = min(PAGE_CACHE_SIZE - pg_offset,
405 PAGE_CACHE_SIZE - buf_offset);
406 bytes = min(bytes, working_bytes);
407 kaddr = kmap_atomic(page_out, KM_USER0);
408 memcpy(kaddr + pg_offset, workspace->buf + buf_offset,
409 bytes);
410 kunmap_atomic(kaddr, KM_USER0);
411 flush_dcache_page(page_out);
412
413 pg_offset += bytes;
414 page_bytes_left -= bytes;
415 buf_offset += bytes;
416 working_bytes -= bytes;
417 current_buf_start += bytes;
418
419 /* check if we need to pick another page */
420 if (page_bytes_left == 0) {
421 page_out_index++;
422 if (page_out_index >= vcnt) {
423 ret = 0;
424 goto done;
425 }
426
427 page_out = bvec[page_out_index].bv_page;
428 pg_offset = 0;
429 page_bytes_left = PAGE_CACHE_SIZE;
430 start_byte = page_offset(page_out) - disk_start;
431
432 /*
433 * make sure our new page is covered by this
434 * working buffer
435 */
436 if (tot_out <= start_byte)
437 break;
438
439 /* the next page in the biovec might not
440 * be adjacent to the last page, but it
441 * might still be found inside this working
442 * buffer. bump our offset pointer
443 */
444 if (tot_out > start_byte &&
445 current_buf_start < start_byte) {
446 buf_offset = start_byte - buf_start;
447 working_bytes = tot_out - start_byte;
448 current_buf_start = buf_start +
449 buf_offset;
450 }
451 }
452 }
453 }
454done:
455 if (data_in)
456 kunmap(pages_in[page_in_index]);
457 return ret;
458}
459
460static int lzo_decompress(struct list_head *ws, unsigned char *data_in,
461 struct page *dest_page,
462 unsigned long start_byte,
463 size_t srclen, size_t destlen)
464{
465 struct workspace *workspace = list_entry(ws, struct workspace, list);
466 size_t in_len;
467 size_t out_len;
468 size_t tot_len;
469 int ret = 0;
470 char *kaddr;
471 unsigned long bytes;
472
473 BUG_ON(srclen < LZO_LEN);
474
475 tot_len = read_compress_length(data_in);
476 data_in += LZO_LEN;
477
478 in_len = read_compress_length(data_in);
479 data_in += LZO_LEN;
480
481 out_len = PAGE_CACHE_SIZE;
482 ret = lzo1x_decompress_safe(data_in, in_len, workspace->buf, &out_len);
483 if (ret != LZO_E_OK) {
484 printk(KERN_WARNING "btrfs decompress failed!\n");
485 ret = -1;
486 goto out;
487 }
488
489 if (out_len < start_byte) {
490 ret = -1;
491 goto out;
492 }
493
494 bytes = min_t(unsigned long, destlen, out_len - start_byte);
495
496 kaddr = kmap_atomic(dest_page, KM_USER0);
497 memcpy(kaddr, workspace->buf + start_byte, bytes);
498 kunmap_atomic(kaddr, KM_USER0);
499out:
500 return ret;
501}
502
503struct btrfs_compress_op btrfs_lzo_compress = {
504 .alloc_workspace = lzo_alloc_workspace,
505 .free_workspace = lzo_free_workspace,
506 .compress_pages = lzo_compress_pages,
507 .decompress_biovec = lzo_decompress_biovec,
508 .decompress = lzo_decompress,
509};
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index f348f2b93164..a1a76b2a61f9 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -168,6 +168,9 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
168 strcmp(args[0].from, "zlib") == 0) { 168 strcmp(args[0].from, "zlib") == 0) {
169 compress_type = "zlib"; 169 compress_type = "zlib";
170 info->compress_type = BTRFS_COMPRESS_ZLIB; 170 info->compress_type = BTRFS_COMPRESS_ZLIB;
171 } else if (strcmp(args[0].from, "lzo") == 0) {
172 compress_type = "lzo";
173 info->compress_type = BTRFS_COMPRESS_LZO;
171 } else { 174 } else {
172 ret = -EINVAL; 175 ret = -EINVAL;
173 goto out; 176 goto out;