diff options
author | Phillip Lougher <phillip@lougher.demon.co.uk> | 2011-02-28 10:31:46 -0500 |
---|---|---|
committer | Phillip Lougher <phillip@lougher.demon.co.uk> | 2011-02-28 13:34:24 -0500 |
commit | ff750311d30acc9564ef577050794953eee59f01 (patch) | |
tree | 03c576ee30624dd94c130747c841e95ae64318a5 /fs | |
parent | b7fc0ff09d24b372dc04b0c02b80659c0a66fdfe (diff) |
Squashfs: add compression options support to xz decompressor
Pass the dictionary size used to compress datablocks. Using a
dictionary size less than the block size saves memory overhead, in many
cases without adversely affecting compression ratio.
Signed-off-by: Phillip Lougher <phillip@lougher.demon.co.uk>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/squashfs/xz_wrapper.c | 49 |
1 files changed, 41 insertions, 8 deletions
diff --git a/fs/squashfs/xz_wrapper.c b/fs/squashfs/xz_wrapper.c index 397adea72eb9..06d0d11b482a 100644 --- a/fs/squashfs/xz_wrapper.c +++ b/fs/squashfs/xz_wrapper.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/buffer_head.h> | 26 | #include <linux/buffer_head.h> |
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/xz.h> | 28 | #include <linux/xz.h> |
29 | #include <linux/bitops.h> | ||
29 | 30 | ||
30 | #include "squashfs_fs.h" | 31 | #include "squashfs_fs.h" |
31 | #include "squashfs_fs_sb.h" | 32 | #include "squashfs_fs_sb.h" |
@@ -38,25 +39,57 @@ struct squashfs_xz { | |||
38 | struct xz_buf buf; | 39 | struct xz_buf buf; |
39 | }; | 40 | }; |
40 | 41 | ||
42 | struct comp_opts { | ||
43 | __le32 dictionary_size; | ||
44 | __le32 flags; | ||
45 | }; | ||
46 | |||
41 | static void *squashfs_xz_init(struct squashfs_sb_info *msblk, void *buff, | 47 | static void *squashfs_xz_init(struct squashfs_sb_info *msblk, void *buff, |
42 | int len) | 48 | int len) |
43 | { | 49 | { |
44 | int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE); | 50 | struct comp_opts *comp_opts = buff; |
51 | struct squashfs_xz *stream; | ||
52 | int dict_size = msblk->block_size; | ||
53 | int err, n; | ||
54 | |||
55 | if (comp_opts) { | ||
56 | /* check compressor options are the expected length */ | ||
57 | if (len < sizeof(*comp_opts)) { | ||
58 | err = -EIO; | ||
59 | goto failed; | ||
60 | } | ||
45 | 61 | ||
46 | struct squashfs_xz *stream = kmalloc(sizeof(*stream), GFP_KERNEL); | 62 | dict_size = le32_to_cpu(comp_opts->dictionary_size); |
47 | if (stream == NULL) | 63 | |
64 | /* the dictionary size should be 2^n or 2^n+2^(n+1) */ | ||
65 | n = ffs(dict_size) - 1; | ||
66 | if (dict_size != (1 << n) && dict_size != (1 << n) + | ||
67 | (1 << (n + 1))) { | ||
68 | err = -EIO; | ||
69 | goto failed; | ||
70 | } | ||
71 | } | ||
72 | |||
73 | dict_size = max_t(int, dict_size, SQUASHFS_METADATA_SIZE); | ||
74 | |||
75 | stream = kmalloc(sizeof(*stream), GFP_KERNEL); | ||
76 | if (stream == NULL) { | ||
77 | err = -ENOMEM; | ||
48 | goto failed; | 78 | goto failed; |
79 | } | ||
49 | 80 | ||
50 | stream->state = xz_dec_init(XZ_PREALLOC, block_size); | 81 | stream->state = xz_dec_init(XZ_PREALLOC, dict_size); |
51 | if (stream->state == NULL) | 82 | if (stream->state == NULL) { |
83 | kfree(stream); | ||
84 | err = -ENOMEM; | ||
52 | goto failed; | 85 | goto failed; |
86 | } | ||
53 | 87 | ||
54 | return stream; | 88 | return stream; |
55 | 89 | ||
56 | failed: | 90 | failed: |
57 | ERROR("Failed to allocate xz workspace\n"); | 91 | ERROR("Failed to initialise xz decompressor\n"); |
58 | kfree(stream); | 92 | return ERR_PTR(err); |
59 | return ERR_PTR(-ENOMEM); | ||
60 | } | 93 | } |
61 | 94 | ||
62 | 95 | ||