Fixes zfs receive errors caused by snapshot replication being processed in a
random order instead of creation order. Eliminates needless filesystem renames caused by removed parent snapshots which subsequently causes many more errors. PR: kern/172259 Submitted by: Steven Hartland Reviewed by: pjd (mentor) Approved by: pjd (mentor) MFC after: 2 weeks
This commit is contained in:
parent
7b332f2020
commit
425fb6dbaf
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=244194
@ -727,7 +727,7 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg)
|
|||||||
sd->parent_fromsnap_guid = 0;
|
sd->parent_fromsnap_guid = 0;
|
||||||
VERIFY(0 == nvlist_alloc(&sd->parent_snaps, NV_UNIQUE_NAME, 0));
|
VERIFY(0 == nvlist_alloc(&sd->parent_snaps, NV_UNIQUE_NAME, 0));
|
||||||
VERIFY(0 == nvlist_alloc(&sd->snapprops, NV_UNIQUE_NAME, 0));
|
VERIFY(0 == nvlist_alloc(&sd->snapprops, NV_UNIQUE_NAME, 0));
|
||||||
(void) zfs_iter_snapshots(zhp, B_FALSE, 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, "snaps", sd->parent_snaps));
|
||||||
VERIFY(0 == nvlist_add_nvlist(nvfs, "snapprops", sd->snapprops));
|
VERIFY(0 == nvlist_add_nvlist(nvfs, "snapprops", sd->snapprops));
|
||||||
nvlist_free(sd->parent_snaps);
|
nvlist_free(sd->parent_snaps);
|
||||||
@ -1945,11 +1945,12 @@ recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs,
|
|||||||
recvflags_t *flags, nvlist_t *stream_nv, avl_tree_t *stream_avl,
|
recvflags_t *flags, nvlist_t *stream_nv, avl_tree_t *stream_avl,
|
||||||
nvlist_t *renamed)
|
nvlist_t *renamed)
|
||||||
{
|
{
|
||||||
nvlist_t *local_nv;
|
nvlist_t *local_nv, *deleted = NULL;
|
||||||
avl_tree_t *local_avl;
|
avl_tree_t *local_avl;
|
||||||
nvpair_t *fselem, *nextfselem;
|
nvpair_t *fselem, *nextfselem;
|
||||||
char *fromsnap;
|
char *fromsnap;
|
||||||
char newname[ZFS_MAXNAMELEN];
|
char newname[ZFS_MAXNAMELEN];
|
||||||
|
char guidname[32];
|
||||||
int error;
|
int error;
|
||||||
boolean_t needagain, progress, recursive;
|
boolean_t needagain, progress, recursive;
|
||||||
char *s1, *s2;
|
char *s1, *s2;
|
||||||
@ -1965,6 +1966,8 @@ recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs,
|
|||||||
again:
|
again:
|
||||||
needagain = progress = B_FALSE;
|
needagain = progress = B_FALSE;
|
||||||
|
|
||||||
|
VERIFY(0 == nvlist_alloc(&deleted, NV_UNIQUE_NAME, 0));
|
||||||
|
|
||||||
if ((error = gather_nvlist(hdl, tofs, fromsnap, NULL,
|
if ((error = gather_nvlist(hdl, tofs, fromsnap, NULL,
|
||||||
recursive, &local_nv, &local_avl)) != 0)
|
recursive, &local_nv, &local_avl)) != 0)
|
||||||
return (error);
|
return (error);
|
||||||
@ -2079,6 +2082,8 @@ recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs,
|
|||||||
needagain = B_TRUE;
|
needagain = B_TRUE;
|
||||||
else
|
else
|
||||||
progress = B_TRUE;
|
progress = B_TRUE;
|
||||||
|
sprintf(guidname, "%lu", thisguid);
|
||||||
|
nvlist_add_boolean(deleted, guidname);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2134,6 +2139,8 @@ recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs,
|
|||||||
needagain = B_TRUE;
|
needagain = B_TRUE;
|
||||||
else
|
else
|
||||||
progress = B_TRUE;
|
progress = B_TRUE;
|
||||||
|
sprintf(guidname, "%lu", parent_fromsnap_guid);
|
||||||
|
nvlist_add_boolean(deleted, guidname);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2155,6 +2162,24 @@ recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs,
|
|||||||
s1 = strrchr(fsname, '/');
|
s1 = strrchr(fsname, '/');
|
||||||
s2 = strrchr(stream_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
|
||||||
|
* rename will fail and is likely unneeded, 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) {
|
||||||
|
sprintf(guidname, "%lu", 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
|
* Check for rename. If the exact receive path is specified, it
|
||||||
* does not count as a rename, but we still need to check the
|
* does not count as a rename, but we still need to check the
|
||||||
@ -2209,8 +2234,10 @@ recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
doagain:
|
||||||
fsavl_destroy(local_avl);
|
fsavl_destroy(local_avl);
|
||||||
nvlist_free(local_nv);
|
nvlist_free(local_nv);
|
||||||
|
nvlist_free(deleted);
|
||||||
|
|
||||||
if (needagain && progress) {
|
if (needagain && progress) {
|
||||||
/* do another pass to fix up temporary names */
|
/* do another pass to fix up temporary names */
|
||||||
|
Loading…
Reference in New Issue
Block a user