aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorPhillip Lougher <phillip@squashfs.org.uk>2013-11-12 21:56:26 -0500
committerPhillip Lougher <phillip@squashfs.org.uk>2013-11-19 22:35:18 -0500
commit9508c6b90b3f57ecea4e7a896cf8325400fc0c6e (patch)
treea31589009d7d85d722b52c0ef21838ca6d2888da /fs
parent959f58544b7f20c92d5eb43d1232c96c15c01bfb (diff)
Squashfs: Refactor decompressor interface and code
The decompressor interface and code was written from the point of view of single-threaded operation. In doing so it mixed a lot of single-threaded implementation specific aspects into the decompressor code and elsewhere which makes it difficult to seamlessly support multiple different decompressor implementations. This patch does the following: 1. It removes compressor_options parsing from the decompressor init() function. This allows the decompressor init() function to be dynamically called to instantiate multiple decompressors, without the compressor options needing to be read and parsed each time. 2. It moves threading and all sleeping operations out of the decompressors. In doing so, it makes the decompressors non-blocking wrappers which only deal with interfacing with the decompressor implementation. 3. It splits decompressor.[ch] into decompressor generic functions in decompressor.[ch], and moves the single threaded decompressor implementation into decompressor_single.c. The result of this patch is Squashfs should now be able to support multiple decompressors by adding new decompressor_xxx.c files with specialised implementations of the functions in decompressor_single.c Signed-off-by: Phillip Lougher <phillip@squashfs.org.uk> Reviewed-by: Minchan Kim <minchan@kernel.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/squashfs/Makefile2
-rw-r--r--fs/squashfs/block.c11
-rw-r--r--fs/squashfs/decompressor.c47
-rw-r--r--fs/squashfs/decompressor.h21
-rw-r--r--fs/squashfs/decompressor_single.c86
-rw-r--r--fs/squashfs/lzo_wrapper.c24
-rw-r--r--fs/squashfs/squashfs.h9
-rw-r--r--fs/squashfs/squashfs_fs_sb.h3
-rw-r--r--fs/squashfs/super.c10
-rw-r--r--fs/squashfs/xz_wrapper.c89
-rw-r--r--fs/squashfs/zlib_wrapper.c50
11 files changed, 216 insertions, 136 deletions
diff --git a/fs/squashfs/Makefile b/fs/squashfs/Makefile
index 110b0476f3b4..c223c8439c21 100644
--- a/fs/squashfs/Makefile
+++ b/fs/squashfs/Makefile
@@ -4,7 +4,7 @@
4 4
5obj-$(CONFIG_SQUASHFS) += squashfs.o 5obj-$(CONFIG_SQUASHFS) += squashfs.o
6squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o 6squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o
7squashfs-y += namei.o super.o symlink.o decompressor.o 7squashfs-y += namei.o super.o symlink.o decompressor.o decompressor_single.o
8squashfs-$(CONFIG_SQUASHFS_XATTR) += xattr.o xattr_id.o 8squashfs-$(CONFIG_SQUASHFS_XATTR) += xattr.o xattr_id.o
9squashfs-$(CONFIG_SQUASHFS_LZO) += lzo_wrapper.o 9squashfs-$(CONFIG_SQUASHFS_LZO) += lzo_wrapper.o
10squashfs-$(CONFIG_SQUASHFS_XZ) += xz_wrapper.o 10squashfs-$(CONFIG_SQUASHFS_XZ) += xz_wrapper.o
diff --git a/fs/squashfs/block.c b/fs/squashfs/block.c
index 41d108ecc9be..4dd402597f22 100644
--- a/fs/squashfs/block.c
+++ b/fs/squashfs/block.c
@@ -93,7 +93,7 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index,
93 struct buffer_head **bh; 93 struct buffer_head **bh;
94 int offset = index & ((1 << msblk->devblksize_log2) - 1); 94 int offset = index & ((1 << msblk->devblksize_log2) - 1);
95 u64 cur_index = index >> msblk->devblksize_log2; 95 u64 cur_index = index >> msblk->devblksize_log2;
96 int bytes, compressed, b = 0, k = 0, page = 0, avail; 96 int bytes, compressed, b = 0, k = 0, page = 0, avail, i;
97 97
98 bh = kcalloc(((srclength + msblk->devblksize - 1) 98 bh = kcalloc(((srclength + msblk->devblksize - 1)
99 >> msblk->devblksize_log2) + 1, sizeof(*bh), GFP_KERNEL); 99 >> msblk->devblksize_log2) + 1, sizeof(*bh), GFP_KERNEL);
@@ -158,6 +158,12 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index,
158 ll_rw_block(READ, b - 1, bh + 1); 158 ll_rw_block(READ, b - 1, bh + 1);
159 } 159 }
160 160
161 for (i = 0; i < b; i++) {
162 wait_on_buffer(bh[i]);
163 if (!buffer_uptodate(bh[i]))
164 goto block_release;
165 }
166
161 if (compressed) { 167 if (compressed) {
162 length = squashfs_decompress(msblk, buffer, bh, b, offset, 168 length = squashfs_decompress(msblk, buffer, bh, b, offset,
163 length, srclength, pages); 169 length, srclength, pages);
@@ -172,9 +178,6 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index,
172 for (bytes = length; k < b; k++) { 178 for (bytes = length; k < b; k++) {
173 in = min(bytes, msblk->devblksize - offset); 179 in = min(bytes, msblk->devblksize - offset);
174 bytes -= in; 180 bytes -= in;
175 wait_on_buffer(bh[k]);
176 if (!buffer_uptodate(bh[k]))
177 goto block_release;
178 while (in) { 181 while (in) {
179 if (pg_offset == PAGE_CACHE_SIZE) { 182 if (pg_offset == PAGE_CACHE_SIZE) {
180 page++; 183 page++;
diff --git a/fs/squashfs/decompressor.c b/fs/squashfs/decompressor.c
index 3f6271d86abc..234291f79ba5 100644
--- a/fs/squashfs/decompressor.c
+++ b/fs/squashfs/decompressor.c
@@ -37,29 +37,29 @@
37 */ 37 */
38 38
39static const struct squashfs_decompressor squashfs_lzma_unsupported_comp_ops = { 39static const struct squashfs_decompressor squashfs_lzma_unsupported_comp_ops = {
40 NULL, NULL, NULL, LZMA_COMPRESSION, "lzma", 0 40 NULL, NULL, NULL, NULL, LZMA_COMPRESSION, "lzma", 0
41}; 41};
42 42
43#ifndef CONFIG_SQUASHFS_LZO 43#ifndef CONFIG_SQUASHFS_LZO
44static const struct squashfs_decompressor squashfs_lzo_comp_ops = { 44static const struct squashfs_decompressor squashfs_lzo_comp_ops = {
45 NULL, NULL, NULL, LZO_COMPRESSION, "lzo", 0 45 NULL, NULL, NULL, NULL, LZO_COMPRESSION, "lzo", 0
46}; 46};
47#endif 47#endif
48 48
49#ifndef CONFIG_SQUASHFS_XZ 49#ifndef CONFIG_SQUASHFS_XZ
50static const struct squashfs_decompressor squashfs_xz_comp_ops = { 50static const struct squashfs_decompressor squashfs_xz_comp_ops = {
51 NULL, NULL, NULL, XZ_COMPRESSION, "xz", 0 51 NULL, NULL, NULL, NULL, XZ_COMPRESSION, "xz", 0
52}; 52};
53#endif 53#endif
54 54
55#ifndef CONFIG_SQUASHFS_ZLIB 55#ifndef CONFIG_SQUASHFS_ZLIB
56static const struct squashfs_decompressor squashfs_zlib_comp_ops = { 56static const struct squashfs_decompressor squashfs_zlib_comp_ops = {
57 NULL, NULL, NULL, ZLIB_COMPRESSION, "zlib", 0 57 NULL, NULL, NULL, NULL, ZLIB_COMPRESSION, "zlib", 0
58}; 58};
59#endif 59#endif
60 60
61static const struct squashfs_decompressor squashfs_unknown_comp_ops = { 61static const struct squashfs_decompressor squashfs_unknown_comp_ops = {
62 NULL, NULL, NULL, 0, "unknown", 0 62 NULL, NULL, NULL, NULL, 0, "unknown", 0
63}; 63};
64 64
65static const struct squashfs_decompressor *decompressor[] = { 65static const struct squashfs_decompressor *decompressor[] = {
@@ -83,10 +83,10 @@ const struct squashfs_decompressor *squashfs_lookup_decompressor(int id)
83} 83}
84 84
85 85
86void *squashfs_decompressor_init(struct super_block *sb, unsigned short flags) 86static void *get_comp_opts(struct super_block *sb, unsigned short flags)
87{ 87{
88 struct squashfs_sb_info *msblk = sb->s_fs_info; 88 struct squashfs_sb_info *msblk = sb->s_fs_info;
89 void *strm, *buffer = NULL; 89 void *buffer = NULL, *comp_opts;
90 int length = 0; 90 int length = 0;
91 91
92 /* 92 /*
@@ -94,23 +94,40 @@ void *squashfs_decompressor_init(struct super_block *sb, unsigned short flags)
94 */ 94 */
95 if (SQUASHFS_COMP_OPTS(flags)) { 95 if (SQUASHFS_COMP_OPTS(flags)) {
96 buffer = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL); 96 buffer = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL);
97 if (buffer == NULL) 97 if (buffer == NULL) {
98 return ERR_PTR(-ENOMEM); 98 comp_opts = ERR_PTR(-ENOMEM);
99 goto out;
100 }
99 101
100 length = squashfs_read_data(sb, &buffer, 102 length = squashfs_read_data(sb, &buffer,
101 sizeof(struct squashfs_super_block), 0, NULL, 103 sizeof(struct squashfs_super_block), 0, NULL,
102 PAGE_CACHE_SIZE, 1); 104 PAGE_CACHE_SIZE, 1);
103 105
104 if (length < 0) { 106 if (length < 0) {
105 strm = ERR_PTR(length); 107 comp_opts = ERR_PTR(length);
106 goto finished; 108 goto out;
107 } 109 }
108 } 110 }
109 111
110 strm = msblk->decompressor->init(msblk, buffer, length); 112 comp_opts = squashfs_comp_opts(msblk, buffer, length);
111 113
112finished: 114out:
113 kfree(buffer); 115 kfree(buffer);
116 return comp_opts;
117}
118
119
120void *squashfs_decompressor_setup(struct super_block *sb, unsigned short flags)
121{
122 struct squashfs_sb_info *msblk = sb->s_fs_info;
123 void *stream, *comp_opts = get_comp_opts(sb, flags);
124
125 if (IS_ERR(comp_opts))
126 return comp_opts;
127
128 stream = squashfs_decompressor_create(msblk, comp_opts);
129 if (IS_ERR(stream))
130 kfree(comp_opts);
114 131
115 return strm; 132 return stream;
116} 133}
diff --git a/fs/squashfs/decompressor.h b/fs/squashfs/decompressor.h
index 330073e29029..6cdb20a3878a 100644
--- a/fs/squashfs/decompressor.h
+++ b/fs/squashfs/decompressor.h
@@ -24,28 +24,21 @@
24 */ 24 */
25 25
26struct squashfs_decompressor { 26struct squashfs_decompressor {
27 void *(*init)(struct squashfs_sb_info *, void *, int); 27 void *(*init)(struct squashfs_sb_info *, void *);
28 void *(*comp_opts)(struct squashfs_sb_info *, void *, int);
28 void (*free)(void *); 29 void (*free)(void *);
29 int (*decompress)(struct squashfs_sb_info *, void **, 30 int (*decompress)(struct squashfs_sb_info *, void *, void **,
30 struct buffer_head **, int, int, int, int, int); 31 struct buffer_head **, int, int, int, int, int);
31 int id; 32 int id;
32 char *name; 33 char *name;
33 int supported; 34 int supported;
34}; 35};
35 36
36static inline void squashfs_decompressor_free(struct squashfs_sb_info *msblk, 37static inline void *squashfs_comp_opts(struct squashfs_sb_info *msblk,
37 void *s) 38 void *buff, int length)
38{ 39{
39 if (msblk->decompressor) 40 return msblk->decompressor->comp_opts ?
40 msblk->decompressor->free(s); 41 msblk->decompressor->comp_opts(msblk, buff, length) : NULL;
41}
42
43static inline int squashfs_decompress(struct squashfs_sb_info *msblk,
44 void **buffer, struct buffer_head **bh, int b, int offset, int length,
45 int srclength, int pages)
46{
47 return msblk->decompressor->decompress(msblk, buffer, bh, b, offset,
48 length, srclength, pages);
49} 42}
50 43
51#ifdef CONFIG_SQUASHFS_XZ 44#ifdef CONFIG_SQUASHFS_XZ
diff --git a/fs/squashfs/decompressor_single.c b/fs/squashfs/decompressor_single.c
new file mode 100644
index 000000000000..f857cf6f22d4
--- /dev/null
+++ b/fs/squashfs/decompressor_single.c
@@ -0,0 +1,86 @@
1/*
2 * Copyright (c) 2013
3 * Phillip Lougher <phillip@squashfs.org.uk>
4 *
5 * This work is licensed under the terms of the GNU GPL, version 2. See
6 * the COPYING file in the top-level directory.
7 */
8
9#include <linux/types.h>
10#include <linux/mutex.h>
11#include <linux/slab.h>
12#include <linux/buffer_head.h>
13
14#include "squashfs_fs.h"
15#include "squashfs_fs_sb.h"
16#include "decompressor.h"
17#include "squashfs.h"
18
19/*
20 * This file implements single-threaded decompression in the
21 * decompressor framework
22 */
23
24struct squashfs_stream {
25 void *stream;
26 struct mutex mutex;
27};
28
29void *squashfs_decompressor_create(struct squashfs_sb_info *msblk,
30 void *comp_opts)
31{
32 struct squashfs_stream *stream;
33 int err = -ENOMEM;
34
35 stream = kmalloc(sizeof(*stream), GFP_KERNEL);
36 if (stream == NULL)
37 goto out;
38
39 stream->stream = msblk->decompressor->init(msblk, comp_opts);
40 if (IS_ERR(stream->stream)) {
41 err = PTR_ERR(stream->stream);
42 goto out;
43 }
44
45 kfree(comp_opts);
46 mutex_init(&stream->mutex);
47 return stream;
48
49out:
50 kfree(stream);
51 return ERR_PTR(err);
52}
53
54void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk)
55{
56 struct squashfs_stream *stream = msblk->stream;
57
58 if (stream) {
59 msblk->decompressor->free(stream->stream);
60 kfree(stream);
61 }
62}
63
64int squashfs_decompress(struct squashfs_sb_info *msblk,
65 void **buffer, struct buffer_head **bh, int b, int offset, int length,
66 int srclength, int pages)
67{
68 int res;
69 struct squashfs_stream *stream = msblk->stream;
70
71 mutex_lock(&stream->mutex);
72 res = msblk->decompressor->decompress(msblk, stream->stream, buffer,
73 bh, b, offset, length, srclength, pages);
74 mutex_unlock(&stream->mutex);
75
76 if (res < 0)
77 ERROR("%s decompression failed, data probably corrupt\n",
78 msblk->decompressor->name);
79
80 return res;
81}
82
83int squashfs_max_decompressors(void)
84{
85 return 1;
86}
diff --git a/fs/squashfs/lzo_wrapper.c b/fs/squashfs/lzo_wrapper.c
index 00f4dfc5f088..75c3b5779172 100644
--- a/fs/squashfs/lzo_wrapper.c
+++ b/fs/squashfs/lzo_wrapper.c
@@ -37,7 +37,7 @@ struct squashfs_lzo {
37 void *output; 37 void *output;
38}; 38};
39 39
40static void *lzo_init(struct squashfs_sb_info *msblk, void *buff, int len) 40static void *lzo_init(struct squashfs_sb_info *msblk, void *buff)
41{ 41{
42 int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE); 42 int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE);
43 43
@@ -74,22 +74,16 @@ static void lzo_free(void *strm)
74} 74}
75 75
76 76
77static int lzo_uncompress(struct squashfs_sb_info *msblk, void **buffer, 77static int lzo_uncompress(struct squashfs_sb_info *msblk, void *strm,
78 struct buffer_head **bh, int b, int offset, int length, int srclength, 78 void **buffer, struct buffer_head **bh, int b, int offset, int length,
79 int pages) 79 int srclength, int pages)
80{ 80{
81 struct squashfs_lzo *stream = msblk->stream; 81 struct squashfs_lzo *stream = strm;
82 void *buff = stream->input; 82 void *buff = stream->input;
83 int avail, i, bytes = length, res; 83 int avail, i, bytes = length, res;
84 size_t out_len = srclength; 84 size_t out_len = srclength;
85 85
86 mutex_lock(&msblk->read_data_mutex);
87
88 for (i = 0; i < b; i++) { 86 for (i = 0; i < b; i++) {
89 wait_on_buffer(bh[i]);
90 if (!buffer_uptodate(bh[i]))
91 goto block_release;
92
93 avail = min(bytes, msblk->devblksize - offset); 87 avail = min(bytes, msblk->devblksize - offset);
94 memcpy(buff, bh[i]->b_data + offset, avail); 88 memcpy(buff, bh[i]->b_data + offset, avail);
95 buff += avail; 89 buff += avail;
@@ -111,17 +105,9 @@ static int lzo_uncompress(struct squashfs_sb_info *msblk, void **buffer,
111 bytes -= avail; 105 bytes -= avail;
112 } 106 }
113 107
114 mutex_unlock(&msblk->read_data_mutex);
115 return res; 108 return res;
116 109
117block_release:
118 for (; i < b; i++)
119 put_bh(bh[i]);
120
121failed: 110failed:
122 mutex_unlock(&msblk->read_data_mutex);
123
124 ERROR("lzo decompression failed, data probably corrupt\n");
125 return -EIO; 111 return -EIO;
126} 112}
127 113
diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h
index d1266516ed08..2e2751df8452 100644
--- a/fs/squashfs/squashfs.h
+++ b/fs/squashfs/squashfs.h
@@ -48,7 +48,14 @@ extern void *squashfs_read_table(struct super_block *, u64, int);
48 48
49/* decompressor.c */ 49/* decompressor.c */
50extern const struct squashfs_decompressor *squashfs_lookup_decompressor(int); 50extern const struct squashfs_decompressor *squashfs_lookup_decompressor(int);
51extern void *squashfs_decompressor_init(struct super_block *, unsigned short); 51extern void *squashfs_decompressor_setup(struct super_block *, unsigned short);
52
53/* decompressor_xxx.c */
54extern void *squashfs_decompressor_create(struct squashfs_sb_info *, void *);
55extern void squashfs_decompressor_destroy(struct squashfs_sb_info *);
56extern int squashfs_decompress(struct squashfs_sb_info *, void **,
57 struct buffer_head **, int, int, int, int, int);
58extern int squashfs_max_decompressors(void);
52 59
53/* export.c */ 60/* export.c */
54extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64, u64, 61extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64, u64,
diff --git a/fs/squashfs/squashfs_fs_sb.h b/fs/squashfs/squashfs_fs_sb.h
index 52934a22f296..9cdcf4150d59 100644
--- a/fs/squashfs/squashfs_fs_sb.h
+++ b/fs/squashfs/squashfs_fs_sb.h
@@ -63,10 +63,9 @@ struct squashfs_sb_info {
63 __le64 *id_table; 63 __le64 *id_table;
64 __le64 *fragment_index; 64 __le64 *fragment_index;
65 __le64 *xattr_id_table; 65 __le64 *xattr_id_table;
66 struct mutex read_data_mutex;
67 struct mutex meta_index_mutex; 66 struct mutex meta_index_mutex;
68 struct meta_index *meta_index; 67 struct meta_index *meta_index;
69 void *stream; 68 struct squashfs_stream *stream;
70 __le64 *inode_lookup_table; 69 __le64 *inode_lookup_table;
71 u64 inode_table; 70 u64 inode_table;
72 u64 directory_table; 71 u64 directory_table;
diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c
index 60553a9053ca..202df6312d4e 100644
--- a/fs/squashfs/super.c
+++ b/fs/squashfs/super.c
@@ -98,7 +98,6 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
98 msblk->devblksize = sb_min_blocksize(sb, SQUASHFS_DEVBLK_SIZE); 98 msblk->devblksize = sb_min_blocksize(sb, SQUASHFS_DEVBLK_SIZE);
99 msblk->devblksize_log2 = ffz(~msblk->devblksize); 99 msblk->devblksize_log2 = ffz(~msblk->devblksize);
100 100
101 mutex_init(&msblk->read_data_mutex);
102 mutex_init(&msblk->meta_index_mutex); 101 mutex_init(&msblk->meta_index_mutex);
103 102
104 /* 103 /*
@@ -206,13 +205,14 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
206 goto failed_mount; 205 goto failed_mount;
207 206
208 /* Allocate read_page block */ 207 /* Allocate read_page block */
209 msblk->read_page = squashfs_cache_init("data", 1, msblk->block_size); 208 msblk->read_page = squashfs_cache_init("data",
209 squashfs_max_decompressors(), msblk->block_size);
210 if (msblk->read_page == NULL) { 210 if (msblk->read_page == NULL) {
211 ERROR("Failed to allocate read_page block\n"); 211 ERROR("Failed to allocate read_page block\n");
212 goto failed_mount; 212 goto failed_mount;
213 } 213 }
214 214
215 msblk->stream = squashfs_decompressor_init(sb, flags); 215 msblk->stream = squashfs_decompressor_setup(sb, flags);
216 if (IS_ERR(msblk->stream)) { 216 if (IS_ERR(msblk->stream)) {
217 err = PTR_ERR(msblk->stream); 217 err = PTR_ERR(msblk->stream);
218 msblk->stream = NULL; 218 msblk->stream = NULL;
@@ -336,7 +336,7 @@ failed_mount:
336 squashfs_cache_delete(msblk->block_cache); 336 squashfs_cache_delete(msblk->block_cache);
337 squashfs_cache_delete(msblk->fragment_cache); 337 squashfs_cache_delete(msblk->fragment_cache);
338 squashfs_cache_delete(msblk->read_page); 338 squashfs_cache_delete(msblk->read_page);
339 squashfs_decompressor_free(msblk, msblk->stream); 339 squashfs_decompressor_destroy(msblk);
340 kfree(msblk->inode_lookup_table); 340 kfree(msblk->inode_lookup_table);
341 kfree(msblk->fragment_index); 341 kfree(msblk->fragment_index);
342 kfree(msblk->id_table); 342 kfree(msblk->id_table);
@@ -383,7 +383,7 @@ static void squashfs_put_super(struct super_block *sb)
383 squashfs_cache_delete(sbi->block_cache); 383 squashfs_cache_delete(sbi->block_cache);
384 squashfs_cache_delete(sbi->fragment_cache); 384 squashfs_cache_delete(sbi->fragment_cache);
385 squashfs_cache_delete(sbi->read_page); 385 squashfs_cache_delete(sbi->read_page);
386 squashfs_decompressor_free(sbi, sbi->stream); 386 squashfs_decompressor_destroy(sbi);
387 kfree(sbi->id_table); 387 kfree(sbi->id_table);
388 kfree(sbi->fragment_index); 388 kfree(sbi->fragment_index);
389 kfree(sbi->meta_index); 389 kfree(sbi->meta_index);
diff --git a/fs/squashfs/xz_wrapper.c b/fs/squashfs/xz_wrapper.c
index 1760b7d108f6..5d1d07cca6b4 100644
--- a/fs/squashfs/xz_wrapper.c
+++ b/fs/squashfs/xz_wrapper.c
@@ -38,38 +38,63 @@ struct squashfs_xz {
38 struct xz_buf buf; 38 struct xz_buf buf;
39}; 39};
40 40
41struct comp_opts { 41struct disk_comp_opts {
42 __le32 dictionary_size; 42 __le32 dictionary_size;
43 __le32 flags; 43 __le32 flags;
44}; 44};
45 45
46static void *squashfs_xz_init(struct squashfs_sb_info *msblk, void *buff, 46struct comp_opts {
47 int len) 47 int dict_size;
48};
49
50static void *squashfs_xz_comp_opts(struct squashfs_sb_info *msblk,
51 void *buff, int len)
48{ 52{
49 struct comp_opts *comp_opts = buff; 53 struct disk_comp_opts *comp_opts = buff;
50 struct squashfs_xz *stream; 54 struct comp_opts *opts;
51 int dict_size = msblk->block_size; 55 int err = 0, n;
52 int err, n; 56
57 opts = kmalloc(sizeof(*opts), GFP_KERNEL);
58 if (opts == NULL) {
59 err = -ENOMEM;
60 goto out2;
61 }
53 62
54 if (comp_opts) { 63 if (comp_opts) {
55 /* check compressor options are the expected length */ 64 /* check compressor options are the expected length */
56 if (len < sizeof(*comp_opts)) { 65 if (len < sizeof(*comp_opts)) {
57 err = -EIO; 66 err = -EIO;
58 goto failed; 67 goto out;
59 } 68 }
60 69
61 dict_size = le32_to_cpu(comp_opts->dictionary_size); 70 opts->dict_size = le32_to_cpu(comp_opts->dictionary_size);
62 71
63 /* the dictionary size should be 2^n or 2^n+2^(n+1) */ 72 /* the dictionary size should be 2^n or 2^n+2^(n+1) */
64 n = ffs(dict_size) - 1; 73 n = ffs(opts->dict_size) - 1;
65 if (dict_size != (1 << n) && dict_size != (1 << n) + 74 if (opts->dict_size != (1 << n) && opts->dict_size != (1 << n) +
66 (1 << (n + 1))) { 75 (1 << (n + 1))) {
67 err = -EIO; 76 err = -EIO;
68 goto failed; 77 goto out;
69 } 78 }
70 } 79 } else
80 /* use defaults */
81 opts->dict_size = max_t(int, msblk->block_size,
82 SQUASHFS_METADATA_SIZE);
71 83
72 dict_size = max_t(int, dict_size, SQUASHFS_METADATA_SIZE); 84 return opts;
85
86out:
87 kfree(opts);
88out2:
89 return ERR_PTR(err);
90}
91
92
93static void *squashfs_xz_init(struct squashfs_sb_info *msblk, void *buff)
94{
95 struct comp_opts *comp_opts = buff;
96 struct squashfs_xz *stream;
97 int err;
73 98
74 stream = kmalloc(sizeof(*stream), GFP_KERNEL); 99 stream = kmalloc(sizeof(*stream), GFP_KERNEL);
75 if (stream == NULL) { 100 if (stream == NULL) {
@@ -77,7 +102,7 @@ static void *squashfs_xz_init(struct squashfs_sb_info *msblk, void *buff,
77 goto failed; 102 goto failed;
78 } 103 }
79 104
80 stream->state = xz_dec_init(XZ_PREALLOC, dict_size); 105 stream->state = xz_dec_init(XZ_PREALLOC, comp_opts->dict_size);
81 if (stream->state == NULL) { 106 if (stream->state == NULL) {
82 kfree(stream); 107 kfree(stream);
83 err = -ENOMEM; 108 err = -ENOMEM;
@@ -103,15 +128,13 @@ static void squashfs_xz_free(void *strm)
103} 128}
104 129
105 130
106static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void **buffer, 131static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void *strm,
107 struct buffer_head **bh, int b, int offset, int length, int srclength, 132 void **buffer, struct buffer_head **bh, int b, int offset, int length,
108 int pages) 133 int srclength, int pages)
109{ 134{
110 enum xz_ret xz_err; 135 enum xz_ret xz_err;
111 int avail, total = 0, k = 0, page = 0; 136 int avail, total = 0, k = 0, page = 0;
112 struct squashfs_xz *stream = msblk->stream; 137 struct squashfs_xz *stream = strm;
113
114 mutex_lock(&msblk->read_data_mutex);
115 138
116 xz_dec_reset(stream->state); 139 xz_dec_reset(stream->state);
117 stream->buf.in_pos = 0; 140 stream->buf.in_pos = 0;
@@ -124,10 +147,6 @@ static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void **buffer,
124 if (stream->buf.in_pos == stream->buf.in_size && k < b) { 147 if (stream->buf.in_pos == stream->buf.in_size && k < b) {
125 avail = min(length, msblk->devblksize - offset); 148 avail = min(length, msblk->devblksize - offset);
126 length -= avail; 149 length -= avail;
127 wait_on_buffer(bh[k]);
128 if (!buffer_uptodate(bh[k]))
129 goto release_mutex;
130
131 stream->buf.in = bh[k]->b_data + offset; 150 stream->buf.in = bh[k]->b_data + offset;
132 stream->buf.in_size = avail; 151 stream->buf.in_size = avail;
133 stream->buf.in_pos = 0; 152 stream->buf.in_pos = 0;
@@ -147,23 +166,12 @@ static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void **buffer,
147 put_bh(bh[k++]); 166 put_bh(bh[k++]);
148 } while (xz_err == XZ_OK); 167 } while (xz_err == XZ_OK);
149 168
150 if (xz_err != XZ_STREAM_END) { 169 if (xz_err != XZ_STREAM_END || k < b)
151 ERROR("xz_dec_run error, data probably corrupt\n"); 170 goto out;
152 goto release_mutex;
153 }
154
155 if (k < b) {
156 ERROR("xz_uncompress error, input remaining\n");
157 goto release_mutex;
158 }
159
160 total += stream->buf.out_pos;
161 mutex_unlock(&msblk->read_data_mutex);
162 return total;
163 171
164release_mutex: 172 return total + stream->buf.out_pos;
165 mutex_unlock(&msblk->read_data_mutex);
166 173
174out:
167 for (; k < b; k++) 175 for (; k < b; k++)
168 put_bh(bh[k]); 176 put_bh(bh[k]);
169 177
@@ -172,6 +180,7 @@ release_mutex:
172 180
173const struct squashfs_decompressor squashfs_xz_comp_ops = { 181const struct squashfs_decompressor squashfs_xz_comp_ops = {
174 .init = squashfs_xz_init, 182 .init = squashfs_xz_init,
183 .comp_opts = squashfs_xz_comp_opts,
175 .free = squashfs_xz_free, 184 .free = squashfs_xz_free,
176 .decompress = squashfs_xz_uncompress, 185 .decompress = squashfs_xz_uncompress,
177 .id = XZ_COMPRESSION, 186 .id = XZ_COMPRESSION,
diff --git a/fs/squashfs/zlib_wrapper.c b/fs/squashfs/zlib_wrapper.c
index 55d918fd2d86..bb049027d15c 100644
--- a/fs/squashfs/zlib_wrapper.c
+++ b/fs/squashfs/zlib_wrapper.c
@@ -33,7 +33,7 @@
33#include "squashfs.h" 33#include "squashfs.h"
34#include "decompressor.h" 34#include "decompressor.h"
35 35
36static void *zlib_init(struct squashfs_sb_info *dummy, void *buff, int len) 36static void *zlib_init(struct squashfs_sb_info *dummy, void *buff)
37{ 37{
38 z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL); 38 z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL);
39 if (stream == NULL) 39 if (stream == NULL)
@@ -61,15 +61,13 @@ static void zlib_free(void *strm)
61} 61}
62 62
63 63
64static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer, 64static int zlib_uncompress(struct squashfs_sb_info *msblk, void *strm,
65 struct buffer_head **bh, int b, int offset, int length, int srclength, 65 void **buffer, struct buffer_head **bh, int b, int offset, int length,
66 int pages) 66 int srclength, int pages)
67{ 67{
68 int zlib_err, zlib_init = 0; 68 int zlib_err, zlib_init = 0;
69 int k = 0, page = 0; 69 int k = 0, page = 0;
70 z_stream *stream = msblk->stream; 70 z_stream *stream = strm;
71
72 mutex_lock(&msblk->read_data_mutex);
73 71
74 stream->avail_out = 0; 72 stream->avail_out = 0;
75 stream->avail_in = 0; 73 stream->avail_in = 0;
@@ -78,10 +76,6 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer,
78 if (stream->avail_in == 0 && k < b) { 76 if (stream->avail_in == 0 && k < b) {
79 int avail = min(length, msblk->devblksize - offset); 77 int avail = min(length, msblk->devblksize - offset);
80 length -= avail; 78 length -= avail;
81 wait_on_buffer(bh[k]);
82 if (!buffer_uptodate(bh[k]))
83 goto release_mutex;
84
85 stream->next_in = bh[k]->b_data + offset; 79 stream->next_in = bh[k]->b_data + offset;
86 stream->avail_in = avail; 80 stream->avail_in = avail;
87 offset = 0; 81 offset = 0;
@@ -94,12 +88,8 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer,
94 88
95 if (!zlib_init) { 89 if (!zlib_init) {
96 zlib_err = zlib_inflateInit(stream); 90 zlib_err = zlib_inflateInit(stream);
97 if (zlib_err != Z_OK) { 91 if (zlib_err != Z_OK)
98 ERROR("zlib_inflateInit returned unexpected " 92 goto out;
99 "result 0x%x, srclength %d\n",
100 zlib_err, srclength);
101 goto release_mutex;
102 }
103 zlib_init = 1; 93 zlib_init = 1;
104 } 94 }
105 95
@@ -109,29 +99,19 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer,
109 put_bh(bh[k++]); 99 put_bh(bh[k++]);
110 } while (zlib_err == Z_OK); 100 } while (zlib_err == Z_OK);
111 101
112 if (zlib_err != Z_STREAM_END) { 102 if (zlib_err != Z_STREAM_END)
113 ERROR("zlib_inflate error, data probably corrupt\n"); 103 goto out;
114 goto release_mutex;
115 }
116 104
117 zlib_err = zlib_inflateEnd(stream); 105 zlib_err = zlib_inflateEnd(stream);
118 if (zlib_err != Z_OK) { 106 if (zlib_err != Z_OK)
119 ERROR("zlib_inflate error, data probably corrupt\n"); 107 goto out;
120 goto release_mutex;
121 }
122
123 if (k < b) {
124 ERROR("zlib_uncompress error, data remaining\n");
125 goto release_mutex;
126 }
127 108
128 length = stream->total_out; 109 if (k < b)
129 mutex_unlock(&msblk->read_data_mutex); 110 goto out;
130 return length;
131 111
132release_mutex: 112 return stream->total_out;
133 mutex_unlock(&msblk->read_data_mutex);
134 113
114out:
135 for (; k < b; k++) 115 for (; k < b; k++)
136 put_bh(bh[k]); 116 put_bh(bh[k]);
137 117