diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c index 6fb35595ccc9..4d2ac81fc214 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -247,9 +247,9 @@ get_usage(zfs_help_t idx) case HELP_PROMOTE: return (gettext("\tpromote \n")); case HELP_RECEIVE: - return (gettext("\treceive [-vnFu] \n" - "\treceive [-vnFu] [-d | -e] \n")); + "\treceive [-vnFus] [-d | -e] \n")); case HELP_RENAME: return (gettext("\trename [-f] " "\n" @@ -3856,7 +3856,7 @@ zfs_do_send(int argc, char **argv) } /* - * zfs receive [-vnFu] [-d | -e] + * zfs receive [-vnFus] [-d | -e] * * Restore a backup stream from stdin. */ @@ -3867,8 +3867,11 @@ zfs_do_receive(int argc, char **argv) recvflags_t flags = { 0 }; /* check options */ - while ((c = getopt(argc, argv, ":denuvF")) != -1) { + while ((c = getopt(argc, argv, ":denuvFs")) != -1) { switch (c) { + case 's': + flags.skip = B_TRUE; + break; case 'd': flags.isprefix = B_TRUE; break; diff --git a/include/libzfs.h b/include/libzfs.h index db8ee7167e17..743e676fc1ef 100644 --- a/include/libzfs.h +++ b/include/libzfs.h @@ -675,6 +675,9 @@ typedef struct recvflags { /* do not mount file systems as they are extracted (private) */ boolean_t nomount; + + /* skip existing snapshots */ + boolean_t skip; } recvflags_t; extern int zfs_receive(libzfs_handle_t *, const char *, recvflags_t *, diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c index 8d1a210947a2..766c93473017 100644 --- a/lib/libzfs/libzfs_sendrecv.c +++ b/lib/libzfs/libzfs_sendrecv.c @@ -2874,13 +2874,14 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, zfs_handle_t *zhp; /* - * Destination fs exists. Therefore this should either + * Destination fs exists (and we have not been asked to + * skip existing snapshots). Therefore this should either * be an incremental, or the stream specifies a new fs * (full stream or clone) and they want us to blow it * away (and have therefore specified -F and removed any * snapshots). */ - if (stream_wantsnewfs) { + if (stream_wantsnewfs && !flags->skip) { if (!flags->force) { zcmd_free_nvlists(&zc); zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, @@ -2968,6 +2969,17 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, zc.zc_begin_record = drr_noswap->drr_u.drr_begin; zc.zc_cookie = infd; zc.zc_guid = flags->force; + + if (zfs_dataset_exists(hdl, zc.zc_value, ZFS_TYPE_SNAPSHOT) && + flags->skip) { + (void) printf("skipping snapshot %s - %s already exists\n", + drrb->drr_toname, zc.zc_value); + (void) fflush(stdout); + + zcmd_free_nvlists(&zc); + return (recv_skip(hdl, infd, flags->byteswap)); + } + if (flags->verbose) { (void) printf("%s %s stream of %s into %s\n", flags->dryrun ? "would receive" : "receiving", diff --git a/man/man8/zfs.8 b/man/man8/zfs.8 index 208abd716708..beb8627d0d88 100644 --- a/man/man8/zfs.8 +++ b/man/man8/zfs.8 @@ -184,12 +184,12 @@ zfs \- configures ZFS file systems .LP .nf -\fBzfs\fR \fBreceive | recv\fR [\fB-vnFu\fR] \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR +\fBzfs\fR \fBreceive | recv\fR [\fB-vnFus\fR] \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR .fi .LP .nf -\fBzfs\fR \fBreceive | recv\fR [\fB-vnFu\fR] [\fB-d\fR|\fB-e\fR] \fIfilesystem\fR +\fBzfs\fR \fBreceive | recv\fR [\fB-vnFus\fR] [\fB-d\fR|\fB-e\fR] \fIfilesystem\fR .fi .LP @@ -2934,11 +2934,11 @@ then the receiving system must have that feature enabled as well. See .ne 2 .mk .na -\fB\fBzfs receive\fR [\fB-vnFu\fR] \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR\fR +\fB\fBzfs receive\fR [\fB-vnFus\fR] \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR\fR .ad .br .na -\fB\fBzfs receive\fR [\fB-vnFu\fR] [\fB-d\fR|\fB-e\fR] \fIfilesystem\fR\fR +\fB\fBzfs receive\fR [\fB-vnFus\fR] [\fB-d\fR|\fB-e\fR] \fIfilesystem\fR\fR .ad .sp .6 .RS 4n @@ -3017,6 +3017,33 @@ Do not actually receive the stream. This can be useful in conjunction with the \ Force a rollback of the file system to the most recent snapshot before performing the receive operation. If receiving an incremental replication stream (for example, one generated by \fBzfs send -R -[iI]\fR), destroy snapshots and file systems that do not exist on the sending side. .RE +.sp +.ne 2 +.na +\fB\fB-e\fR\fR +.ad +.sp .6 +.RS 4n +Generate a more compact stream by using WRITE_EMBEDDED records for blocks +which are stored more compactly on disk by the \fBembedded_data\fR pool +feature. This flag has no effect if the \fBembedded_data\fR feature is +disabled. The receiving system must have the \fBembedded_data\fR feature +enabled. If the \fBlz4_compress\fR feature is active on the sending system, +then the receiving system must have that feature enabled as well. See +\fBzpool-features\fR(5) for details on ZFS feature flags and the +\fBembedded_data\fR feature. +.RE + +.sp +.ne 2 +.mk +.na +\fB\fB-s\fR\fR +.ad +.sp .6 +.RS 4n +Skip existing snapshots in a stream. +.RE .RE .sp