]> granicus.if.org Git - zfs/commitdiff
FreeBSD PR kern/172259: Fixes zfs receive errors
authorsmh <smh@FreeBSD.org>
Thu, 13 Dec 2012 22:03:07 +0000 (22:03 +0000)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Thu, 2 Oct 2014 23:48:19 +0000 (16:48 -0700)
FreeBSD PR kern/172259: 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

References:
  https://github.com/freebsd/freebsd/commit/4995789

Porting notes:

Minor whitespace fixes were made to conform with style requirements:

lib/libzfs/libzfs_sendrecv.c: 2269: indent by spaces instead of tabs
lib/libzfs/libzfs_sendrecv.c: 2270: indent by spaces instead of tabs

Ported-by: Richard Yao <ryao@gentoo.org>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Issue #2729

lib/libzfs/libzfs_sendrecv.c

index ebd8a7be2ce4c197c6b99394089f9c5b47fe4ba8..3b4acc956907762b37d6aaa34c4411f9f62395d6 100644 (file)
@@ -745,7 +745,7 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg)
        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, 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, "snapprops", sd->snapprops));
        nvlist_free(sd->parent_snaps);
@@ -2020,11 +2020,12 @@ 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 guidname[32];
        int error;
        boolean_t needagain, progress, recursive;
        char *s1, *s2;
@@ -2040,6 +2041,8 @@ recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs,
 again:
        needagain = progress = B_FALSE;
 
+       VERIFY(0 == nvlist_alloc(&deleted, NV_UNIQUE_NAME, 0));
+
        if ((error = gather_nvlist(hdl, tofs, fromsnap, NULL,
            recursive, &local_nv, &local_avl)) != 0)
                return (error);
@@ -2154,6 +2157,8 @@ again:
                                        needagain = B_TRUE;
                                else
                                        progress = B_TRUE;
+                               sprintf(guidname, "%lu", thisguid);
+                               nvlist_add_boolean(deleted, guidname);
                                continue;
                        }
 
@@ -2209,6 +2214,8 @@ again:
                                needagain = B_TRUE;
                        else
                                progress = B_TRUE;
+                       sprintf(guidname, "%lu", parent_fromsnap_guid);
+                       nvlist_add_boolean(deleted, guidname);
                        continue;
                }
 
@@ -2230,6 +2237,24 @@ again:
                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
+                * 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
                 * does not count as a rename, but we still need to check the
@@ -2284,8 +2309,10 @@ again:
                }
        }
 
+doagain:
        fsavl_destroy(local_avl);
        nvlist_free(local_nv);
+       nvlist_free(deleted);
 
        if (needagain && progress) {
                /* do another pass to fix up temporary names */