diff options
Diffstat (limited to 'fs/btrfs/zlib.c')
-rw-r--r-- | fs/btrfs/zlib.c | 111 |
1 files changed, 12 insertions, 99 deletions
diff --git a/fs/btrfs/zlib.c b/fs/btrfs/zlib.c index 9a3e693917f2..f5ec2d44150d 100644 --- a/fs/btrfs/zlib.c +++ b/fs/btrfs/zlib.c | |||
@@ -218,24 +218,16 @@ static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in, | |||
218 | size_t srclen) | 218 | size_t srclen) |
219 | { | 219 | { |
220 | struct workspace *workspace = list_entry(ws, struct workspace, list); | 220 | struct workspace *workspace = list_entry(ws, struct workspace, list); |
221 | int ret = 0; | 221 | int ret = 0, ret2; |
222 | int wbits = MAX_WBITS; | 222 | int wbits = MAX_WBITS; |
223 | char *data_in; | 223 | char *data_in; |
224 | size_t total_out = 0; | 224 | size_t total_out = 0; |
225 | unsigned long page_bytes_left; | ||
226 | unsigned long page_in_index = 0; | 225 | unsigned long page_in_index = 0; |
227 | unsigned long page_out_index = 0; | 226 | unsigned long page_out_index = 0; |
228 | struct page *page_out; | ||
229 | unsigned long total_pages_in = (srclen + PAGE_CACHE_SIZE - 1) / | 227 | unsigned long total_pages_in = (srclen + PAGE_CACHE_SIZE - 1) / |
230 | PAGE_CACHE_SIZE; | 228 | PAGE_CACHE_SIZE; |
231 | unsigned long buf_start; | 229 | unsigned long buf_start; |
232 | unsigned long buf_offset; | ||
233 | unsigned long bytes; | ||
234 | unsigned long working_bytes; | ||
235 | unsigned long pg_offset; | 230 | unsigned long pg_offset; |
236 | unsigned long start_byte; | ||
237 | unsigned long current_buf_start; | ||
238 | char *kaddr; | ||
239 | 231 | ||
240 | data_in = kmap(pages_in[page_in_index]); | 232 | data_in = kmap(pages_in[page_in_index]); |
241 | workspace->inf_strm.next_in = data_in; | 233 | workspace->inf_strm.next_in = data_in; |
@@ -245,8 +237,6 @@ static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in, | |||
245 | workspace->inf_strm.total_out = 0; | 237 | workspace->inf_strm.total_out = 0; |
246 | workspace->inf_strm.next_out = workspace->buf; | 238 | workspace->inf_strm.next_out = workspace->buf; |
247 | workspace->inf_strm.avail_out = PAGE_CACHE_SIZE; | 239 | workspace->inf_strm.avail_out = PAGE_CACHE_SIZE; |
248 | page_out = bvec[page_out_index].bv_page; | ||
249 | page_bytes_left = PAGE_CACHE_SIZE; | ||
250 | pg_offset = 0; | 240 | pg_offset = 0; |
251 | 241 | ||
252 | /* If it's deflate, and it's got no preset dictionary, then | 242 | /* If it's deflate, and it's got no preset dictionary, then |
@@ -268,100 +258,23 @@ static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in, | |||
268 | ret = zlib_inflate(&workspace->inf_strm, Z_NO_FLUSH); | 258 | ret = zlib_inflate(&workspace->inf_strm, Z_NO_FLUSH); |
269 | if (ret != Z_OK && ret != Z_STREAM_END) | 259 | if (ret != Z_OK && ret != Z_STREAM_END) |
270 | break; | 260 | break; |
271 | /* | ||
272 | * buf start is the byte offset we're of the start of | ||
273 | * our workspace buffer | ||
274 | */ | ||
275 | buf_start = total_out; | ||
276 | 261 | ||
277 | /* total_out is the last byte of the workspace buffer */ | 262 | buf_start = total_out; |
278 | total_out = workspace->inf_strm.total_out; | 263 | total_out = workspace->inf_strm.total_out; |
279 | 264 | ||
280 | working_bytes = total_out - buf_start; | 265 | /* we didn't make progress in this inflate call, we're done */ |
281 | 266 | if (buf_start == total_out) | |
282 | /* | ||
283 | * start byte is the first byte of the page we're currently | ||
284 | * copying into relative to the start of the compressed data. | ||
285 | */ | ||
286 | start_byte = page_offset(page_out) - disk_start; | ||
287 | |||
288 | if (working_bytes == 0) { | ||
289 | /* we didn't make progress in this inflate | ||
290 | * call, we're done | ||
291 | */ | ||
292 | if (ret != Z_STREAM_END) | ||
293 | ret = -1; | ||
294 | break; | 267 | break; |
295 | } | ||
296 | 268 | ||
297 | /* we haven't yet hit data corresponding to this page */ | 269 | ret2 = btrfs_decompress_buf2page(workspace->buf, buf_start, |
298 | if (total_out <= start_byte) | 270 | total_out, disk_start, |
299 | goto next; | 271 | bvec, vcnt, |
300 | 272 | &page_out_index, &pg_offset); | |
301 | /* | 273 | if (ret2 == 0) { |
302 | * the start of the data we care about is offset into | 274 | ret = 0; |
303 | * the middle of our working buffer | 275 | goto done; |
304 | */ | ||
305 | if (total_out > start_byte && buf_start < start_byte) { | ||
306 | buf_offset = start_byte - buf_start; | ||
307 | working_bytes -= buf_offset; | ||
308 | } else { | ||
309 | buf_offset = 0; | ||
310 | } | ||
311 | current_buf_start = buf_start; | ||
312 | |||
313 | /* copy bytes from the working buffer into the pages */ | ||
314 | while (working_bytes > 0) { | ||
315 | bytes = min(PAGE_CACHE_SIZE - pg_offset, | ||
316 | PAGE_CACHE_SIZE - buf_offset); | ||
317 | bytes = min(bytes, working_bytes); | ||
318 | kaddr = kmap_atomic(page_out, KM_USER0); | ||
319 | memcpy(kaddr + pg_offset, workspace->buf + buf_offset, | ||
320 | bytes); | ||
321 | kunmap_atomic(kaddr, KM_USER0); | ||
322 | flush_dcache_page(page_out); | ||
323 | |||
324 | pg_offset += bytes; | ||
325 | page_bytes_left -= bytes; | ||
326 | buf_offset += bytes; | ||
327 | working_bytes -= bytes; | ||
328 | current_buf_start += bytes; | ||
329 | |||
330 | /* check if we need to pick another page */ | ||
331 | if (page_bytes_left == 0) { | ||
332 | page_out_index++; | ||
333 | if (page_out_index >= vcnt) { | ||
334 | ret = 0; | ||
335 | goto done; | ||
336 | } | ||
337 | |||
338 | page_out = bvec[page_out_index].bv_page; | ||
339 | pg_offset = 0; | ||
340 | page_bytes_left = PAGE_CACHE_SIZE; | ||
341 | start_byte = page_offset(page_out) - disk_start; | ||
342 | |||
343 | /* | ||
344 | * make sure our new page is covered by this | ||
345 | * working buffer | ||
346 | */ | ||
347 | if (total_out <= start_byte) | ||
348 | goto next; | ||
349 | |||
350 | /* the next page in the biovec might not | ||
351 | * be adjacent to the last page, but it | ||
352 | * might still be found inside this working | ||
353 | * buffer. bump our offset pointer | ||
354 | */ | ||
355 | if (total_out > start_byte && | ||
356 | current_buf_start < start_byte) { | ||
357 | buf_offset = start_byte - buf_start; | ||
358 | working_bytes = total_out - start_byte; | ||
359 | current_buf_start = buf_start + | ||
360 | buf_offset; | ||
361 | } | ||
362 | } | ||
363 | } | 276 | } |
364 | next: | 277 | |
365 | workspace->inf_strm.next_out = workspace->buf; | 278 | workspace->inf_strm.next_out = workspace->buf; |
366 | workspace->inf_strm.avail_out = PAGE_CACHE_SIZE; | 279 | workspace->inf_strm.avail_out = PAGE_CACHE_SIZE; |
367 | 280 | ||