aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/squashfs/block.c27
-rw-r--r--fs/squashfs/cache.c28
-rw-r--r--fs/squashfs/decompressor.c14
-rw-r--r--fs/squashfs/decompressor.h5
-rw-r--r--fs/squashfs/decompressor_multi.c7
-rw-r--r--fs/squashfs/decompressor_multi_percpu.c9
-rw-r--r--fs/squashfs/decompressor_single.c9
-rw-r--r--fs/squashfs/lzo_wrapper.c27
-rw-r--r--fs/squashfs/page_actor.h49
-rw-r--r--fs/squashfs/squashfs.h8
-rw-r--r--fs/squashfs/squashfs_fs_sb.h1
-rw-r--r--fs/squashfs/xz_wrapper.c22
-rw-r--r--fs/squashfs/zlib_wrapper.c24
13 files changed, 163 insertions, 67 deletions
diff --git a/fs/squashfs/block.c b/fs/squashfs/block.c
index 4dd402597f22..0cea9b9236d0 100644
--- a/fs/squashfs/block.c
+++ b/fs/squashfs/block.c
@@ -36,6 +36,7 @@
36#include "squashfs_fs_sb.h" 36#include "squashfs_fs_sb.h"
37#include "squashfs.h" 37#include "squashfs.h"
38#include "decompressor.h" 38#include "decompressor.h"
39#include "page_actor.h"
39 40
40/* 41/*
41 * Read the metadata block length, this is stored in the first two 42 * Read the metadata block length, this is stored in the first two
@@ -86,16 +87,16 @@ static struct buffer_head *get_block_length(struct super_block *sb,
86 * generated a larger block - this does occasionally happen with compression 87 * generated a larger block - this does occasionally happen with compression
87 * algorithms). 88 * algorithms).
88 */ 89 */
89int squashfs_read_data(struct super_block *sb, void **buffer, u64 index, 90int squashfs_read_data(struct super_block *sb, u64 index, int length,
90 int length, u64 *next_index, int srclength, int pages) 91 u64 *next_index, struct squashfs_page_actor *output)
91{ 92{
92 struct squashfs_sb_info *msblk = sb->s_fs_info; 93 struct squashfs_sb_info *msblk = sb->s_fs_info;
93 struct buffer_head **bh; 94 struct buffer_head **bh;
94 int offset = index & ((1 << msblk->devblksize_log2) - 1); 95 int offset = index & ((1 << msblk->devblksize_log2) - 1);
95 u64 cur_index = index >> msblk->devblksize_log2; 96 u64 cur_index = index >> msblk->devblksize_log2;
96 int bytes, compressed, b = 0, k = 0, page = 0, avail, i; 97 int bytes, compressed, b = 0, k = 0, avail, i;
97 98
98 bh = kcalloc(((srclength + msblk->devblksize - 1) 99 bh = kcalloc(((output->length + msblk->devblksize - 1)
99 >> msblk->devblksize_log2) + 1, sizeof(*bh), GFP_KERNEL); 100 >> msblk->devblksize_log2) + 1, sizeof(*bh), GFP_KERNEL);
100 if (bh == NULL) 101 if (bh == NULL)
101 return -ENOMEM; 102 return -ENOMEM;
@@ -111,9 +112,9 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index,
111 *next_index = index + length; 112 *next_index = index + length;
112 113
113 TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n", 114 TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n",
114 index, compressed ? "" : "un", length, srclength); 115 index, compressed ? "" : "un", length, output->length);
115 116
116 if (length < 0 || length > srclength || 117 if (length < 0 || length > output->length ||
117 (index + length) > msblk->bytes_used) 118 (index + length) > msblk->bytes_used)
118 goto read_failure; 119 goto read_failure;
119 120
@@ -145,7 +146,7 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index,
145 TRACE("Block @ 0x%llx, %scompressed size %d\n", index, 146 TRACE("Block @ 0x%llx, %scompressed size %d\n", index,
146 compressed ? "" : "un", length); 147 compressed ? "" : "un", length);
147 148
148 if (length < 0 || length > srclength || 149 if (length < 0 || length > output->length ||
149 (index + length) > msblk->bytes_used) 150 (index + length) > msblk->bytes_used)
150 goto block_release; 151 goto block_release;
151 152
@@ -165,8 +166,8 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index,
165 } 166 }
166 167
167 if (compressed) { 168 if (compressed) {
168 length = squashfs_decompress(msblk, buffer, bh, b, offset, 169 length = squashfs_decompress(msblk, bh, b, offset, length,
169 length, srclength, pages); 170 output);
170 if (length < 0) 171 if (length < 0)
171 goto read_failure; 172 goto read_failure;
172 } else { 173 } else {
@@ -174,19 +175,20 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index,
174 * Block is uncompressed. 175 * Block is uncompressed.
175 */ 176 */
176 int in, pg_offset = 0; 177 int in, pg_offset = 0;
178 void *data = squashfs_first_page(output);
177 179
178 for (bytes = length; k < b; k++) { 180 for (bytes = length; k < b; k++) {
179 in = min(bytes, msblk->devblksize - offset); 181 in = min(bytes, msblk->devblksize - offset);
180 bytes -= in; 182 bytes -= in;
181 while (in) { 183 while (in) {
182 if (pg_offset == PAGE_CACHE_SIZE) { 184 if (pg_offset == PAGE_CACHE_SIZE) {
183 page++; 185 data = squashfs_next_page(output);
184 pg_offset = 0; 186 pg_offset = 0;
185 } 187 }
186 avail = min_t(int, in, PAGE_CACHE_SIZE - 188 avail = min_t(int, in, PAGE_CACHE_SIZE -
187 pg_offset); 189 pg_offset);
188 memcpy(buffer[page] + pg_offset, 190 memcpy(data + pg_offset, bh[k]->b_data + offset,
189 bh[k]->b_data + offset, avail); 191 avail);
190 in -= avail; 192 in -= avail;
191 pg_offset += avail; 193 pg_offset += avail;
192 offset += avail; 194 offset += avail;
@@ -194,6 +196,7 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index,
194 offset = 0; 196 offset = 0;
195 put_bh(bh[k]); 197 put_bh(bh[k]);
196 } 198 }
199 squashfs_finish_page(output);
197 } 200 }
198 201
199 kfree(bh); 202 kfree(bh);
diff --git a/fs/squashfs/cache.c b/fs/squashfs/cache.c
index af0b73802592..1cb70a0b2168 100644
--- a/fs/squashfs/cache.c
+++ b/fs/squashfs/cache.c
@@ -56,6 +56,7 @@
56#include "squashfs_fs.h" 56#include "squashfs_fs.h"
57#include "squashfs_fs_sb.h" 57#include "squashfs_fs_sb.h"
58#include "squashfs.h" 58#include "squashfs.h"
59#include "page_actor.h"
59 60
60/* 61/*
61 * Look-up block in cache, and increment usage count. If not in cache, read 62 * Look-up block in cache, and increment usage count. If not in cache, read
@@ -119,9 +120,8 @@ struct squashfs_cache_entry *squashfs_cache_get(struct super_block *sb,
119 entry->error = 0; 120 entry->error = 0;
120 spin_unlock(&cache->lock); 121 spin_unlock(&cache->lock);
121 122
122 entry->length = squashfs_read_data(sb, entry->data, 123 entry->length = squashfs_read_data(sb, block, length,
123 block, length, &entry->next_index, 124 &entry->next_index, entry->actor);
124 cache->block_size, cache->pages);
125 125
126 spin_lock(&cache->lock); 126 spin_lock(&cache->lock);
127 127
@@ -220,6 +220,7 @@ void squashfs_cache_delete(struct squashfs_cache *cache)
220 kfree(cache->entry[i].data[j]); 220 kfree(cache->entry[i].data[j]);
221 kfree(cache->entry[i].data); 221 kfree(cache->entry[i].data);
222 } 222 }
223 kfree(cache->entry[i].actor);
223 } 224 }
224 225
225 kfree(cache->entry); 226 kfree(cache->entry);
@@ -280,6 +281,13 @@ struct squashfs_cache *squashfs_cache_init(char *name, int entries,
280 goto cleanup; 281 goto cleanup;
281 } 282 }
282 } 283 }
284
285 entry->actor = squashfs_page_actor_init(entry->data,
286 cache->pages, 0);
287 if (entry->actor == NULL) {
288 ERROR("Failed to allocate %s cache entry\n", name);
289 goto cleanup;
290 }
283 } 291 }
284 292
285 return cache; 293 return cache;
@@ -410,6 +418,7 @@ void *squashfs_read_table(struct super_block *sb, u64 block, int length)
410 int pages = (length + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; 418 int pages = (length + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
411 int i, res; 419 int i, res;
412 void *table, *buffer, **data; 420 void *table, *buffer, **data;
421 struct squashfs_page_actor *actor;
413 422
414 table = buffer = kmalloc(length, GFP_KERNEL); 423 table = buffer = kmalloc(length, GFP_KERNEL);
415 if (table == NULL) 424 if (table == NULL)
@@ -421,19 +430,28 @@ void *squashfs_read_table(struct super_block *sb, u64 block, int length)
421 goto failed; 430 goto failed;
422 } 431 }
423 432
433 actor = squashfs_page_actor_init(data, pages, length);
434 if (actor == NULL) {
435 res = -ENOMEM;
436 goto failed2;
437 }
438
424 for (i = 0; i < pages; i++, buffer += PAGE_CACHE_SIZE) 439 for (i = 0; i < pages; i++, buffer += PAGE_CACHE_SIZE)
425 data[i] = buffer; 440 data[i] = buffer;
426 441
427 res = squashfs_read_data(sb, data, block, length | 442 res = squashfs_read_data(sb, block, length |
428 SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length, pages); 443 SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, actor);
429 444
430 kfree(data); 445 kfree(data);
446 kfree(actor);
431 447
432 if (res < 0) 448 if (res < 0)
433 goto failed; 449 goto failed;
434 450
435 return table; 451 return table;
436 452
453failed2:
454 kfree(data);
437failed: 455failed:
438 kfree(table); 456 kfree(table);
439 return ERR_PTR(res); 457 return ERR_PTR(res);
diff --git a/fs/squashfs/decompressor.c b/fs/squashfs/decompressor.c
index 234291f79ba5..ac22fe73b0ad 100644
--- a/fs/squashfs/decompressor.c
+++ b/fs/squashfs/decompressor.c
@@ -30,6 +30,7 @@
30#include "squashfs_fs_sb.h" 30#include "squashfs_fs_sb.h"
31#include "decompressor.h" 31#include "decompressor.h"
32#include "squashfs.h" 32#include "squashfs.h"
33#include "page_actor.h"
33 34
34/* 35/*
35 * This file (and decompressor.h) implements a decompressor framework for 36 * This file (and decompressor.h) implements a decompressor framework for
@@ -87,6 +88,7 @@ static void *get_comp_opts(struct super_block *sb, unsigned short flags)
87{ 88{
88 struct squashfs_sb_info *msblk = sb->s_fs_info; 89 struct squashfs_sb_info *msblk = sb->s_fs_info;
89 void *buffer = NULL, *comp_opts; 90 void *buffer = NULL, *comp_opts;
91 struct squashfs_page_actor *actor = NULL;
90 int length = 0; 92 int length = 0;
91 93
92 /* 94 /*
@@ -99,9 +101,14 @@ static void *get_comp_opts(struct super_block *sb, unsigned short flags)
99 goto out; 101 goto out;
100 } 102 }
101 103
102 length = squashfs_read_data(sb, &buffer, 104 actor = squashfs_page_actor_init(&buffer, 1, 0);
103 sizeof(struct squashfs_super_block), 0, NULL, 105 if (actor == NULL) {
104 PAGE_CACHE_SIZE, 1); 106 comp_opts = ERR_PTR(-ENOMEM);
107 goto out;
108 }
109
110 length = squashfs_read_data(sb,
111 sizeof(struct squashfs_super_block), 0, NULL, actor);
105 112
106 if (length < 0) { 113 if (length < 0) {
107 comp_opts = ERR_PTR(length); 114 comp_opts = ERR_PTR(length);
@@ -112,6 +119,7 @@ static void *get_comp_opts(struct super_block *sb, unsigned short flags)
112 comp_opts = squashfs_comp_opts(msblk, buffer, length); 119 comp_opts = squashfs_comp_opts(msblk, buffer, length);
113 120
114out: 121out:
122 kfree(actor);
115 kfree(buffer); 123 kfree(buffer);
116 return comp_opts; 124 return comp_opts;
117} 125}
diff --git a/fs/squashfs/decompressor.h b/fs/squashfs/decompressor.h
index 6cdb20a3878a..af0985321808 100644
--- a/fs/squashfs/decompressor.h
+++ b/fs/squashfs/decompressor.h
@@ -27,8 +27,9 @@ struct squashfs_decompressor {
27 void *(*init)(struct squashfs_sb_info *, void *); 27 void *(*init)(struct squashfs_sb_info *, void *);
28 void *(*comp_opts)(struct squashfs_sb_info *, void *, int); 28 void *(*comp_opts)(struct squashfs_sb_info *, void *, int);
29 void (*free)(void *); 29 void (*free)(void *);
30 int (*decompress)(struct squashfs_sb_info *, void *, void **, 30 int (*decompress)(struct squashfs_sb_info *, void *,
31 struct buffer_head **, int, int, int, int, int); 31 struct buffer_head **, int, int, int,
32 struct squashfs_page_actor *);
32 int id; 33 int id;
33 char *name; 34 char *name;
34 int supported; 35 int supported;
diff --git a/fs/squashfs/decompressor_multi.c b/fs/squashfs/decompressor_multi.c
index 462731db5130..ae54675a3526 100644
--- a/fs/squashfs/decompressor_multi.c
+++ b/fs/squashfs/decompressor_multi.c
@@ -183,15 +183,14 @@ wait:
183} 183}
184 184
185 185
186int squashfs_decompress(struct squashfs_sb_info *msblk, 186int squashfs_decompress(struct squashfs_sb_info *msblk, struct buffer_head **bh,
187 void **buffer, struct buffer_head **bh, int b, int offset, int length, 187 int b, int offset, int length, struct squashfs_page_actor *output)
188 int srclength, int pages)
189{ 188{
190 int res; 189 int res;
191 struct squashfs_stream *stream = msblk->stream; 190 struct squashfs_stream *stream = msblk->stream;
192 struct decomp_stream *decomp_stream = get_decomp_stream(msblk, stream); 191 struct decomp_stream *decomp_stream = get_decomp_stream(msblk, stream);
193 res = msblk->decompressor->decompress(msblk, decomp_stream->stream, 192 res = msblk->decompressor->decompress(msblk, decomp_stream->stream,
194 buffer, bh, b, offset, length, srclength, pages); 193 bh, b, offset, length, output);
195 put_decomp_stream(decomp_stream, stream); 194 put_decomp_stream(decomp_stream, stream);
196 if (res < 0) 195 if (res < 0)
197 ERROR("%s decompression failed, data probably corrupt\n", 196 ERROR("%s decompression failed, data probably corrupt\n",
diff --git a/fs/squashfs/decompressor_multi_percpu.c b/fs/squashfs/decompressor_multi_percpu.c
index 0e7b679bc4ad..23a9c28ad8ea 100644
--- a/fs/squashfs/decompressor_multi_percpu.c
+++ b/fs/squashfs/decompressor_multi_percpu.c
@@ -74,15 +74,14 @@ void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk)
74 } 74 }
75} 75}
76 76
77int squashfs_decompress(struct squashfs_sb_info *msblk, 77int squashfs_decompress(struct squashfs_sb_info *msblk, struct buffer_head **bh,
78 void **buffer, struct buffer_head **bh, int b, int offset, int length, 78 int b, int offset, int length, struct squashfs_page_actor *output)
79 int srclength, int pages)
80{ 79{
81 struct squashfs_stream __percpu *percpu = 80 struct squashfs_stream __percpu *percpu =
82 (struct squashfs_stream __percpu *) msblk->stream; 81 (struct squashfs_stream __percpu *) msblk->stream;
83 struct squashfs_stream *stream = get_cpu_ptr(percpu); 82 struct squashfs_stream *stream = get_cpu_ptr(percpu);
84 int res = msblk->decompressor->decompress(msblk, stream->stream, buffer, 83 int res = msblk->decompressor->decompress(msblk, stream->stream, bh, b,
85 bh, b, offset, length, srclength, pages); 84 offset, length, output);
86 put_cpu_ptr(stream); 85 put_cpu_ptr(stream);
87 86
88 if (res < 0) 87 if (res < 0)
diff --git a/fs/squashfs/decompressor_single.c b/fs/squashfs/decompressor_single.c
index f857cf6f22d4..a6c75929a00e 100644
--- a/fs/squashfs/decompressor_single.c
+++ b/fs/squashfs/decompressor_single.c
@@ -61,16 +61,15 @@ void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk)
61 } 61 }
62} 62}
63 63
64int squashfs_decompress(struct squashfs_sb_info *msblk, 64int squashfs_decompress(struct squashfs_sb_info *msblk, struct buffer_head **bh,
65 void **buffer, struct buffer_head **bh, int b, int offset, int length, 65 int b, int offset, int length, struct squashfs_page_actor *output)
66 int srclength, int pages)
67{ 66{
68 int res; 67 int res;
69 struct squashfs_stream *stream = msblk->stream; 68 struct squashfs_stream *stream = msblk->stream;
70 69
71 mutex_lock(&stream->mutex); 70 mutex_lock(&stream->mutex);
72 res = msblk->decompressor->decompress(msblk, stream->stream, buffer, 71 res = msblk->decompressor->decompress(msblk, stream->stream, bh, b,
73 bh, b, offset, length, srclength, pages); 72 offset, length, output);
74 mutex_unlock(&stream->mutex); 73 mutex_unlock(&stream->mutex);
75 74
76 if (res < 0) 75 if (res < 0)
diff --git a/fs/squashfs/lzo_wrapper.c b/fs/squashfs/lzo_wrapper.c
index 75c3b5779172..244b9fbfff7b 100644
--- a/fs/squashfs/lzo_wrapper.c
+++ b/fs/squashfs/lzo_wrapper.c
@@ -31,6 +31,7 @@
31#include "squashfs_fs_sb.h" 31#include "squashfs_fs_sb.h"
32#include "squashfs.h" 32#include "squashfs.h"
33#include "decompressor.h" 33#include "decompressor.h"
34#include "page_actor.h"
34 35
35struct squashfs_lzo { 36struct squashfs_lzo {
36 void *input; 37 void *input;
@@ -75,13 +76,13 @@ static void lzo_free(void *strm)
75 76
76 77
77static int lzo_uncompress(struct squashfs_sb_info *msblk, void *strm, 78static int lzo_uncompress(struct squashfs_sb_info *msblk, void *strm,
78 void **buffer, struct buffer_head **bh, int b, int offset, int length, 79 struct buffer_head **bh, int b, int offset, int length,
79 int srclength, int pages) 80 struct squashfs_page_actor *output)
80{ 81{
81 struct squashfs_lzo *stream = strm; 82 struct squashfs_lzo *stream = strm;
82 void *buff = stream->input; 83 void *buff = stream->input, *data;
83 int avail, i, bytes = length, res; 84 int avail, i, bytes = length, res;
84 size_t out_len = srclength; 85 size_t out_len = output->length;
85 86
86 for (i = 0; i < b; i++) { 87 for (i = 0; i < b; i++) {
87 avail = min(bytes, msblk->devblksize - offset); 88 avail = min(bytes, msblk->devblksize - offset);
@@ -98,12 +99,20 @@ static int lzo_uncompress(struct squashfs_sb_info *msblk, void *strm,
98 goto failed; 99 goto failed;
99 100
100 res = bytes = (int)out_len; 101 res = bytes = (int)out_len;
101 for (i = 0, buff = stream->output; bytes && i < pages; i++) { 102 data = squashfs_first_page(output);
102 avail = min_t(int, bytes, PAGE_CACHE_SIZE); 103 buff = stream->output;
103 memcpy(buffer[i], buff, avail); 104 while (data) {
104 buff += avail; 105 if (bytes <= PAGE_CACHE_SIZE) {
105 bytes -= avail; 106 memcpy(data, buff, bytes);
107 break;
108 } else {
109 memcpy(data, buff, PAGE_CACHE_SIZE);
110 buff += PAGE_CACHE_SIZE;
111 bytes -= PAGE_CACHE_SIZE;
112 data = squashfs_next_page(output);
113 }
106 } 114 }
115 squashfs_finish_page(output);
107 116
108 return res; 117 return res;
109 118
diff --git a/fs/squashfs/page_actor.h b/fs/squashfs/page_actor.h
new file mode 100644
index 000000000000..5b0ba5a7133a
--- /dev/null
+++ b/fs/squashfs/page_actor.h
@@ -0,0 +1,49 @@
1#ifndef PAGE_ACTOR_H
2#define PAGE_ACTOR_H
3/*
4 * Copyright (c) 2013
5 * Phillip Lougher <phillip@squashfs.org.uk>
6 *
7 * This work is licensed under the terms of the GNU GPL, version 2. See
8 * the COPYING file in the top-level directory.
9 */
10
11struct squashfs_page_actor {
12 void **page;
13 int pages;
14 int length;
15 int next_page;
16};
17
18static inline struct squashfs_page_actor *squashfs_page_actor_init(void **page,
19 int pages, int length)
20{
21 struct squashfs_page_actor *actor = kmalloc(sizeof(*actor), GFP_KERNEL);
22
23 if (actor == NULL)
24 return NULL;
25
26 actor->length = length ? : pages * PAGE_CACHE_SIZE;
27 actor->page = page;
28 actor->pages = pages;
29 actor->next_page = 0;
30 return actor;
31}
32
33static inline void *squashfs_first_page(struct squashfs_page_actor *actor)
34{
35 actor->next_page = 1;
36 return actor->page[0];
37}
38
39static inline void *squashfs_next_page(struct squashfs_page_actor *actor)
40{
41 return actor->next_page == actor->pages ? NULL :
42 actor->page[actor->next_page++];
43}
44
45static inline void squashfs_finish_page(struct squashfs_page_actor *actor)
46{
47 /* empty */
48}
49#endif
diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h
index 2e2751df8452..6a97e63ca173 100644
--- a/fs/squashfs/squashfs.h
+++ b/fs/squashfs/squashfs.h
@@ -28,8 +28,8 @@
28#define WARNING(s, args...) pr_warning("SQUASHFS: "s, ## args) 28#define WARNING(s, args...) pr_warning("SQUASHFS: "s, ## args)
29 29
30/* block.c */ 30/* block.c */
31extern int squashfs_read_data(struct super_block *, void **, u64, int, u64 *, 31extern int squashfs_read_data(struct super_block *, u64, int, u64 *,
32 int, int); 32 struct squashfs_page_actor *);
33 33
34/* cache.c */ 34/* cache.c */
35extern struct squashfs_cache *squashfs_cache_init(char *, int, int); 35extern struct squashfs_cache *squashfs_cache_init(char *, int, int);
@@ -53,8 +53,8 @@ extern void *squashfs_decompressor_setup(struct super_block *, unsigned short);
53/* decompressor_xxx.c */ 53/* decompressor_xxx.c */
54extern void *squashfs_decompressor_create(struct squashfs_sb_info *, void *); 54extern void *squashfs_decompressor_create(struct squashfs_sb_info *, void *);
55extern void squashfs_decompressor_destroy(struct squashfs_sb_info *); 55extern void squashfs_decompressor_destroy(struct squashfs_sb_info *);
56extern int squashfs_decompress(struct squashfs_sb_info *, void **, 56extern int squashfs_decompress(struct squashfs_sb_info *, struct buffer_head **,
57 struct buffer_head **, int, int, int, int, int); 57 int, int, int, struct squashfs_page_actor *);
58extern int squashfs_max_decompressors(void); 58extern int squashfs_max_decompressors(void);
59 59
60/* export.c */ 60/* export.c */
diff --git a/fs/squashfs/squashfs_fs_sb.h b/fs/squashfs/squashfs_fs_sb.h
index 9cdcf4150d59..1da565cb50c3 100644
--- a/fs/squashfs/squashfs_fs_sb.h
+++ b/fs/squashfs/squashfs_fs_sb.h
@@ -50,6 +50,7 @@ struct squashfs_cache_entry {
50 wait_queue_head_t wait_queue; 50 wait_queue_head_t wait_queue;
51 struct squashfs_cache *cache; 51 struct squashfs_cache *cache;
52 void **data; 52 void **data;
53 struct squashfs_page_actor *actor;
53}; 54};
54 55
55struct squashfs_sb_info { 56struct squashfs_sb_info {
diff --git a/fs/squashfs/xz_wrapper.c b/fs/squashfs/xz_wrapper.c
index 5d1d07cca6b4..c609624e4b8a 100644
--- a/fs/squashfs/xz_wrapper.c
+++ b/fs/squashfs/xz_wrapper.c
@@ -32,6 +32,7 @@
32#include "squashfs_fs_sb.h" 32#include "squashfs_fs_sb.h"
33#include "squashfs.h" 33#include "squashfs.h"
34#include "decompressor.h" 34#include "decompressor.h"
35#include "page_actor.h"
35 36
36struct squashfs_xz { 37struct squashfs_xz {
37 struct xz_dec *state; 38 struct xz_dec *state;
@@ -129,11 +130,11 @@ static void squashfs_xz_free(void *strm)
129 130
130 131
131static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void *strm, 132static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void *strm,
132 void **buffer, struct buffer_head **bh, int b, int offset, int length, 133 struct buffer_head **bh, int b, int offset, int length,
133 int srclength, int pages) 134 struct squashfs_page_actor *output)
134{ 135{
135 enum xz_ret xz_err; 136 enum xz_ret xz_err;
136 int avail, total = 0, k = 0, page = 0; 137 int avail, total = 0, k = 0;
137 struct squashfs_xz *stream = strm; 138 struct squashfs_xz *stream = strm;
138 139
139 xz_dec_reset(stream->state); 140 xz_dec_reset(stream->state);
@@ -141,7 +142,7 @@ static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void *strm,
141 stream->buf.in_size = 0; 142 stream->buf.in_size = 0;
142 stream->buf.out_pos = 0; 143 stream->buf.out_pos = 0;
143 stream->buf.out_size = PAGE_CACHE_SIZE; 144 stream->buf.out_size = PAGE_CACHE_SIZE;
144 stream->buf.out = buffer[page++]; 145 stream->buf.out = squashfs_first_page(output);
145 146
146 do { 147 do {
147 if (stream->buf.in_pos == stream->buf.in_size && k < b) { 148 if (stream->buf.in_pos == stream->buf.in_size && k < b) {
@@ -153,11 +154,12 @@ static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void *strm,
153 offset = 0; 154 offset = 0;
154 } 155 }
155 156
156 if (stream->buf.out_pos == stream->buf.out_size 157 if (stream->buf.out_pos == stream->buf.out_size) {
157 && page < pages) { 158 stream->buf.out = squashfs_next_page(output);
158 stream->buf.out = buffer[page++]; 159 if (stream->buf.out != NULL) {
159 stream->buf.out_pos = 0; 160 stream->buf.out_pos = 0;
160 total += PAGE_CACHE_SIZE; 161 total += PAGE_CACHE_SIZE;
162 }
161 } 163 }
162 164
163 xz_err = xz_dec_run(stream->state, &stream->buf); 165 xz_err = xz_dec_run(stream->state, &stream->buf);
@@ -166,6 +168,8 @@ static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void *strm,
166 put_bh(bh[k++]); 168 put_bh(bh[k++]);
167 } while (xz_err == XZ_OK); 169 } while (xz_err == XZ_OK);
168 170
171 squashfs_finish_page(output);
172
169 if (xz_err != XZ_STREAM_END || k < b) 173 if (xz_err != XZ_STREAM_END || k < b)
170 goto out; 174 goto out;
171 175
diff --git a/fs/squashfs/zlib_wrapper.c b/fs/squashfs/zlib_wrapper.c
index bb049027d15c..8727caba6882 100644
--- a/fs/squashfs/zlib_wrapper.c
+++ b/fs/squashfs/zlib_wrapper.c
@@ -32,6 +32,7 @@
32#include "squashfs_fs_sb.h" 32#include "squashfs_fs_sb.h"
33#include "squashfs.h" 33#include "squashfs.h"
34#include "decompressor.h" 34#include "decompressor.h"
35#include "page_actor.h"
35 36
36static void *zlib_init(struct squashfs_sb_info *dummy, void *buff) 37static void *zlib_init(struct squashfs_sb_info *dummy, void *buff)
37{ 38{
@@ -62,14 +63,14 @@ static void zlib_free(void *strm)
62 63
63 64
64static int zlib_uncompress(struct squashfs_sb_info *msblk, void *strm, 65static int zlib_uncompress(struct squashfs_sb_info *msblk, void *strm,
65 void **buffer, struct buffer_head **bh, int b, int offset, int length, 66 struct buffer_head **bh, int b, int offset, int length,
66 int srclength, int pages) 67 struct squashfs_page_actor *output)
67{ 68{
68 int zlib_err, zlib_init = 0; 69 int zlib_err, zlib_init = 0, k = 0;
69 int k = 0, page = 0;
70 z_stream *stream = strm; 70 z_stream *stream = strm;
71 71
72 stream->avail_out = 0; 72 stream->avail_out = PAGE_CACHE_SIZE;
73 stream->next_out = squashfs_first_page(output);
73 stream->avail_in = 0; 74 stream->avail_in = 0;
74 75
75 do { 76 do {
@@ -81,15 +82,18 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void *strm,
81 offset = 0; 82 offset = 0;
82 } 83 }
83 84
84 if (stream->avail_out == 0 && page < pages) { 85 if (stream->avail_out == 0) {
85 stream->next_out = buffer[page++]; 86 stream->next_out = squashfs_next_page(output);
86 stream->avail_out = PAGE_CACHE_SIZE; 87 if (stream->next_out != NULL)
88 stream->avail_out = PAGE_CACHE_SIZE;
87 } 89 }
88 90
89 if (!zlib_init) { 91 if (!zlib_init) {
90 zlib_err = zlib_inflateInit(stream); 92 zlib_err = zlib_inflateInit(stream);
91 if (zlib_err != Z_OK) 93 if (zlib_err != Z_OK) {
94 squashfs_finish_page(output);
92 goto out; 95 goto out;
96 }
93 zlib_init = 1; 97 zlib_init = 1;
94 } 98 }
95 99
@@ -99,6 +103,8 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void *strm,
99 put_bh(bh[k++]); 103 put_bh(bh[k++]);
100 } while (zlib_err == Z_OK); 104 } while (zlib_err == Z_OK);
101 105
106 squashfs_finish_page(output);
107
102 if (zlib_err != Z_STREAM_END) 108 if (zlib_err != Z_STREAM_END)
103 goto out; 109 goto out;
104 110