diff options
Diffstat (limited to 'fs/btrfs/file.c')
| -rw-r--r-- | fs/btrfs/file.c | 100 |
1 files changed, 80 insertions, 20 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index feaa13b105d9..c02033596f02 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
| @@ -506,7 +506,8 @@ next_slot: | |||
| 506 | } | 506 | } |
| 507 | 507 | ||
| 508 | static int extent_mergeable(struct extent_buffer *leaf, int slot, | 508 | static int extent_mergeable(struct extent_buffer *leaf, int slot, |
| 509 | u64 objectid, u64 bytenr, u64 *start, u64 *end) | 509 | u64 objectid, u64 bytenr, u64 orig_offset, |
| 510 | u64 *start, u64 *end) | ||
| 510 | { | 511 | { |
| 511 | struct btrfs_file_extent_item *fi; | 512 | struct btrfs_file_extent_item *fi; |
| 512 | struct btrfs_key key; | 513 | struct btrfs_key key; |
| @@ -522,6 +523,7 @@ static int extent_mergeable(struct extent_buffer *leaf, int slot, | |||
| 522 | fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); | 523 | fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); |
| 523 | if (btrfs_file_extent_type(leaf, fi) != BTRFS_FILE_EXTENT_REG || | 524 | if (btrfs_file_extent_type(leaf, fi) != BTRFS_FILE_EXTENT_REG || |
| 524 | btrfs_file_extent_disk_bytenr(leaf, fi) != bytenr || | 525 | btrfs_file_extent_disk_bytenr(leaf, fi) != bytenr || |
| 526 | btrfs_file_extent_offset(leaf, fi) != key.offset - orig_offset || | ||
| 525 | btrfs_file_extent_compression(leaf, fi) || | 527 | btrfs_file_extent_compression(leaf, fi) || |
| 526 | btrfs_file_extent_encryption(leaf, fi) || | 528 | btrfs_file_extent_encryption(leaf, fi) || |
| 527 | btrfs_file_extent_other_encoding(leaf, fi)) | 529 | btrfs_file_extent_other_encoding(leaf, fi)) |
| @@ -561,6 +563,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, | |||
| 561 | u64 split; | 563 | u64 split; |
| 562 | int del_nr = 0; | 564 | int del_nr = 0; |
| 563 | int del_slot = 0; | 565 | int del_slot = 0; |
| 566 | int recow; | ||
| 564 | int ret; | 567 | int ret; |
| 565 | 568 | ||
| 566 | btrfs_drop_extent_cache(inode, start, end - 1, 0); | 569 | btrfs_drop_extent_cache(inode, start, end - 1, 0); |
| @@ -568,6 +571,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, | |||
| 568 | path = btrfs_alloc_path(); | 571 | path = btrfs_alloc_path(); |
| 569 | BUG_ON(!path); | 572 | BUG_ON(!path); |
| 570 | again: | 573 | again: |
| 574 | recow = 0; | ||
| 571 | split = start; | 575 | split = start; |
| 572 | key.objectid = inode->i_ino; | 576 | key.objectid = inode->i_ino; |
| 573 | key.type = BTRFS_EXTENT_DATA_KEY; | 577 | key.type = BTRFS_EXTENT_DATA_KEY; |
| @@ -591,12 +595,60 @@ again: | |||
| 591 | bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); | 595 | bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); |
| 592 | num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi); | 596 | num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi); |
| 593 | orig_offset = key.offset - btrfs_file_extent_offset(leaf, fi); | 597 | orig_offset = key.offset - btrfs_file_extent_offset(leaf, fi); |
| 598 | memcpy(&new_key, &key, sizeof(new_key)); | ||
| 599 | |||
| 600 | if (start == key.offset && end < extent_end) { | ||
| 601 | other_start = 0; | ||
| 602 | other_end = start; | ||
| 603 | if (extent_mergeable(leaf, path->slots[0] - 1, | ||
| 604 | inode->i_ino, bytenr, orig_offset, | ||
| 605 | &other_start, &other_end)) { | ||
| 606 | new_key.offset = end; | ||
| 607 | btrfs_set_item_key_safe(trans, root, path, &new_key); | ||
| 608 | fi = btrfs_item_ptr(leaf, path->slots[0], | ||
| 609 | struct btrfs_file_extent_item); | ||
| 610 | btrfs_set_file_extent_num_bytes(leaf, fi, | ||
| 611 | extent_end - end); | ||
| 612 | btrfs_set_file_extent_offset(leaf, fi, | ||
| 613 | end - orig_offset); | ||
| 614 | fi = btrfs_item_ptr(leaf, path->slots[0] - 1, | ||
| 615 | struct btrfs_file_extent_item); | ||
| 616 | btrfs_set_file_extent_num_bytes(leaf, fi, | ||
| 617 | end - other_start); | ||
| 618 | btrfs_mark_buffer_dirty(leaf); | ||
| 619 | goto out; | ||
| 620 | } | ||
| 621 | } | ||
| 622 | |||
| 623 | if (start > key.offset && end == extent_end) { | ||
| 624 | other_start = end; | ||
| 625 | other_end = 0; | ||
| 626 | if (extent_mergeable(leaf, path->slots[0] + 1, | ||
| 627 | inode->i_ino, bytenr, orig_offset, | ||
| 628 | &other_start, &other_end)) { | ||
| 629 | fi = btrfs_item_ptr(leaf, path->slots[0], | ||
| 630 | struct btrfs_file_extent_item); | ||
| 631 | btrfs_set_file_extent_num_bytes(leaf, fi, | ||
| 632 | start - key.offset); | ||
| 633 | path->slots[0]++; | ||
| 634 | new_key.offset = start; | ||
| 635 | btrfs_set_item_key_safe(trans, root, path, &new_key); | ||
| 636 | |||
| 637 | fi = btrfs_item_ptr(leaf, path->slots[0], | ||
| 638 | struct btrfs_file_extent_item); | ||
| 639 | btrfs_set_file_extent_num_bytes(leaf, fi, | ||
| 640 | other_end - start); | ||
| 641 | btrfs_set_file_extent_offset(leaf, fi, | ||
| 642 | start - orig_offset); | ||
| 643 | btrfs_mark_buffer_dirty(leaf); | ||
| 644 | goto out; | ||
| 645 | } | ||
| 646 | } | ||
| 594 | 647 | ||
| 595 | while (start > key.offset || end < extent_end) { | 648 | while (start > key.offset || end < extent_end) { |
| 596 | if (key.offset == start) | 649 | if (key.offset == start) |
| 597 | split = end; | 650 | split = end; |
| 598 | 651 | ||
| 599 | memcpy(&new_key, &key, sizeof(new_key)); | ||
| 600 | new_key.offset = split; | 652 | new_key.offset = split; |
| 601 | ret = btrfs_duplicate_item(trans, root, path, &new_key); | 653 | ret = btrfs_duplicate_item(trans, root, path, &new_key); |
| 602 | if (ret == -EAGAIN) { | 654 | if (ret == -EAGAIN) { |
| @@ -631,15 +683,18 @@ again: | |||
| 631 | path->slots[0]--; | 683 | path->slots[0]--; |
| 632 | extent_end = end; | 684 | extent_end = end; |
| 633 | } | 685 | } |
| 686 | recow = 1; | ||
| 634 | } | 687 | } |
| 635 | 688 | ||
| 636 | fi = btrfs_item_ptr(leaf, path->slots[0], | ||
| 637 | struct btrfs_file_extent_item); | ||
| 638 | |||
| 639 | other_start = end; | 689 | other_start = end; |
| 640 | other_end = 0; | 690 | other_end = 0; |
| 641 | if (extent_mergeable(leaf, path->slots[0] + 1, inode->i_ino, | 691 | if (extent_mergeable(leaf, path->slots[0] + 1, |
| 642 | bytenr, &other_start, &other_end)) { | 692 | inode->i_ino, bytenr, orig_offset, |
| 693 | &other_start, &other_end)) { | ||
| 694 | if (recow) { | ||
| 695 | btrfs_release_path(root, path); | ||
| 696 | goto again; | ||
| 697 | } | ||
| 643 | extent_end = other_end; | 698 | extent_end = other_end; |
| 644 | del_slot = path->slots[0] + 1; | 699 | del_slot = path->slots[0] + 1; |
| 645 | del_nr++; | 700 | del_nr++; |
| @@ -650,8 +705,13 @@ again: | |||
| 650 | } | 705 | } |
| 651 | other_start = 0; | 706 | other_start = 0; |
| 652 | other_end = start; | 707 | other_end = start; |
| 653 | if (extent_mergeable(leaf, path->slots[0] - 1, inode->i_ino, | 708 | if (extent_mergeable(leaf, path->slots[0] - 1, |
| 654 | bytenr, &other_start, &other_end)) { | 709 | inode->i_ino, bytenr, orig_offset, |
| 710 | &other_start, &other_end)) { | ||
| 711 | if (recow) { | ||
| 712 | btrfs_release_path(root, path); | ||
| 713 | goto again; | ||
| 714 | } | ||
| 655 | key.offset = other_start; | 715 | key.offset = other_start; |
| 656 | del_slot = path->slots[0]; | 716 | del_slot = path->slots[0]; |
| 657 | del_nr++; | 717 | del_nr++; |
| @@ -660,22 +720,22 @@ again: | |||
| 660 | inode->i_ino, orig_offset); | 720 | inode->i_ino, orig_offset); |
| 661 | BUG_ON(ret); | 721 | BUG_ON(ret); |
| 662 | } | 722 | } |
| 723 | fi = btrfs_item_ptr(leaf, path->slots[0], | ||
| 724 | struct btrfs_file_extent_item); | ||
| 663 | if (del_nr == 0) { | 725 | if (del_nr == 0) { |
| 664 | btrfs_set_file_extent_type(leaf, fi, | 726 | btrfs_set_file_extent_type(leaf, fi, |
| 665 | BTRFS_FILE_EXTENT_REG); | 727 | BTRFS_FILE_EXTENT_REG); |
| 666 | btrfs_mark_buffer_dirty(leaf); | 728 | btrfs_mark_buffer_dirty(leaf); |
| 667 | goto out; | 729 | } else { |
| 668 | } | 730 | btrfs_set_file_extent_type(leaf, fi, |
| 669 | 731 | BTRFS_FILE_EXTENT_REG); | |
| 670 | fi = btrfs_item_ptr(leaf, del_slot - 1, | 732 | btrfs_set_file_extent_num_bytes(leaf, fi, |
| 671 | struct btrfs_file_extent_item); | 733 | extent_end - key.offset); |
| 672 | btrfs_set_file_extent_type(leaf, fi, BTRFS_FILE_EXTENT_REG); | 734 | btrfs_mark_buffer_dirty(leaf); |
| 673 | btrfs_set_file_extent_num_bytes(leaf, fi, | ||
| 674 | extent_end - key.offset); | ||
| 675 | btrfs_mark_buffer_dirty(leaf); | ||
| 676 | 735 | ||
| 677 | ret = btrfs_del_items(trans, root, path, del_slot, del_nr); | 736 | ret = btrfs_del_items(trans, root, path, del_slot, del_nr); |
| 678 | BUG_ON(ret); | 737 | BUG_ON(ret); |
| 738 | } | ||
| 679 | out: | 739 | out: |
| 680 | btrfs_free_path(path); | 740 | btrfs_free_path(path); |
| 681 | return 0; | 741 | return 0; |
