summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/send.c21
1 files changed, 20 insertions, 1 deletions
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index a4011a9148fd..d17d75ebc482 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -2627,6 +2627,12 @@ static int can_rmdir(struct send_ctx *sctx, u64 dir, u64 send_progress)
2627 struct btrfs_key loc; 2627 struct btrfs_key loc;
2628 struct btrfs_dir_item *di; 2628 struct btrfs_dir_item *di;
2629 2629
2630 /*
2631 * Don't try to rmdir the top/root subvolume dir.
2632 */
2633 if (dir == BTRFS_FIRST_FREE_OBJECTID)
2634 return 0;
2635
2630 path = alloc_path_for_send(); 2636 path = alloc_path_for_send();
2631 if (!path) 2637 if (!path)
2632 return -ENOMEM; 2638 return -ENOMEM;
@@ -2687,6 +2693,12 @@ static int process_recorded_refs(struct send_ctx *sctx)
2687 2693
2688verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino); 2694verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
2689 2695
2696 /*
2697 * This should never happen as the root dir always has the same ref
2698 * which is always '..'
2699 */
2700 BUG_ON(sctx->cur_ino <= BTRFS_FIRST_FREE_OBJECTID);
2701
2690 valid_path = fs_path_alloc(sctx); 2702 valid_path = fs_path_alloc(sctx);
2691 if (!valid_path) { 2703 if (!valid_path) {
2692 ret = -ENOMEM; 2704 ret = -ENOMEM;
@@ -4094,7 +4106,14 @@ static int changed_inode(struct send_ctx *sctx,
4094 4106
4095 right_gen = btrfs_inode_generation(sctx->right_path->nodes[0], 4107 right_gen = btrfs_inode_generation(sctx->right_path->nodes[0],
4096 right_ii); 4108 right_ii);
4097 if (left_gen != right_gen) 4109
4110 /*
4111 * The cur_ino = root dir case is special here. We can't treat
4112 * the inode as deleted+reused because it would generate a
4113 * stream that tries to delete/mkdir the root dir.
4114 */
4115 if (left_gen != right_gen &&
4116 sctx->cur_ino != BTRFS_FIRST_FREE_OBJECTID)
4098 sctx->cur_inode_new_gen = 1; 4117 sctx->cur_inode_new_gen = 1;
4099 } 4118 }
4100 4119