diff options
author | Li Zefan <lizf@cn.fujitsu.com> | 2010-11-08 02:22:19 -0500 |
---|---|---|
committer | Li Zefan <lizf@cn.fujitsu.com> | 2010-12-22 10:15:50 -0500 |
commit | 3a39c18d63fec35f49df577d4b2a4e29c2212f22 (patch) | |
tree | 78b8c032e18e2231c18e89ac3f8f5746abdb119c /fs/btrfs | |
parent | 1a419d85a76853d7d04e9b6280a80e96770bf3e3 (diff) |
btrfs: Extract duplicate decompress code
Add a common function to copy decompressed data from working buffer
to bio pages.
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/compression.c | 92 | ||||
-rw-r--r-- | fs/btrfs/compression.h | 5 | ||||
-rw-r--r-- | fs/btrfs/lzo.c | 101 | ||||
-rw-r--r-- | fs/btrfs/zlib.c | 111 |
4 files changed, 115 insertions, 194 deletions
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index 8faa2df9e719..f745287fbf2e 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c | |||
@@ -904,3 +904,95 @@ void __exit btrfs_exit_compress(void) | |||
904 | { | 904 | { |
905 | free_workspaces(); | 905 | free_workspaces(); |
906 | } | 906 | } |
907 | |||
908 | /* | ||
909 | * Copy uncompressed data from working buffer to pages. | ||
910 | * | ||
911 | * buf_start is the byte offset we're of the start of our workspace buffer. | ||
912 | * | ||
913 | * total_out is the last byte of the buffer | ||
914 | */ | ||
915 | int btrfs_decompress_buf2page(char *buf, unsigned long buf_start, | ||
916 | unsigned long total_out, u64 disk_start, | ||
917 | struct bio_vec *bvec, int vcnt, | ||
918 | unsigned long *page_index, | ||
919 | unsigned long *pg_offset) | ||
920 | { | ||
921 | unsigned long buf_offset; | ||
922 | unsigned long current_buf_start; | ||
923 | unsigned long start_byte; | ||
924 | unsigned long working_bytes = total_out - buf_start; | ||
925 | unsigned long bytes; | ||
926 | char *kaddr; | ||
927 | struct page *page_out = bvec[*page_index].bv_page; | ||
928 | |||
929 | /* | ||
930 | * start byte is the first byte of the page we're currently | ||
931 | * copying into relative to the start of the compressed data. | ||
932 | */ | ||
933 | start_byte = page_offset(page_out) - disk_start; | ||
934 | |||
935 | /* we haven't yet hit data corresponding to this page */ | ||
936 | if (total_out <= start_byte) | ||
937 | return 1; | ||
938 | |||
939 | /* | ||
940 | * the start of the data we care about is offset into | ||
941 | * the middle of our working buffer | ||
942 | */ | ||
943 | if (total_out > start_byte && buf_start < start_byte) { | ||
944 | buf_offset = start_byte - buf_start; | ||
945 | working_bytes -= buf_offset; | ||
946 | } else { | ||
947 | buf_offset = 0; | ||
948 | } | ||
949 | current_buf_start = buf_start; | ||
950 | |||
951 | /* copy bytes from the working buffer into the pages */ | ||
952 | while (working_bytes > 0) { | ||
953 | bytes = min(PAGE_CACHE_SIZE - *pg_offset, | ||
954 | PAGE_CACHE_SIZE - buf_offset); | ||
955 | bytes = min(bytes, working_bytes); | ||
956 | kaddr = kmap_atomic(page_out, KM_USER0); | ||
957 | memcpy(kaddr + *pg_offset, buf + buf_offset, bytes); | ||
958 | kunmap_atomic(kaddr, KM_USER0); | ||
959 | flush_dcache_page(page_out); | ||
960 | |||
961 | *pg_offset += bytes; | ||
962 | buf_offset += bytes; | ||
963 | working_bytes -= bytes; | ||
964 | current_buf_start += bytes; | ||
965 | |||
966 | /* check if we need to pick another page */ | ||
967 | if (*pg_offset == PAGE_CACHE_SIZE) { | ||
968 | (*page_index)++; | ||
969 | if (*page_index >= vcnt) | ||
970 | return 0; | ||
971 | |||
972 | page_out = bvec[*page_index].bv_page; | ||
973 | *pg_offset = 0; | ||
974 | start_byte = page_offset(page_out) - disk_start; | ||
975 | |||
976 | /* | ||
977 | * make sure our new page is covered by this | ||
978 | * working buffer | ||
979 | */ | ||
980 | if (total_out <= start_byte) | ||
981 | return 1; | ||
982 | |||
983 | /* | ||
984 | * the next page in the biovec might not be adjacent | ||
985 | * to the last page, but it might still be found | ||
986 | * inside this working buffer. bump our offset pointer | ||
987 | */ | ||
988 | if (total_out > start_byte && | ||
989 | current_buf_start < start_byte) { | ||
990 | buf_offset = start_byte - buf_start; | ||
991 | working_bytes = total_out - start_byte; | ||
992 | current_buf_start = buf_start + buf_offset; | ||
993 | } | ||
994 | } | ||
995 | } | ||
996 | |||
997 | return 1; | ||
998 | } | ||
diff --git a/fs/btrfs/compression.h b/fs/btrfs/compression.h index f7ce217113fa..51000174b9d7 100644 --- a/fs/btrfs/compression.h +++ b/fs/btrfs/compression.h | |||
@@ -34,6 +34,11 @@ int btrfs_decompress_biovec(int type, struct page **pages_in, u64 disk_start, | |||
34 | struct bio_vec *bvec, int vcnt, size_t srclen); | 34 | struct bio_vec *bvec, int vcnt, size_t srclen); |
35 | int btrfs_decompress(int type, unsigned char *data_in, struct page *dest_page, | 35 | int btrfs_decompress(int type, unsigned char *data_in, struct page *dest_page, |
36 | unsigned long start_byte, size_t srclen, size_t destlen); | 36 | unsigned long start_byte, size_t srclen, size_t destlen); |
37 | int btrfs_decompress_buf2page(char *buf, unsigned long buf_start, | ||
38 | unsigned long total_out, u64 disk_start, | ||
39 | struct bio_vec *bvec, int vcnt, | ||
40 | unsigned long *page_index, | ||
41 | unsigned long *pg_offset); | ||
37 | 42 | ||
38 | int btrfs_submit_compressed_write(struct inode *inode, u64 start, | 43 | int btrfs_submit_compressed_write(struct inode *inode, u64 start, |
39 | unsigned long len, u64 disk_start, | 44 | unsigned long len, u64 disk_start, |
diff --git a/fs/btrfs/lzo.c b/fs/btrfs/lzo.c index 523b144e2aec..cc9b450399df 100644 --- a/fs/btrfs/lzo.c +++ b/fs/btrfs/lzo.c | |||
@@ -260,12 +260,10 @@ static int lzo_decompress_biovec(struct list_head *ws, | |||
260 | size_t srclen) | 260 | size_t srclen) |
261 | { | 261 | { |
262 | struct workspace *workspace = list_entry(ws, struct workspace, list); | 262 | struct workspace *workspace = list_entry(ws, struct workspace, list); |
263 | int ret = 0; | 263 | int ret = 0, ret2; |
264 | char *data_in; | 264 | char *data_in; |
265 | unsigned long page_bytes_left; | ||
266 | unsigned long page_in_index = 0; | 265 | unsigned long page_in_index = 0; |
267 | unsigned long page_out_index = 0; | 266 | unsigned long page_out_index = 0; |
268 | struct page *page_out; | ||
269 | unsigned long total_pages_in = (srclen + PAGE_CACHE_SIZE - 1) / | 267 | unsigned long total_pages_in = (srclen + PAGE_CACHE_SIZE - 1) / |
270 | PAGE_CACHE_SIZE; | 268 | PAGE_CACHE_SIZE; |
271 | unsigned long buf_start; | 269 | unsigned long buf_start; |
@@ -273,9 +271,6 @@ static int lzo_decompress_biovec(struct list_head *ws, | |||
273 | unsigned long bytes; | 271 | unsigned long bytes; |
274 | unsigned long working_bytes; | 272 | unsigned long working_bytes; |
275 | unsigned long pg_offset; | 273 | unsigned long pg_offset; |
276 | unsigned long start_byte; | ||
277 | unsigned long current_buf_start; | ||
278 | char *kaddr; | ||
279 | 274 | ||
280 | size_t in_len; | 275 | size_t in_len; |
281 | size_t out_len; | 276 | size_t out_len; |
@@ -295,8 +290,6 @@ static int lzo_decompress_biovec(struct list_head *ws, | |||
295 | in_page_bytes_left = PAGE_CACHE_SIZE - LZO_LEN; | 290 | in_page_bytes_left = PAGE_CACHE_SIZE - LZO_LEN; |
296 | 291 | ||
297 | tot_out = 0; | 292 | tot_out = 0; |
298 | page_out = bvec[0].bv_page; | ||
299 | page_bytes_left = PAGE_CACHE_SIZE; | ||
300 | pg_offset = 0; | 293 | pg_offset = 0; |
301 | 294 | ||
302 | while (tot_in < tot_len) { | 295 | while (tot_in < tot_len) { |
@@ -359,97 +352,15 @@ cont: | |||
359 | break; | 352 | break; |
360 | } | 353 | } |
361 | 354 | ||
362 | /* | ||
363 | * buf start is the byte offset we're of the start of | ||
364 | * our workspace buffer | ||
365 | */ | ||
366 | buf_start = tot_out; | 355 | buf_start = tot_out; |
367 | |||
368 | /* tot_out is the last byte of the workspace buffer */ | ||
369 | tot_out += out_len; | 356 | tot_out += out_len; |
370 | 357 | ||
371 | working_bytes = tot_out - buf_start; | 358 | ret2 = btrfs_decompress_buf2page(workspace->buf, buf_start, |
372 | 359 | tot_out, disk_start, | |
373 | /* | 360 | bvec, vcnt, |
374 | * start_byte is the first byte of the page we're currently | 361 | &page_out_index, &pg_offset); |
375 | * copying into relative to the start of the compressed data. | 362 | if (ret2 == 0) |
376 | */ | ||
377 | start_byte = page_offset(page_out) - disk_start; | ||
378 | |||
379 | if (working_bytes == 0) { | ||
380 | /* we didn't make progress in this inflate | ||
381 | * call, we're done | ||
382 | */ | ||
383 | break; | 363 | break; |
384 | } | ||
385 | |||
386 | /* we haven't yet hit data corresponding to this page */ | ||
387 | if (tot_out <= start_byte) | ||
388 | continue; | ||
389 | |||
390 | /* | ||
391 | * the start of the data we care about is offset into | ||
392 | * the middle of our working buffer | ||
393 | */ | ||
394 | if (tot_out > start_byte && buf_start < start_byte) { | ||
395 | buf_offset = start_byte - buf_start; | ||
396 | working_bytes -= buf_offset; | ||
397 | } else { | ||
398 | buf_offset = 0; | ||
399 | } | ||
400 | current_buf_start = buf_start; | ||
401 | |||
402 | /* copy bytes from the working buffer into the pages */ | ||
403 | while (working_bytes > 0) { | ||
404 | bytes = min(PAGE_CACHE_SIZE - pg_offset, | ||
405 | PAGE_CACHE_SIZE - buf_offset); | ||
406 | bytes = min(bytes, working_bytes); | ||
407 | kaddr = kmap_atomic(page_out, KM_USER0); | ||
408 | memcpy(kaddr + pg_offset, workspace->buf + buf_offset, | ||
409 | bytes); | ||
410 | kunmap_atomic(kaddr, KM_USER0); | ||
411 | flush_dcache_page(page_out); | ||
412 | |||
413 | pg_offset += bytes; | ||
414 | page_bytes_left -= bytes; | ||
415 | buf_offset += bytes; | ||
416 | working_bytes -= bytes; | ||
417 | current_buf_start += bytes; | ||
418 | |||
419 | /* check if we need to pick another page */ | ||
420 | if (page_bytes_left == 0) { | ||
421 | page_out_index++; | ||
422 | if (page_out_index >= vcnt) { | ||
423 | ret = 0; | ||
424 | goto done; | ||
425 | } | ||
426 | |||
427 | page_out = bvec[page_out_index].bv_page; | ||
428 | pg_offset = 0; | ||
429 | page_bytes_left = PAGE_CACHE_SIZE; | ||
430 | start_byte = page_offset(page_out) - disk_start; | ||
431 | |||
432 | /* | ||
433 | * make sure our new page is covered by this | ||
434 | * working buffer | ||
435 | */ | ||
436 | if (tot_out <= start_byte) | ||
437 | break; | ||
438 | |||
439 | /* the next page in the biovec might not | ||
440 | * be adjacent to the last page, but it | ||
441 | * might still be found inside this working | ||
442 | * buffer. bump our offset pointer | ||
443 | */ | ||
444 | if (tot_out > start_byte && | ||
445 | current_buf_start < start_byte) { | ||
446 | buf_offset = start_byte - buf_start; | ||
447 | working_bytes = tot_out - start_byte; | ||
448 | current_buf_start = buf_start + | ||
449 | buf_offset; | ||
450 | } | ||
451 | } | ||
452 | } | ||
453 | } | 364 | } |
454 | done: | 365 | done: |
455 | if (data_in) | 366 | if (data_in) |
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 | ||