aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r--fs/btrfs/inode.c213
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:
587static int run_delalloc_nocow(struct inode *inode, struct page *locked_page, 589static 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);
611again:
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;
628next_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 }
687out_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
688not_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 }
694out: 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/*