aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorLi Zefan <lizf@cn.fujitsu.com>2010-11-08 02:22:19 -0500
committerLi Zefan <lizf@cn.fujitsu.com>2010-12-22 10:15:50 -0500
commit3a39c18d63fec35f49df577d4b2a4e29c2212f22 (patch)
tree78b8c032e18e2231c18e89ac3f8f5746abdb119c /fs/btrfs
parent1a419d85a76853d7d04e9b6280a80e96770bf3e3 (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.c92
-rw-r--r--fs/btrfs/compression.h5
-rw-r--r--fs/btrfs/lzo.c101
-rw-r--r--fs/btrfs/zlib.c111
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 */
915int 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);
35int btrfs_decompress(int type, unsigned char *data_in, struct page *dest_page, 35int 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);
37int 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
38int btrfs_submit_compressed_write(struct inode *inode, u64 start, 43int 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 }
454done: 365done:
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 }
364next: 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