aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/send.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/send.c')
-rw-r--r--fs/btrfs/send.c240
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
2627static 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
2613static void __free_recorded_refs(struct list_head *head) 2643static 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
3019out: 3036out:
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
3120struct find_ref_ctx { 3137struct 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,
3140static int find_iref(struct btrfs_root *root, 3171static 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
4437static 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
4455static 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 }
4491out:
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;