Print this page
3819 zfs receive can fail due to processing order
@@ -721,11 +721,11 @@
/* 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);
+ (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,15 +1934,15 @@
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;
+ nvlist_t *local_nv, *deleted = NULL;
avl_tree_t *local_avl;
nvpair_t *fselem, *nextfselem;
char *fromsnap;
- char newname[ZFS_MAXNAMELEN];
+ 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,10 +1958,12 @@
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,10 +2031,11 @@
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,10 +2071,13 @@
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,10 +2129,13 @@
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,10 +2154,28 @@
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,12 +2225,14 @@
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");