diff options
Diffstat (limited to 'fs/btrfs/file-item.c')
-rw-r--r-- | fs/btrfs/file-item.c | 57 |
1 files changed, 34 insertions, 23 deletions
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index 078b4fd54500..5d158d320233 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c | |||
@@ -25,10 +25,12 @@ | |||
25 | #include "transaction.h" | 25 | #include "transaction.h" |
26 | #include "print-tree.h" | 26 | #include "print-tree.h" |
27 | 27 | ||
28 | #define MAX_CSUM_ITEMS(r, size) ((((BTRFS_LEAF_DATA_SIZE(r) - \ | 28 | #define __MAX_CSUM_ITEMS(r, size) ((((BTRFS_LEAF_DATA_SIZE(r) - \ |
29 | sizeof(struct btrfs_item) * 2) / \ | 29 | sizeof(struct btrfs_item) * 2) / \ |
30 | size) - 1)) | 30 | size) - 1)) |
31 | 31 | ||
32 | #define MAX_CSUM_ITEMS(r, size) (min(__MAX_CSUM_ITEMS(r, size), PAGE_CACHE_SIZE)) | ||
33 | |||
32 | #define MAX_ORDERED_SUM_BYTES(r) ((PAGE_SIZE - \ | 34 | #define MAX_ORDERED_SUM_BYTES(r) ((PAGE_SIZE - \ |
33 | sizeof(struct btrfs_ordered_sum)) / \ | 35 | sizeof(struct btrfs_ordered_sum)) / \ |
34 | sizeof(struct btrfs_sector_sum) * \ | 36 | sizeof(struct btrfs_sector_sum) * \ |
@@ -59,7 +61,7 @@ int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, | |||
59 | sizeof(*item)); | 61 | sizeof(*item)); |
60 | if (ret < 0) | 62 | if (ret < 0) |
61 | goto out; | 63 | goto out; |
62 | BUG_ON(ret); | 64 | BUG_ON(ret); /* Can't happen */ |
63 | leaf = path->nodes[0]; | 65 | leaf = path->nodes[0]; |
64 | item = btrfs_item_ptr(leaf, path->slots[0], | 66 | item = btrfs_item_ptr(leaf, path->slots[0], |
65 | struct btrfs_file_extent_item); | 67 | struct btrfs_file_extent_item); |
@@ -284,6 +286,7 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, | |||
284 | struct btrfs_ordered_sum *sums; | 286 | struct btrfs_ordered_sum *sums; |
285 | struct btrfs_sector_sum *sector_sum; | 287 | struct btrfs_sector_sum *sector_sum; |
286 | struct btrfs_csum_item *item; | 288 | struct btrfs_csum_item *item; |
289 | LIST_HEAD(tmplist); | ||
287 | unsigned long offset; | 290 | unsigned long offset; |
288 | int ret; | 291 | int ret; |
289 | size_t size; | 292 | size_t size; |
@@ -358,7 +361,10 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, | |||
358 | MAX_ORDERED_SUM_BYTES(root)); | 361 | MAX_ORDERED_SUM_BYTES(root)); |
359 | sums = kzalloc(btrfs_ordered_sum_size(root, size), | 362 | sums = kzalloc(btrfs_ordered_sum_size(root, size), |
360 | GFP_NOFS); | 363 | GFP_NOFS); |
361 | BUG_ON(!sums); | 364 | if (!sums) { |
365 | ret = -ENOMEM; | ||
366 | goto fail; | ||
367 | } | ||
362 | 368 | ||
363 | sector_sum = sums->sums; | 369 | sector_sum = sums->sums; |
364 | sums->bytenr = start; | 370 | sums->bytenr = start; |
@@ -380,12 +386,19 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, | |||
380 | offset += csum_size; | 386 | offset += csum_size; |
381 | sector_sum++; | 387 | sector_sum++; |
382 | } | 388 | } |
383 | list_add_tail(&sums->list, list); | 389 | list_add_tail(&sums->list, &tmplist); |
384 | } | 390 | } |
385 | path->slots[0]++; | 391 | path->slots[0]++; |
386 | } | 392 | } |
387 | ret = 0; | 393 | ret = 0; |
388 | fail: | 394 | fail: |
395 | while (ret < 0 && !list_empty(&tmplist)) { | ||
396 | sums = list_entry(&tmplist, struct btrfs_ordered_sum, list); | ||
397 | list_del(&sums->list); | ||
398 | kfree(sums); | ||
399 | } | ||
400 | list_splice_tail(&tmplist, list); | ||
401 | |||
389 | btrfs_free_path(path); | 402 | btrfs_free_path(path); |
390 | return ret; | 403 | return ret; |
391 | } | 404 | } |
@@ -420,7 +433,7 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, | |||
420 | offset = page_offset(bvec->bv_page) + bvec->bv_offset; | 433 | offset = page_offset(bvec->bv_page) + bvec->bv_offset; |
421 | 434 | ||
422 | ordered = btrfs_lookup_ordered_extent(inode, offset); | 435 | ordered = btrfs_lookup_ordered_extent(inode, offset); |
423 | BUG_ON(!ordered); | 436 | BUG_ON(!ordered); /* Logic error */ |
424 | sums->bytenr = ordered->start; | 437 | sums->bytenr = ordered->start; |
425 | 438 | ||
426 | while (bio_index < bio->bi_vcnt) { | 439 | while (bio_index < bio->bi_vcnt) { |
@@ -439,11 +452,11 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, | |||
439 | 452 | ||
440 | sums = kzalloc(btrfs_ordered_sum_size(root, bytes_left), | 453 | sums = kzalloc(btrfs_ordered_sum_size(root, bytes_left), |
441 | GFP_NOFS); | 454 | GFP_NOFS); |
442 | BUG_ON(!sums); | 455 | BUG_ON(!sums); /* -ENOMEM */ |
443 | sector_sum = sums->sums; | 456 | sector_sum = sums->sums; |
444 | sums->len = bytes_left; | 457 | sums->len = bytes_left; |
445 | ordered = btrfs_lookup_ordered_extent(inode, offset); | 458 | ordered = btrfs_lookup_ordered_extent(inode, offset); |
446 | BUG_ON(!ordered); | 459 | BUG_ON(!ordered); /* Logic error */ |
447 | sums->bytenr = ordered->start; | 460 | sums->bytenr = ordered->start; |
448 | } | 461 | } |
449 | 462 | ||
@@ -483,18 +496,17 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, | |||
483 | * This calls btrfs_truncate_item with the correct args based on the | 496 | * This calls btrfs_truncate_item with the correct args based on the |
484 | * overlap, and fixes up the key as required. | 497 | * overlap, and fixes up the key as required. |
485 | */ | 498 | */ |
486 | static noinline int truncate_one_csum(struct btrfs_trans_handle *trans, | 499 | static noinline void truncate_one_csum(struct btrfs_trans_handle *trans, |
487 | struct btrfs_root *root, | 500 | struct btrfs_root *root, |
488 | struct btrfs_path *path, | 501 | struct btrfs_path *path, |
489 | struct btrfs_key *key, | 502 | struct btrfs_key *key, |
490 | u64 bytenr, u64 len) | 503 | u64 bytenr, u64 len) |
491 | { | 504 | { |
492 | struct extent_buffer *leaf; | 505 | struct extent_buffer *leaf; |
493 | u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); | 506 | u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); |
494 | u64 csum_end; | 507 | u64 csum_end; |
495 | u64 end_byte = bytenr + len; | 508 | u64 end_byte = bytenr + len; |
496 | u32 blocksize_bits = root->fs_info->sb->s_blocksize_bits; | 509 | u32 blocksize_bits = root->fs_info->sb->s_blocksize_bits; |
497 | int ret; | ||
498 | 510 | ||
499 | leaf = path->nodes[0]; | 511 | leaf = path->nodes[0]; |
500 | csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size; | 512 | csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size; |
@@ -510,7 +522,7 @@ static noinline int truncate_one_csum(struct btrfs_trans_handle *trans, | |||
510 | */ | 522 | */ |
511 | u32 new_size = (bytenr - key->offset) >> blocksize_bits; | 523 | u32 new_size = (bytenr - key->offset) >> blocksize_bits; |
512 | new_size *= csum_size; | 524 | new_size *= csum_size; |
513 | ret = btrfs_truncate_item(trans, root, path, new_size, 1); | 525 | btrfs_truncate_item(trans, root, path, new_size, 1); |
514 | } else if (key->offset >= bytenr && csum_end > end_byte && | 526 | } else if (key->offset >= bytenr && csum_end > end_byte && |
515 | end_byte > key->offset) { | 527 | end_byte > key->offset) { |
516 | /* | 528 | /* |
@@ -522,15 +534,13 @@ static noinline int truncate_one_csum(struct btrfs_trans_handle *trans, | |||
522 | u32 new_size = (csum_end - end_byte) >> blocksize_bits; | 534 | u32 new_size = (csum_end - end_byte) >> blocksize_bits; |
523 | new_size *= csum_size; | 535 | new_size *= csum_size; |
524 | 536 | ||
525 | ret = btrfs_truncate_item(trans, root, path, new_size, 0); | 537 | btrfs_truncate_item(trans, root, path, new_size, 0); |
526 | 538 | ||
527 | key->offset = end_byte; | 539 | key->offset = end_byte; |
528 | ret = btrfs_set_item_key_safe(trans, root, path, key); | 540 | btrfs_set_item_key_safe(trans, root, path, key); |
529 | BUG_ON(ret); | ||
530 | } else { | 541 | } else { |
531 | BUG(); | 542 | BUG(); |
532 | } | 543 | } |
533 | return 0; | ||
534 | } | 544 | } |
535 | 545 | ||
536 | /* | 546 | /* |
@@ -635,13 +645,14 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans, | |||
635 | * item changed size or key | 645 | * item changed size or key |
636 | */ | 646 | */ |
637 | ret = btrfs_split_item(trans, root, path, &key, offset); | 647 | ret = btrfs_split_item(trans, root, path, &key, offset); |
638 | BUG_ON(ret && ret != -EAGAIN); | 648 | if (ret && ret != -EAGAIN) { |
649 | btrfs_abort_transaction(trans, root, ret); | ||
650 | goto out; | ||
651 | } | ||
639 | 652 | ||
640 | key.offset = end_byte - 1; | 653 | key.offset = end_byte - 1; |
641 | } else { | 654 | } else { |
642 | ret = truncate_one_csum(trans, root, path, | 655 | truncate_one_csum(trans, root, path, &key, bytenr, len); |
643 | &key, bytenr, len); | ||
644 | BUG_ON(ret); | ||
645 | if (key.offset < bytenr) | 656 | if (key.offset < bytenr) |
646 | break; | 657 | break; |
647 | } | 658 | } |
@@ -772,7 +783,7 @@ again: | |||
772 | if (diff != csum_size) | 783 | if (diff != csum_size) |
773 | goto insert; | 784 | goto insert; |
774 | 785 | ||
775 | ret = btrfs_extend_item(trans, root, path, diff); | 786 | btrfs_extend_item(trans, root, path, diff); |
776 | goto csum; | 787 | goto csum; |
777 | } | 788 | } |
778 | 789 | ||