diff options
author | Yan Zheng <zheng.yan@oracle.com> | 2008-10-30 14:20:02 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-10-30 14:20:02 -0400 |
commit | 80ff385665b7fca29fefe358a60ab0d09f9b8e87 (patch) | |
tree | 8a801d3f268d289b62f8dac87df8b757fb3b19d4 | |
parent | 6643558db29006825dbb10012b3f8890aca4bcd5 (diff) |
Btrfs: update nodatacow code v2
This patch simplifies the nodatacow checker. If all references
were created after the latest snapshot, then we can avoid COW
safely. This patch also updates run_delalloc_nocow to do more
fine-grained checking.
Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
-rw-r--r-- | fs/btrfs/ctree.h | 8 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 131 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 213 | ||||
-rw-r--r-- | fs/btrfs/ioctl.c | 1 | ||||
-rw-r--r-- | fs/btrfs/ordered-data.c | 9 | ||||
-rw-r--r-- | fs/btrfs/ordered-data.h | 3 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 2 |
7 files changed, 154 insertions, 213 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index ca5547af6090..8bf6a085a730 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -454,6 +454,7 @@ struct btrfs_root_item { | |||
454 | __le64 bytenr; | 454 | __le64 bytenr; |
455 | __le64 byte_limit; | 455 | __le64 byte_limit; |
456 | __le64 bytes_used; | 456 | __le64 bytes_used; |
457 | __le64 last_snapshot; | ||
457 | __le32 flags; | 458 | __le32 flags; |
458 | __le32 refs; | 459 | __le32 refs; |
459 | struct btrfs_disk_key drop_progress; | 460 | struct btrfs_disk_key drop_progress; |
@@ -1413,6 +1414,8 @@ BTRFS_SETGET_STACK_FUNCS(root_refs, struct btrfs_root_item, refs, 32); | |||
1413 | BTRFS_SETGET_STACK_FUNCS(root_flags, struct btrfs_root_item, flags, 32); | 1414 | BTRFS_SETGET_STACK_FUNCS(root_flags, struct btrfs_root_item, flags, 32); |
1414 | BTRFS_SETGET_STACK_FUNCS(root_used, struct btrfs_root_item, bytes_used, 64); | 1415 | BTRFS_SETGET_STACK_FUNCS(root_used, struct btrfs_root_item, bytes_used, 64); |
1415 | BTRFS_SETGET_STACK_FUNCS(root_limit, struct btrfs_root_item, byte_limit, 64); | 1416 | BTRFS_SETGET_STACK_FUNCS(root_limit, struct btrfs_root_item, byte_limit, 64); |
1417 | BTRFS_SETGET_STACK_FUNCS(root_last_snapshot, struct btrfs_root_item, | ||
1418 | last_snapshot, 64); | ||
1416 | 1419 | ||
1417 | /* struct btrfs_super_block */ | 1420 | /* struct btrfs_super_block */ |
1418 | BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64); | 1421 | BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64); |
@@ -1564,9 +1567,8 @@ int btrfs_update_pinned_extents(struct btrfs_root *root, | |||
1564 | u64 bytenr, u64 num, int pin); | 1567 | u64 bytenr, u64 num, int pin); |
1565 | int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans, | 1568 | int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans, |
1566 | struct btrfs_root *root, struct extent_buffer *leaf); | 1569 | struct btrfs_root *root, struct extent_buffer *leaf); |
1567 | int btrfs_cross_ref_exists(struct btrfs_trans_handle *trans, | 1570 | int btrfs_cross_ref_exist(struct btrfs_trans_handle *trans, |
1568 | struct btrfs_root *root, | 1571 | struct btrfs_root *root, u64 bytenr); |
1569 | struct btrfs_key *key, u64 bytenr); | ||
1570 | int btrfs_extent_post_op(struct btrfs_trans_handle *trans, | 1572 | int btrfs_extent_post_op(struct btrfs_trans_handle *trans, |
1571 | struct btrfs_root *root); | 1573 | struct btrfs_root *root); |
1572 | int btrfs_copy_pinned(struct btrfs_root *root, struct extent_io_tree *copy); | 1574 | int btrfs_copy_pinned(struct btrfs_root *root, struct extent_io_tree *copy); |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 535cee47fcfb..1eb69a91b727 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -848,9 +848,8 @@ out: | |||
848 | return 0; | 848 | return 0; |
849 | } | 849 | } |
850 | 850 | ||
851 | static int get_reference_status(struct btrfs_root *root, u64 bytenr, | 851 | int btrfs_cross_ref_exist(struct btrfs_trans_handle *trans, |
852 | u64 parent_gen, u64 ref_objectid, | 852 | struct btrfs_root *root, u64 bytenr) |
853 | u64 *min_generation, u32 *ref_count) | ||
854 | { | 853 | { |
855 | struct btrfs_root *extent_root = root->fs_info->extent_root; | 854 | struct btrfs_root *extent_root = root->fs_info->extent_root; |
856 | struct btrfs_path *path; | 855 | struct btrfs_path *path; |
@@ -858,8 +857,8 @@ static int get_reference_status(struct btrfs_root *root, u64 bytenr, | |||
858 | struct btrfs_extent_ref *ref_item; | 857 | struct btrfs_extent_ref *ref_item; |
859 | struct btrfs_key key; | 858 | struct btrfs_key key; |
860 | struct btrfs_key found_key; | 859 | struct btrfs_key found_key; |
861 | u64 root_objectid = root->root_key.objectid; | 860 | u64 ref_root; |
862 | u64 ref_generation; | 861 | u64 last_snapshot; |
863 | u32 nritems; | 862 | u32 nritems; |
864 | int ret; | 863 | int ret; |
865 | 864 | ||
@@ -872,7 +871,9 @@ static int get_reference_status(struct btrfs_root *root, u64 bytenr, | |||
872 | if (ret < 0) | 871 | if (ret < 0) |
873 | goto out; | 872 | goto out; |
874 | BUG_ON(ret == 0); | 873 | BUG_ON(ret == 0); |
875 | if (ret < 0 || path->slots[0] == 0) | 874 | |
875 | ret = -ENOENT; | ||
876 | if (path->slots[0] == 0) | ||
876 | goto out; | 877 | goto out; |
877 | 878 | ||
878 | path->slots[0]--; | 879 | path->slots[0]--; |
@@ -880,14 +881,10 @@ static int get_reference_status(struct btrfs_root *root, u64 bytenr, | |||
880 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); | 881 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); |
881 | 882 | ||
882 | if (found_key.objectid != bytenr || | 883 | if (found_key.objectid != bytenr || |
883 | found_key.type != BTRFS_EXTENT_ITEM_KEY) { | 884 | found_key.type != BTRFS_EXTENT_ITEM_KEY) |
884 | ret = 1; | ||
885 | goto out; | 885 | goto out; |
886 | } | ||
887 | |||
888 | *ref_count = 0; | ||
889 | *min_generation = (u64)-1; | ||
890 | 886 | ||
887 | last_snapshot = btrfs_root_last_snapshot(&root->root_item); | ||
891 | while (1) { | 888 | while (1) { |
892 | leaf = path->nodes[0]; | 889 | leaf = path->nodes[0]; |
893 | nritems = btrfs_header_nritems(leaf); | 890 | nritems = btrfs_header_nritems(leaf); |
@@ -910,114 +907,22 @@ static int get_reference_status(struct btrfs_root *root, u64 bytenr, | |||
910 | 907 | ||
911 | ref_item = btrfs_item_ptr(leaf, path->slots[0], | 908 | ref_item = btrfs_item_ptr(leaf, path->slots[0], |
912 | struct btrfs_extent_ref); | 909 | struct btrfs_extent_ref); |
913 | ref_generation = btrfs_ref_generation(leaf, ref_item); | 910 | ref_root = btrfs_ref_root(leaf, ref_item); |
914 | /* | 911 | if (ref_root != root->root_key.objectid && |
915 | * For (parent_gen > 0 && parent_gen > ref_generation): | 912 | ref_root != BTRFS_TREE_LOG_OBJECTID) { |
916 | * | 913 | ret = 1; |
917 | * we reach here through the oldest root, therefore | ||
918 | * all other reference from same snapshot should have | ||
919 | * a larger generation. | ||
920 | */ | ||
921 | if ((root_objectid != btrfs_ref_root(leaf, ref_item)) || | ||
922 | (parent_gen > 0 && parent_gen > ref_generation) || | ||
923 | (ref_objectid >= BTRFS_FIRST_FREE_OBJECTID && | ||
924 | ref_objectid != btrfs_ref_objectid(leaf, ref_item))) { | ||
925 | *ref_count = 2; | ||
926 | break; | ||
927 | } | ||
928 | |||
929 | *ref_count = 1; | ||
930 | if (*min_generation > ref_generation) | ||
931 | *min_generation = ref_generation; | ||
932 | |||
933 | path->slots[0]++; | ||
934 | } | ||
935 | ret = 0; | ||
936 | out: | ||
937 | btrfs_free_path(path); | ||
938 | return ret; | ||
939 | } | ||
940 | |||
941 | int btrfs_cross_ref_exists(struct btrfs_trans_handle *trans, | ||
942 | struct btrfs_root *root, | ||
943 | struct btrfs_key *key, u64 bytenr) | ||
944 | { | ||
945 | struct btrfs_root *old_root; | ||
946 | struct btrfs_path *path = NULL; | ||
947 | struct extent_buffer *eb; | ||
948 | struct btrfs_file_extent_item *item; | ||
949 | u64 ref_generation; | ||
950 | u64 min_generation; | ||
951 | u64 extent_start; | ||
952 | u32 ref_count; | ||
953 | int level; | ||
954 | int ret; | ||
955 | |||
956 | BUG_ON(trans == NULL); | ||
957 | BUG_ON(key->type != BTRFS_EXTENT_DATA_KEY); | ||
958 | ret = get_reference_status(root, bytenr, 0, key->objectid, | ||
959 | &min_generation, &ref_count); | ||
960 | if (ret) | ||
961 | return ret; | ||
962 | |||
963 | if (ref_count != 1) | ||
964 | return 1; | ||
965 | |||
966 | old_root = root->dirty_root->root; | ||
967 | ref_generation = old_root->root_key.offset; | ||
968 | |||
969 | /* all references are created in running transaction */ | ||
970 | if (min_generation > ref_generation) { | ||
971 | ret = 0; | ||
972 | goto out; | ||
973 | } | ||
974 | |||
975 | path = btrfs_alloc_path(); | ||
976 | if (!path) { | ||
977 | ret = -ENOMEM; | ||
978 | goto out; | ||
979 | } | ||
980 | |||
981 | path->skip_locking = 1; | ||
982 | /* if no item found, the extent is referenced by other snapshot */ | ||
983 | ret = btrfs_search_slot(NULL, old_root, key, path, 0, 0); | ||
984 | if (ret) | ||
985 | goto out; | ||
986 | |||
987 | eb = path->nodes[0]; | ||
988 | item = btrfs_item_ptr(eb, path->slots[0], | ||
989 | struct btrfs_file_extent_item); | ||
990 | if (btrfs_file_extent_type(eb, item) != BTRFS_FILE_EXTENT_REG || | ||
991 | btrfs_file_extent_disk_bytenr(eb, item) != bytenr) { | ||
992 | ret = 1; | ||
993 | goto out; | ||
994 | } | ||
995 | |||
996 | for (level = BTRFS_MAX_LEVEL - 1; level >= -1; level--) { | ||
997 | if (level >= 0) { | ||
998 | eb = path->nodes[level]; | ||
999 | if (!eb) | ||
1000 | continue; | ||
1001 | extent_start = eb->start; | ||
1002 | } else | ||
1003 | extent_start = bytenr; | ||
1004 | |||
1005 | ret = get_reference_status(root, extent_start, ref_generation, | ||
1006 | 0, &min_generation, &ref_count); | ||
1007 | if (ret) | ||
1008 | goto out; | 914 | goto out; |
1009 | 915 | } | |
1010 | if (ref_count != 1) { | 916 | if (btrfs_ref_generation(leaf, ref_item) <= last_snapshot) { |
1011 | ret = 1; | 917 | ret = 1; |
1012 | goto out; | 918 | goto out; |
1013 | } | 919 | } |
1014 | if (level >= 0) | 920 | |
1015 | ref_generation = btrfs_header_generation(eb); | 921 | path->slots[0]++; |
1016 | } | 922 | } |
1017 | ret = 0; | 923 | ret = 0; |
1018 | out: | 924 | out: |
1019 | if (path) | 925 | btrfs_free_path(path); |
1020 | btrfs_free_path(path); | ||
1021 | return ret; | 926 | return ret; |
1022 | } | 927 | } |
1023 | 928 | ||
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 | /* |
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index fd3c8b5676c1..7f915d478399 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -112,6 +112,7 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
112 | btrfs_set_root_level(&root_item, 0); | 112 | btrfs_set_root_level(&root_item, 0); |
113 | btrfs_set_root_refs(&root_item, 1); | 113 | btrfs_set_root_refs(&root_item, 1); |
114 | btrfs_set_root_used(&root_item, 0); | 114 | btrfs_set_root_used(&root_item, 0); |
115 | btrfs_set_root_last_snapshot(&root_item, 0); | ||
115 | 116 | ||
116 | memset(&root_item.drop_progress, 0, sizeof(root_item.drop_progress)); | 117 | memset(&root_item.drop_progress, 0, sizeof(root_item.drop_progress)); |
117 | root_item.drop_level = 0; | 118 | root_item.drop_level = 0; |
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index b5745bb96d40..e7317c8fda29 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c | |||
@@ -165,8 +165,7 @@ static inline struct rb_node *tree_search(struct btrfs_ordered_inode_tree *tree, | |||
165 | * inserted. | 165 | * inserted. |
166 | */ | 166 | */ |
167 | int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, | 167 | int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, |
168 | u64 start, u64 len, u64 disk_len, int nocow, | 168 | u64 start, u64 len, u64 disk_len, int type) |
169 | int compressed) | ||
170 | { | 169 | { |
171 | struct btrfs_ordered_inode_tree *tree; | 170 | struct btrfs_ordered_inode_tree *tree; |
172 | struct rb_node *node; | 171 | struct rb_node *node; |
@@ -183,10 +182,8 @@ int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, | |||
183 | entry->len = len; | 182 | entry->len = len; |
184 | entry->disk_len = disk_len; | 183 | entry->disk_len = disk_len; |
185 | entry->inode = inode; | 184 | entry->inode = inode; |
186 | if (nocow) | 185 | if (type == BTRFS_ORDERED_NOCOW || type == BTRFS_ORDERED_COMPRESSED) |
187 | set_bit(BTRFS_ORDERED_NOCOW, &entry->flags); | 186 | set_bit(type, &entry->flags); |
188 | if (compressed) | ||
189 | set_bit(BTRFS_ORDERED_COMPRESSED, &entry->flags); | ||
190 | 187 | ||
191 | /* one ref for the tree */ | 188 | /* one ref for the tree */ |
192 | atomic_set(&entry->refs, 1); | 189 | atomic_set(&entry->refs, 1); |
diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h index 1ef464145d22..e6d9bc54c2b1 100644 --- a/fs/btrfs/ordered-data.h +++ b/fs/btrfs/ordered-data.h | |||
@@ -132,8 +132,7 @@ int btrfs_remove_ordered_extent(struct inode *inode, | |||
132 | int btrfs_dec_test_ordered_pending(struct inode *inode, | 132 | int btrfs_dec_test_ordered_pending(struct inode *inode, |
133 | u64 file_offset, u64 io_size); | 133 | u64 file_offset, u64 io_size); |
134 | int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, | 134 | int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, |
135 | u64 start, u64 len, u64 disk_len, int nocow, | 135 | u64 start, u64 len, u64 disk_len, int type); |
136 | int compressed); | ||
137 | int btrfs_add_ordered_sum(struct inode *inode, | 136 | int btrfs_add_ordered_sum(struct inode *inode, |
138 | struct btrfs_ordered_extent *entry, | 137 | struct btrfs_ordered_extent *entry, |
139 | struct btrfs_ordered_sum *sum); | 138 | struct btrfs_ordered_sum *sum); |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 968b84f17a19..e72a013d24bf 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -763,6 +763,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
763 | if (ret) | 763 | if (ret) |
764 | goto fail; | 764 | goto fail; |
765 | 765 | ||
766 | btrfs_record_root_in_trans(root); | ||
767 | btrfs_set_root_last_snapshot(&root->root_item, trans->transid); | ||
766 | memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); | 768 | memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); |
767 | 769 | ||
768 | key.objectid = objectid; | 770 | key.objectid = objectid; |