Produce a full snapshot list for zfs send -p

In order to accelerate zfs receive operations in the face of many
property-containing snapshots, commit 0574855 changed the header nvlist
("fss") of a send stream to exclude snapshots which aren't part of the
stream.  This, however, would cause zfs receive -F to erroneously remove
snapshots; it would remove any snapshot which wasn't listed in the header
nvlist.

This patch restores the full list of snapshots in fss[<id>[snaps]] but
still suppresses the properties of non-sent snapshots and also removes a
consistency check in which an error is raised if a listed snapshot does
not have any properties in fss[<id>[snapprops]].

The 0574855 commit also introduced a bug in which zfs send -p of a
complete stream (zfs send -p pool/fs@snap) would exclude the snapshot
properties in fss[<id>[snapprops]].  This patch detects the last snapshot
in a series when no "from" snapshot has been specified and includes its
properties.

Signed-off-by: Tim Chase <tim@chase2k.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #2907
This commit is contained in:
Tim Chase 2014-11-16 22:27:58 -06:00 committed by Brian Behlendorf
parent 7fc8c33ede
commit e890dd85a7
1 changed files with 4 additions and 10 deletions

View File

@ -613,13 +613,15 @@ send_iterate_snap(zfs_handle_t *zhp, void *arg)
uint64_t guid = zhp->zfs_dmustats.dds_guid; uint64_t guid = zhp->zfs_dmustats.dds_guid;
char *snapname; char *snapname;
nvlist_t *nv; nvlist_t *nv;
boolean_t isfromsnap, istosnap; boolean_t isfromsnap, istosnap, istosnapwithnofrom;
snapname = strrchr(zhp->zfs_name, '@')+1; snapname = strrchr(zhp->zfs_name, '@')+1;
isfromsnap = (sd->fromsnap != NULL && isfromsnap = (sd->fromsnap != NULL &&
strcmp(sd->fromsnap, snapname) == 0); strcmp(sd->fromsnap, snapname) == 0);
istosnap = (sd->tosnap != NULL && (strcmp(sd->tosnap, snapname) == 0)); istosnap = (sd->tosnap != NULL && (strcmp(sd->tosnap, snapname) == 0));
istosnapwithnofrom = (istosnap && sd->fromsnap == NULL);
VERIFY(0 == nvlist_add_uint64(sd->parent_snaps, snapname, guid));
/* /*
* NB: if there is no fromsnap here (it's a newly created fs in * NB: if there is no fromsnap here (it's a newly created fs in
* an incremental replication), we will substitute the tosnap. * an incremental replication), we will substitute the tosnap.
@ -635,7 +637,7 @@ send_iterate_snap(zfs_handle_t *zhp, void *arg)
return (0); return (0);
} }
if (sd->seento || !sd->seenfrom) { if ((sd->seento || !sd->seenfrom) && !istosnapwithnofrom) {
zfs_close(zhp); zfs_close(zhp);
return (0); return (0);
} }
@ -644,8 +646,6 @@ send_iterate_snap(zfs_handle_t *zhp, void *arg)
sd->seento = B_TRUE; sd->seento = B_TRUE;
} }
VERIFY(0 == nvlist_add_uint64(sd->parent_snaps, snapname, guid));
VERIFY(0 == nvlist_alloc(&nv, NV_UNIQUE_NAME, 0)); VERIFY(0 == nvlist_alloc(&nv, NV_UNIQUE_NAME, 0));
send_iterate_prop(zhp, nv); send_iterate_prop(zhp, nv);
VERIFY(0 == nvlist_add_nvlist(sd->snapprops, snapname, nv)); VERIFY(0 == nvlist_add_nvlist(sd->snapprops, snapname, nv));
@ -2695,12 +2695,6 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
ret = zcmd_write_src_nvlist(hdl, &zc, props); ret = zcmd_write_src_nvlist(hdl, &zc, props);
if (err) if (err)
nvlist_free(props); nvlist_free(props);
if (0 == nvlist_lookup_nvlist(fs, "snapprops", &props)) {
VERIFY(0 == nvlist_lookup_nvlist(props,
snapname, &snapprops_nvlist));
}
if (ret != 0) if (ret != 0)
return (-1); return (-1);
} }