diff options
Diffstat (limited to 'fs/btrfs/send.c')
-rw-r--r-- | fs/btrfs/send.c | 173 |
1 files changed, 162 insertions, 11 deletions
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index b71dd298385c..efe129fe2678 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c | |||
@@ -231,7 +231,6 @@ struct pending_dir_move { | |||
231 | u64 parent_ino; | 231 | u64 parent_ino; |
232 | u64 ino; | 232 | u64 ino; |
233 | u64 gen; | 233 | u64 gen; |
234 | bool is_orphan; | ||
235 | struct list_head update_refs; | 234 | struct list_head update_refs; |
236 | }; | 235 | }; |
237 | 236 | ||
@@ -274,6 +273,39 @@ struct name_cache_entry { | |||
274 | char name[]; | 273 | char name[]; |
275 | }; | 274 | }; |
276 | 275 | ||
276 | static void inconsistent_snapshot_error(struct send_ctx *sctx, | ||
277 | enum btrfs_compare_tree_result result, | ||
278 | const char *what) | ||
279 | { | ||
280 | const char *result_string; | ||
281 | |||
282 | switch (result) { | ||
283 | case BTRFS_COMPARE_TREE_NEW: | ||
284 | result_string = "new"; | ||
285 | break; | ||
286 | case BTRFS_COMPARE_TREE_DELETED: | ||
287 | result_string = "deleted"; | ||
288 | break; | ||
289 | case BTRFS_COMPARE_TREE_CHANGED: | ||
290 | result_string = "updated"; | ||
291 | break; | ||
292 | case BTRFS_COMPARE_TREE_SAME: | ||
293 | ASSERT(0); | ||
294 | result_string = "unchanged"; | ||
295 | break; | ||
296 | default: | ||
297 | ASSERT(0); | ||
298 | result_string = "unexpected"; | ||
299 | } | ||
300 | |||
301 | btrfs_err(sctx->send_root->fs_info, | ||
302 | "Send: inconsistent snapshot, found %s %s for inode %llu without updated inode item, send root is %llu, parent root is %llu", | ||
303 | result_string, what, sctx->cmp_key->objectid, | ||
304 | sctx->send_root->root_key.objectid, | ||
305 | (sctx->parent_root ? | ||
306 | sctx->parent_root->root_key.objectid : 0)); | ||
307 | } | ||
308 | |||
277 | static int is_waiting_for_move(struct send_ctx *sctx, u64 ino); | 309 | static int is_waiting_for_move(struct send_ctx *sctx, u64 ino); |
278 | 310 | ||
279 | static struct waiting_dir_move * | 311 | static struct waiting_dir_move * |
@@ -1861,7 +1893,8 @@ static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen, | |||
1861 | * was already unlinked/moved, so we can safely assume that we will not | 1893 | * was already unlinked/moved, so we can safely assume that we will not |
1862 | * overwrite anything at this point in time. | 1894 | * overwrite anything at this point in time. |
1863 | */ | 1895 | */ |
1864 | if (other_inode > sctx->send_progress) { | 1896 | if (other_inode > sctx->send_progress || |
1897 | is_waiting_for_move(sctx, other_inode)) { | ||
1865 | ret = get_inode_info(sctx->parent_root, other_inode, NULL, | 1898 | ret = get_inode_info(sctx->parent_root, other_inode, NULL, |
1866 | who_gen, NULL, NULL, NULL, NULL); | 1899 | who_gen, NULL, NULL, NULL, NULL); |
1867 | if (ret < 0) | 1900 | if (ret < 0) |
@@ -2502,6 +2535,8 @@ verbose_printk("btrfs: send_utimes %llu\n", ino); | |||
2502 | key.type = BTRFS_INODE_ITEM_KEY; | 2535 | key.type = BTRFS_INODE_ITEM_KEY; |
2503 | key.offset = 0; | 2536 | key.offset = 0; |
2504 | ret = btrfs_search_slot(NULL, sctx->send_root, &key, path, 0, 0); | 2537 | ret = btrfs_search_slot(NULL, sctx->send_root, &key, path, 0, 0); |
2538 | if (ret > 0) | ||
2539 | ret = -ENOENT; | ||
2505 | if (ret < 0) | 2540 | if (ret < 0) |
2506 | goto out; | 2541 | goto out; |
2507 | 2542 | ||
@@ -2947,6 +2982,10 @@ static int can_rmdir(struct send_ctx *sctx, u64 dir, u64 dir_gen, | |||
2947 | } | 2982 | } |
2948 | 2983 | ||
2949 | if (loc.objectid > send_progress) { | 2984 | if (loc.objectid > send_progress) { |
2985 | struct orphan_dir_info *odi; | ||
2986 | |||
2987 | odi = get_orphan_dir_info(sctx, dir); | ||
2988 | free_orphan_dir_info(sctx, odi); | ||
2950 | ret = 0; | 2989 | ret = 0; |
2951 | goto out; | 2990 | goto out; |
2952 | } | 2991 | } |
@@ -3047,7 +3086,6 @@ static int add_pending_dir_move(struct send_ctx *sctx, | |||
3047 | pm->parent_ino = parent_ino; | 3086 | pm->parent_ino = parent_ino; |
3048 | pm->ino = ino; | 3087 | pm->ino = ino; |
3049 | pm->gen = ino_gen; | 3088 | pm->gen = ino_gen; |
3050 | pm->is_orphan = is_orphan; | ||
3051 | INIT_LIST_HEAD(&pm->list); | 3089 | INIT_LIST_HEAD(&pm->list); |
3052 | INIT_LIST_HEAD(&pm->update_refs); | 3090 | INIT_LIST_HEAD(&pm->update_refs); |
3053 | RB_CLEAR_NODE(&pm->node); | 3091 | RB_CLEAR_NODE(&pm->node); |
@@ -3113,6 +3151,48 @@ static struct pending_dir_move *get_pending_dir_moves(struct send_ctx *sctx, | |||
3113 | return NULL; | 3151 | return NULL; |
3114 | } | 3152 | } |
3115 | 3153 | ||
3154 | static int path_loop(struct send_ctx *sctx, struct fs_path *name, | ||
3155 | u64 ino, u64 gen, u64 *ancestor_ino) | ||
3156 | { | ||
3157 | int ret = 0; | ||
3158 | u64 parent_inode = 0; | ||
3159 | u64 parent_gen = 0; | ||
3160 | u64 start_ino = ino; | ||
3161 | |||
3162 | *ancestor_ino = 0; | ||
3163 | while (ino != BTRFS_FIRST_FREE_OBJECTID) { | ||
3164 | fs_path_reset(name); | ||
3165 | |||
3166 | if (is_waiting_for_rm(sctx, ino)) | ||
3167 | break; | ||
3168 | if (is_waiting_for_move(sctx, ino)) { | ||
3169 | if (*ancestor_ino == 0) | ||
3170 | *ancestor_ino = ino; | ||
3171 | ret = get_first_ref(sctx->parent_root, ino, | ||
3172 | &parent_inode, &parent_gen, name); | ||
3173 | } else { | ||
3174 | ret = __get_cur_name_and_parent(sctx, ino, gen, | ||
3175 | &parent_inode, | ||
3176 | &parent_gen, name); | ||
3177 | if (ret > 0) { | ||
3178 | ret = 0; | ||
3179 | break; | ||
3180 | } | ||
3181 | } | ||
3182 | if (ret < 0) | ||
3183 | break; | ||
3184 | if (parent_inode == start_ino) { | ||
3185 | ret = 1; | ||
3186 | if (*ancestor_ino == 0) | ||
3187 | *ancestor_ino = ino; | ||
3188 | break; | ||
3189 | } | ||
3190 | ino = parent_inode; | ||
3191 | gen = parent_gen; | ||
3192 | } | ||
3193 | return ret; | ||
3194 | } | ||
3195 | |||
3116 | static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm) | 3196 | static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm) |
3117 | { | 3197 | { |
3118 | struct fs_path *from_path = NULL; | 3198 | struct fs_path *from_path = NULL; |
@@ -3123,6 +3203,8 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm) | |||
3123 | u64 parent_ino, parent_gen; | 3203 | u64 parent_ino, parent_gen; |
3124 | struct waiting_dir_move *dm = NULL; | 3204 | struct waiting_dir_move *dm = NULL; |
3125 | u64 rmdir_ino = 0; | 3205 | u64 rmdir_ino = 0; |
3206 | u64 ancestor; | ||
3207 | bool is_orphan; | ||
3126 | int ret; | 3208 | int ret; |
3127 | 3209 | ||
3128 | name = fs_path_alloc(); | 3210 | name = fs_path_alloc(); |
@@ -3135,9 +3217,10 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm) | |||
3135 | dm = get_waiting_dir_move(sctx, pm->ino); | 3217 | dm = get_waiting_dir_move(sctx, pm->ino); |
3136 | ASSERT(dm); | 3218 | ASSERT(dm); |
3137 | rmdir_ino = dm->rmdir_ino; | 3219 | rmdir_ino = dm->rmdir_ino; |
3220 | is_orphan = dm->orphanized; | ||
3138 | free_waiting_dir_move(sctx, dm); | 3221 | free_waiting_dir_move(sctx, dm); |
3139 | 3222 | ||
3140 | if (pm->is_orphan) { | 3223 | if (is_orphan) { |
3141 | ret = gen_unique_name(sctx, pm->ino, | 3224 | ret = gen_unique_name(sctx, pm->ino, |
3142 | pm->gen, from_path); | 3225 | pm->gen, from_path); |
3143 | } else { | 3226 | } else { |
@@ -3155,6 +3238,24 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm) | |||
3155 | goto out; | 3238 | goto out; |
3156 | 3239 | ||
3157 | sctx->send_progress = sctx->cur_ino + 1; | 3240 | sctx->send_progress = sctx->cur_ino + 1; |
3241 | ret = path_loop(sctx, name, pm->ino, pm->gen, &ancestor); | ||
3242 | if (ret < 0) | ||
3243 | goto out; | ||
3244 | if (ret) { | ||
3245 | LIST_HEAD(deleted_refs); | ||
3246 | ASSERT(ancestor > BTRFS_FIRST_FREE_OBJECTID); | ||
3247 | ret = add_pending_dir_move(sctx, pm->ino, pm->gen, ancestor, | ||
3248 | &pm->update_refs, &deleted_refs, | ||
3249 | is_orphan); | ||
3250 | if (ret < 0) | ||
3251 | goto out; | ||
3252 | if (rmdir_ino) { | ||
3253 | dm = get_waiting_dir_move(sctx, pm->ino); | ||
3254 | ASSERT(dm); | ||
3255 | dm->rmdir_ino = rmdir_ino; | ||
3256 | } | ||
3257 | goto out; | ||
3258 | } | ||
3158 | fs_path_reset(name); | 3259 | fs_path_reset(name); |
3159 | to_path = name; | 3260 | to_path = name; |
3160 | name = NULL; | 3261 | name = NULL; |
@@ -3174,7 +3275,7 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm) | |||
3174 | /* already deleted */ | 3275 | /* already deleted */ |
3175 | goto finish; | 3276 | goto finish; |
3176 | } | 3277 | } |
3177 | ret = can_rmdir(sctx, rmdir_ino, odi->gen, sctx->cur_ino + 1); | 3278 | ret = can_rmdir(sctx, rmdir_ino, odi->gen, sctx->cur_ino); |
3178 | if (ret < 0) | 3279 | if (ret < 0) |
3179 | goto out; | 3280 | goto out; |
3180 | if (!ret) | 3281 | if (!ret) |
@@ -3204,8 +3305,18 @@ finish: | |||
3204 | * and old parent(s). | 3305 | * and old parent(s). |
3205 | */ | 3306 | */ |
3206 | list_for_each_entry(cur, &pm->update_refs, list) { | 3307 | list_for_each_entry(cur, &pm->update_refs, list) { |
3207 | if (cur->dir == rmdir_ino) | 3308 | /* |
3309 | * The parent inode might have been deleted in the send snapshot | ||
3310 | */ | ||
3311 | ret = get_inode_info(sctx->send_root, cur->dir, NULL, | ||
3312 | NULL, NULL, NULL, NULL, NULL); | ||
3313 | if (ret == -ENOENT) { | ||
3314 | ret = 0; | ||
3208 | continue; | 3315 | continue; |
3316 | } | ||
3317 | if (ret < 0) | ||
3318 | goto out; | ||
3319 | |||
3209 | ret = send_utimes(sctx, cur->dir, cur->dir_gen); | 3320 | ret = send_utimes(sctx, cur->dir, cur->dir_gen); |
3210 | if (ret < 0) | 3321 | if (ret < 0) |
3211 | goto out; | 3322 | goto out; |
@@ -3325,6 +3436,7 @@ static int wait_for_dest_dir_move(struct send_ctx *sctx, | |||
3325 | u64 left_gen; | 3436 | u64 left_gen; |
3326 | u64 right_gen; | 3437 | u64 right_gen; |
3327 | int ret = 0; | 3438 | int ret = 0; |
3439 | struct waiting_dir_move *wdm; | ||
3328 | 3440 | ||
3329 | if (RB_EMPTY_ROOT(&sctx->waiting_dir_moves)) | 3441 | if (RB_EMPTY_ROOT(&sctx->waiting_dir_moves)) |
3330 | return 0; | 3442 | return 0; |
@@ -3383,7 +3495,8 @@ static int wait_for_dest_dir_move(struct send_ctx *sctx, | |||
3383 | goto out; | 3495 | goto out; |
3384 | } | 3496 | } |
3385 | 3497 | ||
3386 | if (is_waiting_for_move(sctx, di_key.objectid)) { | 3498 | wdm = get_waiting_dir_move(sctx, di_key.objectid); |
3499 | if (wdm && !wdm->orphanized) { | ||
3387 | ret = add_pending_dir_move(sctx, | 3500 | ret = add_pending_dir_move(sctx, |
3388 | sctx->cur_ino, | 3501 | sctx->cur_ino, |
3389 | sctx->cur_inode_gen, | 3502 | sctx->cur_inode_gen, |
@@ -3470,7 +3583,8 @@ static int wait_for_parent_move(struct send_ctx *sctx, | |||
3470 | ret = is_ancestor(sctx->parent_root, | 3583 | ret = is_ancestor(sctx->parent_root, |
3471 | sctx->cur_ino, sctx->cur_inode_gen, | 3584 | sctx->cur_ino, sctx->cur_inode_gen, |
3472 | ino, path_before); | 3585 | ino, path_before); |
3473 | break; | 3586 | if (ret) |
3587 | break; | ||
3474 | } | 3588 | } |
3475 | 3589 | ||
3476 | fs_path_reset(path_before); | 3590 | fs_path_reset(path_before); |
@@ -3643,11 +3757,26 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino); | |||
3643 | goto out; | 3757 | goto out; |
3644 | if (ret) { | 3758 | if (ret) { |
3645 | struct name_cache_entry *nce; | 3759 | struct name_cache_entry *nce; |
3760 | struct waiting_dir_move *wdm; | ||
3646 | 3761 | ||
3647 | ret = orphanize_inode(sctx, ow_inode, ow_gen, | 3762 | ret = orphanize_inode(sctx, ow_inode, ow_gen, |
3648 | cur->full_path); | 3763 | cur->full_path); |
3649 | if (ret < 0) | 3764 | if (ret < 0) |
3650 | goto out; | 3765 | goto out; |
3766 | |||
3767 | /* | ||
3768 | * If ow_inode has its rename operation delayed | ||
3769 | * make sure that its orphanized name is used in | ||
3770 | * the source path when performing its rename | ||
3771 | * operation. | ||
3772 | */ | ||
3773 | if (is_waiting_for_move(sctx, ow_inode)) { | ||
3774 | wdm = get_waiting_dir_move(sctx, | ||
3775 | ow_inode); | ||
3776 | ASSERT(wdm); | ||
3777 | wdm->orphanized = true; | ||
3778 | } | ||
3779 | |||
3651 | /* | 3780 | /* |
3652 | * Make sure we clear our orphanized inode's | 3781 | * Make sure we clear our orphanized inode's |
3653 | * name from the name cache. This is because the | 3782 | * name from the name cache. This is because the |
@@ -3663,6 +3792,19 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino); | |||
3663 | name_cache_delete(sctx, nce); | 3792 | name_cache_delete(sctx, nce); |
3664 | kfree(nce); | 3793 | kfree(nce); |
3665 | } | 3794 | } |
3795 | |||
3796 | /* | ||
3797 | * ow_inode might currently be an ancestor of | ||
3798 | * cur_ino, therefore compute valid_path (the | ||
3799 | * current path of cur_ino) again because it | ||
3800 | * might contain the pre-orphanization name of | ||
3801 | * ow_inode, which is no longer valid. | ||
3802 | */ | ||
3803 | fs_path_reset(valid_path); | ||
3804 | ret = get_cur_path(sctx, sctx->cur_ino, | ||
3805 | sctx->cur_inode_gen, valid_path); | ||
3806 | if (ret < 0) | ||
3807 | goto out; | ||
3666 | } else { | 3808 | } else { |
3667 | ret = send_unlink(sctx, cur->full_path); | 3809 | ret = send_unlink(sctx, cur->full_path); |
3668 | if (ret < 0) | 3810 | if (ret < 0) |
@@ -5602,7 +5744,10 @@ static int changed_ref(struct send_ctx *sctx, | |||
5602 | { | 5744 | { |
5603 | int ret = 0; | 5745 | int ret = 0; |
5604 | 5746 | ||
5605 | BUG_ON(sctx->cur_ino != sctx->cmp_key->objectid); | 5747 | if (sctx->cur_ino != sctx->cmp_key->objectid) { |
5748 | inconsistent_snapshot_error(sctx, result, "reference"); | ||
5749 | return -EIO; | ||
5750 | } | ||
5606 | 5751 | ||
5607 | if (!sctx->cur_inode_new_gen && | 5752 | if (!sctx->cur_inode_new_gen && |
5608 | sctx->cur_ino != BTRFS_FIRST_FREE_OBJECTID) { | 5753 | sctx->cur_ino != BTRFS_FIRST_FREE_OBJECTID) { |
@@ -5627,7 +5772,10 @@ static int changed_xattr(struct send_ctx *sctx, | |||
5627 | { | 5772 | { |
5628 | int ret = 0; | 5773 | int ret = 0; |
5629 | 5774 | ||
5630 | BUG_ON(sctx->cur_ino != sctx->cmp_key->objectid); | 5775 | if (sctx->cur_ino != sctx->cmp_key->objectid) { |
5776 | inconsistent_snapshot_error(sctx, result, "xattr"); | ||
5777 | return -EIO; | ||
5778 | } | ||
5631 | 5779 | ||
5632 | if (!sctx->cur_inode_new_gen && !sctx->cur_inode_deleted) { | 5780 | if (!sctx->cur_inode_new_gen && !sctx->cur_inode_deleted) { |
5633 | if (result == BTRFS_COMPARE_TREE_NEW) | 5781 | if (result == BTRFS_COMPARE_TREE_NEW) |
@@ -5651,7 +5799,10 @@ static int changed_extent(struct send_ctx *sctx, | |||
5651 | { | 5799 | { |
5652 | int ret = 0; | 5800 | int ret = 0; |
5653 | 5801 | ||
5654 | BUG_ON(sctx->cur_ino != sctx->cmp_key->objectid); | 5802 | if (sctx->cur_ino != sctx->cmp_key->objectid) { |
5803 | inconsistent_snapshot_error(sctx, result, "extent"); | ||
5804 | return -EIO; | ||
5805 | } | ||
5655 | 5806 | ||
5656 | if (!sctx->cur_inode_new_gen && !sctx->cur_inode_deleted) { | 5807 | if (!sctx->cur_inode_new_gen && !sctx->cur_inode_deleted) { |
5657 | if (result != BTRFS_COMPARE_TREE_DELETED) | 5808 | if (result != BTRFS_COMPARE_TREE_DELETED) |