diff options
Diffstat (limited to 'fs/btrfs/file.c')
-rw-r--r-- | fs/btrfs/file.c | 121 |
1 files changed, 56 insertions, 65 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 58b329ddb426..48a702d41c8c 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -524,6 +524,9 @@ int noinline btrfs_drop_extents(struct btrfs_trans_handle *trans, | |||
524 | { | 524 | { |
525 | u64 extent_end = 0; | 525 | u64 extent_end = 0; |
526 | u64 search_start = start; | 526 | u64 search_start = start; |
527 | u64 leaf_start; | ||
528 | u64 root_gen; | ||
529 | u64 root_owner; | ||
527 | struct extent_buffer *leaf; | 530 | struct extent_buffer *leaf; |
528 | struct btrfs_file_extent_item *extent; | 531 | struct btrfs_file_extent_item *extent; |
529 | struct btrfs_path *path; | 532 | struct btrfs_path *path; |
@@ -562,6 +565,9 @@ next_slot: | |||
562 | bookend = 0; | 565 | bookend = 0; |
563 | found_extent = 0; | 566 | found_extent = 0; |
564 | found_inline = 0; | 567 | found_inline = 0; |
568 | leaf_start = 0; | ||
569 | root_gen = 0; | ||
570 | root_owner = 0; | ||
565 | extent = NULL; | 571 | extent = NULL; |
566 | leaf = path->nodes[0]; | 572 | leaf = path->nodes[0]; |
567 | slot = path->slots[0]; | 573 | slot = path->slots[0]; |
@@ -628,27 +634,18 @@ next_slot: | |||
628 | search_start = extent_end; | 634 | search_start = extent_end; |
629 | if (end <= extent_end && start >= key.offset && found_inline) { | 635 | if (end <= extent_end && start >= key.offset && found_inline) { |
630 | *hint_byte = EXTENT_MAP_INLINE; | 636 | *hint_byte = EXTENT_MAP_INLINE; |
631 | continue; | 637 | goto out; |
638 | } | ||
639 | |||
640 | if (found_extent) { | ||
641 | read_extent_buffer(leaf, &old, (unsigned long)extent, | ||
642 | sizeof(old)); | ||
643 | root_gen = btrfs_header_generation(leaf); | ||
644 | root_owner = btrfs_header_owner(leaf); | ||
645 | leaf_start = leaf->start; | ||
632 | } | 646 | } |
647 | |||
633 | if (end < extent_end && end >= key.offset) { | 648 | if (end < extent_end && end >= key.offset) { |
634 | if (found_extent) { | ||
635 | u64 disk_bytenr = | ||
636 | btrfs_file_extent_disk_bytenr(leaf, extent); | ||
637 | u64 disk_num_bytes = | ||
638 | btrfs_file_extent_disk_num_bytes(leaf, | ||
639 | extent); | ||
640 | read_extent_buffer(leaf, &old, | ||
641 | (unsigned long)extent, | ||
642 | sizeof(old)); | ||
643 | if (disk_bytenr != 0) { | ||
644 | ret = btrfs_inc_extent_ref(trans, root, | ||
645 | disk_bytenr, disk_num_bytes, | ||
646 | root->root_key.objectid, | ||
647 | trans->transid, | ||
648 | key.objectid, end); | ||
649 | BUG_ON(ret); | ||
650 | } | ||
651 | } | ||
652 | bookend = 1; | 649 | bookend = 1; |
653 | if (found_inline && start <= key.offset) | 650 | if (found_inline && start <= key.offset) |
654 | keep = 1; | 651 | keep = 1; |
@@ -687,49 +684,12 @@ next_slot: | |||
687 | } | 684 | } |
688 | /* delete the entire extent */ | 685 | /* delete the entire extent */ |
689 | if (!keep) { | 686 | if (!keep) { |
690 | u64 disk_bytenr = 0; | ||
691 | u64 disk_num_bytes = 0; | ||
692 | u64 extent_num_bytes = 0; | ||
693 | u64 root_gen; | ||
694 | u64 root_owner; | ||
695 | |||
696 | root_gen = btrfs_header_generation(leaf); | ||
697 | root_owner = btrfs_header_owner(leaf); | ||
698 | if (found_extent) { | ||
699 | disk_bytenr = | ||
700 | btrfs_file_extent_disk_bytenr(leaf, | ||
701 | extent); | ||
702 | disk_num_bytes = | ||
703 | btrfs_file_extent_disk_num_bytes(leaf, | ||
704 | extent); | ||
705 | extent_num_bytes = | ||
706 | btrfs_file_extent_num_bytes(leaf, extent); | ||
707 | *hint_byte = | ||
708 | btrfs_file_extent_disk_bytenr(leaf, | ||
709 | extent); | ||
710 | } | ||
711 | ret = btrfs_del_item(trans, root, path); | 687 | ret = btrfs_del_item(trans, root, path); |
712 | /* TODO update progress marker and return */ | 688 | /* TODO update progress marker and return */ |
713 | BUG_ON(ret); | 689 | BUG_ON(ret); |
714 | btrfs_release_path(root, path); | ||
715 | extent = NULL; | 690 | extent = NULL; |
716 | if (found_extent && disk_bytenr != 0) { | 691 | btrfs_release_path(root, path); |
717 | dec_i_blocks(inode, extent_num_bytes); | 692 | /* the extent will be freed later */ |
718 | ret = btrfs_free_extent(trans, root, | ||
719 | disk_bytenr, | ||
720 | disk_num_bytes, | ||
721 | root_owner, | ||
722 | root_gen, inode->i_ino, | ||
723 | key.offset, 0); | ||
724 | } | ||
725 | |||
726 | BUG_ON(ret); | ||
727 | if (!bookend && search_start >= end) { | ||
728 | ret = 0; | ||
729 | goto out; | ||
730 | } | ||
731 | if (!bookend) | ||
732 | continue; | ||
733 | } | 693 | } |
734 | if (bookend && found_inline && start <= key.offset) { | 694 | if (bookend && found_inline && start <= key.offset) { |
735 | u32 new_size; | 695 | u32 new_size; |
@@ -737,10 +697,13 @@ next_slot: | |||
737 | extent_end - end); | 697 | extent_end - end); |
738 | dec_i_blocks(inode, (extent_end - key.offset) - | 698 | dec_i_blocks(inode, (extent_end - key.offset) - |
739 | (extent_end - end)); | 699 | (extent_end - end)); |
740 | btrfs_truncate_item(trans, root, path, new_size, 0); | 700 | ret = btrfs_truncate_item(trans, root, path, |
701 | new_size, 0); | ||
702 | BUG_ON(ret); | ||
741 | } | 703 | } |
742 | /* create bookend, splitting the extent in two */ | 704 | /* create bookend, splitting the extent in two */ |
743 | if (bookend && found_extent) { | 705 | if (bookend && found_extent) { |
706 | u64 disk_bytenr; | ||
744 | struct btrfs_key ins; | 707 | struct btrfs_key ins; |
745 | ins.objectid = inode->i_ino; | 708 | ins.objectid = inode->i_ino; |
746 | ins.offset = end; | 709 | ins.offset = end; |
@@ -748,13 +711,9 @@ next_slot: | |||
748 | btrfs_release_path(root, path); | 711 | btrfs_release_path(root, path); |
749 | ret = btrfs_insert_empty_item(trans, root, path, &ins, | 712 | ret = btrfs_insert_empty_item(trans, root, path, &ins, |
750 | sizeof(*extent)); | 713 | sizeof(*extent)); |
714 | BUG_ON(ret); | ||
751 | 715 | ||
752 | leaf = path->nodes[0]; | 716 | leaf = path->nodes[0]; |
753 | if (ret) { | ||
754 | btrfs_print_leaf(root, leaf); | ||
755 | printk("got %d on inserting %Lu %u %Lu start %Lu end %Lu found %Lu %Lu keep was %d\n", ret , ins.objectid, ins.type, ins.offset, start, end, key.offset, extent_end, keep); | ||
756 | } | ||
757 | BUG_ON(ret); | ||
758 | extent = btrfs_item_ptr(leaf, path->slots[0], | 717 | extent = btrfs_item_ptr(leaf, path->slots[0], |
759 | struct btrfs_file_extent_item); | 718 | struct btrfs_file_extent_item); |
760 | write_extent_buffer(leaf, &old, | 719 | write_extent_buffer(leaf, &old, |
@@ -770,11 +729,43 @@ next_slot: | |||
770 | BTRFS_FILE_EXTENT_REG); | 729 | BTRFS_FILE_EXTENT_REG); |
771 | 730 | ||
772 | btrfs_mark_buffer_dirty(path->nodes[0]); | 731 | btrfs_mark_buffer_dirty(path->nodes[0]); |
773 | if (le64_to_cpu(old.disk_bytenr) != 0) { | 732 | |
733 | disk_bytenr = le64_to_cpu(old.disk_bytenr); | ||
734 | if (disk_bytenr != 0) { | ||
735 | ret = btrfs_inc_extent_ref(trans, root, | ||
736 | disk_bytenr, | ||
737 | le64_to_cpu(old.disk_num_bytes), | ||
738 | leaf->start, | ||
739 | root->root_key.objectid, | ||
740 | trans->transid, | ||
741 | ins.objectid, ins.offset); | ||
742 | BUG_ON(ret); | ||
743 | } | ||
744 | btrfs_release_path(root, path); | ||
745 | if (disk_bytenr != 0) { | ||
774 | inode->i_blocks += | 746 | inode->i_blocks += |
775 | btrfs_file_extent_num_bytes(leaf, | 747 | btrfs_file_extent_num_bytes(leaf, |
776 | extent) >> 9; | 748 | extent) >> 9; |
777 | } | 749 | } |
750 | } | ||
751 | |||
752 | if (found_extent && !keep) { | ||
753 | u64 disk_bytenr = le64_to_cpu(old.disk_bytenr); | ||
754 | |||
755 | if (disk_bytenr != 0) { | ||
756 | dec_i_blocks(inode, le64_to_cpu(old.num_bytes)); | ||
757 | ret = btrfs_free_extent(trans, root, | ||
758 | disk_bytenr, | ||
759 | le64_to_cpu(old.disk_num_bytes), | ||
760 | leaf_start, root_owner, | ||
761 | root_gen, key.objectid, | ||
762 | key.offset, 0); | ||
763 | BUG_ON(ret); | ||
764 | *hint_byte = disk_bytenr; | ||
765 | } | ||
766 | } | ||
767 | |||
768 | if (search_start >= end) { | ||
778 | ret = 0; | 769 | ret = 0; |
779 | goto out; | 770 | goto out; |
780 | } | 771 | } |