Print this page
3819 zfs receive can fail due to processing order
*** 721,731 ****
/* iterate over snaps, and set sd->parent_fromsnap_guid */
sd->parent_fromsnap_guid = 0;
VERIFY(0 == nvlist_alloc(&sd->parent_snaps, NV_UNIQUE_NAME, 0));
VERIFY(0 == nvlist_alloc(&sd->snapprops, NV_UNIQUE_NAME, 0));
! (void) zfs_iter_snapshots(zhp, send_iterate_snap, sd);
VERIFY(0 == nvlist_add_nvlist(nvfs, "snaps", sd->parent_snaps));
VERIFY(0 == nvlist_add_nvlist(nvfs, "snapprops", sd->snapprops));
nvlist_free(sd->parent_snaps);
nvlist_free(sd->snapprops);
--- 721,731 ----
/* iterate over snaps, and set sd->parent_fromsnap_guid */
sd->parent_fromsnap_guid = 0;
VERIFY(0 == nvlist_alloc(&sd->parent_snaps, NV_UNIQUE_NAME, 0));
VERIFY(0 == nvlist_alloc(&sd->snapprops, NV_UNIQUE_NAME, 0));
! (void) zfs_iter_snapshots_sorted(zhp, send_iterate_snap, sd);
VERIFY(0 == nvlist_add_nvlist(nvfs, "snaps", sd->parent_snaps));
VERIFY(0 == nvlist_add_nvlist(nvfs, "snapprops", sd->snapprops));
nvlist_free(sd->parent_snaps);
nvlist_free(sd->snapprops);
*** 1934,1948 ****
static int
recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs,
recvflags_t *flags, nvlist_t *stream_nv, avl_tree_t *stream_avl,
nvlist_t *renamed)
{
! nvlist_t *local_nv;
avl_tree_t *local_avl;
nvpair_t *fselem, *nextfselem;
char *fromsnap;
! char newname[ZFS_MAXNAMELEN];
int error;
boolean_t needagain, progress, recursive;
char *s1, *s2;
VERIFY(0 == nvlist_lookup_string(stream_nv, "fromsnap", &fromsnap));
--- 1934,1948 ----
static int
recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs,
recvflags_t *flags, nvlist_t *stream_nv, avl_tree_t *stream_avl,
nvlist_t *renamed)
{
! nvlist_t *local_nv, *deleted = NULL;
avl_tree_t *local_avl;
nvpair_t *fselem, *nextfselem;
char *fromsnap;
! char newname[ZFS_MAXNAMELEN], guidname[32];
int error;
boolean_t needagain, progress, recursive;
char *s1, *s2;
VERIFY(0 == nvlist_lookup_string(stream_nv, "fromsnap", &fromsnap));
*** 1958,1967 ****
--- 1958,1969 ----
if ((error = gather_nvlist(hdl, tofs, fromsnap, NULL,
recursive, &local_nv, &local_avl)) != 0)
return (error);
+ deleted = fnvlist_alloc();
+
/*
* Process deletes and renames
*/
for (fselem = nvlist_next_nvpair(local_nv, NULL);
fselem; fselem = nextfselem) {
*** 2029,2038 ****
--- 2031,2041 ----
default:
break;
case -1:
fsavl_destroy(local_avl);
nvlist_free(local_nv);
+ nvlist_free(deleted);
return (-1);
}
/*
* We had/have the wrong origin, therefore our
* list of snapshots is wrong. Need to handle
*** 2068,2077 ****
--- 2071,2083 ----
strlen(fsname)+1, newname, flags);
if (error)
needagain = B_TRUE;
else
progress = B_TRUE;
+ (void) sprintf(guidname, "%llu",
+ (u_longlong_t)thisguid);
+ fnvlist_add_boolean(deleted, guidname);
continue;
}
stream_nvfs = found;
*** 2123,2132 ****
--- 2129,2141 ----
newname, flags);
if (error)
needagain = B_TRUE;
else
progress = B_TRUE;
+ (void) sprintf(guidname, "%llu",
+ (u_longlong_t)parent_fromsnap_guid);
+ fnvlist_add_boolean(deleted, guidname);
continue;
}
if (fromguid == 0) {
if (flags->verbose) {
*** 2145,2154 ****
--- 2154,2181 ----
s1 = strrchr(fsname, '/');
s2 = strrchr(stream_fsname, '/');
/*
+ * Check if we're going to rename based on parent guid change
+ * and the current parent guid was also deleted. If it was then
+ * the rename will fail so avoid this and force an early retry
+ * to determine the new parent_fromsnap_guid.
+ */
+ if (stream_parent_fromsnap_guid != 0 &&
+ parent_fromsnap_guid != 0 &&
+ stream_parent_fromsnap_guid != parent_fromsnap_guid) {
+ (void) sprintf(guidname, "%llu",
+ (u_longlong_t)parent_fromsnap_guid);
+ if (nvlist_exists(deleted, guidname)) {
+ progress = B_TRUE;
+ needagain = B_TRUE;
+ goto doagain;
+ }
+ }
+
+ /*
* Check for rename. If the exact receive path is specified, it
* does not count as a rename, but we still need to check the
* datasets beneath it.
*/
if ((stream_parent_fromsnap_guid != 0 &&
*** 2198,2209 ****
--- 2225,2238 ----
else
progress = B_TRUE;
}
}
+ doagain:
fsavl_destroy(local_avl);
nvlist_free(local_nv);
+ nvlist_free(deleted);
if (needagain && progress) {
/* do another pass to fix up temporary names */
if (flags->verbose)
(void) printf("another pass:\n");