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 /fs | |
| 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>
Diffstat (limited to 'fs')
| -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 ca5547af609..8bf6a085a73 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 535cee47fcf..1eb69a91b72 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 e8511d14b11..3e6f0568fdb 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 fd3c8b5676c..7f915d47839 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 b5745bb96d4..e7317c8fda2 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 1ef464145d2..e6d9bc54c2b 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 968b84f17a1..e72a013d24b 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; |
