diff options
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 213 |
1 files changed, 124 insertions, 89 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index e8511d14b119..3e6f0568fdb4 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -298,6 +298,7 @@ static int cow_file_range(struct inode *inode, struct page *locked_page, | |||
298 | unsigned long max_compressed = 128 * 1024; | 298 | unsigned long max_compressed = 128 * 1024; |
299 | unsigned long max_uncompressed = 256 * 1024; | 299 | unsigned long max_uncompressed = 256 * 1024; |
300 | int i; | 300 | int i; |
301 | int ordered_type; | ||
301 | int will_compress; | 302 | int will_compress; |
302 | 303 | ||
303 | trans = btrfs_join_transaction(root, 1); | 304 | trans = btrfs_join_transaction(root, 1); |
@@ -491,9 +492,10 @@ again: | |||
491 | } | 492 | } |
492 | 493 | ||
493 | cur_alloc_size = ins.offset; | 494 | cur_alloc_size = ins.offset; |
495 | ordered_type = will_compress ? BTRFS_ORDERED_COMPRESSED : 0; | ||
494 | ret = btrfs_add_ordered_extent(inode, start, ins.objectid, | 496 | ret = btrfs_add_ordered_extent(inode, start, ins.objectid, |
495 | ram_size, cur_alloc_size, 0, | 497 | ram_size, cur_alloc_size, |
496 | will_compress); | 498 | ordered_type); |
497 | BUG_ON(ret); | 499 | BUG_ON(ret); |
498 | 500 | ||
499 | if (disk_num_bytes < cur_alloc_size) { | 501 | if (disk_num_bytes < cur_alloc_size) { |
@@ -587,115 +589,148 @@ free_pages_out: | |||
587 | static int run_delalloc_nocow(struct inode *inode, struct page *locked_page, | 589 | static int run_delalloc_nocow(struct inode *inode, struct page *locked_page, |
588 | u64 start, u64 end, int *page_started) | 590 | u64 start, u64 end, int *page_started) |
589 | { | 591 | { |
590 | u64 extent_start; | ||
591 | u64 extent_end; | ||
592 | u64 bytenr; | ||
593 | u64 loops = 0; | ||
594 | u64 total_fs_bytes; | ||
595 | struct btrfs_root *root = BTRFS_I(inode)->root; | 592 | struct btrfs_root *root = BTRFS_I(inode)->root; |
596 | struct btrfs_block_group_cache *block_group; | ||
597 | struct btrfs_trans_handle *trans; | 593 | struct btrfs_trans_handle *trans; |
598 | struct extent_buffer *leaf; | 594 | struct extent_buffer *leaf; |
599 | int found_type; | ||
600 | struct btrfs_path *path; | 595 | struct btrfs_path *path; |
601 | struct btrfs_file_extent_item *item; | 596 | struct btrfs_file_extent_item *fi; |
602 | int ret; | ||
603 | int err = 0; | ||
604 | struct btrfs_key found_key; | 597 | struct btrfs_key found_key; |
598 | u64 cow_start; | ||
599 | u64 cur_offset; | ||
600 | u64 extent_end; | ||
601 | u64 disk_bytenr; | ||
602 | u64 num_bytes; | ||
603 | int extent_type; | ||
604 | int ret; | ||
605 | int nocow; | ||
606 | int check_prev = 1; | ||
605 | 607 | ||
606 | total_fs_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy); | ||
607 | path = btrfs_alloc_path(); | 608 | path = btrfs_alloc_path(); |
608 | BUG_ON(!path); | 609 | BUG_ON(!path); |
609 | trans = btrfs_join_transaction(root, 1); | 610 | trans = btrfs_join_transaction(root, 1); |
610 | BUG_ON(!trans); | 611 | BUG_ON(!trans); |
611 | again: | ||
612 | ret = btrfs_lookup_file_extent(NULL, root, path, | ||
613 | inode->i_ino, start, 0); | ||
614 | if (ret < 0) { | ||
615 | err = ret; | ||
616 | goto out; | ||
617 | } | ||
618 | |||
619 | if (ret != 0) { | ||
620 | if (path->slots[0] == 0) | ||
621 | goto not_found; | ||
622 | path->slots[0]--; | ||
623 | } | ||
624 | |||
625 | leaf = path->nodes[0]; | ||
626 | item = btrfs_item_ptr(leaf, path->slots[0], | ||
627 | struct btrfs_file_extent_item); | ||
628 | |||
629 | /* are we inside the extent that was found? */ | ||
630 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); | ||
631 | found_type = btrfs_key_type(&found_key); | ||
632 | if (found_key.objectid != inode->i_ino || | ||
633 | found_type != BTRFS_EXTENT_DATA_KEY) | ||
634 | goto not_found; | ||
635 | |||
636 | found_type = btrfs_file_extent_type(leaf, item); | ||
637 | extent_start = found_key.offset; | ||
638 | if (found_type == BTRFS_FILE_EXTENT_REG) { | ||
639 | u64 extent_num_bytes; | ||
640 | |||
641 | extent_num_bytes = btrfs_file_extent_num_bytes(leaf, item); | ||
642 | extent_end = extent_start + extent_num_bytes; | ||
643 | err = 0; | ||
644 | 612 | ||
645 | if (btrfs_file_extent_compression(leaf, item) || | 613 | cow_start = (u64)-1; |
646 | btrfs_file_extent_encryption(leaf,item) || | 614 | cur_offset = start; |
647 | btrfs_file_extent_other_encoding(leaf, item)) | 615 | while (1) { |
648 | goto not_found; | 616 | ret = btrfs_lookup_file_extent(trans, root, path, inode->i_ino, |
617 | cur_offset, 0); | ||
618 | BUG_ON(ret < 0); | ||
619 | if (ret > 0 && path->slots[0] > 0 && check_prev) { | ||
620 | leaf = path->nodes[0]; | ||
621 | btrfs_item_key_to_cpu(leaf, &found_key, | ||
622 | path->slots[0] - 1); | ||
623 | if (found_key.objectid == inode->i_ino && | ||
624 | found_key.type == BTRFS_EXTENT_DATA_KEY) | ||
625 | path->slots[0]--; | ||
626 | } | ||
627 | check_prev = 0; | ||
628 | next_slot: | ||
629 | leaf = path->nodes[0]; | ||
630 | if (path->slots[0] >= btrfs_header_nritems(leaf)) { | ||
631 | ret = btrfs_next_leaf(root, path); | ||
632 | if (ret < 0) | ||
633 | BUG_ON(1); | ||
634 | if (ret > 0) | ||
635 | break; | ||
636 | leaf = path->nodes[0]; | ||
637 | } | ||
649 | 638 | ||
650 | if (loops && start != extent_start) | 639 | nocow = 0; |
651 | goto not_found; | 640 | disk_bytenr = 0; |
641 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); | ||
652 | 642 | ||
653 | if (start < extent_start || start >= extent_end) | 643 | if (found_key.objectid > inode->i_ino || |
654 | goto not_found; | 644 | found_key.type > BTRFS_EXTENT_DATA_KEY || |
645 | found_key.offset > end) | ||
646 | break; | ||
655 | 647 | ||
656 | bytenr = btrfs_file_extent_disk_bytenr(leaf, item); | 648 | if (found_key.offset > cur_offset) { |
657 | if (bytenr == 0) | 649 | extent_end = found_key.offset; |
658 | goto not_found; | 650 | goto out_check; |
651 | } | ||
659 | 652 | ||
660 | if (btrfs_cross_ref_exists(trans, root, &found_key, bytenr)) | 653 | fi = btrfs_item_ptr(leaf, path->slots[0], |
661 | goto not_found; | 654 | struct btrfs_file_extent_item); |
662 | /* | 655 | extent_type = btrfs_file_extent_type(leaf, fi); |
663 | * we may be called by the resizer, make sure we're inside | ||
664 | * the limits of the FS | ||
665 | */ | ||
666 | block_group = btrfs_lookup_block_group(root->fs_info, | ||
667 | bytenr); | ||
668 | if (!block_group || block_group->ro) | ||
669 | goto not_found; | ||
670 | 656 | ||
671 | bytenr += btrfs_file_extent_offset(leaf, item); | 657 | if (extent_type == BTRFS_FILE_EXTENT_REG) { |
672 | extent_num_bytes = min(end + 1, extent_end) - start; | 658 | struct btrfs_block_group_cache *block_group; |
673 | ret = btrfs_add_ordered_extent(inode, start, bytenr, | 659 | disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); |
674 | extent_num_bytes, | 660 | extent_end = found_key.offset + |
675 | extent_num_bytes, 1, 0); | 661 | btrfs_file_extent_num_bytes(leaf, fi); |
676 | if (ret) { | 662 | if (extent_end <= start) { |
677 | err = ret; | 663 | path->slots[0]++; |
678 | goto out; | 664 | goto next_slot; |
665 | } | ||
666 | if (btrfs_file_extent_compression(leaf, fi) || | ||
667 | btrfs_file_extent_encryption(leaf, fi) || | ||
668 | btrfs_file_extent_other_encoding(leaf, fi)) | ||
669 | goto out_check; | ||
670 | if (disk_bytenr == 0) | ||
671 | goto out_check; | ||
672 | if (btrfs_cross_ref_exist(trans, root, disk_bytenr)) | ||
673 | goto out_check; | ||
674 | block_group = btrfs_lookup_block_group(root->fs_info, | ||
675 | disk_bytenr); | ||
676 | if (!block_group || block_group->ro) | ||
677 | goto out_check; | ||
678 | disk_bytenr += btrfs_file_extent_offset(leaf, fi); | ||
679 | nocow = 1; | ||
680 | } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) { | ||
681 | extent_end = found_key.offset + | ||
682 | btrfs_file_extent_inline_len(leaf, fi); | ||
683 | extent_end = ALIGN(extent_end, root->sectorsize); | ||
684 | } else { | ||
685 | BUG_ON(1); | ||
686 | } | ||
687 | out_check: | ||
688 | if (extent_end <= start) { | ||
689 | path->slots[0]++; | ||
690 | goto next_slot; | ||
691 | } | ||
692 | if (!nocow) { | ||
693 | if (cow_start == (u64)-1) | ||
694 | cow_start = cur_offset; | ||
695 | cur_offset = extent_end; | ||
696 | if (cur_offset > end) | ||
697 | break; | ||
698 | path->slots[0]++; | ||
699 | goto next_slot; | ||
679 | } | 700 | } |
680 | 701 | ||
681 | btrfs_release_path(root, path); | 702 | btrfs_release_path(root, path); |
682 | start = extent_end; | 703 | if (cow_start != (u64)-1) { |
683 | if (start <= end) { | 704 | ret = cow_file_range(inode, locked_page, cow_start, |
684 | loops++; | 705 | found_key.offset - 1, page_started); |
685 | goto again; | 706 | BUG_ON(ret); |
707 | cow_start = (u64)-1; | ||
686 | } | 708 | } |
687 | } else { | 709 | |
688 | not_found: | 710 | disk_bytenr += cur_offset - found_key.offset; |
689 | btrfs_end_transaction(trans, root); | 711 | num_bytes = min(end + 1, extent_end) - cur_offset; |
690 | btrfs_free_path(path); | 712 | |
691 | return cow_file_range(inode, locked_page, start, end, | 713 | ret = btrfs_add_ordered_extent(inode, cur_offset, disk_bytenr, |
692 | page_started); | 714 | num_bytes, num_bytes, |
715 | BTRFS_ORDERED_NOCOW); | ||
716 | cur_offset = extent_end; | ||
717 | if (cur_offset > end) | ||
718 | break; | ||
693 | } | 719 | } |
694 | out: | 720 | btrfs_release_path(root, path); |
695 | WARN_ON(err); | 721 | |
696 | btrfs_end_transaction(trans, root); | 722 | if (cur_offset <= end && cow_start == (u64)-1) |
723 | cow_start = cur_offset; | ||
724 | if (cow_start != (u64)-1) { | ||
725 | ret = cow_file_range(inode, locked_page, cow_start, end, | ||
726 | page_started); | ||
727 | BUG_ON(ret); | ||
728 | } | ||
729 | |||
730 | ret = btrfs_end_transaction(trans, root); | ||
731 | BUG_ON(ret); | ||
697 | btrfs_free_path(path); | 732 | btrfs_free_path(path); |
698 | return err; | 733 | return 0; |
699 | } | 734 | } |
700 | 735 | ||
701 | /* | 736 | /* |