Send stream should only list included snaps
Currently, zfs send streams will include a list of all snapshots on the source side if the '-p' option is provided. This can cause performance problems on the receive side, especially if those snapshots aren't present on the destination. These problems arise because guid_to_name(), which is used for several receive side functions, will search the entire receive-side pool if it can't find a snapshot with a matching guid. This patch corrects the issue by ensuring only streams that require this list of snapshots include them. Reviewed-by: Alek Pinchuk <apinchuk@datto.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: Matt Ahrens <mahrens@delphix.com> Signed-off-by: Tom Caputi <tcaputi@datto.com> Closes #8533
This commit is contained in:
parent
5dbf8b4edd
commit
f94b3cbf43
|
@ -625,6 +625,7 @@ typedef struct send_data {
|
||||||
const char *tosnap;
|
const char *tosnap;
|
||||||
boolean_t recursive;
|
boolean_t recursive;
|
||||||
boolean_t raw;
|
boolean_t raw;
|
||||||
|
boolean_t doall;
|
||||||
boolean_t replicate;
|
boolean_t replicate;
|
||||||
boolean_t verbose;
|
boolean_t verbose;
|
||||||
boolean_t backup;
|
boolean_t backup;
|
||||||
|
@ -949,14 +950,37 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg)
|
||||||
sd->parent_fromsnap_guid = 0;
|
sd->parent_fromsnap_guid = 0;
|
||||||
sd->parent_snaps = fnvlist_alloc();
|
sd->parent_snaps = fnvlist_alloc();
|
||||||
sd->snapprops = fnvlist_alloc();
|
sd->snapprops = fnvlist_alloc();
|
||||||
if (!sd->replicate && fromsnap_txg != 0)
|
|
||||||
min_txg = fromsnap_txg;
|
|
||||||
if (!sd->replicate && tosnap_txg != 0)
|
|
||||||
max_txg = tosnap_txg;
|
|
||||||
if (sd->holds)
|
if (sd->holds)
|
||||||
VERIFY(0 == nvlist_alloc(&sd->snapholds, NV_UNIQUE_NAME, 0));
|
VERIFY(0 == nvlist_alloc(&sd->snapholds, NV_UNIQUE_NAME, 0));
|
||||||
(void) zfs_iter_snapshots_sorted(zhp, send_iterate_snap, sd,
|
|
||||||
min_txg, max_txg);
|
|
||||||
|
/*
|
||||||
|
* If this is a "doall" send, a replicate send or we're just trying
|
||||||
|
* to gather a list of previous snapshots, iterate through all the
|
||||||
|
* snaps in the txg range. Otherwise just look at the one we're
|
||||||
|
* interested in.
|
||||||
|
*/
|
||||||
|
if (sd->doall || sd->replicate || sd->tosnap == NULL) {
|
||||||
|
if (!sd->replicate && fromsnap_txg != 0)
|
||||||
|
min_txg = fromsnap_txg;
|
||||||
|
if (!sd->replicate && tosnap_txg != 0)
|
||||||
|
max_txg = tosnap_txg;
|
||||||
|
(void) zfs_iter_snapshots_sorted(zhp, send_iterate_snap, sd,
|
||||||
|
min_txg, max_txg);
|
||||||
|
} else {
|
||||||
|
char snapname[MAXPATHLEN] = { 0 };
|
||||||
|
zfs_handle_t *snap;
|
||||||
|
|
||||||
|
(void) snprintf(snapname, sizeof (snapname) - 1, "%s@%s",
|
||||||
|
zhp->zfs_name, sd->tosnap);
|
||||||
|
if (sd->fromsnap != NULL)
|
||||||
|
sd->seenfrom = B_TRUE;
|
||||||
|
snap = zfs_open(zhp->zfs_hdl, snapname,
|
||||||
|
ZFS_TYPE_SNAPSHOT);
|
||||||
|
if (snap != NULL)
|
||||||
|
(void) send_iterate_snap(snap, sd);
|
||||||
|
}
|
||||||
|
|
||||||
fnvlist_add_nvlist(nvfs, "snaps", sd->parent_snaps);
|
fnvlist_add_nvlist(nvfs, "snaps", sd->parent_snaps);
|
||||||
fnvlist_add_nvlist(nvfs, "snapprops", sd->snapprops);
|
fnvlist_add_nvlist(nvfs, "snapprops", sd->snapprops);
|
||||||
if (sd->holds)
|
if (sd->holds)
|
||||||
|
@ -987,10 +1011,9 @@ out:
|
||||||
|
|
||||||
static int
|
static int
|
||||||
gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap,
|
gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap,
|
||||||
const char *tosnap, boolean_t recursive, boolean_t raw, boolean_t replicate,
|
const char *tosnap, boolean_t recursive, boolean_t raw, boolean_t doall,
|
||||||
boolean_t verbose, boolean_t backup, boolean_t holds, boolean_t props,
|
boolean_t replicate, boolean_t verbose, boolean_t backup, boolean_t holds,
|
||||||
nvlist_t **nvlp,
|
boolean_t props, nvlist_t **nvlp, avl_tree_t **avlp)
|
||||||
avl_tree_t **avlp)
|
|
||||||
{
|
{
|
||||||
zfs_handle_t *zhp;
|
zfs_handle_t *zhp;
|
||||||
send_data_t sd = { 0 };
|
send_data_t sd = { 0 };
|
||||||
|
@ -1006,6 +1029,7 @@ gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap,
|
||||||
sd.tosnap = tosnap;
|
sd.tosnap = tosnap;
|
||||||
sd.recursive = recursive;
|
sd.recursive = recursive;
|
||||||
sd.raw = raw;
|
sd.raw = raw;
|
||||||
|
sd.doall = doall;
|
||||||
sd.replicate = replicate;
|
sd.replicate = replicate;
|
||||||
sd.verbose = verbose;
|
sd.verbose = verbose;
|
||||||
sd.backup = backup;
|
sd.backup = backup;
|
||||||
|
@ -1478,15 +1502,49 @@ dump_filesystem(zfs_handle_t *zhp, void *arg)
|
||||||
if (sdd->fromsnap == NULL || missingfrom)
|
if (sdd->fromsnap == NULL || missingfrom)
|
||||||
sdd->seenfrom = B_TRUE;
|
sdd->seenfrom = B_TRUE;
|
||||||
|
|
||||||
if (!sdd->replicate && sdd->fromsnap != NULL)
|
|
||||||
min_txg = get_snap_txg(zhp->zfs_hdl, zhp->zfs_name,
|
|
||||||
sdd->fromsnap);
|
|
||||||
if (!sdd->replicate && sdd->tosnap != NULL)
|
|
||||||
max_txg = get_snap_txg(zhp->zfs_hdl, zhp->zfs_name,
|
|
||||||
sdd->tosnap);
|
|
||||||
|
|
||||||
rv = zfs_iter_snapshots_sorted(zhp, dump_snapshot, arg,
|
|
||||||
min_txg, max_txg);
|
/*
|
||||||
|
* Iterate through all snapshots and process the ones we will be
|
||||||
|
* sending. If we only have a "from" and "to" snapshot to deal
|
||||||
|
* with, we can avoid iterating through all the other snapshots.
|
||||||
|
*/
|
||||||
|
if (sdd->doall || sdd->replicate || sdd->tosnap == NULL) {
|
||||||
|
if (!sdd->replicate && sdd->fromsnap != NULL)
|
||||||
|
min_txg = get_snap_txg(zhp->zfs_hdl, zhp->zfs_name,
|
||||||
|
sdd->fromsnap);
|
||||||
|
if (!sdd->replicate && sdd->tosnap != NULL)
|
||||||
|
max_txg = get_snap_txg(zhp->zfs_hdl, zhp->zfs_name,
|
||||||
|
sdd->tosnap);
|
||||||
|
rv = zfs_iter_snapshots_sorted(zhp, dump_snapshot, arg,
|
||||||
|
min_txg, max_txg);
|
||||||
|
} else {
|
||||||
|
char snapname[MAXPATHLEN] = { 0 };
|
||||||
|
zfs_handle_t *snap;
|
||||||
|
|
||||||
|
if (!sdd->seenfrom) {
|
||||||
|
(void) snprintf(snapname, sizeof (snapname) - 1,
|
||||||
|
"%s@%s", zhp->zfs_name, sdd->fromsnap);
|
||||||
|
snap = zfs_open(zhp->zfs_hdl, snapname,
|
||||||
|
ZFS_TYPE_SNAPSHOT);
|
||||||
|
if (snap != NULL)
|
||||||
|
rv = dump_snapshot(snap, sdd);
|
||||||
|
else
|
||||||
|
rv = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rv == 0) {
|
||||||
|
(void) snprintf(snapname, sizeof (snapname) - 1,
|
||||||
|
"%s@%s", zhp->zfs_name, sdd->tosnap);
|
||||||
|
snap = zfs_open(zhp->zfs_hdl, snapname,
|
||||||
|
ZFS_TYPE_SNAPSHOT);
|
||||||
|
if (snap != NULL)
|
||||||
|
rv = dump_snapshot(snap, sdd);
|
||||||
|
else
|
||||||
|
rv = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!sdd->seenfrom) {
|
if (!sdd->seenfrom) {
|
||||||
(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
|
(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
|
||||||
"WARNING: could not send %s@%s:\n"
|
"WARNING: could not send %s@%s:\n"
|
||||||
|
@ -1965,8 +2023,9 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
|
||||||
|
|
||||||
err = gather_nvlist(zhp->zfs_hdl, zhp->zfs_name,
|
err = gather_nvlist(zhp->zfs_hdl, zhp->zfs_name,
|
||||||
fromsnap, tosnap, flags->replicate, flags->raw,
|
fromsnap, tosnap, flags->replicate, flags->raw,
|
||||||
flags->replicate, flags->verbose, flags->backup,
|
flags->doall, flags->replicate, flags->verbose,
|
||||||
flags->holds, flags->props, &fss, &fsavl);
|
flags->backup, flags->holds, flags->props, &fss,
|
||||||
|
&fsavl);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_out;
|
goto err_out;
|
||||||
VERIFY(0 == nvlist_add_nvlist(hdrnv, "fss", fss));
|
VERIFY(0 == nvlist_add_nvlist(hdrnv, "fss", fss));
|
||||||
|
@ -2870,8 +2929,8 @@ again:
|
||||||
VERIFY(0 == nvlist_alloc(&deleted, NV_UNIQUE_NAME, 0));
|
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, B_TRUE, recursive, B_FALSE, B_FALSE, B_FALSE, B_TRUE,
|
recursive, B_TRUE, B_FALSE, recursive, B_FALSE, B_FALSE,
|
||||||
&local_nv, &local_avl)) != 0)
|
B_FALSE, B_TRUE, &local_nv, &local_avl)) != 0)
|
||||||
return (error);
|
return (error);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -4304,8 +4363,8 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
|
||||||
*/
|
*/
|
||||||
*cp = '\0';
|
*cp = '\0';
|
||||||
if (gather_nvlist(hdl, destsnap, NULL, NULL, B_FALSE, B_TRUE,
|
if (gather_nvlist(hdl, destsnap, NULL, NULL, B_FALSE, B_TRUE,
|
||||||
B_FALSE, B_FALSE, B_FALSE, B_FALSE, B_TRUE, &local_nv,
|
B_FALSE, B_FALSE, B_FALSE, B_FALSE, B_FALSE, B_TRUE,
|
||||||
&local_avl) == 0) {
|
&local_nv, &local_avl) == 0) {
|
||||||
*cp = '@';
|
*cp = '@';
|
||||||
fs = fsavl_find(local_avl, drrb->drr_toguid, NULL);
|
fs = fsavl_find(local_avl, drrb->drr_toguid, NULL);
|
||||||
fsavl_destroy(local_avl);
|
fsavl_destroy(local_avl);
|
||||||
|
|
Loading…
Reference in New Issue