summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorpablofsf <[email protected]>2021-04-11 21:05:35 +0200
committerBrian Behlendorf <[email protected]>2021-04-14 13:19:50 -0700
commit07d64c07e06e558219f645b304d891bed9ff652f (patch)
tree462e399ee5c23da0273ed546e3c3912d02df16d7 /lib
parentf8631d0fe065c2211fa3527d4b9f5e04725382fb (diff)
Allow zfs to send replication streams with missing snapshots
A tentative implementation and discussion was done in #5285. According to it a send --skip-missing|-s flag has been added. In a replication stream, when there are snapshots missing in the hierarchy, if -s is provided print a warning and ignore dataset (and its children) instead of throwing an error Reviewed-by: Paul Dagnelie <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Pablo Correa Gómez <[email protected]> Closes #11710
Diffstat (limited to 'lib')
-rw-r--r--lib/libzfs/libzfs_sendrecv.c36
1 files changed, 23 insertions, 13 deletions
diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c
index bc887e72a..ee593f8db 100644
--- a/lib/libzfs/libzfs_sendrecv.c
+++ b/lib/libzfs/libzfs_sendrecv.c
@@ -247,6 +247,7 @@ typedef struct send_data {
boolean_t raw;
boolean_t doall;
boolean_t replicate;
+ boolean_t skipmissing;
boolean_t verbose;
boolean_t backup;
boolean_t seenfrom;
@@ -497,7 +498,8 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg)
* - skip sending the current dataset if it was created later than
* the parent tosnap
* - return error if the current dataset was created earlier than
- * the parent tosnap
+ * the parent tosnap, unless --skip-missing specified. Then
+ * just print a warning
*/
if (sd->tosnap != NULL && tosnap_txg == 0) {
if (sd->tosnap_txg != 0 && txg > sd->tosnap_txg) {
@@ -506,6 +508,11 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg)
"skipping dataset %s: snapshot %s does "
"not exist\n"), zhp->zfs_name, sd->tosnap);
}
+ } else if (sd->skipmissing) {
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "WARNING: skipping dataset %s and its children:"
+ " snapshot %s does not exist\n"),
+ zhp->zfs_name, sd->tosnap);
} else {
(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
"cannot send %s@%s%s: snapshot %s@%s does not "
@@ -649,8 +656,9 @@ out:
static int
gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap,
const char *tosnap, boolean_t recursive, boolean_t raw, boolean_t doall,
- boolean_t replicate, boolean_t verbose, boolean_t backup, boolean_t holds,
- boolean_t props, nvlist_t **nvlp, avl_tree_t **avlp)
+ boolean_t replicate, boolean_t skipmissing, boolean_t verbose,
+ boolean_t backup, boolean_t holds, boolean_t props, nvlist_t **nvlp,
+ avl_tree_t **avlp)
{
zfs_handle_t *zhp;
send_data_t sd = { 0 };
@@ -668,6 +676,7 @@ gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap,
sd.raw = raw;
sd.doall = doall;
sd.replicate = replicate;
+ sd.skipmissing = skipmissing;
sd.verbose = verbose;
sd.backup = backup;
sd.holds = holds;
@@ -1975,8 +1984,8 @@ send_conclusion_record(int fd, zio_cksum_t *zc)
static int
send_prelim_records(zfs_handle_t *zhp, const char *from, int fd,
boolean_t gather_props, boolean_t recursive, boolean_t verbose,
- boolean_t dryrun, boolean_t raw, boolean_t replicate, boolean_t backup,
- boolean_t holds, boolean_t props, boolean_t doall,
+ boolean_t dryrun, boolean_t raw, boolean_t replicate, boolean_t skipmissing,
+ boolean_t backup, boolean_t holds, boolean_t props, boolean_t doall,
nvlist_t **fssp, avl_tree_t **fsavlp)
{
int err = 0;
@@ -2022,8 +2031,8 @@ send_prelim_records(zfs_handle_t *zhp, const char *from, int fd,
}
if ((err = gather_nvlist(zhp->zfs_hdl, tofs,
- from, tosnap, recursive, raw, doall, replicate, verbose,
- backup, holds, props, &fss, fsavlp)) != 0) {
+ from, tosnap, recursive, raw, doall, replicate, skipmissing,
+ verbose, backup, holds, props, &fss, fsavlp)) != 0) {
return (zfs_error(zhp->zfs_hdl, EZFS_BADBACKUP,
errbuf));
}
@@ -2160,8 +2169,9 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
err = send_prelim_records(tosnap, fromsnap, outfd,
flags->replicate || flags->props || flags->holds,
flags->replicate, flags->verbosity > 0, flags->dryrun,
- flags->raw, flags->replicate, flags->backup, flags->holds,
- flags->props, flags->doall, &fss, &fsavl);
+ flags->raw, flags->replicate, flags->skipmissing,
+ flags->backup, flags->holds, flags->props, flags->doall,
+ &fss, &fsavl);
zfs_close(tosnap);
if (err != 0)
goto err_out;
@@ -2464,7 +2474,7 @@ zfs_send_one(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags,
*/
err = send_prelim_records(zhp, NULL, fd, B_TRUE, B_FALSE,
flags->verbosity > 0, flags->dryrun, flags->raw,
- flags->replicate, flags->backup, flags->holds,
+ flags->replicate, B_FALSE, flags->backup, flags->holds,
flags->props, flags->doall, NULL, NULL);
if (err != 0)
return (err);
@@ -3236,7 +3246,7 @@ again:
deleted = fnvlist_alloc();
if ((error = gather_nvlist(hdl, tofs, fromsnap, NULL,
- recursive, B_TRUE, B_FALSE, recursive, B_FALSE, B_FALSE,
+ recursive, B_TRUE, B_FALSE, recursive, B_FALSE, B_FALSE, B_FALSE,
B_FALSE, B_TRUE, &local_nv, &local_avl)) != 0)
return (error);
@@ -4729,8 +4739,8 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
*/
*cp = '\0';
if (gather_nvlist(hdl, destsnap, NULL, NULL, B_FALSE, B_TRUE,
- B_FALSE, B_FALSE, B_FALSE, B_FALSE, B_FALSE, B_TRUE,
- &local_nv, &local_avl) == 0) {
+ B_FALSE, B_FALSE, B_FALSE, B_FALSE, B_FALSE, B_FALSE,
+ B_TRUE, &local_nv, &local_avl) == 0) {
*cp = '@';
fs = fsavl_find(local_avl, drrb->drr_toguid, NULL);
fsavl_destroy(local_avl);