Index: cddl/contrib/opensolaris/cmd/zfs/zfs.8 =================================================================== --- cddl/contrib/opensolaris/cmd/zfs/zfs.8 +++ cddl/contrib/opensolaris/cmd/zfs/zfs.8 @@ -29,6 +29,7 @@ .\" Copyright (c) 2014, Xin LI .\" Copyright (c) 2014-2015, The FreeBSD Foundation, All Rights Reserved. .\" Copyright 2018 Joyent, Inc. +.\" Copyright (c) 2019, Intel Corporation. All rights reserved. .\" .\" $FreeBSD$ .\" @@ -184,7 +185,7 @@ .Ar bookmark .Nm .Cm send -.Op Fl DLPRcenpv +.Op Fl DLPRcenpvf .Op Fl i Ar snapshot | Fl I Ar snapshot .Ar snapshot .Nm @@ -2607,7 +2608,7 @@ .It Xo .Nm .Cm send -.Op Fl DLPRcenpv +.Op Fl DLPRcenpvf .Op Fl i Ar snapshot | Fl I Ar snapshot .Ar snapshot .Xc @@ -2670,6 +2671,11 @@ .Fl F flag is specified when this stream is received, snapshots and file systems that do not exist on the sending side are destroyed. +.It Fl f, -force +When used in conjunction with the +.Fl R +flag, skips parts of the tree with missing snapshots instead of returning an +error. .It Fl D, -dedup Generate a deduplicated stream. Blocks which would have been sent multiple times in the send stream will only be sent once. The receiving system must Index: cddl/contrib/opensolaris/cmd/zfs/zfs_main.c =================================================================== --- cddl/contrib/opensolaris/cmd/zfs/zfs_main.c +++ cddl/contrib/opensolaris/cmd/zfs/zfs_main.c @@ -30,6 +30,7 @@ * Copyright (c) 2014 Integros [integros.com] * Copyright 2016 Igor Kozhukhov . * Copyright 2016 Nexenta Systems, Inc. + * Copyright (c) 2019, Intel Corporation. All rights reserved. */ #include @@ -287,7 +288,7 @@ case HELP_ROLLBACK: return (gettext("\trollback [-rRf] \n")); case HELP_SEND: - return (gettext("\tsend [-DnPpRvLec] [-[iI] snapshot] " + return (gettext("\tsend [-DnPpRvLecf] [-[iI] snapshot] " "\n" "\tsend [-Le] [-i snapshot|bookmark] " "\n" @@ -3800,6 +3801,7 @@ struct option long_options[] = { {"replicate", no_argument, NULL, 'R'}, + {"force", no_argument, NULL, 'f'}, {"props", no_argument, NULL, 'p'}, {"parsable", no_argument, NULL, 'P'}, {"dedup", no_argument, NULL, 'D'}, @@ -3813,7 +3815,7 @@ }; /* check options */ - while ((c = getopt_long(argc, argv, ":i:I:RbDpvnPLet:c", long_options, + while ((c = getopt_long(argc, argv, ":i:I:RfbDpvnPLet:c", long_options, NULL)) != -1) { switch (c) { case 'i': @@ -3830,6 +3832,9 @@ case 'R': flags.replicate = B_TRUE; break; + case 'f': + flags.force = B_TRUE; + break; case 'p': flags.props = B_TRUE; break; Index: cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h =================================================================== --- cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h +++ cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h @@ -29,6 +29,7 @@ * Copyright (c) 2014 Integros [integros.com] * Copyright 2016 Nexenta Systems, Inc. * Copyright (c) 2017 Datto Inc. + * Copyright (c) 2019, Intel Corporation. All rights reserved. */ #ifndef _LIBZFS_H @@ -622,6 +623,9 @@ /* recursive send (ie, -R) */ boolean_t replicate; + /* force recursive send: skip filesystems without snapshots */ + boolean_t force; + /* for incrementals, do all intermediate snapshots */ boolean_t doall; Index: cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c =================================================================== --- cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c +++ cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c @@ -28,6 +28,7 @@ * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved. * Copyright (c) 2014 Integros [integros.com] * Copyright 2016 Igor Kozhukhov + * Copyright (c) 2019, Intel Corporation. All rights reserved. */ #include @@ -609,6 +610,7 @@ const char *fromsnap; const char *tosnap; boolean_t recursive; + boolean_t force; boolean_t verbose; /* @@ -813,7 +815,8 @@ * the parent tosnap */ if (sd->tosnap != NULL && tosnap_txg == 0) { - if (sd->tosnap_txg != 0 && txg > sd->tosnap_txg) { + if (sd->tosnap_txg != 0 && txg > sd->tosnap_txg || + sd->recursive && sd->force) { if (sd->verbose) { (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "skipping dataset %s: snapshot %s does " @@ -883,8 +886,8 @@ static int gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap, - const char *tosnap, boolean_t recursive, boolean_t verbose, - nvlist_t **nvlp, avl_tree_t **avlp) + const char *tosnap, boolean_t recursive, boolean_t force, + boolean_t verbose, nvlist_t **nvlp, avl_tree_t **avlp) { zfs_handle_t *zhp; send_data_t sd = { 0 }; @@ -899,6 +902,7 @@ sd.fromsnap = fromsnap; sd.tosnap = tosnap; sd.recursive = recursive; + sd.force = force; sd.verbose = verbose; if ((error = send_iterate_fs(zhp, &sd)) != 0) { @@ -930,7 +934,7 @@ uint64_t prevsnap_obj; boolean_t seenfrom, seento, replicate, doall, fromorigin; boolean_t verbose, dryrun, parsable, progress, embed_data, std_out; - boolean_t large_block, compress; + boolean_t large_block, compress, force; int outfd; boolean_t err; nvlist_t *fss; @@ -1816,8 +1820,8 @@ } err = gather_nvlist(zhp->zfs_hdl, zhp->zfs_name, - fromsnap, tosnap, flags->replicate, flags->verbose, - &fss, &fsavl); + fromsnap, tosnap, flags->replicate, flags->force, + flags->verbose, &fss, &fsavl); if (err) goto err_out; VERIFY(0 == nvlist_add_nvlist(hdrnv, "fss", fss)); @@ -1871,6 +1875,7 @@ else sdd.outfd = outfd; sdd.replicate = flags->replicate; + sdd.force = flags->force; sdd.doall = flags->doall; sdd.fromorigin = flags->fromorigin; sdd.fss = fss; @@ -2427,7 +2432,7 @@ VERIFY(0 == nvlist_alloc(&deleted, NV_UNIQUE_NAME, 0)); if ((error = gather_nvlist(hdl, tofs, fromsnap, NULL, - recursive, B_FALSE, &local_nv, &local_avl)) != 0) + recursive, B_FALSE, B_FALSE, &local_nv, &local_avl)) != 0) return (error); /* @@ -3497,7 +3502,7 @@ */ *cp = '\0'; if (gather_nvlist(hdl, zc.zc_value, NULL, NULL, B_FALSE, - B_FALSE, &local_nv, &local_avl) == 0) { + B_FALSE, B_FALSE, &local_nv, &local_avl) == 0) { *cp = '@'; fs = fsavl_find(local_avl, drrb->drr_toguid, NULL); fsavl_destroy(local_avl);