aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorSergey Senozhatsky <sergey.senozhatsky@gmail.com>2014-07-07 10:38:29 -0400
committerChris Mason <clm@fb.com>2014-09-17 16:37:33 -0400
commit7880991344f73647fa2222b198cf5cfc10805ac2 (patch)
tree6a4da88ef232059ba8de77f7715dd274b972e825 /fs
parent555e12864063762964433139dee651c5b859a047 (diff)
btrfs compression: merge inflate and deflate z_streams
`struct workspace' used for zlib compression contains two zlib z_stream-s: `def_strm' used in zlib_compress_pages(), and `inf_strm' used in zlib_decompress/zlib_decompress_biovec(). None of these functions use `inf_strm' and `def_strm' simultaniously, meaning that for every compress/decompress operation we need only one z_stream (out of two available). `inf_strm' and `def_strm' are different in size of ->workspace. For inflate stream we vmalloc() zlib_inflate_workspacesize() bytes, for deflate stream - zlib_deflate_workspacesize() bytes. On my system zlib returns the following workspace sizes, correspondingly: 42312 and 268104 (+ guard pages). Keep only one `z_stream' in `struct workspace' and use it for both compression and decompression. Hence, instead of vmalloc() of two z_stream->worskpace-s, allocate only one of size: max(zlib_deflate_workspacesize(), zlib_inflate_workspacesize()) Reviewed-by: David Sterba <dsterba@suse.cz> Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/zlib.c138
1 files changed, 68 insertions, 70 deletions
diff --git a/fs/btrfs/zlib.c b/fs/btrfs/zlib.c
index 77a0e5dba818..759fa4e2de8f 100644
--- a/fs/btrfs/zlib.c
+++ b/fs/btrfs/zlib.c
@@ -33,8 +33,7 @@
33#include "compression.h" 33#include "compression.h"
34 34
35struct workspace { 35struct workspace {
36 z_stream inf_strm; 36 z_stream strm;
37 z_stream def_strm;
38 char *buf; 37 char *buf;
39 struct list_head list; 38 struct list_head list;
40}; 39};
@@ -43,8 +42,7 @@ static void zlib_free_workspace(struct list_head *ws)
43{ 42{
44 struct workspace *workspace = list_entry(ws, struct workspace, list); 43 struct workspace *workspace = list_entry(ws, struct workspace, list);
45 44
46 vfree(workspace->def_strm.workspace); 45 vfree(workspace->strm.workspace);
47 vfree(workspace->inf_strm.workspace);
48 kfree(workspace->buf); 46 kfree(workspace->buf);
49 kfree(workspace); 47 kfree(workspace);
50} 48}
@@ -52,17 +50,17 @@ static void zlib_free_workspace(struct list_head *ws)
52static struct list_head *zlib_alloc_workspace(void) 50static struct list_head *zlib_alloc_workspace(void)
53{ 51{
54 struct workspace *workspace; 52 struct workspace *workspace;
53 int workspacesize;
55 54
56 workspace = kzalloc(sizeof(*workspace), GFP_NOFS); 55 workspace = kzalloc(sizeof(*workspace), GFP_NOFS);
57 if (!workspace) 56 if (!workspace)
58 return ERR_PTR(-ENOMEM); 57 return ERR_PTR(-ENOMEM);
59 58
60 workspace->def_strm.workspace = vmalloc(zlib_deflate_workspacesize( 59 workspacesize = max(zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL),
61 MAX_WBITS, MAX_MEM_LEVEL)); 60 zlib_inflate_workspacesize());
62 workspace->inf_strm.workspace = vmalloc(zlib_inflate_workspacesize()); 61 workspace->strm.workspace = vmalloc(workspacesize);
63 workspace->buf = kmalloc(PAGE_CACHE_SIZE, GFP_NOFS); 62 workspace->buf = kmalloc(PAGE_CACHE_SIZE, GFP_NOFS);
64 if (!workspace->def_strm.workspace || 63 if (!workspace->strm.workspace || !workspace->buf)
65 !workspace->inf_strm.workspace || !workspace->buf)
66 goto fail; 64 goto fail;
67 65
68 INIT_LIST_HEAD(&workspace->list); 66 INIT_LIST_HEAD(&workspace->list);
@@ -96,14 +94,14 @@ static int zlib_compress_pages(struct list_head *ws,
96 *total_out = 0; 94 *total_out = 0;
97 *total_in = 0; 95 *total_in = 0;
98 96
99 if (Z_OK != zlib_deflateInit(&workspace->def_strm, 3)) { 97 if (Z_OK != zlib_deflateInit(&workspace->strm, 3)) {
100 printk(KERN_WARNING "BTRFS: deflateInit failed\n"); 98 printk(KERN_WARNING "BTRFS: deflateInit failed\n");
101 ret = -EIO; 99 ret = -EIO;
102 goto out; 100 goto out;
103 } 101 }
104 102
105 workspace->def_strm.total_in = 0; 103 workspace->strm.total_in = 0;
106 workspace->def_strm.total_out = 0; 104 workspace->strm.total_out = 0;
107 105
108 in_page = find_get_page(mapping, start >> PAGE_CACHE_SHIFT); 106 in_page = find_get_page(mapping, start >> PAGE_CACHE_SHIFT);
109 data_in = kmap(in_page); 107 data_in = kmap(in_page);
@@ -117,25 +115,25 @@ static int zlib_compress_pages(struct list_head *ws,
117 pages[0] = out_page; 115 pages[0] = out_page;
118 nr_pages = 1; 116 nr_pages = 1;
119 117
120 workspace->def_strm.next_in = data_in; 118 workspace->strm.next_in = data_in;
121 workspace->def_strm.next_out = cpage_out; 119 workspace->strm.next_out = cpage_out;
122 workspace->def_strm.avail_out = PAGE_CACHE_SIZE; 120 workspace->strm.avail_out = PAGE_CACHE_SIZE;
123 workspace->def_strm.avail_in = min(len, PAGE_CACHE_SIZE); 121 workspace->strm.avail_in = min(len, PAGE_CACHE_SIZE);
124 122
125 while (workspace->def_strm.total_in < len) { 123 while (workspace->strm.total_in < len) {
126 ret = zlib_deflate(&workspace->def_strm, Z_SYNC_FLUSH); 124 ret = zlib_deflate(&workspace->strm, Z_SYNC_FLUSH);
127 if (ret != Z_OK) { 125 if (ret != Z_OK) {
128 printk(KERN_DEBUG "BTRFS: deflate in loop returned %d\n", 126 printk(KERN_DEBUG "BTRFS: deflate in loop returned %d\n",
129 ret); 127 ret);
130 zlib_deflateEnd(&workspace->def_strm); 128 zlib_deflateEnd(&workspace->strm);
131 ret = -EIO; 129 ret = -EIO;
132 goto out; 130 goto out;
133 } 131 }
134 132
135 /* we're making it bigger, give up */ 133 /* we're making it bigger, give up */
136 if (workspace->def_strm.total_in > 8192 && 134 if (workspace->strm.total_in > 8192 &&
137 workspace->def_strm.total_in < 135 workspace->strm.total_in <
138 workspace->def_strm.total_out) { 136 workspace->strm.total_out) {
139 ret = -E2BIG; 137 ret = -E2BIG;
140 goto out; 138 goto out;
141 } 139 }
@@ -143,7 +141,7 @@ static int zlib_compress_pages(struct list_head *ws,
143 * before the total_in so we will pull in a new page for 141 * before the total_in so we will pull in a new page for
144 * the stream end if required 142 * the stream end if required
145 */ 143 */
146 if (workspace->def_strm.avail_out == 0) { 144 if (workspace->strm.avail_out == 0) {
147 kunmap(out_page); 145 kunmap(out_page);
148 if (nr_pages == nr_dest_pages) { 146 if (nr_pages == nr_dest_pages) {
149 out_page = NULL; 147 out_page = NULL;
@@ -158,19 +156,19 @@ static int zlib_compress_pages(struct list_head *ws,
158 cpage_out = kmap(out_page); 156 cpage_out = kmap(out_page);
159 pages[nr_pages] = out_page; 157 pages[nr_pages] = out_page;
160 nr_pages++; 158 nr_pages++;
161 workspace->def_strm.avail_out = PAGE_CACHE_SIZE; 159 workspace->strm.avail_out = PAGE_CACHE_SIZE;
162 workspace->def_strm.next_out = cpage_out; 160 workspace->strm.next_out = cpage_out;
163 } 161 }
164 /* we're all done */ 162 /* we're all done */
165 if (workspace->def_strm.total_in >= len) 163 if (workspace->strm.total_in >= len)
166 break; 164 break;
167 165
168 /* we've read in a full page, get a new one */ 166 /* we've read in a full page, get a new one */
169 if (workspace->def_strm.avail_in == 0) { 167 if (workspace->strm.avail_in == 0) {
170 if (workspace->def_strm.total_out > max_out) 168 if (workspace->strm.total_out > max_out)
171 break; 169 break;
172 170
173 bytes_left = len - workspace->def_strm.total_in; 171 bytes_left = len - workspace->strm.total_in;
174 kunmap(in_page); 172 kunmap(in_page);
175 page_cache_release(in_page); 173 page_cache_release(in_page);
176 174
@@ -178,28 +176,28 @@ static int zlib_compress_pages(struct list_head *ws,
178 in_page = find_get_page(mapping, 176 in_page = find_get_page(mapping,
179 start >> PAGE_CACHE_SHIFT); 177 start >> PAGE_CACHE_SHIFT);
180 data_in = kmap(in_page); 178 data_in = kmap(in_page);
181 workspace->def_strm.avail_in = min(bytes_left, 179 workspace->strm.avail_in = min(bytes_left,
182 PAGE_CACHE_SIZE); 180 PAGE_CACHE_SIZE);
183 workspace->def_strm.next_in = data_in; 181 workspace->strm.next_in = data_in;
184 } 182 }
185 } 183 }
186 workspace->def_strm.avail_in = 0; 184 workspace->strm.avail_in = 0;
187 ret = zlib_deflate(&workspace->def_strm, Z_FINISH); 185 ret = zlib_deflate(&workspace->strm, Z_FINISH);
188 zlib_deflateEnd(&workspace->def_strm); 186 zlib_deflateEnd(&workspace->strm);
189 187
190 if (ret != Z_STREAM_END) { 188 if (ret != Z_STREAM_END) {
191 ret = -EIO; 189 ret = -EIO;
192 goto out; 190 goto out;
193 } 191 }
194 192
195 if (workspace->def_strm.total_out >= workspace->def_strm.total_in) { 193 if (workspace->strm.total_out >= workspace->strm.total_in) {
196 ret = -E2BIG; 194 ret = -E2BIG;
197 goto out; 195 goto out;
198 } 196 }
199 197
200 ret = 0; 198 ret = 0;
201 *total_out = workspace->def_strm.total_out; 199 *total_out = workspace->strm.total_out;
202 *total_in = workspace->def_strm.total_in; 200 *total_in = workspace->strm.total_in;
203out: 201out:
204 *out_pages = nr_pages; 202 *out_pages = nr_pages;
205 if (out_page) 203 if (out_page)
@@ -230,13 +228,13 @@ static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in,
230 unsigned long pg_offset; 228 unsigned long pg_offset;
231 229
232 data_in = kmap(pages_in[page_in_index]); 230 data_in = kmap(pages_in[page_in_index]);
233 workspace->inf_strm.next_in = data_in; 231 workspace->strm.next_in = data_in;
234 workspace->inf_strm.avail_in = min_t(size_t, srclen, PAGE_CACHE_SIZE); 232 workspace->strm.avail_in = min_t(size_t, srclen, PAGE_CACHE_SIZE);
235 workspace->inf_strm.total_in = 0; 233 workspace->strm.total_in = 0;
236 234
237 workspace->inf_strm.total_out = 0; 235 workspace->strm.total_out = 0;
238 workspace->inf_strm.next_out = workspace->buf; 236 workspace->strm.next_out = workspace->buf;
239 workspace->inf_strm.avail_out = PAGE_CACHE_SIZE; 237 workspace->strm.avail_out = PAGE_CACHE_SIZE;
240 pg_offset = 0; 238 pg_offset = 0;
241 239
242 /* If it's deflate, and it's got no preset dictionary, then 240 /* If it's deflate, and it's got no preset dictionary, then
@@ -246,21 +244,21 @@ static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in,
246 !(((data_in[0]<<8) + data_in[1]) % 31)) { 244 !(((data_in[0]<<8) + data_in[1]) % 31)) {
247 245
248 wbits = -((data_in[0] >> 4) + 8); 246 wbits = -((data_in[0] >> 4) + 8);
249 workspace->inf_strm.next_in += 2; 247 workspace->strm.next_in += 2;
250 workspace->inf_strm.avail_in -= 2; 248 workspace->strm.avail_in -= 2;
251 } 249 }
252 250
253 if (Z_OK != zlib_inflateInit2(&workspace->inf_strm, wbits)) { 251 if (Z_OK != zlib_inflateInit2(&workspace->strm, wbits)) {
254 printk(KERN_WARNING "BTRFS: inflateInit failed\n"); 252 printk(KERN_WARNING "BTRFS: inflateInit failed\n");
255 return -EIO; 253 return -EIO;
256 } 254 }
257 while (workspace->inf_strm.total_in < srclen) { 255 while (workspace->strm.total_in < srclen) {
258 ret = zlib_inflate(&workspace->inf_strm, Z_NO_FLUSH); 256 ret = zlib_inflate(&workspace->strm, Z_NO_FLUSH);
259 if (ret != Z_OK && ret != Z_STREAM_END) 257 if (ret != Z_OK && ret != Z_STREAM_END)
260 break; 258 break;
261 259
262 buf_start = total_out; 260 buf_start = total_out;
263 total_out = workspace->inf_strm.total_out; 261 total_out = workspace->strm.total_out;
264 262
265 /* we didn't make progress in this inflate call, we're done */ 263 /* we didn't make progress in this inflate call, we're done */
266 if (buf_start == total_out) 264 if (buf_start == total_out)
@@ -275,10 +273,10 @@ static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in,
275 goto done; 273 goto done;
276 } 274 }
277 275
278 workspace->inf_strm.next_out = workspace->buf; 276 workspace->strm.next_out = workspace->buf;
279 workspace->inf_strm.avail_out = PAGE_CACHE_SIZE; 277 workspace->strm.avail_out = PAGE_CACHE_SIZE;
280 278
281 if (workspace->inf_strm.avail_in == 0) { 279 if (workspace->strm.avail_in == 0) {
282 unsigned long tmp; 280 unsigned long tmp;
283 kunmap(pages_in[page_in_index]); 281 kunmap(pages_in[page_in_index]);
284 page_in_index++; 282 page_in_index++;
@@ -287,9 +285,9 @@ static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in,
287 break; 285 break;
288 } 286 }
289 data_in = kmap(pages_in[page_in_index]); 287 data_in = kmap(pages_in[page_in_index]);
290 workspace->inf_strm.next_in = data_in; 288 workspace->strm.next_in = data_in;
291 tmp = srclen - workspace->inf_strm.total_in; 289 tmp = srclen - workspace->strm.total_in;
292 workspace->inf_strm.avail_in = min(tmp, 290 workspace->strm.avail_in = min(tmp,
293 PAGE_CACHE_SIZE); 291 PAGE_CACHE_SIZE);
294 } 292 }
295 } 293 }
@@ -298,7 +296,7 @@ static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in,
298 else 296 else
299 ret = 0; 297 ret = 0;
300done: 298done:
301 zlib_inflateEnd(&workspace->inf_strm); 299 zlib_inflateEnd(&workspace->strm);
302 if (data_in) 300 if (data_in)
303 kunmap(pages_in[page_in_index]); 301 kunmap(pages_in[page_in_index]);
304 return ret; 302 return ret;
@@ -316,13 +314,13 @@ static int zlib_decompress(struct list_head *ws, unsigned char *data_in,
316 unsigned long total_out = 0; 314 unsigned long total_out = 0;
317 char *kaddr; 315 char *kaddr;
318 316
319 workspace->inf_strm.next_in = data_in; 317 workspace->strm.next_in = data_in;
320 workspace->inf_strm.avail_in = srclen; 318 workspace->strm.avail_in = srclen;
321 workspace->inf_strm.total_in = 0; 319 workspace->strm.total_in = 0;
322 320
323 workspace->inf_strm.next_out = workspace->buf; 321 workspace->strm.next_out = workspace->buf;
324 workspace->inf_strm.avail_out = PAGE_CACHE_SIZE; 322 workspace->strm.avail_out = PAGE_CACHE_SIZE;
325 workspace->inf_strm.total_out = 0; 323 workspace->strm.total_out = 0;
326 /* If it's deflate, and it's got no preset dictionary, then 324 /* If it's deflate, and it's got no preset dictionary, then
327 we can tell zlib to skip the adler32 check. */ 325 we can tell zlib to skip the adler32 check. */
328 if (srclen > 2 && !(data_in[1] & PRESET_DICT) && 326 if (srclen > 2 && !(data_in[1] & PRESET_DICT) &&
@@ -330,11 +328,11 @@ static int zlib_decompress(struct list_head *ws, unsigned char *data_in,
330 !(((data_in[0]<<8) + data_in[1]) % 31)) { 328 !(((data_in[0]<<8) + data_in[1]) % 31)) {
331 329
332 wbits = -((data_in[0] >> 4) + 8); 330 wbits = -((data_in[0] >> 4) + 8);
333 workspace->inf_strm.next_in += 2; 331 workspace->strm.next_in += 2;
334 workspace->inf_strm.avail_in -= 2; 332 workspace->strm.avail_in -= 2;
335 } 333 }
336 334
337 if (Z_OK != zlib_inflateInit2(&workspace->inf_strm, wbits)) { 335 if (Z_OK != zlib_inflateInit2(&workspace->strm, wbits)) {
338 printk(KERN_WARNING "BTRFS: inflateInit failed\n"); 336 printk(KERN_WARNING "BTRFS: inflateInit failed\n");
339 return -EIO; 337 return -EIO;
340 } 338 }
@@ -345,12 +343,12 @@ static int zlib_decompress(struct list_head *ws, unsigned char *data_in,
345 unsigned long bytes; 343 unsigned long bytes;
346 unsigned long pg_offset = 0; 344 unsigned long pg_offset = 0;
347 345
348 ret = zlib_inflate(&workspace->inf_strm, Z_NO_FLUSH); 346 ret = zlib_inflate(&workspace->strm, Z_NO_FLUSH);
349 if (ret != Z_OK && ret != Z_STREAM_END) 347 if (ret != Z_OK && ret != Z_STREAM_END)
350 break; 348 break;
351 349
352 buf_start = total_out; 350 buf_start = total_out;
353 total_out = workspace->inf_strm.total_out; 351 total_out = workspace->strm.total_out;
354 352
355 if (total_out == buf_start) { 353 if (total_out == buf_start) {
356 ret = -EIO; 354 ret = -EIO;
@@ -376,8 +374,8 @@ static int zlib_decompress(struct list_head *ws, unsigned char *data_in,
376 pg_offset += bytes; 374 pg_offset += bytes;
377 bytes_left -= bytes; 375 bytes_left -= bytes;
378next: 376next:
379 workspace->inf_strm.next_out = workspace->buf; 377 workspace->strm.next_out = workspace->buf;
380 workspace->inf_strm.avail_out = PAGE_CACHE_SIZE; 378 workspace->strm.avail_out = PAGE_CACHE_SIZE;
381 } 379 }
382 380
383 if (ret != Z_STREAM_END && bytes_left != 0) 381 if (ret != Z_STREAM_END && bytes_left != 0)
@@ -385,7 +383,7 @@ next:
385 else 383 else
386 ret = 0; 384 ret = 0;
387 385
388 zlib_inflateEnd(&workspace->inf_strm); 386 zlib_inflateEnd(&workspace->strm);
389 return ret; 387 return ret;
390} 388}
391 389