|
@@ -1856,7 +1856,7 @@ out:
|
|
*/
|
|
*/
|
|
static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen,
|
|
static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen,
|
|
const char *name, int name_len,
|
|
const char *name, int name_len,
|
|
- u64 *who_ino, u64 *who_gen)
|
|
|
|
|
|
+ u64 *who_ino, u64 *who_gen, u64 *who_mode)
|
|
{
|
|
{
|
|
int ret = 0;
|
|
int ret = 0;
|
|
u64 gen;
|
|
u64 gen;
|
|
@@ -1905,7 +1905,7 @@ static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen,
|
|
if (other_inode > sctx->send_progress ||
|
|
if (other_inode > sctx->send_progress ||
|
|
is_waiting_for_move(sctx, other_inode)) {
|
|
is_waiting_for_move(sctx, other_inode)) {
|
|
ret = get_inode_info(sctx->parent_root, other_inode, NULL,
|
|
ret = get_inode_info(sctx->parent_root, other_inode, NULL,
|
|
- who_gen, NULL, NULL, NULL, NULL);
|
|
|
|
|
|
+ who_gen, who_mode, NULL, NULL, NULL);
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
@@ -3683,6 +3683,36 @@ out:
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int update_ref_path(struct send_ctx *sctx, struct recorded_ref *ref)
|
|
|
|
+{
|
|
|
|
+ int ret;
|
|
|
|
+ struct fs_path *new_path;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Our reference's name member points to its full_path member string, so
|
|
|
|
+ * we use here a new path.
|
|
|
|
+ */
|
|
|
|
+ new_path = fs_path_alloc();
|
|
|
|
+ if (!new_path)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+
|
|
|
|
+ ret = get_cur_path(sctx, ref->dir, ref->dir_gen, new_path);
|
|
|
|
+ if (ret < 0) {
|
|
|
|
+ fs_path_free(new_path);
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+ ret = fs_path_add(new_path, ref->name, ref->name_len);
|
|
|
|
+ if (ret < 0) {
|
|
|
|
+ fs_path_free(new_path);
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fs_path_free(ref->full_path);
|
|
|
|
+ set_ref_path(ref, new_path);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* This does all the move/link/unlink/rmdir magic.
|
|
* This does all the move/link/unlink/rmdir magic.
|
|
*/
|
|
*/
|
|
@@ -3696,10 +3726,12 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move)
|
|
struct fs_path *valid_path = NULL;
|
|
struct fs_path *valid_path = NULL;
|
|
u64 ow_inode = 0;
|
|
u64 ow_inode = 0;
|
|
u64 ow_gen;
|
|
u64 ow_gen;
|
|
|
|
+ u64 ow_mode;
|
|
int did_overwrite = 0;
|
|
int did_overwrite = 0;
|
|
int is_orphan = 0;
|
|
int is_orphan = 0;
|
|
u64 last_dir_ino_rm = 0;
|
|
u64 last_dir_ino_rm = 0;
|
|
bool can_rename = true;
|
|
bool can_rename = true;
|
|
|
|
+ bool orphanized_dir = false;
|
|
bool orphanized_ancestor = false;
|
|
bool orphanized_ancestor = false;
|
|
|
|
|
|
btrfs_debug(fs_info, "process_recorded_refs %llu", sctx->cur_ino);
|
|
btrfs_debug(fs_info, "process_recorded_refs %llu", sctx->cur_ino);
|
|
@@ -3798,7 +3830,7 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move)
|
|
*/
|
|
*/
|
|
ret = will_overwrite_ref(sctx, cur->dir, cur->dir_gen,
|
|
ret = will_overwrite_ref(sctx, cur->dir, cur->dir_gen,
|
|
cur->name, cur->name_len,
|
|
cur->name, cur->name_len,
|
|
- &ow_inode, &ow_gen);
|
|
|
|
|
|
+ &ow_inode, &ow_gen, &ow_mode);
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
goto out;
|
|
goto out;
|
|
if (ret) {
|
|
if (ret) {
|
|
@@ -3815,6 +3847,8 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move)
|
|
cur->full_path);
|
|
cur->full_path);
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
goto out;
|
|
goto out;
|
|
|
|
+ if (S_ISDIR(ow_mode))
|
|
|
|
+ orphanized_dir = true;
|
|
|
|
|
|
/*
|
|
/*
|
|
* If ow_inode has its rename operation delayed
|
|
* If ow_inode has its rename operation delayed
|
|
@@ -3920,6 +3954,18 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move)
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
goto out;
|
|
goto out;
|
|
} else {
|
|
} else {
|
|
|
|
+ /*
|
|
|
|
+ * We might have previously orphanized an inode
|
|
|
|
+ * which is an ancestor of our current inode,
|
|
|
|
+ * so our reference's full path, which was
|
|
|
|
+ * computed before any such orphanizations, must
|
|
|
|
+ * be updated.
|
|
|
|
+ */
|
|
|
|
+ if (orphanized_dir) {
|
|
|
|
+ ret = update_ref_path(sctx, cur);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
ret = send_link(sctx, cur->full_path,
|
|
ret = send_link(sctx, cur->full_path,
|
|
valid_path);
|
|
valid_path);
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
@@ -3990,34 +4036,9 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move)
|
|
* ancestor inode.
|
|
* ancestor inode.
|
|
*/
|
|
*/
|
|
if (orphanized_ancestor) {
|
|
if (orphanized_ancestor) {
|
|
- struct fs_path *new_path;
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Our reference's name member points to
|
|
|
|
- * its full_path member string, so we
|
|
|
|
- * use here a new path.
|
|
|
|
- */
|
|
|
|
- new_path = fs_path_alloc();
|
|
|
|
- if (!new_path) {
|
|
|
|
- ret = -ENOMEM;
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
- ret = get_cur_path(sctx, cur->dir,
|
|
|
|
- cur->dir_gen,
|
|
|
|
- new_path);
|
|
|
|
- if (ret < 0) {
|
|
|
|
- fs_path_free(new_path);
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
- ret = fs_path_add(new_path,
|
|
|
|
- cur->name,
|
|
|
|
- cur->name_len);
|
|
|
|
- if (ret < 0) {
|
|
|
|
- fs_path_free(new_path);
|
|
|
|
|
|
+ ret = update_ref_path(sctx, cur);
|
|
|
|
+ if (ret < 0)
|
|
goto out;
|
|
goto out;
|
|
- }
|
|
|
|
- fs_path_free(cur->full_path);
|
|
|
|
- set_ref_path(cur, new_path);
|
|
|
|
}
|
|
}
|
|
ret = send_unlink(sctx, cur->full_path);
|
|
ret = send_unlink(sctx, cur->full_path);
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
@@ -5249,15 +5270,12 @@ static int is_extent_unchanged(struct send_ctx *sctx,
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
- right_disknr = btrfs_file_extent_disk_bytenr(eb, ei);
|
|
|
|
if (right_type == BTRFS_FILE_EXTENT_INLINE) {
|
|
if (right_type == BTRFS_FILE_EXTENT_INLINE) {
|
|
right_len = btrfs_file_extent_inline_len(eb, slot, ei);
|
|
right_len = btrfs_file_extent_inline_len(eb, slot, ei);
|
|
right_len = PAGE_ALIGN(right_len);
|
|
right_len = PAGE_ALIGN(right_len);
|
|
} else {
|
|
} else {
|
|
right_len = btrfs_file_extent_num_bytes(eb, ei);
|
|
right_len = btrfs_file_extent_num_bytes(eb, ei);
|
|
}
|
|
}
|
|
- right_offset = btrfs_file_extent_offset(eb, ei);
|
|
|
|
- right_gen = btrfs_file_extent_generation(eb, ei);
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
* Are we at extent 8? If yes, we know the extent is changed.
|
|
* Are we at extent 8? If yes, we know the extent is changed.
|
|
@@ -5282,6 +5300,10 @@ static int is_extent_unchanged(struct send_ctx *sctx,
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ right_disknr = btrfs_file_extent_disk_bytenr(eb, ei);
|
|
|
|
+ right_offset = btrfs_file_extent_offset(eb, ei);
|
|
|
|
+ right_gen = btrfs_file_extent_generation(eb, ei);
|
|
|
|
+
|
|
left_offset_fixed = left_offset;
|
|
left_offset_fixed = left_offset;
|
|
if (key.offset < ekey->offset) {
|
|
if (key.offset < ekey->offset) {
|
|
/* Fix the right offset for 2a and 7. */
|
|
/* Fix the right offset for 2a and 7. */
|