diff options
Diffstat (limited to 'fs/btrfs/send.c')
-rw-r--r-- | fs/btrfs/send.c | 240 |
1 files changed, 192 insertions, 48 deletions
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 2e14fd89a8b4..e46e0ed74925 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/radix-tree.h> | 26 | #include <linux/radix-tree.h> |
27 | #include <linux/crc32c.h> | 27 | #include <linux/crc32c.h> |
28 | #include <linux/vmalloc.h> | 28 | #include <linux/vmalloc.h> |
29 | #include <linux/string.h> | ||
29 | 30 | ||
30 | #include "send.h" | 31 | #include "send.h" |
31 | #include "backref.h" | 32 | #include "backref.h" |
@@ -54,8 +55,8 @@ struct fs_path { | |||
54 | 55 | ||
55 | char *buf; | 56 | char *buf; |
56 | int buf_len; | 57 | int buf_len; |
57 | int reversed:1; | 58 | unsigned int reversed:1; |
58 | int virtual_mem:1; | 59 | unsigned int virtual_mem:1; |
59 | char inline_buf[]; | 60 | char inline_buf[]; |
60 | }; | 61 | }; |
61 | char pad[PAGE_SIZE]; | 62 | char pad[PAGE_SIZE]; |
@@ -1668,6 +1669,7 @@ static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen, | |||
1668 | u64 *who_ino, u64 *who_gen) | 1669 | u64 *who_ino, u64 *who_gen) |
1669 | { | 1670 | { |
1670 | int ret = 0; | 1671 | int ret = 0; |
1672 | u64 gen; | ||
1671 | u64 other_inode = 0; | 1673 | u64 other_inode = 0; |
1672 | u8 other_type = 0; | 1674 | u8 other_type = 0; |
1673 | 1675 | ||
@@ -1678,6 +1680,24 @@ static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen, | |||
1678 | if (ret <= 0) | 1680 | if (ret <= 0) |
1679 | goto out; | 1681 | goto out; |
1680 | 1682 | ||
1683 | /* | ||
1684 | * If we have a parent root we need to verify that the parent dir was | ||
1685 | * not delted and then re-created, if it was then we have no overwrite | ||
1686 | * and we can just unlink this entry. | ||
1687 | */ | ||
1688 | if (sctx->parent_root) { | ||
1689 | ret = get_inode_info(sctx->parent_root, dir, NULL, &gen, NULL, | ||
1690 | NULL, NULL, NULL); | ||
1691 | if (ret < 0 && ret != -ENOENT) | ||
1692 | goto out; | ||
1693 | if (ret) { | ||
1694 | ret = 0; | ||
1695 | goto out; | ||
1696 | } | ||
1697 | if (gen != dir_gen) | ||
1698 | goto out; | ||
1699 | } | ||
1700 | |||
1681 | ret = lookup_dir_item_inode(sctx->parent_root, dir, name, name_len, | 1701 | ret = lookup_dir_item_inode(sctx->parent_root, dir, name, name_len, |
1682 | &other_inode, &other_type); | 1702 | &other_inode, &other_type); |
1683 | if (ret < 0 && ret != -ENOENT) | 1703 | if (ret < 0 && ret != -ENOENT) |
@@ -2519,7 +2539,8 @@ static int did_create_dir(struct send_ctx *sctx, u64 dir) | |||
2519 | di = btrfs_item_ptr(eb, slot, struct btrfs_dir_item); | 2539 | di = btrfs_item_ptr(eb, slot, struct btrfs_dir_item); |
2520 | btrfs_dir_item_key_to_cpu(eb, di, &di_key); | 2540 | btrfs_dir_item_key_to_cpu(eb, di, &di_key); |
2521 | 2541 | ||
2522 | if (di_key.objectid < sctx->send_progress) { | 2542 | if (di_key.type != BTRFS_ROOT_ITEM_KEY && |
2543 | di_key.objectid < sctx->send_progress) { | ||
2523 | ret = 1; | 2544 | ret = 1; |
2524 | goto out; | 2545 | goto out; |
2525 | } | 2546 | } |
@@ -2581,7 +2602,6 @@ static int record_ref(struct list_head *head, u64 dir, | |||
2581 | u64 dir_gen, struct fs_path *path) | 2602 | u64 dir_gen, struct fs_path *path) |
2582 | { | 2603 | { |
2583 | struct recorded_ref *ref; | 2604 | struct recorded_ref *ref; |
2584 | char *tmp; | ||
2585 | 2605 | ||
2586 | ref = kmalloc(sizeof(*ref), GFP_NOFS); | 2606 | ref = kmalloc(sizeof(*ref), GFP_NOFS); |
2587 | if (!ref) | 2607 | if (!ref) |
@@ -2591,25 +2611,35 @@ static int record_ref(struct list_head *head, u64 dir, | |||
2591 | ref->dir_gen = dir_gen; | 2611 | ref->dir_gen = dir_gen; |
2592 | ref->full_path = path; | 2612 | ref->full_path = path; |
2593 | 2613 | ||
2594 | tmp = strrchr(ref->full_path->start, '/'); | 2614 | ref->name = (char *)kbasename(ref->full_path->start); |
2595 | if (!tmp) { | 2615 | ref->name_len = ref->full_path->end - ref->name; |
2596 | ref->name_len = ref->full_path->end - ref->full_path->start; | 2616 | ref->dir_path = ref->full_path->start; |
2597 | ref->name = ref->full_path->start; | 2617 | if (ref->name == ref->full_path->start) |
2598 | ref->dir_path_len = 0; | 2618 | ref->dir_path_len = 0; |
2599 | ref->dir_path = ref->full_path->start; | 2619 | else |
2600 | } else { | ||
2601 | tmp++; | ||
2602 | ref->name_len = ref->full_path->end - tmp; | ||
2603 | ref->name = tmp; | ||
2604 | ref->dir_path = ref->full_path->start; | ||
2605 | ref->dir_path_len = ref->full_path->end - | 2620 | ref->dir_path_len = ref->full_path->end - |
2606 | ref->full_path->start - 1 - ref->name_len; | 2621 | ref->full_path->start - 1 - ref->name_len; |
2607 | } | ||
2608 | 2622 | ||
2609 | list_add_tail(&ref->list, head); | 2623 | list_add_tail(&ref->list, head); |
2610 | return 0; | 2624 | return 0; |
2611 | } | 2625 | } |
2612 | 2626 | ||
2627 | static int dup_ref(struct recorded_ref *ref, struct list_head *list) | ||
2628 | { | ||
2629 | struct recorded_ref *new; | ||
2630 | |||
2631 | new = kmalloc(sizeof(*ref), GFP_NOFS); | ||
2632 | if (!new) | ||
2633 | return -ENOMEM; | ||
2634 | |||
2635 | new->dir = ref->dir; | ||
2636 | new->dir_gen = ref->dir_gen; | ||
2637 | new->full_path = NULL; | ||
2638 | INIT_LIST_HEAD(&new->list); | ||
2639 | list_add_tail(&new->list, list); | ||
2640 | return 0; | ||
2641 | } | ||
2642 | |||
2613 | static void __free_recorded_refs(struct list_head *head) | 2643 | static void __free_recorded_refs(struct list_head *head) |
2614 | { | 2644 | { |
2615 | struct recorded_ref *cur; | 2645 | struct recorded_ref *cur; |
@@ -2724,9 +2754,7 @@ static int process_recorded_refs(struct send_ctx *sctx) | |||
2724 | int ret = 0; | 2754 | int ret = 0; |
2725 | struct recorded_ref *cur; | 2755 | struct recorded_ref *cur; |
2726 | struct recorded_ref *cur2; | 2756 | struct recorded_ref *cur2; |
2727 | struct ulist *check_dirs = NULL; | 2757 | struct list_head check_dirs; |
2728 | struct ulist_iterator uit; | ||
2729 | struct ulist_node *un; | ||
2730 | struct fs_path *valid_path = NULL; | 2758 | struct fs_path *valid_path = NULL; |
2731 | u64 ow_inode = 0; | 2759 | u64 ow_inode = 0; |
2732 | u64 ow_gen; | 2760 | u64 ow_gen; |
@@ -2740,6 +2768,7 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino); | |||
2740 | * which is always '..' | 2768 | * which is always '..' |
2741 | */ | 2769 | */ |
2742 | BUG_ON(sctx->cur_ino <= BTRFS_FIRST_FREE_OBJECTID); | 2770 | BUG_ON(sctx->cur_ino <= BTRFS_FIRST_FREE_OBJECTID); |
2771 | INIT_LIST_HEAD(&check_dirs); | ||
2743 | 2772 | ||
2744 | valid_path = fs_path_alloc(); | 2773 | valid_path = fs_path_alloc(); |
2745 | if (!valid_path) { | 2774 | if (!valid_path) { |
@@ -2747,12 +2776,6 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino); | |||
2747 | goto out; | 2776 | goto out; |
2748 | } | 2777 | } |
2749 | 2778 | ||
2750 | check_dirs = ulist_alloc(GFP_NOFS); | ||
2751 | if (!check_dirs) { | ||
2752 | ret = -ENOMEM; | ||
2753 | goto out; | ||
2754 | } | ||
2755 | |||
2756 | /* | 2779 | /* |
2757 | * First, check if the first ref of the current inode was overwritten | 2780 | * First, check if the first ref of the current inode was overwritten |
2758 | * before. If yes, we know that the current inode was already orphanized | 2781 | * before. If yes, we know that the current inode was already orphanized |
@@ -2889,8 +2912,7 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino); | |||
2889 | goto out; | 2912 | goto out; |
2890 | } | 2913 | } |
2891 | } | 2914 | } |
2892 | ret = ulist_add(check_dirs, cur->dir, cur->dir_gen, | 2915 | ret = dup_ref(cur, &check_dirs); |
2893 | GFP_NOFS); | ||
2894 | if (ret < 0) | 2916 | if (ret < 0) |
2895 | goto out; | 2917 | goto out; |
2896 | } | 2918 | } |
@@ -2918,8 +2940,7 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino); | |||
2918 | } | 2940 | } |
2919 | 2941 | ||
2920 | list_for_each_entry(cur, &sctx->deleted_refs, list) { | 2942 | list_for_each_entry(cur, &sctx->deleted_refs, list) { |
2921 | ret = ulist_add(check_dirs, cur->dir, cur->dir_gen, | 2943 | ret = dup_ref(cur, &check_dirs); |
2922 | GFP_NOFS); | ||
2923 | if (ret < 0) | 2944 | if (ret < 0) |
2924 | goto out; | 2945 | goto out; |
2925 | } | 2946 | } |
@@ -2930,8 +2951,7 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino); | |||
2930 | */ | 2951 | */ |
2931 | cur = list_entry(sctx->deleted_refs.next, struct recorded_ref, | 2952 | cur = list_entry(sctx->deleted_refs.next, struct recorded_ref, |
2932 | list); | 2953 | list); |
2933 | ret = ulist_add(check_dirs, cur->dir, cur->dir_gen, | 2954 | ret = dup_ref(cur, &check_dirs); |
2934 | GFP_NOFS); | ||
2935 | if (ret < 0) | 2955 | if (ret < 0) |
2936 | goto out; | 2956 | goto out; |
2937 | } else if (!S_ISDIR(sctx->cur_inode_mode)) { | 2957 | } else if (!S_ISDIR(sctx->cur_inode_mode)) { |
@@ -2951,12 +2971,10 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino); | |||
2951 | if (ret < 0) | 2971 | if (ret < 0) |
2952 | goto out; | 2972 | goto out; |
2953 | } | 2973 | } |
2954 | ret = ulist_add(check_dirs, cur->dir, cur->dir_gen, | 2974 | ret = dup_ref(cur, &check_dirs); |
2955 | GFP_NOFS); | ||
2956 | if (ret < 0) | 2975 | if (ret < 0) |
2957 | goto out; | 2976 | goto out; |
2958 | } | 2977 | } |
2959 | |||
2960 | /* | 2978 | /* |
2961 | * If the inode is still orphan, unlink the orphan. This may | 2979 | * If the inode is still orphan, unlink the orphan. This may |
2962 | * happen when a previous inode did overwrite the first ref | 2980 | * happen when a previous inode did overwrite the first ref |
@@ -2978,33 +2996,32 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino); | |||
2978 | * deletion and if it's finally possible to perform the rmdir now. | 2996 | * deletion and if it's finally possible to perform the rmdir now. |
2979 | * We also update the inode stats of the parent dirs here. | 2997 | * We also update the inode stats of the parent dirs here. |
2980 | */ | 2998 | */ |
2981 | ULIST_ITER_INIT(&uit); | 2999 | list_for_each_entry(cur, &check_dirs, list) { |
2982 | while ((un = ulist_next(check_dirs, &uit))) { | ||
2983 | /* | 3000 | /* |
2984 | * In case we had refs into dirs that were not processed yet, | 3001 | * In case we had refs into dirs that were not processed yet, |
2985 | * we don't need to do the utime and rmdir logic for these dirs. | 3002 | * we don't need to do the utime and rmdir logic for these dirs. |
2986 | * The dir will be processed later. | 3003 | * The dir will be processed later. |
2987 | */ | 3004 | */ |
2988 | if (un->val > sctx->cur_ino) | 3005 | if (cur->dir > sctx->cur_ino) |
2989 | continue; | 3006 | continue; |
2990 | 3007 | ||
2991 | ret = get_cur_inode_state(sctx, un->val, un->aux); | 3008 | ret = get_cur_inode_state(sctx, cur->dir, cur->dir_gen); |
2992 | if (ret < 0) | 3009 | if (ret < 0) |
2993 | goto out; | 3010 | goto out; |
2994 | 3011 | ||
2995 | if (ret == inode_state_did_create || | 3012 | if (ret == inode_state_did_create || |
2996 | ret == inode_state_no_change) { | 3013 | ret == inode_state_no_change) { |
2997 | /* TODO delayed utimes */ | 3014 | /* TODO delayed utimes */ |
2998 | ret = send_utimes(sctx, un->val, un->aux); | 3015 | ret = send_utimes(sctx, cur->dir, cur->dir_gen); |
2999 | if (ret < 0) | 3016 | if (ret < 0) |
3000 | goto out; | 3017 | goto out; |
3001 | } else if (ret == inode_state_did_delete) { | 3018 | } else if (ret == inode_state_did_delete) { |
3002 | ret = can_rmdir(sctx, un->val, sctx->cur_ino); | 3019 | ret = can_rmdir(sctx, cur->dir, sctx->cur_ino); |
3003 | if (ret < 0) | 3020 | if (ret < 0) |
3004 | goto out; | 3021 | goto out; |
3005 | if (ret) { | 3022 | if (ret) { |
3006 | ret = get_cur_path(sctx, un->val, un->aux, | 3023 | ret = get_cur_path(sctx, cur->dir, |
3007 | valid_path); | 3024 | cur->dir_gen, valid_path); |
3008 | if (ret < 0) | 3025 | if (ret < 0) |
3009 | goto out; | 3026 | goto out; |
3010 | ret = send_rmdir(sctx, valid_path); | 3027 | ret = send_rmdir(sctx, valid_path); |
@@ -3017,8 +3034,8 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino); | |||
3017 | ret = 0; | 3034 | ret = 0; |
3018 | 3035 | ||
3019 | out: | 3036 | out: |
3037 | __free_recorded_refs(&check_dirs); | ||
3020 | free_recorded_refs(sctx); | 3038 | free_recorded_refs(sctx); |
3021 | ulist_free(check_dirs); | ||
3022 | fs_path_free(valid_path); | 3039 | fs_path_free(valid_path); |
3023 | return ret; | 3040 | return ret; |
3024 | } | 3041 | } |
@@ -3119,6 +3136,8 @@ out: | |||
3119 | 3136 | ||
3120 | struct find_ref_ctx { | 3137 | struct find_ref_ctx { |
3121 | u64 dir; | 3138 | u64 dir; |
3139 | u64 dir_gen; | ||
3140 | struct btrfs_root *root; | ||
3122 | struct fs_path *name; | 3141 | struct fs_path *name; |
3123 | int found_idx; | 3142 | int found_idx; |
3124 | }; | 3143 | }; |
@@ -3128,9 +3147,21 @@ static int __find_iref(int num, u64 dir, int index, | |||
3128 | void *ctx_) | 3147 | void *ctx_) |
3129 | { | 3148 | { |
3130 | struct find_ref_ctx *ctx = ctx_; | 3149 | struct find_ref_ctx *ctx = ctx_; |
3150 | u64 dir_gen; | ||
3151 | int ret; | ||
3131 | 3152 | ||
3132 | if (dir == ctx->dir && fs_path_len(name) == fs_path_len(ctx->name) && | 3153 | if (dir == ctx->dir && fs_path_len(name) == fs_path_len(ctx->name) && |
3133 | strncmp(name->start, ctx->name->start, fs_path_len(name)) == 0) { | 3154 | strncmp(name->start, ctx->name->start, fs_path_len(name)) == 0) { |
3155 | /* | ||
3156 | * To avoid doing extra lookups we'll only do this if everything | ||
3157 | * else matches. | ||
3158 | */ | ||
3159 | ret = get_inode_info(ctx->root, dir, NULL, &dir_gen, NULL, | ||
3160 | NULL, NULL, NULL); | ||
3161 | if (ret) | ||
3162 | return ret; | ||
3163 | if (dir_gen != ctx->dir_gen) | ||
3164 | return 0; | ||
3134 | ctx->found_idx = num; | 3165 | ctx->found_idx = num; |
3135 | return 1; | 3166 | return 1; |
3136 | } | 3167 | } |
@@ -3140,14 +3171,16 @@ static int __find_iref(int num, u64 dir, int index, | |||
3140 | static int find_iref(struct btrfs_root *root, | 3171 | static int find_iref(struct btrfs_root *root, |
3141 | struct btrfs_path *path, | 3172 | struct btrfs_path *path, |
3142 | struct btrfs_key *key, | 3173 | struct btrfs_key *key, |
3143 | u64 dir, struct fs_path *name) | 3174 | u64 dir, u64 dir_gen, struct fs_path *name) |
3144 | { | 3175 | { |
3145 | int ret; | 3176 | int ret; |
3146 | struct find_ref_ctx ctx; | 3177 | struct find_ref_ctx ctx; |
3147 | 3178 | ||
3148 | ctx.dir = dir; | 3179 | ctx.dir = dir; |
3149 | ctx.name = name; | 3180 | ctx.name = name; |
3181 | ctx.dir_gen = dir_gen; | ||
3150 | ctx.found_idx = -1; | 3182 | ctx.found_idx = -1; |
3183 | ctx.root = root; | ||
3151 | 3184 | ||
3152 | ret = iterate_inode_ref(root, path, key, 0, __find_iref, &ctx); | 3185 | ret = iterate_inode_ref(root, path, key, 0, __find_iref, &ctx); |
3153 | if (ret < 0) | 3186 | if (ret < 0) |
@@ -3163,11 +3196,17 @@ static int __record_changed_new_ref(int num, u64 dir, int index, | |||
3163 | struct fs_path *name, | 3196 | struct fs_path *name, |
3164 | void *ctx) | 3197 | void *ctx) |
3165 | { | 3198 | { |
3199 | u64 dir_gen; | ||
3166 | int ret; | 3200 | int ret; |
3167 | struct send_ctx *sctx = ctx; | 3201 | struct send_ctx *sctx = ctx; |
3168 | 3202 | ||
3203 | ret = get_inode_info(sctx->send_root, dir, NULL, &dir_gen, NULL, | ||
3204 | NULL, NULL, NULL); | ||
3205 | if (ret) | ||
3206 | return ret; | ||
3207 | |||
3169 | ret = find_iref(sctx->parent_root, sctx->right_path, | 3208 | ret = find_iref(sctx->parent_root, sctx->right_path, |
3170 | sctx->cmp_key, dir, name); | 3209 | sctx->cmp_key, dir, dir_gen, name); |
3171 | if (ret == -ENOENT) | 3210 | if (ret == -ENOENT) |
3172 | ret = __record_new_ref(num, dir, index, name, sctx); | 3211 | ret = __record_new_ref(num, dir, index, name, sctx); |
3173 | else if (ret > 0) | 3212 | else if (ret > 0) |
@@ -3180,11 +3219,17 @@ static int __record_changed_deleted_ref(int num, u64 dir, int index, | |||
3180 | struct fs_path *name, | 3219 | struct fs_path *name, |
3181 | void *ctx) | 3220 | void *ctx) |
3182 | { | 3221 | { |
3222 | u64 dir_gen; | ||
3183 | int ret; | 3223 | int ret; |
3184 | struct send_ctx *sctx = ctx; | 3224 | struct send_ctx *sctx = ctx; |
3185 | 3225 | ||
3226 | ret = get_inode_info(sctx->parent_root, dir, NULL, &dir_gen, NULL, | ||
3227 | NULL, NULL, NULL); | ||
3228 | if (ret) | ||
3229 | return ret; | ||
3230 | |||
3186 | ret = find_iref(sctx->send_root, sctx->left_path, sctx->cmp_key, | 3231 | ret = find_iref(sctx->send_root, sctx->left_path, sctx->cmp_key, |
3187 | dir, name); | 3232 | dir, dir_gen, name); |
3188 | if (ret == -ENOENT) | 3233 | if (ret == -ENOENT) |
3189 | ret = __record_deleted_ref(num, dir, index, name, sctx); | 3234 | ret = __record_deleted_ref(num, dir, index, name, sctx); |
3190 | else if (ret > 0) | 3235 | else if (ret > 0) |
@@ -3869,7 +3914,8 @@ static int is_extent_unchanged(struct send_ctx *sctx, | |||
3869 | btrfs_item_key_to_cpu(eb, &found_key, slot); | 3914 | btrfs_item_key_to_cpu(eb, &found_key, slot); |
3870 | if (found_key.objectid != key.objectid || | 3915 | if (found_key.objectid != key.objectid || |
3871 | found_key.type != key.type) { | 3916 | found_key.type != key.type) { |
3872 | ret = 0; | 3917 | /* If we're a hole then just pretend nothing changed */ |
3918 | ret = (left_disknr) ? 0 : 1; | ||
3873 | goto out; | 3919 | goto out; |
3874 | } | 3920 | } |
3875 | 3921 | ||
@@ -3895,7 +3941,8 @@ static int is_extent_unchanged(struct send_ctx *sctx, | |||
3895 | * This may only happen on the first iteration. | 3941 | * This may only happen on the first iteration. |
3896 | */ | 3942 | */ |
3897 | if (found_key.offset + right_len <= ekey->offset) { | 3943 | if (found_key.offset + right_len <= ekey->offset) { |
3898 | ret = 0; | 3944 | /* If we're a hole just pretend nothing changed */ |
3945 | ret = (left_disknr) ? 0 : 1; | ||
3899 | goto out; | 3946 | goto out; |
3900 | } | 3947 | } |
3901 | 3948 | ||
@@ -3960,8 +4007,8 @@ static int process_extent(struct send_ctx *sctx, | |||
3960 | struct btrfs_path *path, | 4007 | struct btrfs_path *path, |
3961 | struct btrfs_key *key) | 4008 | struct btrfs_key *key) |
3962 | { | 4009 | { |
3963 | int ret = 0; | ||
3964 | struct clone_root *found_clone = NULL; | 4010 | struct clone_root *found_clone = NULL; |
4011 | int ret = 0; | ||
3965 | 4012 | ||
3966 | if (S_ISLNK(sctx->cur_inode_mode)) | 4013 | if (S_ISLNK(sctx->cur_inode_mode)) |
3967 | return 0; | 4014 | return 0; |
@@ -3974,6 +4021,32 @@ static int process_extent(struct send_ctx *sctx, | |||
3974 | ret = 0; | 4021 | ret = 0; |
3975 | goto out; | 4022 | goto out; |
3976 | } | 4023 | } |
4024 | } else { | ||
4025 | struct btrfs_file_extent_item *ei; | ||
4026 | u8 type; | ||
4027 | |||
4028 | ei = btrfs_item_ptr(path->nodes[0], path->slots[0], | ||
4029 | struct btrfs_file_extent_item); | ||
4030 | type = btrfs_file_extent_type(path->nodes[0], ei); | ||
4031 | if (type == BTRFS_FILE_EXTENT_PREALLOC || | ||
4032 | type == BTRFS_FILE_EXTENT_REG) { | ||
4033 | /* | ||
4034 | * The send spec does not have a prealloc command yet, | ||
4035 | * so just leave a hole for prealloc'ed extents until | ||
4036 | * we have enough commands queued up to justify rev'ing | ||
4037 | * the send spec. | ||
4038 | */ | ||
4039 | if (type == BTRFS_FILE_EXTENT_PREALLOC) { | ||
4040 | ret = 0; | ||
4041 | goto out; | ||
4042 | } | ||
4043 | |||
4044 | /* Have a hole, just skip it. */ | ||
4045 | if (btrfs_file_extent_disk_bytenr(path->nodes[0], ei) == 0) { | ||
4046 | ret = 0; | ||
4047 | goto out; | ||
4048 | } | ||
4049 | } | ||
3977 | } | 4050 | } |
3978 | 4051 | ||
3979 | ret = find_extent_clone(sctx, path, key->objectid, key->offset, | 4052 | ret = find_extent_clone(sctx, path, key->objectid, key->offset, |
@@ -4361,6 +4434,64 @@ static int changed_extent(struct send_ctx *sctx, | |||
4361 | return ret; | 4434 | return ret; |
4362 | } | 4435 | } |
4363 | 4436 | ||
4437 | static int dir_changed(struct send_ctx *sctx, u64 dir) | ||
4438 | { | ||
4439 | u64 orig_gen, new_gen; | ||
4440 | int ret; | ||
4441 | |||
4442 | ret = get_inode_info(sctx->send_root, dir, NULL, &new_gen, NULL, NULL, | ||
4443 | NULL, NULL); | ||
4444 | if (ret) | ||
4445 | return ret; | ||
4446 | |||
4447 | ret = get_inode_info(sctx->parent_root, dir, NULL, &orig_gen, NULL, | ||
4448 | NULL, NULL, NULL); | ||
4449 | if (ret) | ||
4450 | return ret; | ||
4451 | |||
4452 | return (orig_gen != new_gen) ? 1 : 0; | ||
4453 | } | ||
4454 | |||
4455 | static int compare_refs(struct send_ctx *sctx, struct btrfs_path *path, | ||
4456 | struct btrfs_key *key) | ||
4457 | { | ||
4458 | struct btrfs_inode_extref *extref; | ||
4459 | struct extent_buffer *leaf; | ||
4460 | u64 dirid = 0, last_dirid = 0; | ||
4461 | unsigned long ptr; | ||
4462 | u32 item_size; | ||
4463 | u32 cur_offset = 0; | ||
4464 | int ref_name_len; | ||
4465 | int ret = 0; | ||
4466 | |||
4467 | /* Easy case, just check this one dirid */ | ||
4468 | if (key->type == BTRFS_INODE_REF_KEY) { | ||
4469 | dirid = key->offset; | ||
4470 | |||
4471 | ret = dir_changed(sctx, dirid); | ||
4472 | goto out; | ||
4473 | } | ||
4474 | |||
4475 | leaf = path->nodes[0]; | ||
4476 | item_size = btrfs_item_size_nr(leaf, path->slots[0]); | ||
4477 | ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); | ||
4478 | while (cur_offset < item_size) { | ||
4479 | extref = (struct btrfs_inode_extref *)(ptr + | ||
4480 | cur_offset); | ||
4481 | dirid = btrfs_inode_extref_parent(leaf, extref); | ||
4482 | ref_name_len = btrfs_inode_extref_name_len(leaf, extref); | ||
4483 | cur_offset += ref_name_len + sizeof(*extref); | ||
4484 | if (dirid == last_dirid) | ||
4485 | continue; | ||
4486 | ret = dir_changed(sctx, dirid); | ||
4487 | if (ret) | ||
4488 | break; | ||
4489 | last_dirid = dirid; | ||
4490 | } | ||
4491 | out: | ||
4492 | return ret; | ||
4493 | } | ||
4494 | |||
4364 | /* | 4495 | /* |
4365 | * Updates compare related fields in sctx and simply forwards to the actual | 4496 | * Updates compare related fields in sctx and simply forwards to the actual |
4366 | * changed_xxx functions. | 4497 | * changed_xxx functions. |
@@ -4376,6 +4507,19 @@ static int changed_cb(struct btrfs_root *left_root, | |||
4376 | int ret = 0; | 4507 | int ret = 0; |
4377 | struct send_ctx *sctx = ctx; | 4508 | struct send_ctx *sctx = ctx; |
4378 | 4509 | ||
4510 | if (result == BTRFS_COMPARE_TREE_SAME) { | ||
4511 | if (key->type != BTRFS_INODE_REF_KEY && | ||
4512 | key->type != BTRFS_INODE_EXTREF_KEY) | ||
4513 | return 0; | ||
4514 | ret = compare_refs(sctx, left_path, key); | ||
4515 | if (!ret) | ||
4516 | return 0; | ||
4517 | if (ret < 0) | ||
4518 | return ret; | ||
4519 | result = BTRFS_COMPARE_TREE_CHANGED; | ||
4520 | ret = 0; | ||
4521 | } | ||
4522 | |||
4379 | sctx->left_path = left_path; | 4523 | sctx->left_path = left_path; |
4380 | sctx->right_path = right_path; | 4524 | sctx->right_path = right_path; |
4381 | sctx->cmp_key = key; | 4525 | sctx->cmp_key = key; |