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");