--- old/usr/src/cmd/zfs/zfs_main.c	2015-12-29 17:17:29.012322533 -0500
+++ new/usr/src/cmd/zfs/zfs_main.c	2015-12-29 17:17:29.018425149 -0500
@@ -26,6 +26,7 @@
  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
  * Copyright (c) 2013 Steven Hartland.  All rights reserved.
  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2015 RackTop Systems.
  */
 
 #include <assert.h>
@@ -259,9 +260,9 @@
 	case HELP_ROLLBACK:
 		return (gettext("\trollback [-rRf] <snapshot>\n"));
 	case HELP_SEND:
-		return (gettext("\tsend [-DnPpRvLe] [-[iI] snapshot] "
+		return (gettext("\tsend [-DnPpRvLeF] [-[iI] snapshot] "
 		    "<snapshot>\n"
-		    "\tsend [-Le] [-i snapshot|bookmark] "
+		    "\tsend [-LeF] [-i snapshot|bookmark] "
 		    "<filesystem|volume|snapshot>\n"
 		    "\tsend [-nvPe] -t <receive_resume_token>\n"));
 	case HELP_SET:
@@ -3687,7 +3688,7 @@
 	boolean_t extraverbose = B_FALSE;
 
 	/* check options */
-	while ((c = getopt(argc, argv, ":i:I:RDpvnPLet:")) != -1) {
+	while ((c = getopt(argc, argv, ":i:I:RDpvnPLet:F")) != -1) {
 		switch (c) {
 		case 'i':
 			if (fromname)
@@ -3731,6 +3732,9 @@
 		case 't':
 			resume_token = optarg;
 			break;
+		case 'F':
+			flags.skip_free = B_TRUE;
+			break;
 		case ':':
 			(void) fprintf(stderr, gettext("missing argument for "
 			    "'%c' option\n"), optopt);
--- old/usr/src/lib/libzfs/common/libzfs.h	2015-12-29 17:17:29.370523610 -0500
+++ new/usr/src/lib/libzfs/common/libzfs.h	2015-12-29 17:17:29.376207971 -0500
@@ -25,6 +25,7 @@
  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2015 RackTop Systems.
  */
 
 #ifndef	_LIBZFS_H
@@ -597,6 +598,9 @@
 
 	/* WRITE_EMBEDDED records of type DATA are permitted */
 	boolean_t embed_data;
+
+	/* skip free records, not receivable as a clone */
+	boolean_t skip_free;
 } sendflags_t;
 
 typedef boolean_t (snapfilter_cb_t)(zfs_handle_t *, void *);
--- old/usr/src/lib/libzfs/common/libzfs_sendrecv.c	2015-12-29 17:17:29.552598056 -0500
+++ new/usr/src/lib/libzfs/common/libzfs_sendrecv.c	2015-12-29 17:17:29.559370667 -0500
@@ -25,6 +25,7 @@
  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
  * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
+ * Copyright 2015 RackTop Systems.
  */
 
 #include <assert.h>
@@ -814,6 +815,7 @@
 	boolean_t seenfrom, seento, replicate, doall, fromorigin;
 	boolean_t verbose, dryrun, parsable, progress, embed_data, std_out;
 	boolean_t large_block;
+	boolean_t skip_free;
 	int outfd;
 	boolean_t err;
 	nvlist_t *fss;
@@ -1184,6 +1186,8 @@
 			flags |= LZC_SEND_FLAG_LARGE_BLOCK;
 		if (sdd->embed_data)
 			flags |= LZC_SEND_FLAG_EMBED_DATA;
+		if (sdd->skip_free)
+			flags |= LZC_SEND_FLAG_SKIP_FREE;
 
 		err = dump_ioctl(zhp, sdd->prevsnap, sdd->prevsnap_obj,
 		    fromorigin, sdd->outfd, flags, sdd->debugnv);
@@ -1750,6 +1754,7 @@
 	sdd.progress = flags->progress;
 	sdd.dryrun = flags->dryrun;
 	sdd.large_block = flags->largeblock;
+	sdd.skip_free = flags->skip_free;
 	sdd.embed_data = flags->embed_data;
 	sdd.filter_cb = filter_func;
 	sdd.filter_cb_arg = cb_arg;
--- old/usr/src/lib/libzfs_core/common/libzfs_core.c	2015-12-29 17:17:29.823807667 -0500
+++ new/usr/src/lib/libzfs_core/common/libzfs_core.c	2015-12-29 17:17:29.829409877 -0500
@@ -22,6 +22,7 @@
 /*
  * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
+ * Copyright 2015 RackTop Systems.
  */
 
 /*
@@ -486,6 +487,8 @@
 		fnvlist_add_boolean(args, "largeblockok");
 	if (flags & LZC_SEND_FLAG_EMBED_DATA)
 		fnvlist_add_boolean(args, "embedok");
+	if (flags & LZC_SEND_FLAG_SKIP_FREE)
+		fnvlist_add_boolean(args, "skip_free");
 	if (resumeobj != 0 || resumeoff != 0) {
 		fnvlist_add_uint64(args, "resume_object", resumeobj);
 		fnvlist_add_uint64(args, "resume_offset", resumeoff);
--- old/usr/src/lib/libzfs_core/common/libzfs_core.h	2015-12-29 17:17:30.004026294 -0500
+++ new/usr/src/lib/libzfs_core/common/libzfs_core.h	2015-12-29 17:17:30.009786439 -0500
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright 2015 RackTop Systems.
  */
 
 #ifndef	_LIBZFS_CORE_H
@@ -54,7 +55,8 @@
 
 enum lzc_send_flags {
 	LZC_SEND_FLAG_EMBED_DATA = 1 << 0,
-	LZC_SEND_FLAG_LARGE_BLOCK = 1 << 1
+	LZC_SEND_FLAG_LARGE_BLOCK = 1 << 1,
+	LZC_SEND_FLAG_SKIP_FREE = 1 << 2
 };
 
 int lzc_send(const char *, const char *, int, enum lzc_send_flags);
--- old/usr/src/man/man1m/zfs.1m	2015-12-29 17:17:30.167097378 -0500
+++ new/usr/src/man/man1m/zfs.1m	2015-12-29 17:17:30.173954451 -0500
@@ -26,8 +26,9 @@
 .\" Copyright (c) 2014, Joyent, Inc. All rights reserved.
 .\" Copyright (c) 2014 by Adam Stevko. All rights reserved.
 .\" Copyright 2015 Nexenta Systems, Inc.  All Rights Reserved.
+.\" Copyright 2015 RackTop Systems.
 .\"
-.Dd June 8, 2015
+.Dd December 29, 2015
 .Dt ZFS 1M
 .Os
 .Sh NAME
@@ -164,12 +165,12 @@
 .Ar snapshot bookmark
 .Nm
 .Cm send
-.Op Fl DLPRenpv
+.Op Fl DFLPRenpv
 .Op Oo Fl I Ns | Ns Fl i Oc Ar snapshot
 .Ar snapshot
 .Nm
 .Cm send
-.Op Fl Le
+.Op Fl FLe
 .Op Fl i Ar snapshot Ns | Ns Ar bookmark
 .Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot
 .Nm
@@ -2469,7 +2470,7 @@
 .It Xo
 .Nm
 .Cm send
-.Op Fl DLPRenpv
+.Op Fl DFLPRenpv
 .Op Oo Fl I Ns | Ns Fl i Oc Ar snapshot
 .Ar snapshot
 .Xc
@@ -2553,6 +2554,9 @@
 for details on ZFS feature flags and the
 .Sy embedded_data
 feature.
+.It Fl F
+Generate a stream which omits free records.  The stream will be more compact
+but the receiving system will not be able to receive the stream as a clone.
 .It Fl i Ar snapshot
 Generate an incremental stream from the first
 .Ar snapshot
@@ -2602,7 +2606,7 @@
 .It Xo
 .Nm
 .Cm send
-.Op Fl Le
+.Op Fl FLe
 .Op Fl i Ar snapshot Ns | Ns Ar bookmark
 .Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot
 .Xc
@@ -2643,6 +2647,9 @@
 for details on ZFS feature flags and the
 .Sy embedded_data
 feature.
+.It Fl F
+Generate a stream which omits free records.  The stream will be more compact
+but the receiving system will not be able to receive the stream as a clone.
 .It Fl i Ar snapshot Ns | Ns Ar bookmark
 Generate an incremental send stream. The incremental source must be an earlier
 snapshot in the destination's history. It will commonly be an earlier snapshot
--- old/usr/src/uts/common/fs/zfs/dmu_send.c	2015-12-29 17:17:30.720430474 -0500
+++ new/usr/src/uts/common/fs/zfs/dmu_send.c	2015-12-29 17:17:30.726253997 -0500
@@ -24,6 +24,7 @@
  * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  * Copyright (c) 2014, Joyent, Inc. All rights reserved.
  * Copyright 2014 HybridCluster. All rights reserved.
+ * Copyright 2015 RackTop Systems.
  */
 
 #include <sys/dmu.h>
@@ -152,6 +153,13 @@
 	struct drr_free *drrf = &(dsp->dsa_drr->drr_u.drr_free);
 
 	/*
+	 * Skip free records if asked not to send them.  The resulting
+	 * stream cannot be received as a clone.
+	 */
+	if (dsp->dsa_skip_free)
+		return (0);
+
+	/*
 	 * When we receive a free record, dbuf_free_range() assumes
 	 * that the receiving system doesn't have any dbufs in the range
 	 * being freed.  This is always true because there is a one-record
@@ -346,6 +354,10 @@
 {
 	struct drr_freeobjects *drrfo = &(dsp->dsa_drr->drr_u.drr_freeobjects);
 
+	/* See comment in dump_free(). */
+	if (dsp->dsa_skip_free)
+		return (0);
+
 	/*
 	 * If there is a pending op, but it's not PENDING_FREEOBJECTS,
 	 * push it out, since free block aggregation can only be done for
@@ -684,7 +696,7 @@
 dmu_send_impl(void *tag, dsl_pool_t *dp, dsl_dataset_t *to_ds,
     zfs_bookmark_phys_t *ancestor_zb,
     boolean_t is_clone, boolean_t embedok, boolean_t large_block_ok, int outfd,
-    uint64_t resumeobj, uint64_t resumeoff,
+    uint64_t resumeobj, uint64_t resumeoff, boolean_t skip_free,
     vnode_t *vp, offset_t *off)
 {
 	objset_t *os;
@@ -745,7 +757,8 @@
 	drr->drr_u.drr_begin.drr_toguid = dsl_dataset_phys(to_ds)->ds_guid;
 	if (dsl_dataset_phys(to_ds)->ds_flags & DS_FLAG_CI_DATASET)
 		drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CI_DATA;
-	drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_FREERECORDS;
+	if (!skip_free)
+		drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_FREERECORDS;
 
 	if (ancestor_zb != NULL) {
 		drr->drr_u.drr_begin.drr_fromguid =
@@ -771,6 +784,7 @@
 	dsp->dsa_featureflags = featureflags;
 	dsp->dsa_resume_object = resumeobj;
 	dsp->dsa_resume_offset = resumeoff;
+	dsp->dsa_skip_free = skip_free;
 
 	mutex_enter(&to_ds->ds_sendstream_lock);
 	list_insert_head(&to_ds->ds_sendstreams, dsp);
@@ -874,7 +888,7 @@
 int
 dmu_send_obj(const char *pool, uint64_t tosnap, uint64_t fromsnap,
     boolean_t embedok, boolean_t large_block_ok,
-    int outfd, vnode_t *vp, offset_t *off)
+    int outfd, boolean_t skip_free, vnode_t *vp, offset_t *off)
 {
 	dsl_pool_t *dp;
 	dsl_dataset_t *ds;
@@ -910,10 +924,10 @@
 		is_clone = (fromds->ds_dir != ds->ds_dir);
 		dsl_dataset_rele(fromds, FTAG);
 		err = dmu_send_impl(FTAG, dp, ds, &zb, is_clone,
-		    embedok, large_block_ok, outfd, 0, 0, vp, off);
+		    embedok, large_block_ok, outfd, 0, 0, skip_free, vp, off);
 	} else {
 		err = dmu_send_impl(FTAG, dp, ds, NULL, B_FALSE,
-		    embedok, large_block_ok, outfd, 0, 0, vp, off);
+		    embedok, large_block_ok, outfd, 0, 0, skip_free, vp, off);
 	}
 	dsl_dataset_rele(ds, FTAG);
 	return (err);
@@ -922,7 +936,7 @@
 int
 dmu_send(const char *tosnap, const char *fromsnap, boolean_t embedok,
     boolean_t large_block_ok, int outfd, uint64_t resumeobj, uint64_t resumeoff,
-    vnode_t *vp, offset_t *off)
+    boolean_t skip_free, vnode_t *vp, offset_t *off)
 {
 	dsl_pool_t *dp;
 	dsl_dataset_t *ds;
@@ -990,11 +1004,11 @@
 		}
 		err = dmu_send_impl(FTAG, dp, ds, &zb, is_clone,
 		    embedok, large_block_ok,
-		    outfd, resumeobj, resumeoff, vp, off);
+		    outfd, resumeobj, resumeoff, skip_free, vp, off);
 	} else {
 		err = dmu_send_impl(FTAG, dp, ds, NULL, B_FALSE,
 		    embedok, large_block_ok,
-		    outfd, resumeobj, resumeoff, vp, off);
+		    outfd, resumeobj, resumeoff, skip_free, vp, off);
 	}
 	if (owned)
 		dsl_dataset_disown(ds, FTAG);
--- old/usr/src/uts/common/fs/zfs/sys/dmu_impl.h	2015-12-29 17:17:30.972505540 -0500
+++ new/usr/src/uts/common/fs/zfs/sys/dmu_impl.h	2015-12-29 17:17:30.978254728 -0500
@@ -25,6 +25,7 @@
 /*
  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
  * Copyright (c) 2013, 2015 by Delphix. All rights reserved.
+ * Copyright 2015 RackTop Systems.
  */
 
 #ifndef _SYS_DMU_IMPL_H
@@ -298,6 +299,7 @@
 	uint64_t dsa_last_data_offset;
 	uint64_t dsa_resume_object;
 	uint64_t dsa_resume_offset;
+	boolean_t dsa_skip_free;
 } dmu_sendarg_t;
 
 void dmu_object_zapify(objset_t *, uint64_t, dmu_object_type_t, dmu_tx_t *);
--- old/usr/src/uts/common/fs/zfs/sys/dmu_send.h	2015-12-29 17:17:31.139676443 -0500
+++ new/usr/src/uts/common/fs/zfs/sys/dmu_send.h	2015-12-29 17:17:31.146842482 -0500
@@ -24,6 +24,7 @@
  * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
  * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright 2015 RackTop Systems.
  */
 
 #ifndef _DMU_SEND_H
@@ -42,14 +43,14 @@
 
 int dmu_send(const char *tosnap, const char *fromsnap, boolean_t embedok,
     boolean_t large_block_ok, int outfd, uint64_t resumeobj, uint64_t resumeoff,
-    struct vnode *vp, offset_t *off);
+    boolean_t skip_free, struct vnode *vp, offset_t *off);
 int dmu_send_estimate(struct dsl_dataset *ds, struct dsl_dataset *fromds,
     uint64_t *sizep);
 int dmu_send_estimate_from_txg(struct dsl_dataset *ds, uint64_t fromtxg,
     uint64_t *sizep);
 int dmu_send_obj(const char *pool, uint64_t tosnap, uint64_t fromsnap,
     boolean_t embedok, boolean_t large_block_ok,
-    int outfd, struct vnode *vp, offset_t *off);
+    int outfd, boolean_t skip_free, struct vnode *vp, offset_t *off);
 
 typedef struct dmu_recv_cookie {
 	struct dsl_dataset *drc_ds;
--- old/usr/src/uts/common/fs/zfs/zfs_ioctl.c	2015-12-29 17:17:31.303614324 -0500
+++ new/usr/src/uts/common/fs/zfs/zfs_ioctl.c	2015-12-29 17:17:31.309682657 -0500
@@ -28,6 +28,7 @@
  * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
+ * Copyright 2015 RackTop Systems.
  */
 
 /*
@@ -4405,6 +4406,7 @@
 	boolean_t estimate = (zc->zc_guid != 0);
 	boolean_t embedok = (zc->zc_flags & 0x1);
 	boolean_t large_block_ok = (zc->zc_flags & 0x2);
+	boolean_t skip_free = (zc->zc_flags & 0x4);
 
 	if (zc->zc_obj != 0) {
 		dsl_pool_t *dp;
@@ -4467,7 +4469,7 @@
 		off = fp->f_offset;
 		error = dmu_send_obj(zc->zc_name, zc->zc_sendobj,
 		    zc->zc_fromobj, embedok, large_block_ok,
-		    zc->zc_cookie, fp->f_vnode, &off);
+		    zc->zc_cookie, skip_free, fp->f_vnode, &off);
 
 		if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
 			fp->f_offset = off;
@@ -5396,6 +5398,8 @@
  *         indicates that blocks > 128KB are permitted
  *     (optional) "embedok" -> (value ignored)
  *         presence indicates DRR_WRITE_EMBEDDED records are permitted
+ *     (optional) "skip_free" -> (value ignored)
+ *         presence indicates free records should be omitted
  *     (optional) "resume_object" and "resume_offset" -> (uint64)
  *         if present, resume send stream from specified object and offset.
  * }
@@ -5412,6 +5416,7 @@
 	int fd;
 	boolean_t largeblockok;
 	boolean_t embedok;
+	boolean_t skip_free;
 	uint64_t resumeobj = 0;
 	uint64_t resumeoff = 0;
 
@@ -5423,6 +5428,7 @@
 
 	largeblockok = nvlist_exists(innvl, "largeblockok");
 	embedok = nvlist_exists(innvl, "embedok");
+	skip_free = nvlist_exists(innvl, "skip_free");
 
 	(void) nvlist_lookup_uint64(innvl, "resume_object", &resumeobj);
 	(void) nvlist_lookup_uint64(innvl, "resume_offset", &resumeoff);
@@ -5433,7 +5439,7 @@
 
 	off = fp->f_offset;
 	error = dmu_send(snapname, fromname, embedok, largeblockok, fd,
-	    resumeobj, resumeoff, fp->f_vnode, &off);
+	    resumeobj, resumeoff, skip_free, fp->f_vnode, &off);
 
 	if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
 		fp->f_offset = off;
