diff options
-rw-r--r-- | fs/squashfs/block.c | 27 | ||||
-rw-r--r-- | fs/squashfs/cache.c | 28 | ||||
-rw-r--r-- | fs/squashfs/decompressor.c | 14 | ||||
-rw-r--r-- | fs/squashfs/decompressor.h | 5 | ||||
-rw-r--r-- | fs/squashfs/decompressor_multi.c | 7 | ||||
-rw-r--r-- | fs/squashfs/decompressor_multi_percpu.c | 9 | ||||
-rw-r--r-- | fs/squashfs/decompressor_single.c | 9 | ||||
-rw-r--r-- | fs/squashfs/lzo_wrapper.c | 27 | ||||
-rw-r--r-- | fs/squashfs/page_actor.h | 49 | ||||
-rw-r--r-- | fs/squashfs/squashfs.h | 8 | ||||
-rw-r--r-- | fs/squashfs/squashfs_fs_sb.h | 1 | ||||
-rw-r--r-- | fs/squashfs/xz_wrapper.c | 22 | ||||
-rw-r--r-- | fs/squashfs/zlib_wrapper.c | 24 |
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 | */ |
89 | int squashfs_read_data(struct super_block *sb, void **buffer, u64 index, | 90 | int 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 | ||
453 | failed2: | ||
454 | kfree(data); | ||
437 | failed: | 455 | failed: |
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 | ||
114 | out: | 121 | out: |
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 | ||
186 | int squashfs_decompress(struct squashfs_sb_info *msblk, | 186 | int 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 | ||
77 | int squashfs_decompress(struct squashfs_sb_info *msblk, | 77 | int 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 | ||
64 | int squashfs_decompress(struct squashfs_sb_info *msblk, | 64 | int 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 | ||
35 | struct squashfs_lzo { | 36 | struct squashfs_lzo { |
36 | void *input; | 37 | void *input; |
@@ -75,13 +76,13 @@ static void lzo_free(void *strm) | |||
75 | 76 | ||
76 | 77 | ||
77 | static int lzo_uncompress(struct squashfs_sb_info *msblk, void *strm, | 78 | static 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 | |||
11 | struct squashfs_page_actor { | ||
12 | void **page; | ||
13 | int pages; | ||
14 | int length; | ||
15 | int next_page; | ||
16 | }; | ||
17 | |||
18 | static 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 | |||
33 | static inline void *squashfs_first_page(struct squashfs_page_actor *actor) | ||
34 | { | ||
35 | actor->next_page = 1; | ||
36 | return actor->page[0]; | ||
37 | } | ||
38 | |||
39 | static 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 | |||
45 | static 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 */ |
31 | extern int squashfs_read_data(struct super_block *, void **, u64, int, u64 *, | 31 | extern 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 */ |
35 | extern struct squashfs_cache *squashfs_cache_init(char *, int, int); | 35 | extern 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 */ |
54 | extern void *squashfs_decompressor_create(struct squashfs_sb_info *, void *); | 54 | extern void *squashfs_decompressor_create(struct squashfs_sb_info *, void *); |
55 | extern void squashfs_decompressor_destroy(struct squashfs_sb_info *); | 55 | extern void squashfs_decompressor_destroy(struct squashfs_sb_info *); |
56 | extern int squashfs_decompress(struct squashfs_sb_info *, void **, | 56 | extern 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 *); |
58 | extern int squashfs_max_decompressors(void); | 58 | extern 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 | ||
55 | struct squashfs_sb_info { | 56 | struct 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 | ||
36 | struct squashfs_xz { | 37 | struct 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 | ||
131 | static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void *strm, | 132 | static 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 | ||
36 | static void *zlib_init(struct squashfs_sb_info *dummy, void *buff) | 37 | static 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 | ||
64 | static int zlib_uncompress(struct squashfs_sb_info *msblk, void *strm, | 65 | static 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 | ||