diff options
author | Sergey Senozhatsky <sergey.senozhatsky@gmail.com> | 2014-07-07 10:38:29 -0400 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2014-09-17 16:37:33 -0400 |
commit | 7880991344f73647fa2222b198cf5cfc10805ac2 (patch) | |
tree | 6a4da88ef232059ba8de77f7715dd274b972e825 /fs | |
parent | 555e12864063762964433139dee651c5b859a047 (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.c | 138 |
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 | ||
35 | struct workspace { | 35 | struct 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) | |||
52 | static struct list_head *zlib_alloc_workspace(void) | 50 | static 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; |
203 | out: | 201 | out: |
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; |
300 | done: | 298 | done: |
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; |
378 | next: | 376 | next: |
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 | ||