[Midnightbsd-cvs] src [10229] trunk/cddl/contrib/opensolaris/lib/pyzfs/common/ioctl.c: sync with freebsd

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Sat Jun 2 12:07:31 EDT 2018


Revision: 10229
          http://svnweb.midnightbsd.org/src/?rev=10229
Author:   laffer1
Date:     2018-06-02 12:07:30 -0400 (Sat, 02 Jun 2018)
Log Message:
-----------
sync with freebsd

Modified Paths:
--------------
    trunk/cddl/contrib/opensolaris/common/avl/avl.c
    trunk/cddl/contrib/opensolaris/common/ctf/ctf_create.c
    trunk/cddl/contrib/opensolaris/common/ctf/ctf_decl.c
    trunk/cddl/contrib/opensolaris/common/ctf/ctf_error.c
    trunk/cddl/contrib/opensolaris/common/ctf/ctf_hash.c
    trunk/cddl/contrib/opensolaris/common/ctf/ctf_impl.h
    trunk/cddl/contrib/opensolaris/common/ctf/ctf_labels.c
    trunk/cddl/contrib/opensolaris/common/ctf/ctf_lookup.c
    trunk/cddl/contrib/opensolaris/common/ctf/ctf_open.c
    trunk/cddl/contrib/opensolaris/common/ctf/ctf_types.c
    trunk/cddl/contrib/opensolaris/common/ctf/ctf_util.c
    trunk/cddl/contrib/opensolaris/head/assert.h
    trunk/cddl/contrib/opensolaris/head/atomic.h
    trunk/cddl/contrib/opensolaris/head/libintl.h
    trunk/cddl/contrib/opensolaris/head/nlist.h
    trunk/cddl/contrib/opensolaris/head/note.h
    trunk/cddl/contrib/opensolaris/head/stdio_ext.h
    trunk/cddl/contrib/opensolaris/head/storclass.h
    trunk/cddl/contrib/opensolaris/head/syms.h
    trunk/cddl/contrib/opensolaris/head/synch.h
    trunk/cddl/contrib/opensolaris/head/thread.h
    trunk/cddl/contrib/opensolaris/lib/libctf/common/ctf_lib.c
    trunk/cddl/contrib/opensolaris/lib/libctf/common/ctf_subr.c
    trunk/cddl/contrib/opensolaris/lib/libctf/common/libctf.h
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_aggregate.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_as.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_as.h
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_buf.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_buf.h
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cg.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_decl.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_decl.h
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dis.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.h
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_error.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_errtags.h
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_grammar.y
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_handle.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_ident.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_ident.h
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_inttab.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_inttab.h
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_lex.l
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_list.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_list.h
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_map.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.h
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_options.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pcb.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pcb.h
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.h
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pragma.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.h
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_proc.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_proc.h
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_program.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_program.h
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.h
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_regset.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_regset.h
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_string.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_string.h
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_strtab.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_strtab.h
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_subr.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_work.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_xlator.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_xlator.h
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h
    trunk/cddl/contrib/opensolaris/lib/libdtrace/i386/dt_isadep.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/sparc/dt_isadep.c
    trunk/cddl/contrib/opensolaris/lib/libgen/common/gmatch.c
    trunk/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.c
    trunk/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.h
    trunk/cddl/contrib/opensolaris/lib/libnvpair/nvpair_alloc_system.c
    trunk/cddl/contrib/opensolaris/lib/libuutil/common/libuutil.h
    trunk/cddl/contrib/opensolaris/lib/libuutil/common/libuutil_common.h
    trunk/cddl/contrib/opensolaris/lib/libuutil/common/libuutil_impl.h
    trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_alloc.c
    trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_avl.c
    trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_dprintf.c
    trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_ident.c
    trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_list.c
    trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_misc.c
    trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_open.c
    trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_pname.c
    trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_string.c
    trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_strtoint.c
    trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
    trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_changelist.c
    trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c
    trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.h
    trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_config.c
    trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
    trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_diff.c
    trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_fru.c
    trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h
    trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c
    trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c
    trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_mount.c
    trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
    trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c
    trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_status.c
    trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c
    trunk/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c
    trunk/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h
    trunk/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core_compat.c
    trunk/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core_compat.h
    trunk/cddl/contrib/opensolaris/lib/libzpool/common/kernel.c
    trunk/cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h
    trunk/cddl/contrib/opensolaris/lib/libzpool/common/taskq.c
    trunk/cddl/contrib/opensolaris/lib/libzpool/common/util.c
    trunk/cddl/contrib/opensolaris/lib/pyzfs/common/allow.py
    trunk/cddl/contrib/opensolaris/lib/pyzfs/common/ioctl.c

Added Paths:
-----------
    trunk/cddl/contrib/opensolaris/common/util/
    trunk/cddl/contrib/opensolaris/common/util/strtolctype.h
    trunk/cddl/contrib/opensolaris/lib/libcmdutils/
    trunk/cddl/contrib/opensolaris/lib/libcmdutils/common/
    trunk/cddl/contrib/opensolaris/lib/libcmdutils/common/nicenum.c
    trunk/cddl/contrib/opensolaris/lib/libcmdutils/libcmdutils.h
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pq.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pq.h
    trunk/cddl/contrib/opensolaris/lib/libdtrace/mips/
    trunk/cddl/contrib/opensolaris/lib/libdtrace/mips/dt_isadep.c
    trunk/cddl/contrib/opensolaris/lib/libdtrace/powerpc/
    trunk/cddl/contrib/opensolaris/lib/libdtrace/powerpc/dt_isadep.c
    trunk/cddl/contrib/opensolaris/lib/libnvpair/nvpair_json.c

Property Changed:
----------------
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_grammar.y
    trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_lex.l
    trunk/cddl/contrib/opensolaris/lib/pyzfs/common/allow.py

Modified: trunk/cddl/contrib/opensolaris/common/avl/avl.c
===================================================================
--- trunk/cddl/contrib/opensolaris/common/avl/avl.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/common/avl/avl.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/common/ctf/ctf_create.c
===================================================================
--- trunk/cddl/contrib/opensolaris/common/ctf/ctf_create.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/common/ctf/ctf_create.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -24,13 +25,15 @@
  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
+ */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/sysmacros.h>
 #include <sys/param.h>
 #include <sys/mman.h>
 #include <ctf_impl.h>
+#include <sys/debug.h>
 
 /*
  * This static string is used as the template for initially populating a
@@ -63,7 +66,7 @@
 	cts.cts_name = _CTF_SECTION;
 	cts.cts_type = SHT_PROGBITS;
 	cts.cts_flags = 0;
-	cts.cts_data = &hdr;
+	cts.cts_data = (void *)&hdr;
 	cts.cts_size = sizeof (hdr);
 	cts.cts_entsize = 1;
 	cts.cts_offset = 0;
@@ -167,6 +170,51 @@
 }
 
 /*
+ * Only types of dyanmic CTF containers contain reference counts. These
+ * containers are marked RD/WR. Because of that we basically make this a no-op
+ * for compatability with non-dynamic CTF sections. This is also a no-op for
+ * types which are not dynamic types. It is the responsibility of the caller to
+ * make sure it is a valid type. We help that caller out on debug builds.
+ *
+ * Note that the reference counts are not maintained for types that are not
+ * within this container. In other words if we have a type in a parent, that
+ * will not have its reference count increased. On the flip side, the parent
+ * will not be allowed to remove dynamic types if it has children.
+ */
+static void
+ctf_ref_inc(ctf_file_t *fp, ctf_id_t tid)
+{
+	ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, tid);
+
+	if (dtd == NULL)
+		return;
+
+	if (!(fp->ctf_flags & LCTF_RDWR))
+		return;
+
+	dtd->dtd_ref++;
+}
+
+/*
+ * Just as with ctf_ref_inc, this is a no-op on non-writeable containers and the
+ * caller should ensure that this is already a valid type.
+ */
+static void
+ctf_ref_dec(ctf_file_t *fp, ctf_id_t tid)
+{
+	ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, tid);
+
+	if (dtd == NULL)
+		return;
+
+	if (!(fp->ctf_flags & LCTF_RDWR))
+		return;
+
+	ASSERT(dtd->dtd_ref >= 1);
+	dtd->dtd_ref--;
+}
+
+/*
  * If the specified CTF container is writable and has been modified, reload
  * this container with the updated type definitions.  In order to make this
  * code and the rest of libctf as simple as possible, we perform updates by
@@ -180,6 +228,10 @@
  * ctf_bufopen() will return a new ctf_file_t, but we want to keep the fp
  * constant for the caller, so after ctf_bufopen() returns, we use bcopy to
  * swap the interior of the old and new ctf_file_t's, and then free the old.
+ *
+ * Note that the lists of dynamic types stays around and the resulting container
+ * is still writeable. Furthermore, the reference counts that are on the dtd's
+ * are still valid.
  */
 int
 ctf_update(ctf_file_t *fp)
@@ -432,6 +484,7 @@
 	ctf_dtdef_t *p, **q = &fp->ctf_dthash[h];
 	ctf_dmdef_t *dmd, *nmd;
 	size_t len;
+	int kind, i;
 
 	for (p = *q; p != NULL; p = p->dtd_hash) {
 		if (p != dtd)
@@ -443,7 +496,8 @@
 	if (p != NULL)
 		*q = p->dtd_hash;
 
-	switch (CTF_INFO_KIND(dtd->dtd_data.ctt_info)) {
+	kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info);
+	switch (kind) {
 	case CTF_K_STRUCT:
 	case CTF_K_UNION:
 	case CTF_K_ENUM:
@@ -454,14 +508,33 @@
 				ctf_free(dmd->dmd_name, len);
 				fp->ctf_dtstrlen -= len;
 			}
+			if (kind != CTF_K_ENUM)
+				ctf_ref_dec(fp, dmd->dmd_type);
 			nmd = ctf_list_next(dmd);
 			ctf_free(dmd, sizeof (ctf_dmdef_t));
 		}
 		break;
 	case CTF_K_FUNCTION:
+		ctf_ref_dec(fp, dtd->dtd_data.ctt_type);
+		for (i = 0; i < CTF_INFO_VLEN(dtd->dtd_data.ctt_info); i++)
+			if (dtd->dtd_u.dtu_argv[i] != 0)
+				ctf_ref_dec(fp, dtd->dtd_u.dtu_argv[i]);
 		ctf_free(dtd->dtd_u.dtu_argv, sizeof (ctf_id_t) *
 		    CTF_INFO_VLEN(dtd->dtd_data.ctt_info));
 		break;
+	case CTF_K_ARRAY:
+		ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_contents);
+		ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_index);
+		break;
+	case CTF_K_TYPEDEF:
+		ctf_ref_dec(fp, dtd->dtd_data.ctt_type);
+		break;
+	case CTF_K_POINTER:
+	case CTF_K_VOLATILE:
+	case CTF_K_CONST:
+	case CTF_K_RESTRICT:
+		ctf_ref_dec(fp, dtd->dtd_data.ctt_type);
+		break;
 	}
 
 	if (dtd->dtd_name) {
@@ -495,7 +568,9 @@
  * Discard all of the dynamic type definitions that have been added to the
  * container since the last call to ctf_update().  We locate such types by
  * scanning the list and deleting elements that have type IDs greater than
- * ctf_dtoldid, which is set by ctf_update(), above.
+ * ctf_dtoldid, which is set by ctf_update(), above. Note that to work properly
+ * with our reference counting schemes, we must delete the dynamic list in
+ * reverse.
  */
 int
 ctf_discard(ctf_file_t *fp)
@@ -508,11 +583,11 @@
 	if (!(fp->ctf_flags & LCTF_DIRTY))
 		return (0); /* no update required */
 
-	for (dtd = ctf_list_next(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) {
-		if (dtd->dtd_type <= fp->ctf_dtoldid)
+	for (dtd = ctf_list_prev(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) {
+		ntd = ctf_list_prev(dtd);
+		if (CTF_TYPE_TO_INDEX(dtd->dtd_type) <= fp->ctf_dtoldid)
 			continue; /* skip types that have been committed */
 
-		ntd = ctf_list_next(dtd);
 		ctf_dtd_delete(fp, dtd);
 	}
 
@@ -614,6 +689,8 @@
 	if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR)
 		return (CTF_ERR); /* errno is set for us */
 
+	ctf_ref_inc(fp, ref);
+
 	dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, flag, 0);
 	dtd->dtd_data.ctt_type = (ushort_t)ref;
 
@@ -645,10 +722,21 @@
 {
 	ctf_dtdef_t *dtd;
 	ctf_id_t type;
+	ctf_file_t *fpd;
 
 	if (arp == NULL)
 		return (ctf_set_errno(fp, EINVAL));
 
+	fpd = fp;
+	if (ctf_lookup_by_id(&fpd, arp->ctr_contents) == NULL &&
+	    ctf_dtd_lookup(fp, arp->ctr_contents) == NULL)
+		return (ctf_set_errno(fp, ECTF_BADID));
+
+	fpd = fp;
+	if (ctf_lookup_by_id(&fpd, arp->ctr_index) == NULL &&
+	    ctf_dtd_lookup(fp, arp->ctr_index) == NULL)
+		return (ctf_set_errno(fp, ECTF_BADID));
+
 	if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR)
 		return (CTF_ERR); /* errno is set for us */
 
@@ -655,6 +743,8 @@
 	dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_ARRAY, flag, 0);
 	dtd->dtd_data.ctt_size = 0;
 	dtd->dtd_u.dtu_arr = *arp;
+	ctf_ref_inc(fp, arp->ctr_contents);
+	ctf_ref_inc(fp, arp->ctr_index);
 
 	return (type);
 }
@@ -662,6 +752,7 @@
 int
 ctf_set_array(ctf_file_t *fp, ctf_id_t type, const ctf_arinfo_t *arp)
 {
+	ctf_file_t *fpd;
 	ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, type);
 
 	if (!(fp->ctf_flags & LCTF_RDWR))
@@ -670,8 +761,22 @@
 	if (dtd == NULL || CTF_INFO_KIND(dtd->dtd_data.ctt_info) != CTF_K_ARRAY)
 		return (ctf_set_errno(fp, ECTF_BADID));
 
+	fpd = fp;
+	if (ctf_lookup_by_id(&fpd, arp->ctr_contents) == NULL &&
+	    ctf_dtd_lookup(fp, arp->ctr_contents) == NULL)
+		return (ctf_set_errno(fp, ECTF_BADID));
+
+	fpd = fp;
+	if (ctf_lookup_by_id(&fpd, arp->ctr_index) == NULL &&
+	    ctf_dtd_lookup(fp, arp->ctr_index) == NULL)
+		return (ctf_set_errno(fp, ECTF_BADID));
+
+	ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_contents);
+	ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_index);
 	fp->ctf_flags |= LCTF_DIRTY;
 	dtd->dtd_u.dtu_arr = *arp;
+	ctf_ref_inc(fp, arp->ctr_contents);
+	ctf_ref_inc(fp, arp->ctr_index);
 
 	return (0);
 }
@@ -683,7 +788,9 @@
 	ctf_dtdef_t *dtd;
 	ctf_id_t type;
 	uint_t vlen;
+	int i;
 	ctf_id_t *vdat = NULL;
+	ctf_file_t *fpd;
 
 	if (ctc == NULL || (ctc->ctc_flags & ~CTF_FUNC_VARARG) != 0 ||
 	    (ctc->ctc_argc != 0 && argv == NULL))
@@ -696,6 +803,18 @@
 	if (vlen > CTF_MAX_VLEN)
 		return (ctf_set_errno(fp, EOVERFLOW));
 
+	fpd = fp;
+	if (ctf_lookup_by_id(&fpd, ctc->ctc_return) == NULL &&
+	    ctf_dtd_lookup(fp, ctc->ctc_return) == NULL)
+		return (ctf_set_errno(fp, ECTF_BADID));
+
+	for (i = 0; i < ctc->ctc_argc; i++) {
+		fpd = fp;
+		if (ctf_lookup_by_id(&fpd, argv[i]) == NULL &&
+		    ctf_dtd_lookup(fp, argv[i]) == NULL)
+			return (ctf_set_errno(fp, ECTF_BADID));
+	}
+
 	if (vlen != 0 && (vdat = ctf_alloc(sizeof (ctf_id_t) * vlen)) == NULL)
 		return (ctf_set_errno(fp, EAGAIN));
 
@@ -707,6 +826,10 @@
 	dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_FUNCTION, flag, vlen);
 	dtd->dtd_data.ctt_type = (ushort_t)ctc->ctc_return;
 
+	ctf_ref_inc(fp, ctc->ctc_return);
+	for (i = 0; i < ctc->ctc_argc; i++)
+		ctf_ref_inc(fp, argv[i]);
+
 	bcopy(argv, vdat, sizeof (ctf_id_t) * ctc->ctc_argc);
 	if (ctc->ctc_flags & CTF_FUNC_VARARG)
 		vdat[vlen - 1] = 0; /* add trailing zero to indicate varargs */
@@ -825,8 +948,11 @@
 {
 	ctf_dtdef_t *dtd;
 	ctf_id_t type;
+	ctf_file_t *fpd;
 
-	if (ref == CTF_ERR || ref < 0 || ref > CTF_MAX_TYPE)
+	fpd = fp;
+	if (ref == CTF_ERR || (ctf_lookup_by_id(&fpd, ref) == NULL &&
+	    ctf_dtd_lookup(fp, ref) == NULL))
 		return (ctf_set_errno(fp, EINVAL));
 
 	if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR)
@@ -834,6 +960,7 @@
 
 	dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_TYPEDEF, flag, 0);
 	dtd->dtd_data.ctt_type = (ushort_t)ref;
+	ctf_ref_inc(fp, ref);
 
 	return (type);
 }
@@ -1008,10 +1135,49 @@
 	if (s != NULL)
 		fp->ctf_dtstrlen += strlen(s) + 1;
 
+	ctf_ref_inc(fp, type);
 	fp->ctf_flags |= LCTF_DIRTY;
 	return (0);
 }
 
+/*
+ * This removes a type from the dynamic section. This will fail if the type is
+ * referenced by another type. Note that the CTF ID is never reused currently by
+ * CTF. Note that if this container is a parent container then we just outright
+ * refuse to remove the type. There currently is no notion of searching for the
+ * ctf_dtdef_t in parent containers. If there is, then this constraint could
+ * become finer grained.
+ */
+int
+ctf_delete_type(ctf_file_t *fp, ctf_id_t type)
+{
+	ctf_file_t *fpd;
+	ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, type);
+
+	if (!(fp->ctf_flags & LCTF_RDWR))
+		return (ctf_set_errno(fp, ECTF_RDONLY));
+
+	/*
+	 * We want to give as useful an errno as possible. That means that we
+	 * want to distinguish between a type which does not exist and one for
+	 * which the type is not dynamic.
+	 */
+	fpd = fp;
+	if (ctf_lookup_by_id(&fpd, type) == NULL &&
+	    ctf_dtd_lookup(fp, type) == NULL)
+		return (CTF_ERR); /* errno is set for us */
+
+	if (dtd == NULL)
+		return (ctf_set_errno(fp, ECTF_NOTDYN));
+
+	if (dtd->dtd_ref != 0 || fp->ctf_refcnt > 1)
+		return (ctf_set_errno(fp, ECTF_REFERENCED));
+
+	ctf_dtd_delete(fp, dtd);
+	fp->ctf_flags |= LCTF_DIRTY;
+	return (0);
+}
+
 static int
 enumcmp(const char *name, int value, void *arg)
 {
@@ -1103,6 +1269,9 @@
 	ctf_hash_t *hp;
 	ctf_helem_t *hep;
 
+	if (dst_fp == src_fp)
+		return (src_type);
+
 	if (!(dst_fp->ctf_flags & LCTF_RDWR))
 		return (ctf_set_errno(dst_fp, ECTF_RDONLY));
 
@@ -1145,10 +1314,13 @@
 	 * unless dst_type is a forward declaration and src_type is a struct,
 	 * union, or enum (i.e. the definition of the previous forward decl).
 	 */
-	if (dst_type != CTF_ERR && dst_kind != kind && (
-	    dst_kind != CTF_K_FORWARD || (kind != CTF_K_ENUM &&
-	    kind != CTF_K_STRUCT && kind != CTF_K_UNION)))
-		return (ctf_set_errno(dst_fp, ECTF_CONFLICT));
+	if (dst_type != CTF_ERR && dst_kind != kind) {
+		if (dst_kind != CTF_K_FORWARD || (kind != CTF_K_ENUM &&
+		    kind != CTF_K_STRUCT && kind != CTF_K_UNION))
+			return (ctf_set_errno(dst_fp, ECTF_CONFLICT));
+		else
+			dst_type = CTF_ERR;
+	}
 
 	/*
 	 * If the non-empty name was not found in the appropriate hash, search
@@ -1157,15 +1329,28 @@
 	 * we are looking for.  This is necessary to permit ctf_add_type() to
 	 * operate recursively on entities such as a struct that contains a
 	 * pointer member that refers to the same struct type.
+	 *
+	 * In the case of integer and floating point types, we match using the
+	 * type encoding as well - else we may incorrectly return a bitfield
+	 * type, for instance.
 	 */
 	if (dst_type == CTF_ERR && name[0] != '\0') {
 		for (dtd = ctf_list_prev(&dst_fp->ctf_dtdefs); dtd != NULL &&
-		    dtd->dtd_type > dst_fp->ctf_dtoldid;
+		    CTF_TYPE_TO_INDEX(dtd->dtd_type) > dst_fp->ctf_dtoldid;
 		    dtd = ctf_list_prev(dtd)) {
-			if (CTF_INFO_KIND(dtd->dtd_data.ctt_info) == kind &&
-			    dtd->dtd_name != NULL &&
-			    strcmp(dtd->dtd_name, name) == 0)
-				return (dtd->dtd_type);
+			if (CTF_INFO_KIND(dtd->dtd_data.ctt_info) != kind ||
+			    dtd->dtd_name == NULL ||
+			    strcmp(dtd->dtd_name, name) != 0)
+				continue;
+			if (kind == CTF_K_INTEGER || kind == CTF_K_FLOAT) {
+				if (ctf_type_encoding(src_fp, src_type,
+				    &src_en) != 0)
+					continue;
+				if (bcmp(&src_en, &dtd->dtd_u.dtu_enc,
+				    sizeof (ctf_encoding_t)) != 0)
+					continue;
+			}
+			return (dtd->dtd_type);
 		}
 	}
 
@@ -1313,6 +1498,14 @@
 
 		if (errs)
 			return (CTF_ERR); /* errno is set for us */
+
+		/*
+		 * Now that we know that we can't fail, we go through and bump
+		 * all the reference counts on the member types.
+		 */
+		for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members);
+		    dmd != NULL; dmd = ctf_list_next(dmd))
+			ctf_ref_inc(dst_fp, dmd->dmd_type);
 		break;
 	}
 

Modified: trunk/cddl/contrib/opensolaris/common/ctf/ctf_decl.c
===================================================================
--- trunk/cddl/contrib/opensolaris/common/ctf/ctf_decl.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/common/ctf/ctf_decl.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/common/ctf/ctf_error.c
===================================================================
--- trunk/cddl/contrib/opensolaris/common/ctf/ctf_error.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/common/ctf/ctf_error.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -23,9 +24,10 @@
  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright (c) 2012, Joyent, Inc.
+ */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <ctf_impl.h>
 
 static const char *const _ctf_errlist[] = {
@@ -73,6 +75,8 @@
 	"Limit on number of dynamic types reached",	 /* ECTF_FULL */
 	"Duplicate member name definition",		 /* ECTF_DUPMEMBER */
 	"Conflicting type is already defined",		 /* ECTF_CONFLICT */
+	"Type has outstanding references",		 /* ECTF_REFERENCED */
+	"Type is not a dynamic type"			 /* ECTF_NOTDYN */
 };
 
 static const int _ctf_nerr = sizeof (_ctf_errlist) / sizeof (_ctf_errlist[0]);

Modified: trunk/cddl/contrib/opensolaris/common/ctf/ctf_hash.c
===================================================================
--- trunk/cddl/contrib/opensolaris/common/ctf/ctf_hash.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/common/ctf/ctf_hash.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/common/ctf/ctf_impl.h
===================================================================
--- trunk/cddl/contrib/opensolaris/common/ctf/ctf_impl.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/common/ctf/ctf_impl.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -24,12 +25,13 @@
  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright (c) 2012, Joyent, Inc.  All rights reserved.
+ */
 
 #ifndef	_CTF_IMPL_H
 #define	_CTF_IMPL_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <sys/errno.h>
 #include <sys/sysmacros.h>
@@ -149,6 +151,7 @@
 	char *dtd_name;		/* name associated with definition (if any) */
 	ctf_id_t dtd_type;	/* type identifier for this definition */
 	ctf_type_t dtd_data;	/* type node (see <sys/ctf.h>) */
+	int dtd_ref;		/* recfount for dyanmic types */
 	union {
 		ctf_list_t dtu_members;	/* struct, union, or enum */
 		ctf_arinfo_t dtu_arr;	/* array */
@@ -269,7 +272,9 @@
 	ECTF_DTFULL,		/* CTF type is full (no more members allowed) */
 	ECTF_FULL,		/* CTF container is full */
 	ECTF_DUPMEMBER,		/* duplicate member name definition */
-	ECTF_CONFLICT		/* conflicting type definition present */
+	ECTF_CONFLICT,		/* conflicting type definition present */
+	ECTF_REFERENCED,	/* type has outstanding references */
+	ECTF_NOTDYN		/* type is not a dynamic type */
 };
 
 extern ssize_t ctf_get_ctt_size(const ctf_file_t *, const ctf_type_t *,

Modified: trunk/cddl/contrib/opensolaris/common/ctf/ctf_labels.c
===================================================================
--- trunk/cddl/contrib/opensolaris/common/ctf/ctf_labels.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/common/ctf/ctf_labels.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/common/ctf/ctf_lookup.c
===================================================================
--- trunk/cddl/contrib/opensolaris/common/ctf/ctf_lookup.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/common/ctf/ctf_lookup.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/common/ctf/ctf_open.c
===================================================================
--- trunk/cddl/contrib/opensolaris/common/ctf/ctf_open.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/common/ctf/ctf_open.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -24,9 +25,10 @@
  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
+ */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <ctf_impl.h>
 #include <sys/mman.h>
 #include <sys/zmod.h>
@@ -787,6 +789,92 @@
 }
 
 /*
+ * Dupliate a ctf_file_t and its underlying section information into a new
+ * container. This works by copying the three ctf_sect_t's of the original
+ * container if they exist and passing those into ctf_bufopen. To copy those, we
+ * mmap anonymous memory with ctf_data_alloc and bcopy the data across. It's not
+ * the cheapest thing, but it's what we've got.
+ */
+ctf_file_t *
+ctf_dup(ctf_file_t *ofp)
+{
+	ctf_file_t *fp;
+	ctf_sect_t ctfsect, symsect, strsect;
+	ctf_sect_t *ctp, *symp, *strp;
+	void *cbuf, *symbuf, *strbuf;
+	int err;
+
+	cbuf = symbuf = strbuf = NULL;
+	/*
+	 * The ctfsect isn't allowed to not exist, but the symbol and string
+	 * section might not. We only need to copy the data of the section, not
+	 * the name, as ctf_bufopen will take care of that.
+	 */
+	bcopy(&ofp->ctf_data, &ctfsect, sizeof (ctf_sect_t));
+	cbuf = ctf_data_alloc(ctfsect.cts_size);
+	if (cbuf == NULL) {
+		(void) ctf_set_errno(ofp, ECTF_MMAP);
+		return (NULL);
+	}
+
+	bcopy(ctfsect.cts_data, cbuf, ctfsect.cts_size);
+	ctf_data_protect(cbuf, ctfsect.cts_size);
+	ctfsect.cts_data = cbuf;
+	ctfsect.cts_offset = 0;
+	ctp = &ctfsect;
+
+	if (ofp->ctf_symtab.cts_data != NULL) {
+		bcopy(&ofp->ctf_symtab, &symsect, sizeof (ctf_sect_t));
+		symbuf = ctf_data_alloc(symsect.cts_size);
+		if (symbuf == NULL) {
+			(void) ctf_set_errno(ofp, ECTF_MMAP);
+			goto err;
+		}
+		bcopy(symsect.cts_data, symbuf, symsect.cts_size);
+		ctf_data_protect(symbuf, symsect.cts_size);
+		symsect.cts_data = symbuf;
+		symsect.cts_offset = 0;
+		symp = &symsect;
+	} else {
+		symp = NULL;
+	}
+
+	if (ofp->ctf_strtab.cts_data != NULL) {
+		bcopy(&ofp->ctf_strtab, &strsect, sizeof (ctf_sect_t));
+		strbuf = ctf_data_alloc(strsect.cts_size);
+		if (strbuf == NULL) {
+			(void) ctf_set_errno(ofp, ECTF_MMAP);
+			goto err;
+		}
+		bcopy(strsect.cts_data, strbuf, strsect.cts_size);
+		ctf_data_protect(strbuf, strsect.cts_size);
+		strsect.cts_data = strbuf;
+		strsect.cts_offset = 0;
+		strp = &strsect;
+	} else {
+		strp = NULL;
+	}
+
+	fp = ctf_bufopen(ctp, symp, strp, &err);
+	if (fp == NULL) {
+		(void) ctf_set_errno(ofp, err);
+		goto err;
+	}
+
+	fp->ctf_flags |= LCTF_MMAP;
+
+	return (fp);
+
+err:
+	ctf_data_free(cbuf, ctfsect.cts_size);
+	if (symbuf != NULL)
+		ctf_data_free(symbuf, symsect.cts_size);
+	if (strbuf != NULL)
+		ctf_data_free(strbuf, strsect.cts_size);
+	return (NULL);
+}
+
+/*
  * Close the specified CTF container and free associated data structures.  Note
  * that ctf_close() is a reference counted operation: if the specified file is
  * the parent of other active containers, its reference count will be greater
@@ -810,8 +898,12 @@
 	if (fp->ctf_parent != NULL)
 		ctf_close(fp->ctf_parent);
 
-	for (dtd = ctf_list_next(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) {
-		ntd = ctf_list_next(dtd);
+	/*
+	 * Note, to work properly with reference counting on the dynamic
+	 * section, we must delete the list in reverse.
+	 */
+	for (dtd = ctf_list_prev(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) {
+		ntd = ctf_list_prev(dtd);
 		ctf_dtd_delete(fp, dtd);
 	}
 

Modified: trunk/cddl/contrib/opensolaris/common/ctf/ctf_types.c
===================================================================
--- trunk/cddl/contrib/opensolaris/common/ctf/ctf_types.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/common/ctf/ctf_types.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -25,8 +26,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <ctf_impl.h>
 
 ssize_t
@@ -199,8 +198,9 @@
  * Lookup the given type ID and print a string name for it into buf.  Return
  * the actual number of bytes (not including \0) needed to format the name.
  */
-ssize_t
-ctf_type_lname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len)
+static ssize_t
+ctf_type_qlname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len,
+    const char *qname)
 {
 	ctf_decl_t cd;
 	ctf_decl_node_t *cdp;
@@ -255,6 +255,8 @@
 			case CTF_K_INTEGER:
 			case CTF_K_FLOAT:
 			case CTF_K_TYPEDEF:
+				if (qname != NULL)
+					ctf_decl_sprintf(&cd, "%s`", qname);
 				ctf_decl_sprintf(&cd, "%s", name);
 				break;
 			case CTF_K_POINTER:
@@ -268,13 +270,22 @@
 				break;
 			case CTF_K_STRUCT:
 			case CTF_K_FORWARD:
-				ctf_decl_sprintf(&cd, "struct %s", name);
+				ctf_decl_sprintf(&cd, "struct ");
+				if (qname != NULL)
+					ctf_decl_sprintf(&cd, "%s`", qname);
+				ctf_decl_sprintf(&cd, "%s", name);
 				break;
 			case CTF_K_UNION:
-				ctf_decl_sprintf(&cd, "union %s", name);
+				ctf_decl_sprintf(&cd, "union ");
+				if (qname != NULL)
+					ctf_decl_sprintf(&cd, "%s`", qname);
+				ctf_decl_sprintf(&cd, "%s", name);
 				break;
 			case CTF_K_ENUM:
-				ctf_decl_sprintf(&cd, "enum %s", name);
+				ctf_decl_sprintf(&cd, "enum ");
+				if (qname != NULL)
+					ctf_decl_sprintf(&cd, "%s`", qname);
+				ctf_decl_sprintf(&cd, "%s", name);
 				break;
 			case CTF_K_VOLATILE:
 				ctf_decl_sprintf(&cd, "volatile");
@@ -301,6 +312,12 @@
 	return (cd.cd_len);
 }
 
+ssize_t
+ctf_type_lname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len)
+{
+	return (ctf_type_qlname(fp, type, buf, len, NULL));
+}
+
 /*
  * Lookup the given type ID and print a string name for it into buf.  If buf
  * is too small, return NULL: the ECTF_NAMELEN error is set on 'fp' for us.
@@ -308,10 +325,19 @@
 char *
 ctf_type_name(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len)
 {
-	ssize_t rv = ctf_type_lname(fp, type, buf, len);
+	ssize_t rv = ctf_type_qlname(fp, type, buf, len, NULL);
 	return (rv >= 0 && rv < len ? buf : NULL);
 }
 
+char *
+ctf_type_qname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len,
+    const char *qname)
+{
+	ssize_t rv = ctf_type_qlname(fp, type, buf, len, qname);
+	return (rv >= 0 && rv < len ? buf : NULL);
+}
+
+
 /*
  * Resolve the type down to a base type node, and then return the size
  * of the type storage in bytes.

Modified: trunk/cddl/contrib/opensolaris/common/ctf/ctf_util.c
===================================================================
--- trunk/cddl/contrib/opensolaris/common/ctf/ctf_util.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/common/ctf/ctf_util.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Added: trunk/cddl/contrib/opensolaris/common/util/strtolctype.h
===================================================================
--- trunk/cddl/contrib/opensolaris/common/util/strtolctype.h	                        (rev 0)
+++ trunk/cddl/contrib/opensolaris/common/util/strtolctype.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -0,0 +1,80 @@
+/* $MidnightBSD$ */
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*	Copyright (c) 1988 AT&T	*/
+/*	  All Rights Reserved  	*/
+
+#ifndef	_COMMON_UTIL_CTYPE_H
+#define	_COMMON_UTIL_CTYPE_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+ * This header file contains a collection of macros that the strtou?ll?
+ * functions in common/util use to test characters.  What we need is a kernel
+ * version of ctype.h.
+ *
+ * NOTE: These macros are used within several DTrace probe context functions.
+ * They must not be altered to make function calls or perform actions not
+ * safe in probe context.
+ */
+
+#if defined(illumos) && (defined(_KERNEL) || defined(_BOOT))
+
+#define	isalnum(ch)	(isalpha(ch) || isdigit(ch))
+#define	isalpha(ch)	(isupper(ch) || islower(ch))
+#define	isdigit(ch)	((ch) >= '0' && (ch) <= '9')
+#define	islower(ch)	((ch) >= 'a' && (ch) <= 'z')
+#define	isspace(ch)	(((ch) == ' ') || ((ch) == '\r') || ((ch) == '\n') || \
+			((ch) == '\t') || ((ch) == '\f'))
+#define	isupper(ch)	((ch) >= 'A' && (ch) <= 'Z')
+#define	isxdigit(ch)	(isdigit(ch) || ((ch) >= 'a' && (ch) <= 'f') || \
+			((ch) >= 'A' && (ch) <= 'F'))
+
+#endif	/* _KERNEL || _BOOT */
+
+#define	DIGIT(x)	\
+	(isdigit(x) ? (x) - '0' : islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A')
+
+#define	MBASE	('z' - 'a' + 1 + 10)
+
+/*
+ * The following macro is a version of isalnum() that limits alphabetic
+ * characters to the ranges a-z and A-Z; locale dependent characters will not
+ * return 1.  The members of a-z and A-Z are assumed to be in ascending order
+ * and contiguous.
+ */
+#define	lisalnum(x)	\
+	(isdigit(x) || ((x) >= 'a' && (x) <= 'z') || ((x) >= 'A' && (x) <= 'Z'))
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _COMMON_UTIL_CTYPE_H */


Property changes on: trunk/cddl/contrib/opensolaris/common/util/strtolctype.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/cddl/contrib/opensolaris/head/assert.h
===================================================================
--- trunk/cddl/contrib/opensolaris/head/assert.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/head/assert.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/head/atomic.h
===================================================================
--- trunk/cddl/contrib/opensolaris/head/atomic.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/head/atomic.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/head/libintl.h
===================================================================
--- trunk/cddl/contrib/opensolaris/head/libintl.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/head/libintl.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -19,6 +20,8 @@
  * CDDL HEADER END
  */
 /*
+ * Copyright 2014 Garrett D'Amore <garrett at damore.org>
+ *
  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
@@ -27,8 +30,6 @@
 #ifndef	_LIBINTL_H
 #define	_LIBINTL_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/isa_defs.h>
 
 #ifdef	__cplusplus
@@ -64,7 +65,6 @@
 #define	__GNU_GETTEXT_SUPPORTED_REVISION(m)	\
 	((((m) == 0) || ((m) == 1)) ? 1 : -1)
 
-#ifdef __STDC__
 extern char *dcgettext(const char *, const char *, const int);
 extern char *dgettext(const char *, const char *);
 extern char *gettext(const char *);
@@ -91,33 +91,6 @@
 extern wchar_t mcfiller(void);
 extern int mcwrap(void);
 
-#else
-extern char *dcgettext();
-extern char *dgettext();
-extern char *gettext();
-extern char *textdomain();
-extern char *bindtextdomain();
-
-/*
- * LI18NUX 2000 Globalization Specification Version 1.0
- * with Amendment 2
- */
-extern char *dcngettext();
-extern char *dngettext();
-extern char *ngettext();
-extern char *bind_textdomain_codeset();
-
-/* Word handling functions --- requires dynamic linking */
-/* Warning: these are experimental and subject to change. */
-extern int wdinit();
-extern int wdchkind();
-extern int wdbindf();
-extern wchar_t *wddelim();
-extern wchar_t mcfiller();
-extern int mcwrap();
-
-#endif
-
 #ifdef	__cplusplus
 }
 #endif

Modified: trunk/cddl/contrib/opensolaris/head/nlist.h
===================================================================
--- trunk/cddl/contrib/opensolaris/head/nlist.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/head/nlist.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -19,6 +20,9 @@
  *
  * CDDL HEADER END
  */
+/*
+ * Copyright 2014 Garrett D'Amore <garrett at damore.org>
+ */
 /*	Copyright (c) 1988 AT&T	*/
 /*	  All Rights Reserved  	*/
 
@@ -26,8 +30,6 @@
 #ifndef _NLIST_H
 #define	_NLIST_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.8.2.4 */
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -41,11 +43,7 @@
 	char		n_numaux;	/* number of aux. entries */
 };
 
-#if defined(__STDC__)
 extern int nlist(const char *, struct nlist *);
-#else	/* __STDC__ */
-extern int nlist();
-#endif  /* __STDC__ */
 
 #ifdef	__cplusplus
 }

Modified: trunk/cddl/contrib/opensolaris/head/note.h
===================================================================
--- trunk/cddl/contrib/opensolaris/head/note.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/head/note.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/head/stdio_ext.h
===================================================================
--- trunk/cddl/contrib/opensolaris/head/stdio_ext.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/head/stdio_ext.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/head/storclass.h
===================================================================
--- trunk/cddl/contrib/opensolaris/head/storclass.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/head/storclass.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/head/syms.h
===================================================================
--- trunk/cddl/contrib/opensolaris/head/syms.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/head/syms.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/head/synch.h
===================================================================
--- trunk/cddl/contrib/opensolaris/head/synch.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/head/synch.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -20,6 +21,7 @@
  */
 
 /*
+ * Copyright 2014 Garrett D'Amore <garrett at damore.org>
  * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
@@ -86,7 +88,6 @@
 	cond_t		writercv;	/* used only to indicate ownership */
 } rwlock_t;
 
-#ifdef	__STDC__
 int	_lwp_mutex_lock(lwp_mutex_t *);
 int	_lwp_mutex_unlock(lwp_mutex_t *);
 int	_lwp_mutex_trylock(lwp_mutex_t *);
@@ -127,50 +128,6 @@
 int	sema_post(sema_t *);
 int	sema_trywait(sema_t *);
 
-#else	/* __STDC__ */
-
-int	_lwp_mutex_lock();
-int	_lwp_mutex_unlock();
-int	_lwp_mutex_trylock();
-int	_lwp_cond_wait();
-int	_lwp_cond_timedwait();
-int	_lwp_cond_reltimedwait();
-int	_lwp_cond_signal();
-int	_lwp_cond_broadcast();
-int	_lwp_sema_init();
-int	_lwp_sema_wait();
-int	_lwp_sema_trywait();
-int	_lwp_sema_post();
-int	cond_init();
-int	cond_destroy();
-int	cond_wait();
-int	cond_timedwait();
-int	cond_reltimedwait();
-int	cond_signal();
-int	cond_broadcast();
-int	mutex_init();
-int	mutex_destroy();
-int	mutex_consistent();
-int	mutex_lock();
-int	mutex_trylock();
-int	mutex_unlock();
-int	rwlock_init();
-int	rwlock_destroy();
-int	rw_rdlock();
-int	rw_wrlock();
-int	rw_unlock();
-int	rw_tryrdlock();
-int	rw_trywrlock();
-int	sema_init();
-int	sema_destroy();
-int	sema_wait();
-int	sema_timedwait();
-int	sema_reltimedwait();
-int	sema_post();
-int	sema_trywait();
-
-#endif	/* __STDC__ */
-
 #endif /* _ASM */
 
 /* "Magic numbers" tagging synchronization object types */
@@ -238,8 +195,6 @@
 
 #ifndef _ASM
 
-#ifdef	__STDC__
-
 /*
  * The *_held() functions apply equally well to Solaris threads
  * and to Posix threads synchronization objects, but the formal
@@ -252,21 +207,8 @@
 int _rw_write_held(void *);		/* rwlock_t or pthread_rwlock_t */
 int _mutex_held(void *);		/* mutex_t or pthread_mutex_t */
 
-#else	/* __STDC__ */
-
-int _sema_held();
-int _rw_read_held();
-int _rw_write_held();
-int _mutex_held();
-
-#endif	/* __STDC__ */
-
 /* Pause API */
-#ifdef	__STDC__
 void smt_pause(void);
-#else	/* __STDC__ */
-void smt_pause();
-#endif	/* __STDC__ */
 
 #endif /* _ASM */
 

Modified: trunk/cddl/contrib/opensolaris/head/thread.h
===================================================================
--- trunk/cddl/contrib/opensolaris/head/thread.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/head/thread.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -20,6 +21,8 @@
  */
 
 /*
+ * Copyright 2014 Garrett D'Amore <garrett at damore.org>
+ *
  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
@@ -27,8 +30,6 @@
 #ifndef	_THREAD_H
 #define	_THREAD_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <pthread.h>
 #include <pthread_np.h>
 #include <assert.h>

Added: trunk/cddl/contrib/opensolaris/lib/libcmdutils/common/nicenum.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libcmdutils/common/nicenum.c	                        (rev 0)
+++ trunk/cddl/contrib/opensolaris/lib/libcmdutils/common/nicenum.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -0,0 +1,131 @@
+/* $MidnightBSD$ */
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 Jason king
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/debug.h>
+#include "libcmdutils.h"
+
+/* The largest suffix that can fit, aka an exabyte (2^60 / 10^18) */
+#define	INDEX_MAX	(6)
+
+/* Verify INDEX_MAX fits */
+CTASSERT(INDEX_MAX * 10 < sizeof (uint64_t) * 8);
+
+void
+nicenum_scale(uint64_t n, size_t units, char *buf, size_t buflen,
+    uint32_t flags)
+{
+	uint64_t divamt = 1024;
+	uint64_t divisor = 1;
+	int index = 0;
+	int rc = 0;
+	char u;
+
+	if (units == 0)
+		units = 1;
+
+	if (n > 0) {
+		n *= units;
+		if (n < units)
+			goto overflow;
+	}
+
+	if (flags & NN_DIVISOR_1000)
+		divamt = 1000;
+
+	/*
+	 * This tries to find the suffix S(n) such that
+	 * S(n) <= n < S(n+1), where S(n) = 2^(n*10) | 10^(3*n)
+	 * (i.e. 1024/1000, 1,048,576/1,000,000, etc).  Stop once S(n)
+	 * is the largest prefix supported (i.e. don't bother computing
+	 * and checking S(n+1).  Since INDEX_MAX should be the largest
+	 * suffix that fits (currently an exabyte), S(INDEX_MAX + 1) is
+	 * never checked as it would overflow.
+	 */
+	while (index < INDEX_MAX) {
+		uint64_t newdiv = divisor * divamt;
+
+		/* CTASSERT() guarantee these never trip */
+		VERIFY3U(newdiv, >=, divamt);
+		VERIFY3U(newdiv, >=, divisor);
+
+		if (n < newdiv)
+			break;
+
+		divisor = newdiv;
+		index++;
+	}
+
+	u = " KMGTPE"[index];
+
+	if (index == 0) {
+		rc = snprintf(buf, buflen, "%llu", n);
+	} else if (n % divisor == 0) {
+		/*
+		 * If this is an even multiple of the base, always display
+		 * without any decimal precision.
+		 */
+		rc = snprintf(buf, buflen, "%llu%c", n / divisor, u);
+	} else {
+		/*
+		 * We want to choose a precision that reflects the best choice
+		 * for fitting in 5 characters.  This can get rather tricky
+		 * when we have numbers that are very close to an order of
+		 * magnitude.  For example, when displaying 10239 (which is
+		 * really 9.999K), we want only a single place of precision
+		 * for 10.0K.  We could develop some complex heuristics for
+		 * this, but it's much easier just to try each combination
+		 * in turn.
+		 */
+		int i;
+		for (i = 2; i >= 0; i--) {
+			if ((rc = snprintf(buf, buflen, "%.*f%c", i,
+			    (double)n / divisor, u)) <= 5)
+				break;
+		}
+	}
+
+	if (rc + 1 > buflen || rc < 0)
+		goto overflow;
+
+	return;
+
+overflow:
+	/* prefer a more verbose message if possible */
+	if (buflen > 10)
+		(void) strlcpy(buf, "<overflow>", buflen);
+	else
+		(void) strlcpy(buf, "??", buflen);
+}
+
+void
+nicenum(uint64_t num, char *buf, size_t buflen)
+{
+	nicenum_scale(num, 1, buf, buflen, 0);
+}


Property changes on: trunk/cddl/contrib/opensolaris/lib/libcmdutils/common/nicenum.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/cddl/contrib/opensolaris/lib/libcmdutils/libcmdutils.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libcmdutils/libcmdutils.h	                        (rev 0)
+++ trunk/cddl/contrib/opensolaris/lib/libcmdutils/libcmdutils.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -0,0 +1,236 @@
+/* $MidnightBSD$ */
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2013 RackTop Systems.
+ */
+/*
+ * Copyright 2017 Joyent, Inc.
+ */
+
+/*
+ * Declarations for the functions in libcmdutils.
+ */
+
+#ifndef	_LIBCMDUTILS_H
+#define	_LIBCMDUTILS_H
+
+#ifdef illumos
+#if !defined(_LP64) && \
+	!((_FILE_OFFSET_BITS == 64) || defined(_LARGEFILE64_SOURCE))
+#error "libcmdutils.h can only be used in a largefile compilation environment"
+#endif
+#endif
+
+/*
+ * This is a private header file.  Applications should not directly include
+ * this file.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <libintl.h>
+#include <string.h>
+#include <dirent.h>
+#ifdef illumos
+#include <attr.h>
+#endif
+#include <sys/avl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <libnvpair.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/* extended system attribute support */
+#define	_NOT_SATTR	0
+#define	_RO_SATTR	1
+#define	_RW_SATTR	2
+
+#define	MAXMAPSIZE	(1024*1024*8)	/* map at most 8MB */
+#define	SMALLFILESIZE	(32*1024)	/* don't use mmap on little file */
+
+/* Type used for a node containing a device id and inode number */
+
+#if defined(_LP64) || (_FILE_OFFSET_BITS == 64)
+typedef struct tree_node {
+	dev_t		node_dev;
+	ino_t		node_ino;
+	avl_node_t	avl_link;
+} tree_node_t;
+#else
+typedef struct tree_node {
+	dev_t		node_dev;
+	ino64_t		node_ino;
+	avl_node_t	avl_link;
+} tree_node_t;
+#endif
+
+		/* extended system attribute support */
+
+/* Determine if a file is the name of an extended system attribute file */
+extern int sysattr_type(char *);
+
+/* Determine if the underlying file system supports system attributes */
+extern int sysattr_support(char *, int);
+
+/* Copies the content of the source file to the target file */
+#if defined(_LP64) || (_FILE_OFFSET_BITS == 64)
+extern int writefile(int, int, char *, char *, char *, char *,
+	struct stat *, struct stat *);
+#else
+extern int writefile(int, int, char *, char *, char *, char *,
+	struct stat64 *, struct stat64 *);
+#endif
+
+/* Gets file descriptors of the source and target attribute files */
+extern int get_attrdirs(int, int, char *, int *, int *);
+
+/* Move extended attribute and extended system attribute */
+extern int mv_xattrs(char *, char *, char *, int, int);
+
+/* Returns non default extended system attribute list */
+extern nvlist_t *sysattr_list(char *, int, char *);
+
+
+
+		/* avltree */
+
+/*
+ * Used to compare two nodes.  We are attempting to match the 1st
+ * argument (node) against the 2nd argument (a node which
+ * is already in the search tree).
+ */
+
+extern int tnode_compare(const void *, const void *);
+
+/*
+ * Used to add a single node (containing the input device id and
+ * inode number) to the specified search tree.  The calling
+ * application must set the tree pointer to NULL before calling
+ * add_tnode() for the first time.
+ */
+#if defined(_LP64) || (_FILE_OFFSET_BITS == 64)
+extern int add_tnode(avl_tree_t **, dev_t, ino_t);
+#else
+extern int add_tnode(avl_tree_t **, dev_t, ino64_t);
+#endif
+
+/*
+ * Used to destroy a whole tree (all nodes) without rebalancing.
+ * The calling application is responsible for setting the tree
+ * pointer to NULL upon return.
+ */
+extern void destroy_tree(avl_tree_t *);
+
+
+
+		/* user/group id helpers */
+
+/*
+ * Used to get the next available user id in given range.
+ */
+extern int findnextuid(uid_t, uid_t, uid_t *);
+
+/*
+ * Used to get the next available group id in given range.
+ */
+extern int findnextgid(gid_t, gid_t, gid_t *);
+
+
+
+		/* dynamic string utilities */
+
+typedef struct custr custr_t;
+
+/*
+ * Allocate and free a "custr_t" dynamic string object.  Returns 0 on success
+ * and -1 otherwise.
+ */
+extern int custr_alloc(custr_t **);
+extern void custr_free(custr_t *);
+
+/*
+ * Allocate a "custr_t" dynamic string object that operates on a fixed external
+ * buffer.
+ */
+extern int custr_alloc_buf(custr_t **, void *, size_t);
+
+/*
+ * Append a single character, or a NUL-terminated string of characters, to a
+ * dynamic string.  Returns 0 on success and -1 otherwise.  The dynamic string
+ * will be unmodified if the function returns -1.
+ */
+extern int custr_appendc(custr_t *, char);
+extern int custr_append(custr_t *, const char *);
+
+/*
+ * Append a format string and arguments as though the contents were being parsed
+ * through snprintf. Returns 0 on success and -1 otherwise.  The dynamic string
+ * will be unmodified if the function returns -1.
+ */
+extern int custr_append_printf(custr_t *, const char *, ...);
+extern int custr_append_vprintf(custr_t *, const char *, va_list);
+
+/*
+ * Determine the length in bytes, not including the NUL terminator, of the
+ * dynamic string.
+ */
+extern size_t custr_len(custr_t *);
+
+/*
+ * Clear the contents of a dynamic string.  Does not free the underlying
+ * memory.
+ */
+extern void custr_reset(custr_t *);
+
+/*
+ * Retrieve a const pointer to a NUL-terminated string version of the contents
+ * of the dynamic string.  Storage for this string should not be freed, and
+ * the pointer will be invalidated by any mutations to the dynamic string.
+ */
+extern const char *custr_cstr(custr_t *str);
+
+#define	NN_DIVISOR_1000		(1U << 0)
+
+/* Minimum size for the output of nicenum, including NULL */
+#define	NN_NUMBUF_SZ		(6)
+
+void nicenum(uint64_t, char *, size_t);
+void nicenum_scale(uint64_t, size_t, char *, size_t, uint32_t);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* _LIBCMDUTILS_H */


Property changes on: trunk/cddl/contrib/opensolaris/lib/libcmdutils/libcmdutils.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/cddl/contrib/opensolaris/lib/libctf/common/ctf_lib.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libctf/common/ctf_lib.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libctf/common/ctf_lib.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -34,7 +35,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
-#if defined(sun)
+#ifdef illumos
 #include <dlfcn.h>
 #else
 #include <zlib.h>
@@ -41,7 +42,7 @@
 #endif
 #include <gelf.h>
 
-#if defined(sun)
+#ifdef illumos
 #ifdef _LP64
 static const char *_libctf_zlib = "/usr/lib/64/libz.so";
 #else
@@ -58,7 +59,7 @@
 static size_t _PAGESIZE;
 static size_t _PAGEMASK;
 
-#if defined(sun)
+#ifdef illumos
 #pragma init(_libctf_init)
 #else
 void    _libctf_init(void) __attribute__ ((constructor));
@@ -66,7 +67,7 @@
 void
 _libctf_init(void)
 {
-#if defined(sun)
+#ifdef illumos
 	const char *p = getenv("LIBCTF_DECOMPRESSOR");
 
 	if (p != NULL)
@@ -87,7 +88,7 @@
 void *
 ctf_zopen(int *errp)
 {
-#if defined(sun)
+#ifdef illumos
 	ctf_dprintf("decompressing CTF data using %s\n", _libctf_zlib);
 
 	if (zlib.z_dlp != NULL)
@@ -216,6 +217,7 @@
 {
 	ctf_sect_t ctfsect, symsect, strsect;
 	ctf_file_t *fp = NULL;
+	size_t shstrndx, shnum;
 
 	struct stat64 st;
 	ssize_t nbytes;
@@ -273,16 +275,15 @@
 	 */
 	if (nbytes >= (ssize_t) sizeof (Elf32_Ehdr) &&
 	    bcmp(&hdr.e32.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0) {
-#ifdef	_BIG_ENDIAN
+#if BYTE_ORDER == _BIG_ENDIAN
 		uchar_t order = ELFDATA2MSB;
 #else
 		uchar_t order = ELFDATA2LSB;
 #endif
-		GElf_Half i, n;
 		GElf_Shdr *sp;
 
 		void *strs_map;
-		size_t strs_mapsz;
+		size_t strs_mapsz, i;
 		char *strs;
 
 		if (hdr.e32.e_ident[EI_DATA] != order)
@@ -298,11 +299,38 @@
 			ehdr_to_gelf(&e32, &hdr.e64);
 		}
 
-		if (hdr.e64.e_shstrndx >= hdr.e64.e_shnum)
+		shnum = hdr.e64.e_shnum;
+		shstrndx = hdr.e64.e_shstrndx;
+
+		/* Extended ELF sections */
+		if ((shstrndx == SHN_XINDEX) || (shnum == 0)) {
+			if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS32) {
+				Elf32_Shdr x32;
+
+				if (pread64(fd, &x32, sizeof (x32),
+				    hdr.e64.e_shoff) != sizeof (x32))
+					return (ctf_set_open_errno(errp,
+					    errno));
+
+				shnum = x32.sh_size;
+				shstrndx = x32.sh_link;
+			} else {
+				Elf64_Shdr x64;
+
+				if (pread64(fd, &x64, sizeof (x64),
+				    hdr.e64.e_shoff) != sizeof (x64))
+					return (ctf_set_open_errno(errp,
+					    errno));
+
+				shnum = x64.sh_size;
+				shstrndx = x64.sh_link;
+			}
+		}
+
+		if (shstrndx >= shnum)
 			return (ctf_set_open_errno(errp, ECTF_CORRUPT));
 
-		n = hdr.e64.e_shnum;
-		nbytes = sizeof (GElf_Shdr) * n;
+		nbytes = sizeof (GElf_Shdr) * shnum;
 
 		if ((sp = malloc(nbytes)) == NULL)
 			return (ctf_set_open_errno(errp, errno));
@@ -314,7 +342,7 @@
 		if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS32) {
 			Elf32_Shdr *sp32;
 
-			nbytes = sizeof (Elf32_Shdr) * n;
+			nbytes = sizeof (Elf32_Shdr) * shnum;
 
 			if ((sp32 = malloc(nbytes)) == NULL || pread64(fd,
 			    sp32, nbytes, hdr.e64.e_shoff) != nbytes) {
@@ -322,7 +350,7 @@
 				return (ctf_set_open_errno(errp, errno));
 			}
 
-			for (i = 0; i < n; i++)
+			for (i = 0; i < shnum; i++)
 				shdr_to_gelf(&sp32[i], &sp[i]);
 
 			free(sp32);
@@ -336,14 +364,14 @@
 		 * Now mmap the section header strings section so that we can
 		 * perform string comparison on the section names.
 		 */
-		strs_mapsz = sp[hdr.e64.e_shstrndx].sh_size +
-		    (sp[hdr.e64.e_shstrndx].sh_offset & ~_PAGEMASK);
+		strs_mapsz = sp[shstrndx].sh_size +
+		    (sp[shstrndx].sh_offset & ~_PAGEMASK);
 
 		strs_map = mmap64(NULL, strs_mapsz, PROT_READ, MAP_PRIVATE,
-		    fd, sp[hdr.e64.e_shstrndx].sh_offset & _PAGEMASK);
+		    fd, sp[shstrndx].sh_offset & _PAGEMASK);
 
 		strs = (char *)strs_map +
-		    (sp[hdr.e64.e_shstrndx].sh_offset & ~_PAGEMASK);
+		    (sp[shstrndx].sh_offset & ~_PAGEMASK);
 
 		if (strs_map == MAP_FAILED) {
 			free(sp);
@@ -354,15 +382,15 @@
 		 * Iterate over the section header array looking for the CTF
 		 * section and symbol table.  The strtab is linked to symtab.
 		 */
-		for (i = 0; i < n; i++) {
+		for (i = 0; i < shnum; i++) {
 			const GElf_Shdr *shp = &sp[i];
 			const GElf_Shdr *lhp = &sp[shp->sh_link];
 
-			if (shp->sh_link >= hdr.e64.e_shnum)
+			if (shp->sh_link >= shnum)
 				continue; /* corrupt sh_link field */
 
-			if (shp->sh_name >= sp[hdr.e64.e_shstrndx].sh_size ||
-			    lhp->sh_name >= sp[hdr.e64.e_shstrndx].sh_size)
+			if (shp->sh_name >= sp[shstrndx].sh_size ||
+			    lhp->sh_name >= sp[shstrndx].sh_size)
 				continue; /* corrupt sh_name field */
 
 			if (shp->sh_type == SHT_PROGBITS &&

Modified: trunk/cddl/contrib/opensolaris/lib/libctf/common/ctf_subr.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libctf/common/ctf_subr.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libctf/common/ctf_subr.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libctf/common/libctf.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libctf/common/libctf.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libctf/common/libctf.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -20,6 +21,7 @@
  */
 /*
  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2013 Voxer Inc. All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -55,13 +57,13 @@
  */
 
 static const char *devnamep = "/dev/dtrace/helper";
-#if defined(sun)
+#ifdef illumos
 static const char *olddevname = "/devices/pseudo/dtrace at 0:helper";
 #endif
 
 static const char *modname;	/* Name of this load object */
 static int gen;			/* DOF helper generation */
-#if defined(sun)
+#ifdef illumos
 extern dof_hdr_t __SUNW_dof;	/* DOF defined in the .SUNW_dof section */
 #endif
 static boolean_t dof_init_debug = B_FALSE;	/* From DTRACE_DOF_INIT_DEBUG */
@@ -89,7 +91,7 @@
 	va_end(ap);
 }
 
-#if !defined(sun)
+#ifndef illumos
 static void
 fixsymbol(Elf *e, Elf_Data *data, size_t idx, int nprobes, char *buf,
     dof_sec_t *sec, int *fixedprobes, char *dofstrtab)
@@ -119,7 +121,7 @@
 }
 #endif
 
-#if defined(sun)
+#ifdef illumos
 #pragma init(dtrace_dof_init)
 #else
 static void dtrace_dof_init(void) __attribute__ ((constructor));
@@ -128,7 +130,7 @@
 static void
 dtrace_dof_init(void)
 {
-#if defined(sun)
+#ifdef illumos
 	dof_hdr_t *dof = &__SUNW_dof;
 #else
 	dof_hdr_t *dof = NULL;
@@ -140,26 +142,29 @@
 #endif
 	dof_helper_t dh;
 	Link_map *lmp;
-#if defined(sun)
+#ifdef illumos
 	Lmid_t lmid;
 #else
 	u_long lmid = 0;
-	dof_sec_t *sec;
+	dof_sec_t *sec, *secstart, *dofstrtab, *dofprobes;
+	dof_provider_t *dofprovider;
 	size_t i;
 #endif
 	int fd;
 	const char *p;
-#if !defined(sun)
+#ifndef illumos
 	Elf *e;
 	Elf_Scn *scn = NULL;
-	Elf_Data *symtabdata = NULL, *dynsymdata = NULL;
+	Elf_Data *symtabdata = NULL, *dynsymdata = NULL, *dofdata = NULL;
+	dof_hdr_t *dof_next = NULL;
 	GElf_Shdr shdr;
 	int efd, nprobes;
 	char *s;
+	char *dofstrtabraw;
 	size_t shstridx, symtabidx = 0, dynsymidx = 0;
-	unsigned char *dofstrtab = NULL;
 	unsigned char *buf;
-	int fixedprobes = 0;
+	int fixedprobes;
+	uint64_t aligned_filesz;
 #endif
 
 	if (getenv("DTRACE_DOF_INIT_DISABLE") != NULL)
@@ -173,7 +178,7 @@
 		return;
 	}
 
-#if defined(sun)
+#ifdef illumos
 	if (dlinfo(RTLD_SELF, RTLD_DI_LMID, &lmid) == -1) {
 		dprintf(1, "couldn't discover link map ID\n");
 		return;
@@ -185,7 +190,7 @@
 		modname = lmp->l_name;
 	else
 		modname++;
-#if !defined(sun)
+#ifndef illumos
 	elf_version(EV_CURRENT);
 	if ((efd = open(lmp->l_name, O_RDONLY, 0)) < 0) {
 		dprintf(1, "couldn't open file for reading\n");
@@ -209,7 +214,8 @@
 		} else if (shdr.sh_type == SHT_PROGBITS) {
 			s = elf_strptr(e, shstridx, shdr.sh_name);
 			if  (s && strcmp(s, ".SUNW_dof") == 0) {
-				dof = elf_getdata(scn, NULL)->d_buf;
+				dofdata = elf_getdata(scn, NULL);
+				dof = dofdata->d_buf;
 			}
 		}
 	}
@@ -219,6 +225,12 @@
 		close(efd);
 		return;
 	}
+
+	while ((char *) dof < (char *) dofdata->d_buf + dofdata->d_size) {
+		fixedprobes = 0;
+		aligned_filesz = (shdr.sh_addralign == 0 ? dof->dofh_filesz :
+		    roundup2(dof->dofh_filesz, shdr.sh_addralign));
+		dof_next = (void *) ((char *) dof + aligned_filesz);
 #endif
 
 	if (dof->dofh_ident[DOF_ID_MAG0] != DOF_MAG_MAG0 ||
@@ -247,7 +259,7 @@
 
 	if ((fd = open64(devnamep, O_RDWR)) < 0) {
 		dprintf(1, "failed to open helper device %s", devnamep);
-#if defined(sun)
+#ifdef illumos
 		/*
 		 * If the device path wasn't explicitly set, try again with
 		 * the old device path.
@@ -290,53 +302,73 @@
 	 * We are assuming the number of probes is less than the number of
 	 * symbols (libc can have 4k symbols, for example).
 	 */
-	sec = (dof_sec_t *)(dof + 1);
+	secstart = sec = (dof_sec_t *)(dof + 1);
 	buf = (char *)dof;
 	for (i = 0; i < dof->dofh_secnum; i++, sec++) {
-		if (sec->dofs_type == DOF_SECT_STRTAB)
-			dofstrtab = (unsigned char *)(buf + sec->dofs_offset);
-		else if (sec->dofs_type == DOF_SECT_PROBES && dofstrtab)
+		if (sec->dofs_type != DOF_SECT_PROVIDER)
+			continue;
+
+		dofprovider = (void *) (buf + sec->dofs_offset);
+		dofstrtab = secstart + dofprovider->dofpv_strtab;
+		dofprobes = secstart + dofprovider->dofpv_probes;
+
+		if (dofstrtab->dofs_type != DOF_SECT_STRTAB) {
+			fprintf(stderr, "WARNING: expected STRTAB section, but got %d\n",
+					dofstrtab->dofs_type);
 			break;
-	
+		}
+		if (dofprobes->dofs_type != DOF_SECT_PROBES) {
+			fprintf(stderr, "WARNING: expected PROBES section, but got %d\n",
+			    dofprobes->dofs_type);
+			break;
+		}
+
+		dprintf(1, "found provider %p\n", dofprovider);
+		dofstrtabraw = (char *)(buf + dofstrtab->dofs_offset);
+		nprobes = dofprobes->dofs_size / dofprobes->dofs_entsize;
+		fixsymbol(e, symtabdata, symtabidx, nprobes, buf, dofprobes, &fixedprobes,
+				dofstrtabraw);
+		if (fixedprobes != nprobes) {
+			/*
+			 * If we haven't fixed all the probes using the
+			 * symtab section, look inside the dynsym
+			 * section.
+			 */
+			fixsymbol(e, dynsymdata, dynsymidx, nprobes, buf, dofprobes,
+					&fixedprobes, dofstrtabraw);
+		}
+		if (fixedprobes != nprobes) {
+			fprintf(stderr, "WARNING: number of probes "
+			    "fixed does not match the number of "
+			    "defined probes (%d != %d, "
+			    "respectively)\n", fixedprobes, nprobes);
+			fprintf(stderr, "WARNING: some probes might "
+			    "not fire or your program might crash\n");
+		}
 	}
-	nprobes = sec->dofs_size / sec->dofs_entsize;
-	fixsymbol(e, symtabdata, symtabidx, nprobes, buf, sec, &fixedprobes,
-	    dofstrtab);
-	if (fixedprobes != nprobes) {
-		/*
-		 * If we haven't fixed all the probes using the
-		 * symtab section, look inside the dynsym
-		 * section.
-		 */
-		fixsymbol(e, dynsymdata, dynsymidx, nprobes, buf, sec,
-		    &fixedprobes, dofstrtab);
-	}
-	if (fixedprobes != nprobes) {
-		fprintf(stderr, "WARNING: number of probes "
-		    "fixed does not match the number of "
-		    "defined probes (%d != %d, "
-		    "respectively)\n", fixedprobes, nprobes);
-		fprintf(stderr, "WARNING: some probes might "
-		    "not fire or your program might crash\n");
-	}
 #endif
 	if ((gen = ioctl(fd, DTRACEHIOC_ADDDOF, &dh)) == -1)
 		dprintf(1, "DTrace ioctl failed for DOF at %p", dof);
 	else {
 		dprintf(1, "DTrace ioctl succeeded for DOF at %p\n", dof);
-#if !defined(sun)
+#ifndef illumos
 		gen = dh.gen;
 #endif
 	}
 
 	(void) close(fd);
-#if !defined(sun)
+
+#ifndef illumos
+		/* End of while loop */
+		dof = dof_next;
+	}
+
 	elf_end(e);
 	(void) close(efd);
 #endif
 }
 
-#if defined(sun)
+#ifdef illumos
 #pragma fini(dtrace_dof_fini)
 #else
 static void dtrace_dof_fini(void) __attribute__ ((destructor));

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_aggregate.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_aggregate.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_aggregate.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -25,7 +26,8 @@
  */
 
 /*
- * Copyright (c) 2011, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
  */
 
 #include <stdlib.h>
@@ -34,7 +36,7 @@
 #include <unistd.h>
 #include <dt_impl.h>
 #include <assert.h>
-#if defined(sun)
+#ifdef illumos
 #include <alloca.h>
 #else
 #include <sys/sysctl.h>
@@ -452,7 +454,7 @@
 
 	buf->dtbd_cpu = cpu;
 
-#if defined(sun)
+#ifdef illumos
 	if (dt_ioctl(dtp, DTRACEIOC_AGGSNAP, buf) == -1) {
 #else
 	if (dt_ioctl(dtp, DTRACEIOC_AGGSNAP, &buf) == -1) {
@@ -894,34 +896,15 @@
 	caddr_t rdata = rh->dtahe_data.dtada_data;
 	dtrace_recdesc_t *lrec, *rrec;
 	int64_t *laddr, *raddr;
-	int rval, i;
+	int rval;
 
-	if ((rval = dt_aggregate_hashcmp(lhs, rhs)) != 0)
-		return (rval);
+	assert(lagg->dtagd_nrecs == ragg->dtagd_nrecs);
 
-	if (lagg->dtagd_nrecs > ragg->dtagd_nrecs)
-		return (DT_GREATERTHAN);
+	lrec = &lagg->dtagd_rec[lagg->dtagd_nrecs - 1];
+	rrec = &ragg->dtagd_rec[ragg->dtagd_nrecs - 1];
 
-	if (lagg->dtagd_nrecs < ragg->dtagd_nrecs)
-		return (DT_LESSTHAN);
+	assert(lrec->dtrd_action == rrec->dtrd_action);
 
-	for (i = 0; i < lagg->dtagd_nrecs; i++) {
-		lrec = &lagg->dtagd_rec[i];
-		rrec = &ragg->dtagd_rec[i];
-
-		if (lrec->dtrd_offset < rrec->dtrd_offset)
-			return (DT_LESSTHAN);
-
-		if (lrec->dtrd_offset > rrec->dtrd_offset)
-			return (DT_GREATERTHAN);
-
-		if (lrec->dtrd_action < rrec->dtrd_action)
-			return (DT_LESSTHAN);
-
-		if (lrec->dtrd_action > rrec->dtrd_action)
-			return (DT_GREATERTHAN);
-	}
-
 	laddr = (int64_t *)(uintptr_t)(ldata + lrec->dtrd_offset);
 	raddr = (int64_t *)(uintptr_t)(rdata + rrec->dtrd_offset);
 
@@ -1319,6 +1302,231 @@
 }
 
 static int
+dt_aggregate_total(dtrace_hdl_t *dtp, boolean_t clear)
+{
+	dt_ahashent_t *h;
+	dtrace_aggdata_t **total;
+	dtrace_aggid_t max = DTRACE_AGGVARIDNONE, id;
+	dt_aggregate_t *agp = &dtp->dt_aggregate;
+	dt_ahash_t *hash = &agp->dtat_hash;
+	uint32_t tflags;
+
+	tflags = DTRACE_A_TOTAL | DTRACE_A_HASNEGATIVES | DTRACE_A_HASPOSITIVES;
+
+	/*
+	 * If we need to deliver per-aggregation totals, we're going to take
+	 * three passes over the aggregate:  one to clear everything out and
+	 * determine our maximum aggregation ID, one to actually total
+	 * everything up, and a final pass to assign the totals to the
+	 * individual elements.
+	 */
+	for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
+		dtrace_aggdata_t *aggdata = &h->dtahe_data;
+
+		if ((id = dt_aggregate_aggvarid(h)) > max)
+			max = id;
+
+		aggdata->dtada_total = 0;
+		aggdata->dtada_flags &= ~tflags;
+	}
+
+	if (clear || max == DTRACE_AGGVARIDNONE)
+		return (0);
+
+	total = dt_zalloc(dtp, (max + 1) * sizeof (dtrace_aggdata_t *));
+
+	if (total == NULL)
+		return (-1);
+
+	for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
+		dtrace_aggdata_t *aggdata = &h->dtahe_data;
+		dtrace_aggdesc_t *agg = aggdata->dtada_desc;
+		dtrace_recdesc_t *rec;
+		caddr_t data;
+		int64_t val, *addr;
+
+		rec = &agg->dtagd_rec[agg->dtagd_nrecs - 1];
+		data = aggdata->dtada_data;
+		addr = (int64_t *)(uintptr_t)(data + rec->dtrd_offset);
+
+		switch (rec->dtrd_action) {
+		case DTRACEAGG_STDDEV:
+			val = dt_stddev((uint64_t *)addr, 1);
+			break;
+
+		case DTRACEAGG_SUM:
+		case DTRACEAGG_COUNT:
+			val = *addr;
+			break;
+
+		case DTRACEAGG_AVG:
+			val = addr[0] ? (addr[1] / addr[0]) : 0;
+			break;
+
+		default:
+			continue;
+		}
+
+		if (total[agg->dtagd_varid] == NULL) {
+			total[agg->dtagd_varid] = aggdata;
+			aggdata->dtada_flags |= DTRACE_A_TOTAL;
+		} else {
+			aggdata = total[agg->dtagd_varid];
+		}
+
+		if (val > 0)
+			aggdata->dtada_flags |= DTRACE_A_HASPOSITIVES;
+
+		if (val < 0) {
+			aggdata->dtada_flags |= DTRACE_A_HASNEGATIVES;
+			val = -val;
+		}
+
+		if (dtp->dt_options[DTRACEOPT_AGGZOOM] != DTRACEOPT_UNSET) {
+			val = (int64_t)((long double)val *
+			    (1 / DTRACE_AGGZOOM_MAX));
+
+			if (val > aggdata->dtada_total)
+				aggdata->dtada_total = val;
+		} else {
+			aggdata->dtada_total += val;
+		}
+	}
+
+	/*
+	 * And now one final pass to set everyone's total.
+	 */
+	for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
+		dtrace_aggdata_t *aggdata = &h->dtahe_data, *t;
+		dtrace_aggdesc_t *agg = aggdata->dtada_desc;
+
+		if ((t = total[agg->dtagd_varid]) == NULL || aggdata == t)
+			continue;
+
+		aggdata->dtada_total = t->dtada_total;
+		aggdata->dtada_flags |= (t->dtada_flags & tflags);
+	}
+
+	dt_free(dtp, total);
+
+	return (0);
+}
+
+static int
+dt_aggregate_minmaxbin(dtrace_hdl_t *dtp, boolean_t clear)
+{
+	dt_ahashent_t *h;
+	dtrace_aggdata_t **minmax;
+	dtrace_aggid_t max = DTRACE_AGGVARIDNONE, id;
+	dt_aggregate_t *agp = &dtp->dt_aggregate;
+	dt_ahash_t *hash = &agp->dtat_hash;
+
+	for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
+		dtrace_aggdata_t *aggdata = &h->dtahe_data;
+
+		if ((id = dt_aggregate_aggvarid(h)) > max)
+			max = id;
+
+		aggdata->dtada_minbin = 0;
+		aggdata->dtada_maxbin = 0;
+		aggdata->dtada_flags &= ~DTRACE_A_MINMAXBIN;
+	}
+
+	if (clear || max == DTRACE_AGGVARIDNONE)
+		return (0);
+
+	minmax = dt_zalloc(dtp, (max + 1) * sizeof (dtrace_aggdata_t *));
+
+	if (minmax == NULL)
+		return (-1);
+
+	for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
+		dtrace_aggdata_t *aggdata = &h->dtahe_data;
+		dtrace_aggdesc_t *agg = aggdata->dtada_desc;
+		dtrace_recdesc_t *rec;
+		caddr_t data;
+		int64_t *addr;
+		int minbin = -1, maxbin = -1, i;
+		int start = 0, size;
+
+		rec = &agg->dtagd_rec[agg->dtagd_nrecs - 1];
+		size = rec->dtrd_size / sizeof (int64_t);
+		data = aggdata->dtada_data;
+		addr = (int64_t *)(uintptr_t)(data + rec->dtrd_offset);
+
+		switch (rec->dtrd_action) {
+		case DTRACEAGG_LQUANTIZE:
+			/*
+			 * For lquantize(), we always display the entire range
+			 * of the aggregation when aggpack is set.
+			 */
+			start = 1;
+			minbin = start;
+			maxbin = size - 1 - start;
+			break;
+
+		case DTRACEAGG_QUANTIZE:
+			for (i = start; i < size; i++) {
+				if (!addr[i])
+					continue;
+
+				if (minbin == -1)
+					minbin = i - start;
+
+				maxbin = i - start;
+			}
+
+			if (minbin == -1) {
+				/*
+				 * If we have no data (e.g., due to a clear()
+				 * or negative increments), we'll use the
+				 * zero bucket as both our min and max.
+				 */
+				minbin = maxbin = DTRACE_QUANTIZE_ZEROBUCKET;
+			}
+
+			break;
+
+		default:
+			continue;
+		}
+
+		if (minmax[agg->dtagd_varid] == NULL) {
+			minmax[agg->dtagd_varid] = aggdata;
+			aggdata->dtada_flags |= DTRACE_A_MINMAXBIN;
+			aggdata->dtada_minbin = minbin;
+			aggdata->dtada_maxbin = maxbin;
+			continue;
+		}
+
+		if (minbin < minmax[agg->dtagd_varid]->dtada_minbin)
+			minmax[agg->dtagd_varid]->dtada_minbin = minbin;
+
+		if (maxbin > minmax[agg->dtagd_varid]->dtada_maxbin)
+			minmax[agg->dtagd_varid]->dtada_maxbin = maxbin;
+	}
+
+	/*
+	 * And now one final pass to set everyone's minbin and maxbin.
+	 */
+	for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
+		dtrace_aggdata_t *aggdata = &h->dtahe_data, *mm;
+		dtrace_aggdesc_t *agg = aggdata->dtada_desc;
+
+		if ((mm = minmax[agg->dtagd_varid]) == NULL || aggdata == mm)
+			continue;
+
+		aggdata->dtada_minbin = mm->dtada_minbin;
+		aggdata->dtada_maxbin = mm->dtada_maxbin;
+		aggdata->dtada_flags |= DTRACE_A_MINMAXBIN;
+	}
+
+	dt_free(dtp, minmax);
+
+	return (0);
+}
+
+static int
 dt_aggregate_walk_sorted(dtrace_hdl_t *dtp,
     dtrace_aggregate_f *func, void *arg,
     int (*sfunc)(const void *, const void *))
@@ -1327,7 +1535,24 @@
 	dt_ahashent_t *h, **sorted;
 	dt_ahash_t *hash = &agp->dtat_hash;
 	size_t i, nentries = 0;
+	int rval = -1;
 
+	agp->dtat_flags &= ~(DTRACE_A_TOTAL | DTRACE_A_MINMAXBIN);
+
+	if (dtp->dt_options[DTRACEOPT_AGGHIST] != DTRACEOPT_UNSET) {
+		agp->dtat_flags |= DTRACE_A_TOTAL;
+
+		if (dt_aggregate_total(dtp, B_FALSE) != 0)
+			return (-1);
+	}
+
+	if (dtp->dt_options[DTRACEOPT_AGGPACK] != DTRACEOPT_UNSET) {
+		agp->dtat_flags |= DTRACE_A_MINMAXBIN;
+
+		if (dt_aggregate_minmaxbin(dtp, B_FALSE) != 0)
+			return (-1);
+	}
+
 	for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall)
 		nentries++;
 
@@ -1334,7 +1559,7 @@
 	sorted = dt_alloc(dtp, nentries * sizeof (dt_ahashent_t *));
 
 	if (sorted == NULL)
-		return (-1);
+		goto out;
 
 	for (h = hash->dtah_all, i = 0; h != NULL; h = h->dtahe_nextall)
 		sorted[i++] = h;
@@ -1358,14 +1583,20 @@
 	for (i = 0; i < nentries; i++) {
 		h = sorted[i];
 
-		if (dt_aggwalk_rval(dtp, h, func(&h->dtahe_data, arg)) == -1) {
-			dt_free(dtp, sorted);
-			return (-1);
-		}
+		if (dt_aggwalk_rval(dtp, h, func(&h->dtahe_data, arg)) == -1)
+			goto out;
 	}
 
+	rval = 0;
+out:
+	if (agp->dtat_flags & DTRACE_A_TOTAL)
+		(void) dt_aggregate_total(dtp, B_TRUE);
+
+	if (agp->dtat_flags & DTRACE_A_MINMAXBIN)
+		(void) dt_aggregate_minmaxbin(dtp, B_TRUE);
+
 	dt_free(dtp, sorted);
-	return (0);
+	return (rval);
 }
 
 int
@@ -1888,6 +2119,8 @@
 {
 	dt_print_aggdata_t pd;
 
+	bzero(&pd, sizeof (pd));
+
 	pd.dtpa_dtp = dtp;
 	pd.dtpa_fp = fp;
 	pd.dtpa_allunprint = 1;

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_as.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_as.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_as.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -23,9 +24,11 @@
  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013 Joyent, Inc. All rights reserved.
+ */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <strings.h>
 #include <stdlib.h>
@@ -125,7 +128,7 @@
 		dvp->dtdv_flags |= DIFV_F_MOD;
 
 	bzero(&dn, sizeof (dn));
-	dt_node_type_assign(&dn, idp->di_ctfp, idp->di_type);
+	dt_node_type_assign(&dn, idp->di_ctfp, idp->di_type, B_FALSE);
 	dt_node_diftype(pcb->pcb_hdl, &dn, &dvp->dtdv_type);
 
 	idp->di_flags &= ~(DT_IDFLG_DIFR | DT_IDFLG_DIFW);

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_as.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_as.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_as.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_buf.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_buf.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_buf.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_buf.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_buf.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_buf.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -21,8 +22,8 @@
 
 /*
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, Joyent Inc. All rights reserved.
- * Copyright (c) 2011 by Delphix. All rights reserved.
+ * Copyright (c) 2013, Joyent Inc. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
  */
 
 /*
@@ -663,64 +664,76 @@
 static void
 dt_action_trace(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
 {
+	int ctflib;
+
 	dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
+	boolean_t istrace = (dnp->dn_ident->di_id == DT_ACT_TRACE);
+	const char *act = istrace ?  "trace" : "print";
 
 	if (dt_node_is_void(dnp->dn_args)) {
-		dnerror(dnp->dn_args, D_TRACE_VOID,
-		    "trace( ) may not be applied to a void expression\n");
+		dnerror(dnp->dn_args, istrace ? D_TRACE_VOID : D_PRINT_VOID,
+		    "%s( ) may not be applied to a void expression\n", act);
 	}
 
-	if (dt_node_is_dynamic(dnp->dn_args)) {
-		dnerror(dnp->dn_args, D_TRACE_DYN,
-		    "trace( ) may not be applied to a dynamic expression\n");
+	if (dt_node_resolve(dnp->dn_args, DT_IDENT_XLPTR) != NULL) {
+		dnerror(dnp->dn_args, istrace ? D_TRACE_DYN : D_PRINT_DYN,
+		    "%s( ) may not be applied to a translated pointer\n", act);
 	}
 
+	if (dnp->dn_args->dn_kind == DT_NODE_AGG) {
+		dnerror(dnp->dn_args, istrace ? D_TRACE_AGG : D_PRINT_AGG,
+		    "%s( ) may not be applied to an aggregation%s\n", act,
+		    istrace ? "" : " -- did you mean printa()?");
+	}
+
 	dt_cg(yypcb, dnp->dn_args);
-	ap->dtad_difo = dt_as(yypcb);
-	ap->dtad_kind = DTRACEACT_DIFEXPR;
-}
 
-/*
- * The print() action behaves identically to trace(), except that it stores the
- * CTF type of the argument (if present) within the DOF for the DIFEXPR action.
- * To do this, we set the 'dtsd_strdata' to point to the fully-qualified CTF
- * type ID for the result of the DIF action.  We use the ID instead of the name
- * to handles complex types like arrays and function pointers that can't be
- * resolved by ctf_type_lookup().  This is later processed by
- * dtrace_dof_create() and turned into a reference into the string table so
- * that we can get the type information when we process the data after the
- * fact.
- */
-static void
-dt_action_print(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
-{
-	dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
-	dt_node_t *dret;
-	size_t len;
-	dt_module_t *dmp;
+	/*
+	 * The print() action behaves identically to trace(), except that it
+	 * stores the CTF type of the argument (if present) within the DOF for
+	 * the DIFEXPR action.  To do this, we set the 'dtsd_strdata' to point
+	 * to the fully-qualified CTF type ID for the result of the DIF
+	 * action.  We use the ID instead of the name to handles complex types
+	 * like arrays and function pointers that can't be resolved by
+	 * ctf_type_lookup().  This is later processed by dtrace_dof_create()
+	 * and turned into a reference into the string table so that we can
+	 * get the type information when we process the data after the fact.  In
+	 * the case where we are referring to userland CTF data, we also need to
+	 * to identify which ctf container in question we care about and encode
+	 * that within the name.
+	 */
+	if (dnp->dn_ident->di_id == DT_ACT_PRINT) {
+		dt_node_t *dret;
+		size_t n;
+		dt_module_t *dmp;
 
-	if (dt_node_is_void(dnp->dn_args)) {
-		dnerror(dnp->dn_args, D_PRINT_VOID,
-		    "print( ) may not be applied to a void expression\n");
-	}
+		dret = yypcb->pcb_dret;
+		dmp = dt_module_lookup_by_ctf(dtp, dret->dn_ctfp);
 
-	if (dt_node_is_dynamic(dnp->dn_args)) {
-		dnerror(dnp->dn_args, D_PRINT_DYN,
-		    "print( ) may not be applied to a dynamic expression\n");
+		n = snprintf(NULL, 0, "%s`%ld", dmp->dm_name, dret->dn_type) + 1;
+		if (dmp->dm_pid != 0) {
+			ctflib = dt_module_getlibid(dtp, dmp, dret->dn_ctfp);
+			assert(ctflib >= 0);
+			n = snprintf(NULL, 0, "%s`%d`%ld", dmp->dm_name,
+			    ctflib, dret->dn_type) + 1;
+		} else {
+			n = snprintf(NULL, 0, "%s`%ld", dmp->dm_name,
+			    dret->dn_type) + 1;
+		}
+		sdp->dtsd_strdata = dt_alloc(dtp, n);
+		if (sdp->dtsd_strdata == NULL)
+			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+		(void) snprintf(sdp->dtsd_strdata, n, "%s`%ld", dmp->dm_name,
+		    dret->dn_type);
+		if (dmp->dm_pid != 0) {
+			(void) snprintf(sdp->dtsd_strdata, n, "%s`%d`%ld",
+			    dmp->dm_name, ctflib, dret->dn_type);
+		} else {
+			(void) snprintf(sdp->dtsd_strdata, n, "%s`%ld",
+			    dmp->dm_name, dret->dn_type);
+		}
 	}
 
-	dt_cg(yypcb, dnp->dn_args);
-
-	dret = yypcb->pcb_dret;
-	dmp = dt_module_lookup_by_ctf(dtp, dret->dn_ctfp);
-
-	len = snprintf(NULL, 0, "%s`%ld", dmp->dm_name, dret->dn_type) + 1;
-	sdp->dtsd_strdata = dt_alloc(dtp, len);
-	if (sdp->dtsd_strdata == NULL)
-		longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
-	(void) snprintf(sdp->dtsd_strdata, len, "%s`%ld", dmp->dm_name,
-	    dret->dn_type);
-
 	ap->dtad_difo = dt_as(yypcb);
 	ap->dtad_kind = DTRACEACT_DIFEXPR;
 }
@@ -1145,6 +1158,9 @@
 	case DT_ACT_PANIC:
 		dt_action_panic(dtp, dnp->dn_expr, sdp);
 		break;
+	case DT_ACT_PRINT:
+		dt_action_trace(dtp, dnp->dn_expr, sdp);
+		break;
 	case DT_ACT_PRINTA:
 		dt_action_printa(dtp, dnp->dn_expr, sdp);
 		break;
@@ -1181,9 +1197,6 @@
 	case DT_ACT_TRACE:
 		dt_action_trace(dtp, dnp->dn_expr, sdp);
 		break;
-	case DT_ACT_PRINT:
-		dt_action_print(dtp, dnp->dn_expr, sdp);
-		break;
 	case DT_ACT_TRACEMEM:
 		dt_action_tracemem(dtp, dnp->dn_expr, sdp);
 		break;
@@ -1876,7 +1889,7 @@
 	char **argv = malloc(sizeof (char *) * (argc + 5));
 	FILE *ofp = tmpfile();
 
-#if defined(sun)
+#ifdef illumos
 	char ipath[20], opath[20]; /* big enough for /dev/fd/ + INT_MAX + \0 */
 #endif
 	char verdef[32]; /* big enough for -D__SUNW_D_VERSION=0x%08x + \0 */
@@ -1886,7 +1899,7 @@
 
 	int wstat, estat;
 	pid_t pid;
-#if defined(sun)
+#ifdef illumos
 	off64_t off;
 #else
 	off_t off = 0;
@@ -1917,7 +1930,7 @@
 		(void) fseeko64(ifp, off, SEEK_SET);
 	}
 
-#if defined(sun)
+#ifdef illumos
 	(void) snprintf(ipath, sizeof (ipath), "/dev/fd/%d", fileno(ifp));
 	(void) snprintf(opath, sizeof (opath), "/dev/fd/%d", fileno(ofp));
 #endif
@@ -1928,7 +1941,7 @@
 	    "-D__SUNW_D_VERSION=0x%08x", dtp->dt_vmax);
 	argv[argc++] = verdef;
 
-#if defined(sun)
+#ifdef illumos
 	switch (dtp->dt_stdcmode) {
 	case DT_STDC_XA:
 	case DT_STDC_XT:
@@ -1970,7 +1983,7 @@
 	}
 
 	if (pid == 0) {
-#if !defined(sun)
+#ifndef illumos
 		if (isatty(fileno(ifp)) == 0)
 			lseek(fileno(ifp), off, SEEK_SET);
 		dup2(fileno(ifp), 0);
@@ -2277,12 +2290,15 @@
 			dt_dprintf("skipping library %s, already processed "
 			    "library with the same name: %s", dp->d_name,
 			    dld->dtld_library);
+			(void) fclose(fp);
 			continue;
 		}
 
 		dtp->dt_filetag = fname;
-		if (dt_lib_depend_add(dtp, &dtp->dt_lib_dep, fname) != 0)
+		if (dt_lib_depend_add(dtp, &dtp->dt_lib_dep, fname) != 0) {
+			(void) fclose(fp);
 			return (-1); /* preserve dt_errno */
+		}
 
 		rv = dt_compile(dtp, DT_CTX_DPROG,
 		    DTRACE_PROBESPEC_NAME, NULL,
@@ -2290,8 +2306,10 @@
 
 		if (rv != NULL && dtp->dt_errno &&
 		    (dtp->dt_errno != EDT_COMPILER ||
-		    dtp->dt_errtag != dt_errtag(D_PRAGMA_DEPEND)))
+		    dtp->dt_errtag != dt_errtag(D_PRAGMA_DEPEND))) {
+			(void) fclose(fp);
 			return (-1); /* preserve dt_errno */
+		}
 
 		if (dtp->dt_errno)
 			dt_dprintf("error parsing library %s: %s\n",
@@ -2559,7 +2577,8 @@
 	}
 
 out:
-	if (context != DT_CTX_DTYPE && DT_TREEDUMP_PASS(dtp, 3))
+	if (context != DT_CTX_DTYPE && yypcb->pcb_root != NULL &&
+	    DT_TREEDUMP_PASS(dtp, 3))
 		dt_node_printr(yypcb->pcb_root, stderr, 0);
 
 	if (dtp->dt_cdefs_fd != -1 && (ftruncate64(dtp->dt_cdefs_fd, 0) == -1 ||

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cg.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cg.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cg.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -19,12 +20,15 @@
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
 
 #include <sys/types.h>
 #include <sys/sysmacros.h>
@@ -193,9 +197,6 @@
 	ssize_t size;
 	int sreg;
 
-	if ((sreg = dt_regset_alloc(drp)) == -1)
-		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
-
 	type = ctf_type_resolve(ctfp, dnp->dn_type);
 	kind = ctf_type_kind(ctfp, type);
 	assert(kind == CTF_K_POINTER || kind == CTF_K_ARRAY);
@@ -212,6 +213,7 @@
 	if ((size = ctf_type_size(ctfp, type)) == 1)
 		return; /* multiply or divide by one can be omitted */
 
+	sreg = dt_regset_alloc(drp);
 	dt_cg_setx(dlp, sreg, size);
 	instr = DIF_INSTR_FMT(op, dreg, sreg, dreg);
 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
@@ -251,10 +253,8 @@
 
 	assert(dnp->dn_op == DT_TOK_PTR || dnp->dn_op == DT_TOK_DOT);
 	r1 = dnp->dn_left->dn_reg;
+	r2 = dt_regset_alloc(drp);
 
-	if ((r2 = dt_regset_alloc(drp)) == -1)
-		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
-
 	/*
 	 * On little-endian architectures, ctm_offset counts from the right so
 	 * ctm_offset % NBBY itself is the amount we want to shift right to
@@ -356,10 +356,9 @@
 		    "bits %u\n", m.ctm_offset, m.ctm_type, e.cte_bits);
 	}
 
-	if ((r1 = dt_regset_alloc(drp)) == -1 ||
-	    (r2 = dt_regset_alloc(drp)) == -1 ||
-	    (r3 = dt_regset_alloc(drp)) == -1)
-		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+	r1 = dt_regset_alloc(drp);
+	r2 = dt_regset_alloc(drp);
+	r3 = dt_regset_alloc(drp);
 
 	/*
 	 * Compute shifts and masks.  We need to compute "shift" as the amount
@@ -423,8 +422,7 @@
 		size = dt_node_type_size(src);
 
 	if (src->dn_flags & DT_NF_REF) {
-		if ((reg = dt_regset_alloc(drp)) == -1)
-			longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+		reg = dt_regset_alloc(drp);
 		dt_cg_setx(dlp, reg, size);
 		instr = DIF_INSTR_COPYS(src->dn_reg, reg, dst->dn_reg);
 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
@@ -474,30 +472,58 @@
 	size_t dstsize = dt_node_type_size(dst);
 
 	dif_instr_t instr;
-	int reg, n;
+	int rg;
 
-	if (dt_node_is_scalar(dst) && (dstsize < srcsize ||
-	    (src->dn_flags & DT_NF_SIGNED) ^ (dst->dn_flags & DT_NF_SIGNED))) {
-		if ((reg = dt_regset_alloc(drp)) == -1)
-			longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+	if (!dt_node_is_scalar(dst))
+		return; /* not a scalar */
+	if (dstsize == srcsize &&
+	    ((src->dn_flags ^ dst->dn_flags) & DT_NF_SIGNED) != 0)
+		return; /* not narrowing or changing signed-ness */
+	if (dstsize > srcsize && (src->dn_flags & DT_NF_SIGNED) == 0)
+		return; /* nothing to do in this case */
 
-		if (dstsize < srcsize)
-			n = sizeof (uint64_t) * NBBY - dstsize * NBBY;
-		else
-			n = sizeof (uint64_t) * NBBY - srcsize * NBBY;
+	rg = dt_regset_alloc(drp);
 
-		dt_cg_setx(dlp, reg, n);
+	if (dstsize > srcsize) {
+		int n = sizeof (uint64_t) * NBBY - srcsize * NBBY;
+		int s = (dstsize - srcsize) * NBBY;
 
-		instr = DIF_INSTR_FMT(DIF_OP_SLL,
-		    src->dn_reg, reg, dst->dn_reg);
+		dt_cg_setx(dlp, rg, n);
+
+		instr = DIF_INSTR_FMT(DIF_OP_SLL, src->dn_reg, rg, dst->dn_reg);
 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
 
-		instr = DIF_INSTR_FMT((dst->dn_flags & DT_NF_SIGNED) ?
-		    DIF_OP_SRA : DIF_OP_SRL, dst->dn_reg, reg, dst->dn_reg);
+		if ((dst->dn_flags & DT_NF_SIGNED) || n == s) {
+			instr = DIF_INSTR_FMT(DIF_OP_SRA,
+			    dst->dn_reg, rg, dst->dn_reg);
+			dt_irlist_append(dlp,
+			    dt_cg_node_alloc(DT_LBL_NONE, instr));
+		} else {
+			dt_cg_setx(dlp, rg, s);
+			instr = DIF_INSTR_FMT(DIF_OP_SRA,
+			    dst->dn_reg, rg, dst->dn_reg);
+			dt_irlist_append(dlp,
+			    dt_cg_node_alloc(DT_LBL_NONE, instr));
+			dt_cg_setx(dlp, rg, n - s);
+			instr = DIF_INSTR_FMT(DIF_OP_SRL,
+			    dst->dn_reg, rg, dst->dn_reg);
+			dt_irlist_append(dlp,
+			    dt_cg_node_alloc(DT_LBL_NONE, instr));
+		}
+	} else if (dstsize != sizeof (uint64_t)) {
+		int n = sizeof (uint64_t) * NBBY - dstsize * NBBY;
 
+		dt_cg_setx(dlp, rg, n);
+
+		instr = DIF_INSTR_FMT(DIF_OP_SLL, src->dn_reg, rg, dst->dn_reg);
 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
-		dt_regset_free(drp, reg);
+
+		instr = DIF_INSTR_FMT((dst->dn_flags & DT_NF_SIGNED) ?
+		    DIF_OP_SRA : DIF_OP_SRL, dst->dn_reg, rg, dst->dn_reg);
+		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
 	}
+
+	dt_regset_free(drp, rg);
 }
 
 /*
@@ -523,8 +549,7 @@
 	for (dnp = args; dnp != NULL; dnp = dnp->dn_list)
 		dt_cg_node(dnp, dlp, drp);
 
-	dt_irlist_append(dlp,
-	    dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS));
+	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS));
 
 	for (dnp = args; dnp != NULL; dnp = dnp->dn_list, i++) {
 		dtrace_diftype_t t;
@@ -538,17 +563,18 @@
 		dt_cg_typecast(dnp, &isp->dis_args[i], dlp, drp);
 		isp->dis_args[i].dn_reg = -1;
 
-		if (t.dtdt_flags & DIF_TF_BYREF)
+		if (t.dtdt_flags & DIF_TF_BYREF) {
 			op = DIF_OP_PUSHTR;
-		else
+			if (t.dtdt_size != 0) {
+				reg = dt_regset_alloc(drp);
+				dt_cg_setx(dlp, reg, t.dtdt_size);
+			} else {
+				reg = DIF_REG_R0;
+			}
+		} else {
 			op = DIF_OP_PUSHTV;
-
-		if (t.dtdt_size != 0) {
-			if ((reg = dt_regset_alloc(drp)) == -1)
-				longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
-			dt_cg_setx(dlp, reg, t.dtdt_size);
-		} else
 			reg = DIF_REG_R0;
+		}
 
 		instr = DIF_INSTR_PUSHTS(op, t.dtdt_kind, reg, dnp->dn_reg);
 		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
@@ -629,9 +655,7 @@
 	dt_cg_node(dnp->dn_child, dlp, drp);
 	dnp->dn_reg = dnp->dn_child->dn_reg;
 
-	if ((reg = dt_regset_alloc(drp)) == -1)
-		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
-
+	reg = dt_regset_alloc(drp);
 	dt_cg_setx(dlp, reg, size);
 
 	instr = DIF_INSTR_FMT(op, dnp->dn_reg, reg, dnp->dn_reg);
@@ -688,9 +712,7 @@
 	dt_cg_node(dnp->dn_child, dlp, drp);
 	dnp->dn_reg = dnp->dn_child->dn_reg;
 
-	if ((nreg = dt_regset_alloc(drp)) == -1)
-		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
-
+	nreg = dt_regset_alloc(drp);
 	dt_cg_setx(dlp, nreg, size);
 	instr = DIF_INSTR_FMT(op, dnp->dn_reg, nreg, nreg);
 	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
@@ -1008,9 +1030,7 @@
 		 * set it to the size of our data structure, and then replace
 		 * it with the result of an allocs of the specified size.
 		 */
-		if ((r1 = dt_regset_alloc(drp)) == -1)
-			longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
-
+		r1 = dt_regset_alloc(drp);
 		dt_cg_setx(dlp, r1,
 		    ctf_type_size(dxp->dx_dst_ctfp, dxp->dx_dst_base));
 
@@ -1054,8 +1074,7 @@
 			 * and add r1 to it before storing the result.
 			 */
 			if (ctm.ctm_offset != 0) {
-				if ((r2 = dt_regset_alloc(drp)) == -1)
-					longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+				r2 = dt_regset_alloc(drp);
 
 				/*
 				 * Add the member offset rounded down to the
@@ -1142,8 +1161,7 @@
 
 	dt_cg_arglist(dnp->dn_ident, dnp->dn_args, dlp, drp);
 
-	if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
-		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+	dnp->dn_reg = dt_regset_alloc(drp);
 
 	if (dnp->dn_ident->di_flags & DT_IDFLG_TLS)
 		op = DIF_OP_LDTAA;
@@ -1273,9 +1291,7 @@
 	if ((size = dt_node_type_size(dnp)) == sizeof (uint64_t))
 		return;
 
-	if ((reg = dt_regset_alloc(drp)) == -1)
-		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
-
+	reg = dt_regset_alloc(drp);
 	assert(size < sizeof (uint64_t));
 	n = sizeof (uint64_t) * NBBY - size * NBBY;
 
@@ -1372,6 +1388,162 @@
 	typs->dn_value = ctf_type_size(dtt.dtt_ctfp, dtt.dtt_type);
 }
 
+typedef struct dt_xlmemb {
+	dt_ident_t *dtxl_idp;		/* translated ident */
+	dt_irlist_t *dtxl_dlp;		/* instruction list */
+	dt_regset_t *dtxl_drp;		/* register set */
+	int dtxl_sreg;			/* location of the translation input */
+	int dtxl_dreg;			/* location of our allocated buffer */
+} dt_xlmemb_t;
+
+/*ARGSUSED*/
+static int
+dt_cg_xlate_member(const char *name, ctf_id_t type, ulong_t off, void *arg)
+{
+	dt_xlmemb_t *dx = arg;
+	dt_ident_t *idp = dx->dtxl_idp;
+	dt_irlist_t *dlp = dx->dtxl_dlp;
+	dt_regset_t *drp = dx->dtxl_drp;
+
+	dt_node_t *mnp;
+	dt_xlator_t *dxp;
+
+	int reg, treg;
+	uint32_t instr;
+	size_t size;
+
+	/* Generate code for the translation. */
+	dxp = idp->di_data;
+	mnp = dt_xlator_member(dxp, name);
+
+	/* If there's no translator for the given member, skip it. */
+	if (mnp == NULL)
+		return (0);
+
+	dxp->dx_ident->di_flags |= DT_IDFLG_CGREG;
+	dxp->dx_ident->di_id = dx->dtxl_sreg;
+
+	dt_cg_node(mnp->dn_membexpr, dlp, drp);
+
+	dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG;
+	dxp->dx_ident->di_id = 0;
+
+	treg = mnp->dn_membexpr->dn_reg;
+
+	/* Compute the offset into our buffer and store the result there. */
+	reg = dt_regset_alloc(drp);
+
+	dt_cg_setx(dlp, reg, off / NBBY);
+	instr = DIF_INSTR_FMT(DIF_OP_ADD, dx->dtxl_dreg, reg, reg);
+	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+	size = ctf_type_size(mnp->dn_membexpr->dn_ctfp,
+	    mnp->dn_membexpr->dn_type);
+	if (dt_node_is_scalar(mnp->dn_membexpr)) {
+		/*
+		 * Copying scalars is simple.
+		 */
+		switch (size) {
+		case 1:
+			instr = DIF_INSTR_STORE(DIF_OP_STB, treg, reg);
+			break;
+		case 2:
+			instr = DIF_INSTR_STORE(DIF_OP_STH, treg, reg);
+			break;
+		case 4:
+			instr = DIF_INSTR_STORE(DIF_OP_STW, treg, reg);
+			break;
+		case 8:
+			instr = DIF_INSTR_STORE(DIF_OP_STX, treg, reg);
+			break;
+		default:
+			xyerror(D_UNKNOWN, "internal error -- unexpected "
+			    "size: %lu\n", (ulong_t)size);
+		}
+
+		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+	} else if (dt_node_is_string(mnp->dn_membexpr)) {
+		int szreg;
+
+		/*
+		 * Use the copys instruction for strings.
+		 */
+		szreg = dt_regset_alloc(drp);
+		dt_cg_setx(dlp, szreg, size);
+		instr = DIF_INSTR_COPYS(treg, szreg, reg);
+		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+		dt_regset_free(drp, szreg);
+	} else {
+		int szreg;
+
+		/*
+		 * If it's anything else then we'll just bcopy it.
+		 */
+		szreg = dt_regset_alloc(drp);
+		dt_cg_setx(dlp, szreg, size);
+		dt_irlist_append(dlp,
+		    dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS));
+		instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF,
+		    DIF_REG_R0, treg);
+		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+		instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF,
+		    DIF_REG_R0, reg);
+		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+		instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF,
+		    DIF_REG_R0, szreg);
+		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+		instr = DIF_INSTR_CALL(DIF_SUBR_BCOPY, szreg);
+		dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+		dt_regset_free(drp, szreg);
+	}
+
+	dt_regset_free(drp, reg);
+	dt_regset_free(drp, treg);
+
+	return (0);
+}
+
+/*
+ * If we're expanding a translated type, we create an appropriately sized
+ * buffer with alloca() and then translate each member into it.
+ */
+static int
+dt_cg_xlate_expand(dt_node_t *dnp, dt_ident_t *idp, dt_irlist_t *dlp,
+    dt_regset_t *drp)
+{
+	dt_xlmemb_t dlm;
+	uint32_t instr;
+	int dreg;
+	size_t size;
+
+	dreg = dt_regset_alloc(drp);
+	size = ctf_type_size(dnp->dn_ident->di_ctfp, dnp->dn_ident->di_type);
+
+	/* Call alloca() to create the buffer. */
+	dt_cg_setx(dlp, dreg, size);
+
+	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS));
+
+	instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF, DIF_REG_R0, dreg);
+	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+	instr = DIF_INSTR_CALL(DIF_SUBR_ALLOCA, dreg);
+	dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+
+	/* Generate the translation for each member. */
+	dlm.dtxl_idp = idp;
+	dlm.dtxl_dlp = dlp;
+	dlm.dtxl_drp = drp;
+	dlm.dtxl_sreg = dnp->dn_reg;
+	dlm.dtxl_dreg = dreg;
+	(void) ctf_member_iter(dnp->dn_ident->di_ctfp,
+	    dnp->dn_ident->di_type, dt_cg_xlate_member,
+	    &dlm);
+
+	return (dreg);
+}
+
 static void
 dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
 {
@@ -1384,7 +1556,6 @@
 	dt_ident_t *idp;
 	ssize_t stroff;
 	uint_t op;
-	int reg;
 
 	switch (dnp->dn_op) {
 	case DT_TOK_COMMA:
@@ -1586,7 +1757,16 @@
 		dt_cg_node(dnp->dn_child, dlp, drp);
 		dnp->dn_reg = dnp->dn_child->dn_reg;
 
-		if (!(dnp->dn_flags & DT_NF_REF)) {
+		if (dt_node_is_dynamic(dnp->dn_child)) {
+			int reg;
+			idp = dt_node_resolve(dnp->dn_child, DT_IDENT_XLPTR);
+			assert(idp != NULL);
+			reg = dt_cg_xlate_expand(dnp, idp, dlp, drp);
+
+			dt_regset_free(drp, dnp->dn_child->dn_reg);
+			dnp->dn_reg = reg;
+
+		} else if (!(dnp->dn_flags & DT_NF_REF)) {
 			uint_t ubit = dnp->dn_flags & DT_NF_USERLAND;
 
 			/*
@@ -1622,10 +1802,7 @@
 
 	case DT_TOK_SIZEOF: {
 		size_t size = dt_node_sizeof(dnp->dn_child);
-
-		if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
-			longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
-
+		dnp->dn_reg = dt_regset_alloc(drp);
 		assert(size != 0);
 		dt_cg_setx(dlp, dnp->dn_reg, size);
 		break;
@@ -1650,8 +1827,7 @@
 			assert(dxp->dx_ident->di_flags & DT_IDFLG_CGREG);
 			assert(dxp->dx_ident->di_id != 0);
 
-			if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
-				longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+			dnp->dn_reg = dt_regset_alloc(drp);
 
 			if (dxp->dx_arg == -1) {
 				instr = DIF_INSTR_MOV(
@@ -1735,9 +1911,10 @@
 		}
 
 		if (m.ctm_offset != 0) {
-			if ((reg = dt_regset_alloc(drp)) == -1)
-				longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+			int reg;
 
+			reg = dt_regset_alloc(drp);
+
 			/*
 			 * If the offset is not aligned on a byte boundary, it
 			 * is a bit-field member and we will extract the value
@@ -1782,8 +1959,7 @@
 		break;
 
 	case DT_TOK_STRING:
-		if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
-			longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+		dnp->dn_reg = dt_regset_alloc(drp);
 
 		assert(dnp->dn_kind == DT_NODE_STRING);
 		stroff = dt_strtab_insert(yypcb->pcb_strtab, dnp->dn_string);
@@ -1806,8 +1982,7 @@
 		 */
 		if (dnp->dn_kind == DT_NODE_VAR &&
 		    (dnp->dn_ident->di_flags & DT_IDFLG_CGREG)) {
-			if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
-				longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+			dnp->dn_reg = dt_regset_alloc(drp);
 			instr = DIF_INSTR_MOV(dnp->dn_ident->di_id,
 			    dnp->dn_reg);
 			dt_irlist_append(dlp,
@@ -1848,12 +2023,10 @@
 
 			dt_cg_arglist(dnp->dn_ident, dnp->dn_args, dlp, drp);
 
-			if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
-				longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+			dnp->dn_reg = dt_regset_alloc(drp);
+			instr = DIF_INSTR_CALL(dnp->dn_ident->di_id,
+			    dnp->dn_reg);
 
-			instr = DIF_INSTR_CALL(
-			    dnp->dn_ident->di_id, dnp->dn_reg);
-
 			dt_irlist_append(dlp,
 			    dt_cg_node_alloc(DT_LBL_NONE, instr));
 
@@ -1880,8 +2053,7 @@
 				break;
 			}
 
-			if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
-				longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+			dnp->dn_reg = dt_regset_alloc(drp);
 
 			if (dnp->dn_ident->di_flags & DT_IDFLG_LOCAL)
 				op = DIF_OP_LDLS;
@@ -1911,9 +2083,7 @@
 				    dtrace_errmsg(dtp, dtrace_errno(dtp)));
 			}
 
-			if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
-				longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
-
+			dnp->dn_reg = dt_regset_alloc(drp);
 			dt_cg_xsetx(dlp, dnp->dn_ident,
 			    DT_LBL_NONE, dnp->dn_reg, sym.st_value);
 
@@ -1933,9 +2103,7 @@
 		break;
 
 	case DT_TOK_INT:
-		if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
-			longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
-
+		dnp->dn_reg = dt_regset_alloc(drp);
 		dt_cg_setx(dlp, dnp->dn_reg, dnp->dn_value);
 		break;
 
@@ -1950,6 +2118,7 @@
 {
 	dif_instr_t instr;
 	dt_xlator_t *dxp;
+	dt_ident_t *idp;
 
 	if (pcb->pcb_regs == NULL && (pcb->pcb_regs =
 	    dt_regset_create(pcb->pcb_hdl->dt_conf.dtc_difintregs)) == NULL)
@@ -1976,9 +2145,9 @@
 	assert(pcb->pcb_dret == NULL);
 	pcb->pcb_dret = dnp;
 
-	if (dt_node_is_dynamic(dnp)) {
+	if (dt_node_resolve(dnp, DT_IDENT_XLPTR) != NULL) {
 		dnerror(dnp, D_CG_DYN, "expression cannot evaluate to result "
-		    "of dynamic type\n");
+		    "of a translated pointer\n");
 	}
 
 	/*
@@ -1994,6 +2163,14 @@
 	}
 
 	dt_cg_node(dnp, &pcb->pcb_ir, pcb->pcb_regs);
+
+	if ((idp = dt_node_resolve(dnp, DT_IDENT_XLSOU)) != NULL) {
+		int reg = dt_cg_xlate_expand(dnp, idp,
+		    &pcb->pcb_ir, pcb->pcb_regs);
+		dt_regset_free(pcb->pcb_regs, dnp->dn_reg);
+		dnp->dn_reg = reg;
+	}
+
 	instr = DIF_INSTR_RET(dnp->dn_reg);
 	dt_regset_free(pcb->pcb_regs, dnp->dn_reg);
 	dt_irlist_append(&pcb->pcb_ir, dt_cg_node_alloc(DT_LBL_NONE, instr));
@@ -2003,4 +2180,7 @@
 		dxp->dx_ident->di_id = 0;
 		dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG;
 	}
+
+	dt_regset_free(pcb->pcb_regs, 0);
+	dt_regset_assert_free(pcb->pcb_regs);
 }

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -24,8 +25,8 @@
  */
 
 /*
- * Copyright (c) 2011, Joyent, Inc. All rights reserved.
- * Copyright (c) 2011 by Delphix. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
  */
 
 #include <stdlib.h>
@@ -35,11 +36,12 @@
 #include <limits.h>
 #include <assert.h>
 #include <ctype.h>
-#if defined(sun)
+#ifdef illumos
 #include <alloca.h>
 #endif
 #include <dt_impl.h>
-#if !defined(sun)
+#include <dt_pq.h>
+#ifndef illumos
 #include <libproc_compat.h>
 #endif
 
@@ -58,6 +60,25 @@
 	return (x);
 }
 
+static int
+dt_ndigits(long long val)
+{
+	int rval = 1;
+	long long cmp = 10;
+
+	if (val < 0) {
+		val = val == INT64_MIN ? INT64_MAX : -val;
+		rval++;
+	}
+
+	while (val > cmp && cmp > 0) {
+		rval++;
+		cmp *= 10;
+	}
+
+	return (rval < 4 ? 4 : rval);
+}
+
 /*
  * 128-bit arithmetic functions needed to support the stddev() aggregating
  * action.
@@ -362,12 +383,17 @@
 	int64_t norm_avg;
 	uint64_t diff[2];
 
+	if (data[0] == 0)
+		return (0);
+
 	/*
 	 * The standard approximation for standard deviation is
 	 * sqrt(average(x**2) - average(x)**2), i.e. the square root
 	 * of the average of the squares minus the square of the average.
+	 * When normalizing, we should divide the sum of x**2 by normal**2.
 	 */
 	dt_divide_128(data + 2, normal, avg_of_squares);
+	dt_divide_128(avg_of_squares, normal, avg_of_squares);
 	dt_divide_128(avg_of_squares, data[0], avg_of_squares);
 
 	norm_avg = (int64_t)data[1] / (int64_t)normal / (int64_t)data[0];
@@ -443,17 +469,8 @@
 		offs += epd->dtepd_size;
 
 		do {
-			if (offs >= buf->dtbd_size) {
-				/*
-				 * We're at the end -- maybe.  If the oldest
-				 * record is non-zero, we need to wrap.
-				 */
-				if (buf->dtbd_oldest != 0) {
-					offs = 0;
-				} else {
-					goto out;
-				}
-			}
+			if (offs >= buf->dtbd_size)
+				goto out;
 
 			next = *(uint32_t *)((uintptr_t)buf->dtbd_data + offs);
 
@@ -495,7 +512,125 @@
 	return (DTRACE_CONSUME_NEXT);
 }
 
-int
+static void
+dt_quantize_total(dtrace_hdl_t *dtp, int64_t datum, long double *total)
+{
+	long double val = dt_fabsl((long double)datum);
+
+	if (dtp->dt_options[DTRACEOPT_AGGZOOM] == DTRACEOPT_UNSET) {
+		*total += val;
+		return;
+	}
+
+	/*
+	 * If we're zooming in on an aggregation, we want the height of the
+	 * highest value to be approximately 95% of total bar height -- so we
+	 * adjust up by the reciprocal of DTRACE_AGGZOOM_MAX when comparing to
+	 * our highest value.
+	 */
+	val *= 1 / DTRACE_AGGZOOM_MAX;
+
+	if (*total < val)
+		*total = val;
+}
+
+static int
+dt_print_quanthdr(dtrace_hdl_t *dtp, FILE *fp, int width)
+{
+	return (dt_printf(dtp, fp, "\n%*s %41s %-9s\n",
+	    width ? width : 16, width ? "key" : "value",
+	    "------------- Distribution -------------", "count"));
+}
+
+static int
+dt_print_quanthdr_packed(dtrace_hdl_t *dtp, FILE *fp, int width,
+    const dtrace_aggdata_t *aggdata, dtrace_actkind_t action)
+{
+	int min = aggdata->dtada_minbin, max = aggdata->dtada_maxbin;
+	int minwidth, maxwidth, i;
+
+	assert(action == DTRACEAGG_QUANTIZE || action == DTRACEAGG_LQUANTIZE);
+
+	if (action == DTRACEAGG_QUANTIZE) {
+		if (min != 0 && min != DTRACE_QUANTIZE_ZEROBUCKET)
+			min--;
+
+		if (max < DTRACE_QUANTIZE_NBUCKETS - 1)
+			max++;
+
+		minwidth = dt_ndigits(DTRACE_QUANTIZE_BUCKETVAL(min));
+		maxwidth = dt_ndigits(DTRACE_QUANTIZE_BUCKETVAL(max));
+	} else {
+		maxwidth = 8;
+		minwidth = maxwidth - 1;
+		max++;
+	}
+
+	if (dt_printf(dtp, fp, "\n%*s %*s .",
+	    width, width > 0 ? "key" : "", minwidth, "min") < 0)
+		return (-1);
+
+	for (i = min; i <= max; i++) {
+		if (dt_printf(dtp, fp, "-") < 0)
+			return (-1);
+	}
+
+	return (dt_printf(dtp, fp, ". %*s | count\n", -maxwidth, "max"));
+}
+
+/*
+ * We use a subset of the Unicode Block Elements (U+2588 through U+258F,
+ * inclusive) to represent aggregations via UTF-8 -- which are expressed via
+ * 3-byte UTF-8 sequences.
+ */
+#define	DTRACE_AGGUTF8_FULL	0x2588
+#define	DTRACE_AGGUTF8_BASE	0x258f
+#define	DTRACE_AGGUTF8_LEVELS	8
+
+#define	DTRACE_AGGUTF8_BYTE0(val)	(0xe0 | ((val) >> 12))
+#define	DTRACE_AGGUTF8_BYTE1(val)	(0x80 | (((val) >> 6) & 0x3f))
+#define	DTRACE_AGGUTF8_BYTE2(val)	(0x80 | ((val) & 0x3f))
+
+static int
+dt_print_quantline_utf8(dtrace_hdl_t *dtp, FILE *fp, int64_t val,
+    uint64_t normal, long double total)
+{
+	uint_t len = 40, i, whole, partial;
+	long double f = (dt_fabsl((long double)val) * len) / total;
+	const char *spaces = "                                        ";
+
+	whole = (uint_t)f;
+	partial = (uint_t)((f - (long double)(uint_t)f) *
+	    (long double)DTRACE_AGGUTF8_LEVELS);
+
+	if (dt_printf(dtp, fp, "|") < 0)
+		return (-1);
+
+	for (i = 0; i < whole; i++) {
+		if (dt_printf(dtp, fp, "%c%c%c",
+		    DTRACE_AGGUTF8_BYTE0(DTRACE_AGGUTF8_FULL),
+		    DTRACE_AGGUTF8_BYTE1(DTRACE_AGGUTF8_FULL),
+		    DTRACE_AGGUTF8_BYTE2(DTRACE_AGGUTF8_FULL)) < 0)
+			return (-1);
+	}
+
+	if (partial != 0) {
+		partial = DTRACE_AGGUTF8_BASE - (partial - 1);
+
+		if (dt_printf(dtp, fp, "%c%c%c",
+		    DTRACE_AGGUTF8_BYTE0(partial),
+		    DTRACE_AGGUTF8_BYTE1(partial),
+		    DTRACE_AGGUTF8_BYTE2(partial)) < 0)
+			return (-1);
+
+		i++;
+	}
+
+	return (dt_printf(dtp, fp, "%s %-9lld\n", spaces + i,
+	    (long long)val / normal));
+}
+
+static int
 dt_print_quantline(dtrace_hdl_t *dtp, FILE *fp, int64_t val,
     uint64_t normal, long double total, char positives, char negatives)
 {
@@ -513,6 +648,11 @@
 
 	if (!negatives) {
 		if (positives) {
+			if (dtp->dt_encoding == DT_ENCODING_UTF8) {
+				return (dt_print_quantline_utf8(dtp, fp, val,
+				    normal, total));
+			}
+
 			f = (dt_fabsl((long double)val) * len) / total;
 			depth = (uint_t)(f + 0.5);
 		} else {
@@ -555,6 +695,73 @@
 	}
 }
 
+/*
+ * As with UTF-8 printing of aggregations, we use a subset of the Unicode
+ * Block Elements (U+2581 through U+2588, inclusive) to represent our packed
+ * aggregation.
+ */
+#define	DTRACE_AGGPACK_BASE	0x2581
+#define	DTRACE_AGGPACK_LEVELS	8
+
+static int
+dt_print_packed(dtrace_hdl_t *dtp, FILE *fp,
+    long double datum, long double total)
+{
+	static boolean_t utf8_checked = B_FALSE;
+	static boolean_t utf8;
+	char *ascii = "__xxxxXX";
+	char *neg = "vvvvVV";
+	unsigned int len;
+	long double val;
+
+	if (!utf8_checked) {
+		char *term;
+
+		/*
+		 * We want to determine if we can reasonably emit UTF-8 for our
+		 * packed aggregation.  To do this, we will check for terminals
+		 * that are known to be primitive to emit UTF-8 on these.
+		 */
+		utf8_checked = B_TRUE;
+
+		if (dtp->dt_encoding == DT_ENCODING_ASCII) {
+			utf8 = B_FALSE;
+		} else if (dtp->dt_encoding == DT_ENCODING_UTF8) {
+			utf8 = B_TRUE;
+		} else if ((term = getenv("TERM")) != NULL &&
+		    (strcmp(term, "sun") == 0 ||
+		    strcmp(term, "sun-color") == 0 ||
+		    strcmp(term, "dumb") == 0)) {
+			utf8 = B_FALSE;
+		} else {
+			utf8 = B_TRUE;
+		}
+	}
+
+	if (datum == 0)
+		return (dt_printf(dtp, fp, " "));
+
+	if (datum < 0) {
+		len = strlen(neg);
+		val = dt_fabsl(datum * (len - 1)) / total;
+		return (dt_printf(dtp, fp, "%c", neg[(uint_t)(val + 0.5)]));
+	}
+
+	if (utf8) {
+		int block = DTRACE_AGGPACK_BASE + (unsigned int)(((datum *
+		    (DTRACE_AGGPACK_LEVELS - 1)) / total) + 0.5);
+
+		return (dt_printf(dtp, fp, "%c%c%c",
+		    DTRACE_AGGUTF8_BYTE0(block),
+		    DTRACE_AGGUTF8_BYTE1(block),
+		    DTRACE_AGGUTF8_BYTE2(block)));
+	}
+
+	len = strlen(ascii);
+	val = (datum * (len - 1)) / total;
+	return (dt_printf(dtp, fp, "%c", ascii[(uint_t)(val + 0.5)]));
+}
+
 int
 dt_print_quantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
     size_t size, uint64_t normal)
@@ -572,9 +779,9 @@
 
 	if (first_bin == DTRACE_QUANTIZE_NBUCKETS - 1) {
 		/*
-		 * There isn't any data.  This is possible if (and only if)
-		 * negative increment values have been used.  In this case,
-		 * we'll print the buckets around 0.
+		 * There isn't any data.  This is possible if the aggregation
+		 * has been clear()'d or if negative increment values have been
+		 * used.  Regardless, we'll print the buckets around 0.
 		 */
 		first_bin = DTRACE_QUANTIZE_ZEROBUCKET - 1;
 		last_bin = DTRACE_QUANTIZE_ZEROBUCKET + 1;
@@ -592,11 +799,10 @@
 	for (i = first_bin; i <= last_bin; i++) {
 		positives |= (data[i] > 0);
 		negatives |= (data[i] < 0);
-		total += dt_fabsl((long double)data[i]);
+		dt_quantize_total(dtp, data[i], &total);
 	}
 
-	if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value",
-	    "------------- Distribution -------------", "count") < 0)
+	if (dt_print_quanthdr(dtp, fp, 0) < 0)
 		return (-1);
 
 	for (i = first_bin; i <= last_bin; i++) {
@@ -613,6 +819,48 @@
 }
 
 int
+dt_print_quantize_packed(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
+    size_t size, const dtrace_aggdata_t *aggdata)
+{
+	const int64_t *data = addr;
+	long double total = 0, count = 0;
+	int min = aggdata->dtada_minbin, max = aggdata->dtada_maxbin, i;
+	int64_t minval, maxval;
+
+	if (size != DTRACE_QUANTIZE_NBUCKETS * sizeof (uint64_t))
+		return (dt_set_errno(dtp, EDT_DMISMATCH));
+
+	if (min != 0 && min != DTRACE_QUANTIZE_ZEROBUCKET)
+		min--;
+
+	if (max < DTRACE_QUANTIZE_NBUCKETS - 1)
+		max++;
+
+	minval = DTRACE_QUANTIZE_BUCKETVAL(min);
+	maxval = DTRACE_QUANTIZE_BUCKETVAL(max);
+
+	if (dt_printf(dtp, fp, " %*lld :", dt_ndigits(minval),
+	    (long long)minval) < 0)
+		return (-1);
+
+	for (i = min; i <= max; i++) {
+		dt_quantize_total(dtp, data[i], &total);
+		count += data[i];
+	}
+
+	for (i = min; i <= max; i++) {
+		if (dt_print_packed(dtp, fp, data[i], total) < 0)
+			return (-1);
+	}
+
+	if (dt_printf(dtp, fp, ": %*lld | %lld\n",
+	    -dt_ndigits(maxval), (long long)maxval, (long long)count) < 0)
+		return (-1);
+
+	return (0);
+}
+
+int
 dt_print_lquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
     size_t size, uint64_t normal)
 {
@@ -659,7 +907,7 @@
 	for (i = first_bin; i <= last_bin; i++) {
 		positives |= (data[i] > 0);
 		negatives |= (data[i] < 0);
-		total += dt_fabsl((long double)data[i]);
+		dt_quantize_total(dtp, data[i], &total);
 	}
 
 	if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value",
@@ -671,8 +919,7 @@
 		int err;
 
 		if (i == 0) {
-			(void) snprintf(c, sizeof (c), "< %d",
-			    base / (uint32_t)normal);
+			(void) snprintf(c, sizeof (c), "< %d", base);
 			err = dt_printf(dtp, fp, "%16s ", c);
 		} else if (i == levels + 1) {
 			(void) snprintf(c, sizeof (c), ">= %d",
@@ -691,7 +938,60 @@
 	return (0);
 }
 
+/*ARGSUSED*/
 int
+dt_print_lquantize_packed(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
+    size_t size, const dtrace_aggdata_t *aggdata)
+{
+	const int64_t *data = addr;
+	long double total = 0, count = 0;
+	int min, max, base, err;
+	uint64_t arg;
+	uint16_t step, levels;
+	char c[32];
+	unsigned int i;
+
+	if (size < sizeof (uint64_t))
+		return (dt_set_errno(dtp, EDT_DMISMATCH));
+
+	arg = *data++;
+	size -= sizeof (uint64_t);
+
+	base = DTRACE_LQUANTIZE_BASE(arg);
+	step = DTRACE_LQUANTIZE_STEP(arg);
+	levels = DTRACE_LQUANTIZE_LEVELS(arg);
+
+	if (size != sizeof (uint64_t) * (levels + 2))
+		return (dt_set_errno(dtp, EDT_DMISMATCH));
+
+	min = 0;
+	max = levels + 1;
+
+	if (min == 0) {
+		(void) snprintf(c, sizeof (c), "< %d", base);
+		err = dt_printf(dtp, fp, "%8s :", c);
+	} else {
+		err = dt_printf(dtp, fp, "%8d :", base + (min - 1) * step);
+	}
+
+	if (err < 0)
+		return (-1);
+
+	for (i = min; i <= max; i++) {
+		dt_quantize_total(dtp, data[i], &total);
+		count += data[i];
+	}
+
+	for (i = min; i <= max; i++) {
+		if (dt_print_packed(dtp, fp, data[i], total) < 0)
+			return (-1);
+	}
+
+	(void) snprintf(c, sizeof (c), ">= %d", base + (levels * step));
+	return (dt_printf(dtp, fp, ": %-8s | %lld\n", c, (long long)count));
+}
+
+int
 dt_print_llquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
     size_t size, uint64_t normal)
 {
@@ -748,7 +1048,7 @@
 	for (i = first_bin; i <= last_bin; i++) {
 		positives |= (data[i] > 0);
 		negatives |= (data[i] < 0);
-		total += dt_fabsl((long double)data[i]);
+		dt_quantize_total(dtp, data[i], &total);
 	}
 
 	if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value",
@@ -831,7 +1131,7 @@
 }
 
 /*ARGSUSED*/
-int
+static int
 dt_print_bytes(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr,
     size_t nbytes, int width, int quiet, int forceraw)
 {
@@ -884,10 +1184,12 @@
 			if (j != nbytes)
 				break;
 
-			if (quiet)
+			if (quiet) {
 				return (dt_printf(dtp, fp, "%s", c));
-			else
-				return (dt_printf(dtp, fp, "  %-*s", width, c));
+			} else {
+				return (dt_printf(dtp, fp, " %s%*s",
+				    width < 0 ? " " : "", width, c));
+			}
 		}
 
 		break;
@@ -1801,11 +2103,84 @@
 
 static int
 dt_print_datum(dtrace_hdl_t *dtp, FILE *fp, dtrace_recdesc_t *rec,
-    caddr_t addr, size_t size, uint64_t normal)
+    caddr_t addr, size_t size, const dtrace_aggdata_t *aggdata,
+    uint64_t normal, dt_print_aggdata_t *pd)
 {
-	int err;
+	int err, width;
 	dtrace_actkind_t act = rec->dtrd_action;
+	boolean_t packed = pd->dtpa_agghist || pd->dtpa_aggpack;
+	dtrace_aggdesc_t *agg = aggdata->dtada_desc;
 
+	static struct {
+		size_t size;
+		int width;
+		int packedwidth;
+	} *fmt, fmttab[] = {
+		{ sizeof (uint8_t),	3,	3 },
+		{ sizeof (uint16_t),	5,	5 },
+		{ sizeof (uint32_t),	8,	8 },
+		{ sizeof (uint64_t),	16,	16 },
+		{ 0,			-50,	16 }
+	};
+
+	if (packed && pd->dtpa_agghisthdr != agg->dtagd_varid) {
+		dtrace_recdesc_t *r;
+
+		width = 0;
+
+		/*
+		 * To print our quantization header for either an agghist or
+		 * aggpack aggregation, we need to iterate through all of our
+		 * of our records to determine their width.
+		 */
+		for (r = rec; !DTRACEACT_ISAGG(r->dtrd_action); r++) {
+			for (fmt = fmttab; fmt->size &&
+			    fmt->size != r->dtrd_size; fmt++)
+				continue;
+
+			width += fmt->packedwidth + 1;
+		}
+
+		if (pd->dtpa_agghist) {
+			if (dt_print_quanthdr(dtp, fp, width) < 0)
+				return (-1);
+		} else {
+			if (dt_print_quanthdr_packed(dtp, fp,
+			    width, aggdata, r->dtrd_action) < 0)
+				return (-1);
+		}
+
+		pd->dtpa_agghisthdr = agg->dtagd_varid;
+	}
+
+	if (pd->dtpa_agghist && DTRACEACT_ISAGG(act)) {
+		char positives = aggdata->dtada_flags & DTRACE_A_HASPOSITIVES;
+		char negatives = aggdata->dtada_flags & DTRACE_A_HASNEGATIVES;
+		int64_t val;
+
+		assert(act == DTRACEAGG_SUM || act == DTRACEAGG_COUNT);
+		val = (long long)*((uint64_t *)addr);
+
+		if (dt_printf(dtp, fp, " ") < 0)
+			return (-1);
+
+		return (dt_print_quantline(dtp, fp, val, normal,
+		    aggdata->dtada_total, positives, negatives));
+	}
+
+	if (pd->dtpa_aggpack && DTRACEACT_ISAGG(act)) {
+		switch (act) {
+		case DTRACEAGG_QUANTIZE:
+			return (dt_print_quantize_packed(dtp,
+			    fp, addr, size, aggdata));
+		case DTRACEAGG_LQUANTIZE:
+			return (dt_print_lquantize_packed(dtp,
+			    fp, addr, size, aggdata));
+		default:
+			break;
+		}
+	}
+
 	switch (act) {
 	case DTRACEACT_STACK:
 		return (dt_print_stack(dtp, fp, NULL, addr,
@@ -1847,28 +2222,33 @@
 		break;
 	}
 
+	for (fmt = fmttab; fmt->size && fmt->size != size; fmt++)
+		continue;
+
+	width = packed ? fmt->packedwidth : fmt->width;
+
 	switch (size) {
 	case sizeof (uint64_t):
-		err = dt_printf(dtp, fp, " %16lld",
+		err = dt_printf(dtp, fp, " %*lld", width,
 		    /* LINTED - alignment */
 		    (long long)*((uint64_t *)addr) / normal);
 		break;
 	case sizeof (uint32_t):
 		/* LINTED - alignment */
-		err = dt_printf(dtp, fp, " %8d", *((uint32_t *)addr) /
+		err = dt_printf(dtp, fp, " %*d", width, *((uint32_t *)addr) /
 		    (uint32_t)normal);
 		break;
 	case sizeof (uint16_t):
 		/* LINTED - alignment */
-		err = dt_printf(dtp, fp, " %5d", *((uint16_t *)addr) /
+		err = dt_printf(dtp, fp, " %*d", width, *((uint16_t *)addr) /
 		    (uint32_t)normal);
 		break;
 	case sizeof (uint8_t):
-		err = dt_printf(dtp, fp, " %3d", *((uint8_t *)addr) /
+		err = dt_printf(dtp, fp, " %*d", width, *((uint8_t *)addr) /
 		    (uint32_t)normal);
 		break;
 	default:
-		err = dt_print_bytes(dtp, fp, addr, size, 50, 0, 0);
+		err = dt_print_bytes(dtp, fp, addr, size, width, 0, 0);
 		break;
 	}
 
@@ -1889,6 +2269,9 @@
 	caddr_t addr;
 	size_t size;
 
+	pd->dtpa_agghist = (aggdata->dtada_flags & DTRACE_A_TOTAL);
+	pd->dtpa_aggpack = (aggdata->dtada_flags & DTRACE_A_MINMAXBIN);
+
 	/*
 	 * Iterate over each record description in the key, printing the traced
 	 * data, skipping the first datum (the tuple member created by the
@@ -1905,7 +2288,8 @@
 			break;
 		}
 
-		if (dt_print_datum(dtp, fp, rec, addr, size, 1) < 0)
+		if (dt_print_datum(dtp, fp, rec, addr,
+		    size, aggdata, 1, pd) < 0)
 			return (-1);
 
 		if (dt_buffered_flush(dtp, NULL, rec, aggdata,
@@ -1928,7 +2312,8 @@
 		assert(DTRACEACT_ISAGG(act));
 		normal = aggdata->dtada_normal;
 
-		if (dt_print_datum(dtp, fp, rec, addr, size, normal) < 0)
+		if (dt_print_datum(dtp, fp, rec, addr,
+		    size, aggdata, normal, pd) < 0)
 			return (-1);
 
 		if (dt_buffered_flush(dtp, NULL, rec, aggdata,
@@ -1939,8 +2324,10 @@
 			agg->dtagd_flags |= DTRACE_AGD_PRINTED;
 	}
 
-	if (dt_printf(dtp, fp, "\n") < 0)
-		return (-1);
+	if (!pd->dtpa_agghist && !pd->dtpa_aggpack) {
+		if (dt_printf(dtp, fp, "\n") < 0)
+			return (-1);
+	}
 
 	if (dt_buffered_flush(dtp, NULL, NULL, aggdata,
 	    DTRACE_BUFDATA_AGGFORMAT | DTRACE_BUFDATA_AGGLAST) < 0)
@@ -2014,26 +2401,27 @@
 }
 
 static int
-dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, int cpu, dtrace_bufdesc_t *buf,
+dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, int cpu,
+    dtrace_bufdesc_t *buf, boolean_t just_one,
     dtrace_consume_probe_f *efunc, dtrace_consume_rec_f *rfunc, void *arg)
 {
 	dtrace_epid_t id;
-	size_t offs, start = buf->dtbd_oldest, end = buf->dtbd_size;
+	size_t offs;
 	int flow = (dtp->dt_options[DTRACEOPT_FLOWINDENT] != DTRACEOPT_UNSET);
 	int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET);
 	int rval, i, n;
-	dtrace_epid_t last = DTRACE_EPIDNONE;
 	uint64_t tracememsize = 0;
 	dtrace_probedata_t data;
 	uint64_t drops;
-	caddr_t addr;
 
 	bzero(&data, sizeof (data));
 	data.dtpda_handle = dtp;
 	data.dtpda_cpu = cpu;
+	data.dtpda_flow = dtp->dt_flow;
+	data.dtpda_indent = dtp->dt_indent;
+	data.dtpda_prefix = dtp->dt_prefix;
 
-again:
-	for (offs = start; offs < end; ) {
+	for (offs = buf->dtbd_oldest; offs < buf->dtbd_size; ) {
 		dtrace_eprobedesc_t *epd;
 
 		/*
@@ -2068,7 +2456,8 @@
 		}
 
 		if (flow)
-			(void) dt_flowindent(dtp, &data, last, buf, offs);
+			(void) dt_flowindent(dtp, &data, dtp->dt_last_epid,
+			    buf, offs);
 
 		rval = (*efunc)(&data, arg);
 
@@ -2087,6 +2476,7 @@
 			return (dt_set_errno(dtp, EDT_BADRVAL));
 
 		for (i = 0; i < epd->dtepd_nrecs; i++) {
+			caddr_t addr;
 			dtrace_recdesc_t *rec = &epd->dtepd_rec[i];
 			dtrace_actkind_t act = rec->dtrd_action;
 
@@ -2406,7 +2796,7 @@
 				}
 
 				n = dt_print_bytes(dtp, fp, addr,
-				    tracememsize, 33, quiet, 1);
+				    tracememsize, -33, quiet, 1);
 
 				tracememsize = 0;
 
@@ -2439,7 +2829,7 @@
 				break;
 			default:
 				n = dt_print_bytes(dtp, fp, addr,
-				    rec->dtrd_size, 33, quiet, 0);
+				    rec->dtrd_size, -33, quiet, 0);
 				break;
 			}
 
@@ -2458,14 +2848,16 @@
 		rval = (*rfunc)(&data, NULL, arg);
 nextepid:
 		offs += epd->dtepd_size;
-		last = id;
+		dtp->dt_last_epid = id;
+		if (just_one) {
+			buf->dtbd_oldest = offs;
+			break;
+		}
 	}
 
-	if (buf->dtbd_oldest != 0 && start == buf->dtbd_oldest) {
-		end = buf->dtbd_oldest;
-		start = 0;
-		goto again;
-	}
+	dtp->dt_flow = data.dtpda_flow;
+	dtp->dt_indent = data.dtpda_indent;
+	dtp->dt_prefix = data.dtpda_prefix;
 
 	if ((drops = buf->dtbd_drops) == 0)
 		return (0);
@@ -2478,6 +2870,131 @@
 	return (dt_handle_cpudrop(dtp, cpu, DTRACEDROP_PRINCIPAL, drops));
 }
 
+/*
+ * Reduce memory usage by shrinking the buffer if it's no more than half full.
+ * Note, we need to preserve the alignment of the data at dtbd_oldest, which is
+ * only 4-byte aligned.
+ */
+static void
+dt_realloc_buf(dtrace_hdl_t *dtp, dtrace_bufdesc_t *buf, int cursize)
+{
+	uint64_t used = buf->dtbd_size - buf->dtbd_oldest;
+	if (used < cursize / 2) {
+		int misalign = buf->dtbd_oldest & (sizeof (uint64_t) - 1);
+		char *newdata = dt_alloc(dtp, used + misalign);
+		if (newdata == NULL)
+			return;
+		bzero(newdata, misalign);
+		bcopy(buf->dtbd_data + buf->dtbd_oldest,
+		    newdata + misalign, used);
+		dt_free(dtp, buf->dtbd_data);
+		buf->dtbd_oldest = misalign;
+		buf->dtbd_size = used + misalign;
+		buf->dtbd_data = newdata;
+	}
+}
+
+/*
+ * If the ring buffer has wrapped, the data is not in order.  Rearrange it
+ * so that it is.  Note, we need to preserve the alignment of the data at
+ * dtbd_oldest, which is only 4-byte aligned.
+ */
+static int
+dt_unring_buf(dtrace_hdl_t *dtp, dtrace_bufdesc_t *buf)
+{
+	int misalign;
+	char *newdata, *ndp;
+
+	if (buf->dtbd_oldest == 0)
+		return (0);
+
+	misalign = buf->dtbd_oldest & (sizeof (uint64_t) - 1);
+	newdata = ndp = dt_alloc(dtp, buf->dtbd_size + misalign);
+
+	if (newdata == NULL)
+		return (-1);
+
+	assert(0 == (buf->dtbd_size & (sizeof (uint64_t) - 1)));
+
+	bzero(ndp, misalign);
+	ndp += misalign;
+
+	bcopy(buf->dtbd_data + buf->dtbd_oldest, ndp,
+	    buf->dtbd_size - buf->dtbd_oldest);
+	ndp += buf->dtbd_size - buf->dtbd_oldest;
+
+	bcopy(buf->dtbd_data, ndp, buf->dtbd_oldest);
+
+	dt_free(dtp, buf->dtbd_data);
+	buf->dtbd_oldest = 0;
+	buf->dtbd_data = newdata;
+	buf->dtbd_size += misalign;
+
+	return (0);
+}
+
+static void
+dt_put_buf(dtrace_hdl_t *dtp, dtrace_bufdesc_t *buf)
+{
+	dt_free(dtp, buf->dtbd_data);
+	dt_free(dtp, buf);
+}
+
+/*
+ * Returns 0 on success, in which case *cbp will be filled in if we retrieved
+ * data, or NULL if there is no data for this CPU.
+ * Returns -1 on failure and sets dt_errno.
+ */
+static int
+dt_get_buf(dtrace_hdl_t *dtp, int cpu, dtrace_bufdesc_t **bufp)
+{
+	dtrace_optval_t size;
+	dtrace_bufdesc_t *buf = dt_zalloc(dtp, sizeof (*buf));
+	int error, rval;
+
+	if (buf == NULL)
+		return (-1);
+
+	(void) dtrace_getopt(dtp, "bufsize", &size);
+	buf->dtbd_data = dt_alloc(dtp, size);
+	if (buf->dtbd_data == NULL) {
+		dt_free(dtp, buf);
+		return (-1);
+	}
+	buf->dtbd_size = size;
+	buf->dtbd_cpu = cpu;
+
+#ifdef illumos
+	if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) {
+#else
+	if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, &buf) == -1) {
+#endif
+		/*
+		 * If we failed with ENOENT, it may be because the
+		 * CPU was unconfigured -- this is okay.  Any other
+		 * error, however, is unexpected.
+		 */
+		if (errno == ENOENT) {
+			*bufp = NULL;
+			rval = 0;
+		} else
+			rval = dt_set_errno(dtp, errno);
+
+		dt_put_buf(dtp, buf);
+		return (rval);
+	}
+
+	error = dt_unring_buf(dtp, buf);
+	if (error != 0) {
+		dt_put_buf(dtp, buf);
+		return (error);
+	}
+	dt_realloc_buf(dtp, buf, size);
+
+	*bufp = buf;
+	return (0);
+}
+
 typedef struct dt_begin {
 	dtrace_consume_probe_f *dtbgn_probefunc;
 	dtrace_consume_rec_f *dtbgn_recfunc;
@@ -2490,7 +3007,7 @@
 static int
 dt_consume_begin_probe(const dtrace_probedata_t *data, void *arg)
 {
-	dt_begin_t *begin = (dt_begin_t *)arg;
+	dt_begin_t *begin = arg;
 	dtrace_probedesc_t *pd = data->dtpda_pdesc;
 
 	int r1 = (strcmp(pd->dtpd_provider, "dtrace") == 0);
@@ -2515,7 +3032,7 @@
 dt_consume_begin_record(const dtrace_probedata_t *data,
     const dtrace_recdesc_t *rec, void *arg)
 {
-	dt_begin_t *begin = (dt_begin_t *)arg;
+	dt_begin_t *begin = arg;
 
 	return (begin->dtbgn_recfunc(data, rec, begin->dtbgn_arg));
 }
@@ -2541,7 +3058,7 @@
 }
 
 static int
-dt_consume_begin(dtrace_hdl_t *dtp, FILE *fp, dtrace_bufdesc_t *buf,
+dt_consume_begin(dtrace_hdl_t *dtp, FILE *fp,
     dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg)
 {
 	/*
@@ -2565,34 +3082,20 @@
 	 * first pass, and that we only process ERROR enablings _not_ induced
 	 * by BEGIN enablings in the second pass.
 	 */
+
 	dt_begin_t begin;
 	processorid_t cpu = dtp->dt_beganon;
-	dtrace_bufdesc_t nbuf;
-#if !defined(sun)
-	dtrace_bufdesc_t *pbuf;
-#endif
 	int rval, i;
 	static int max_ncpus;
-	dtrace_optval_t size;
+	dtrace_bufdesc_t *buf;
 
 	dtp->dt_beganon = -1;
 
-#if defined(sun)
-	if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) {
-#else
-	if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, &buf) == -1) {
-#endif
-		/*
-		 * We really don't expect this to fail, but it is at least
-		 * technically possible for this to fail with ENOENT.  In this
-		 * case, we just drive on...
-		 */
-		if (errno == ENOENT)
-			return (0);
+	if (dt_get_buf(dtp, cpu, &buf) != 0)
+		return (-1);
+	if (buf == NULL)
+		return (0);
 
-		return (dt_set_errno(dtp, errno));
-	}
-
 	if (!dtp->dt_stopped || buf->dtbd_cpu != dtp->dt_endedon) {
 		/*
 		 * This is the simple case.  We're either not stopped, or if
@@ -2599,7 +3102,10 @@
 		 * we are, we actually processed any END probes on another
 		 * CPU.  We can simply consume this buffer and return.
 		 */
-		return (dt_consume_cpu(dtp, fp, cpu, buf, pf, rf, arg));
+		rval = dt_consume_cpu(dtp, fp, cpu, buf, B_FALSE,
+		    pf, rf, arg);
+		dt_put_buf(dtp, buf);
+		return (rval);
 	}
 
 	begin.dtbgn_probefunc = pf;
@@ -2616,61 +3122,41 @@
 	dtp->dt_errhdlr = dt_consume_begin_error;
 	dtp->dt_errarg = &begin;
 
-	rval = dt_consume_cpu(dtp, fp, cpu, buf, dt_consume_begin_probe,
-	    dt_consume_begin_record, &begin);
+	rval = dt_consume_cpu(dtp, fp, cpu, buf, B_FALSE,
+	    dt_consume_begin_probe, dt_consume_begin_record, &begin);
 
 	dtp->dt_errhdlr = begin.dtbgn_errhdlr;
 	dtp->dt_errarg = begin.dtbgn_errarg;
 
-	if (rval != 0)
+	if (rval != 0) {
+		dt_put_buf(dtp, buf);
 		return (rval);
+	}
 
-	/*
-	 * Now allocate a new buffer.  We'll use this to deal with every other
-	 * CPU.
-	 */
-	bzero(&nbuf, sizeof (dtrace_bufdesc_t));
-	(void) dtrace_getopt(dtp, "bufsize", &size);
-	if ((nbuf.dtbd_data = malloc(size)) == NULL)
-		return (dt_set_errno(dtp, EDT_NOMEM));
-
 	if (max_ncpus == 0)
 		max_ncpus = dt_sysconf(dtp, _SC_CPUID_MAX) + 1;
 
 	for (i = 0; i < max_ncpus; i++) {
-		nbuf.dtbd_cpu = i;
-
+		dtrace_bufdesc_t *nbuf;
 		if (i == cpu)
 			continue;
 
-#if defined(sun)
-		if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, &nbuf) == -1) {
-#else
-		pbuf = &nbuf;
-		if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, &pbuf) == -1) {
-#endif
-			/*
-			 * If we failed with ENOENT, it may be because the
-			 * CPU was unconfigured -- this is okay.  Any other
-			 * error, however, is unexpected.
-			 */
-			if (errno == ENOENT)
-				continue;
-
-			free(nbuf.dtbd_data);
-
-			return (dt_set_errno(dtp, errno));
+		if (dt_get_buf(dtp, i, &nbuf) != 0) {
+			dt_put_buf(dtp, buf);
+			return (-1);
 		}
+		if (nbuf == NULL)
+			continue;
 
-		if ((rval = dt_consume_cpu(dtp, fp,
-		    i, &nbuf, pf, rf, arg)) != 0) {
-			free(nbuf.dtbd_data);
+		rval = dt_consume_cpu(dtp, fp, i, nbuf, B_FALSE,
+		    pf, rf, arg);
+		dt_put_buf(dtp, nbuf);
+		if (rval != 0) {
+			dt_put_buf(dtp, buf);
 			return (rval);
 		}
 	}
 
-	free(nbuf.dtbd_data);
-
 	/*
 	 * Okay -- we're done with the other buffers.  Now we want to
 	 * reconsume the first buffer -- but this time we're looking for
@@ -2685,8 +3171,8 @@
 	dtp->dt_errhdlr = dt_consume_begin_error;
 	dtp->dt_errarg = &begin;
 
-	rval = dt_consume_cpu(dtp, fp, cpu, buf, dt_consume_begin_probe,
-	    dt_consume_begin_record, &begin);
+	rval = dt_consume_cpu(dtp, fp, cpu, buf, B_FALSE,
+	    dt_consume_begin_probe, dt_consume_begin_record, &begin);
 
 	dtp->dt_errhdlr = begin.dtbgn_errhdlr;
 	dtp->dt_errarg = begin.dtbgn_errarg;
@@ -2694,11 +3180,32 @@
 	return (rval);
 }
 
+/* ARGSUSED */
+static uint64_t
+dt_buf_oldest(void *elem, void *arg)
+{
+	dtrace_bufdesc_t *buf = elem;
+	size_t offs = buf->dtbd_oldest;
+
+	while (offs < buf->dtbd_size) {
+		dtrace_rechdr_t *dtrh =
+		    /* LINTED - alignment */
+		    (dtrace_rechdr_t *)(buf->dtbd_data + offs);
+		if (dtrh->dtrh_epid == DTRACE_EPIDNONE) {
+			offs += sizeof (dtrace_epid_t);
+		} else {
+			return (DTRACE_RECORD_LOAD_TIMESTAMP(dtrh));
+		}
+	}
+
+	/* There are no records left; use the time the buffer was retrieved. */
+	return (buf->dtbd_timestamp);
+}
+
 int
 dtrace_consume(dtrace_hdl_t *dtp, FILE *fp,
     dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg)
 {
-	dtrace_bufdesc_t *buf = &dtp->dt_buf;
 	dtrace_optval_t size;
 	static int max_ncpus;
 	int i, rval;
@@ -2726,79 +3233,158 @@
 	if (rf == NULL)
 		rf = (dtrace_consume_rec_f *)dt_nullrec;
 
-	if (buf->dtbd_data == NULL) {
-		(void) dtrace_getopt(dtp, "bufsize", &size);
-		if ((buf->dtbd_data = malloc(size)) == NULL)
-			return (dt_set_errno(dtp, EDT_NOMEM));
-
-		buf->dtbd_size = size;
-	}
-
-	/*
-	 * If we have just begun, we want to first process the CPU that
-	 * executed the BEGIN probe (if any).
-	 */
-	if (dtp->dt_active && dtp->dt_beganon != -1) {
-		buf->dtbd_cpu = dtp->dt_beganon;
-		if ((rval = dt_consume_begin(dtp, fp, buf, pf, rf, arg)) != 0)
+	if (dtp->dt_options[DTRACEOPT_TEMPORAL] == DTRACEOPT_UNSET) {
+		/*
+		 * The output will not be in the order it was traced.  Rather,
+		 * we will consume all of the data from each CPU's buffer in
+		 * turn.  We apply special handling for the records from BEGIN
+		 * and END probes so that they are consumed first and last,
+		 * respectively.
+		 *
+		 * If we have just begun, we want to first process the CPU that
+		 * executed the BEGIN probe (if any).
+		 */
+		if (dtp->dt_active && dtp->dt_beganon != -1 &&
+		    (rval = dt_consume_begin(dtp, fp, pf, rf, arg)) != 0)
 			return (rval);
-	}
 
-	for (i = 0; i < max_ncpus; i++) {
-		buf->dtbd_cpu = i;
+		for (i = 0; i < max_ncpus; i++) {
+			dtrace_bufdesc_t *buf;
 
-		/*
-		 * If we have stopped, we want to process the CPU on which the
-		 * END probe was processed only _after_ we have processed
-		 * everything else.
-		 */
-		if (dtp->dt_stopped && (i == dtp->dt_endedon))
-			continue;
-
-#if defined(sun)
-		if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) {
-#else
-		if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, &buf) == -1) {
-#endif
 			/*
-			 * If we failed with ENOENT, it may be because the
-			 * CPU was unconfigured -- this is okay.  Any other
-			 * error, however, is unexpected.
+			 * If we have stopped, we want to process the CPU on
+			 * which the END probe was processed only _after_ we
+			 * have processed everything else.
 			 */
-			if (errno == ENOENT)
+			if (dtp->dt_stopped && (i == dtp->dt_endedon))
 				continue;
 
-			return (dt_set_errno(dtp, errno));
+			if (dt_get_buf(dtp, i, &buf) != 0)
+				return (-1);
+			if (buf == NULL)
+				continue;
+
+			dtp->dt_flow = 0;
+			dtp->dt_indent = 0;
+			dtp->dt_prefix = NULL;
+			rval = dt_consume_cpu(dtp, fp, i,
+			    buf, B_FALSE, pf, rf, arg);
+			dt_put_buf(dtp, buf);
+			if (rval != 0)
+				return (rval);
 		}
+		if (dtp->dt_stopped) {
+			dtrace_bufdesc_t *buf;
 
-		if ((rval = dt_consume_cpu(dtp, fp, i, buf, pf, rf, arg)) != 0)
+			if (dt_get_buf(dtp, dtp->dt_endedon, &buf) != 0)
+				return (-1);
+			if (buf == NULL)
+				return (0);
+
+			rval = dt_consume_cpu(dtp, fp, dtp->dt_endedon,
+			    buf, B_FALSE, pf, rf, arg);
+			dt_put_buf(dtp, buf);
 			return (rval);
-	}
+		}
+	} else {
+		/*
+		 * The output will be in the order it was traced (or for
+		 * speculations, when it was committed).  We retrieve a buffer
+		 * from each CPU and put it into a priority queue, which sorts
+		 * based on the first entry in the buffer.  This is sufficient
+		 * because entries within a buffer are already sorted.
+		 *
+		 * We then consume records one at a time, always consuming the
+		 * oldest record, as determined by the priority queue.  When
+		 * we reach the end of the time covered by these buffers,
+		 * we need to stop and retrieve more records on the next pass.
+		 * The kernel tells us the time covered by each buffer, in
+		 * dtbd_timestamp.  The first buffer's timestamp tells us the
+		 * time covered by all buffers, as subsequently retrieved
+		 * buffers will cover to a more recent time.
+		 */
 
-	if (!dtp->dt_stopped)
-		return (0);
+		uint64_t *drops = alloca(max_ncpus * sizeof (uint64_t));
+		uint64_t first_timestamp = 0;
+		uint_t cookie = 0;
+		dtrace_bufdesc_t *buf;
 
-	buf->dtbd_cpu = dtp->dt_endedon;
+		bzero(drops, max_ncpus * sizeof (uint64_t));
 
-#if defined(sun)
-	if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) {
-#else
-	if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, &buf) == -1) {
-#endif
+		if (dtp->dt_bufq == NULL) {
+			dtp->dt_bufq = dt_pq_init(dtp, max_ncpus * 2,
+			    dt_buf_oldest, NULL);
+			if (dtp->dt_bufq == NULL) /* ENOMEM */
+				return (-1);
+		}
+
+		/* Retrieve data from each CPU. */
+		(void) dtrace_getopt(dtp, "bufsize", &size);
+		for (i = 0; i < max_ncpus; i++) {
+			dtrace_bufdesc_t *buf;
+
+			if (dt_get_buf(dtp, i, &buf) != 0)
+				return (-1);
+			if (buf != NULL) {
+				if (first_timestamp == 0)
+					first_timestamp = buf->dtbd_timestamp;
+				assert(buf->dtbd_timestamp >= first_timestamp);
+
+				dt_pq_insert(dtp->dt_bufq, buf);
+				drops[i] = buf->dtbd_drops;
+				buf->dtbd_drops = 0;
+			}
+		}
+
+		/* Consume records. */
+		for (;;) {
+			dtrace_bufdesc_t *buf = dt_pq_pop(dtp->dt_bufq);
+			uint64_t timestamp;
+
+			if (buf == NULL)
+				break;
+
+			timestamp = dt_buf_oldest(buf, dtp);
+			assert(timestamp >= dtp->dt_last_timestamp);
+			dtp->dt_last_timestamp = timestamp;
+
+			if (timestamp == buf->dtbd_timestamp) {
+				/*
+				 * We've reached the end of the time covered
+				 * by this buffer.  If this is the oldest
+				 * buffer, we must do another pass
+				 * to retrieve more data.
+				 */
+				dt_put_buf(dtp, buf);
+				if (timestamp == first_timestamp &&
+				    !dtp->dt_stopped)
+					break;
+				continue;
+			}
+
+			if ((rval = dt_consume_cpu(dtp, fp,
+			    buf->dtbd_cpu, buf, B_TRUE, pf, rf, arg)) != 0)
+				return (rval);
+			dt_pq_insert(dtp->dt_bufq, buf);
+		}
+
+		/* Consume drops. */
+		for (i = 0; i < max_ncpus; i++) {
+			if (drops[i] != 0) {
+				int error = dt_handle_cpudrop(dtp, i,
+				    DTRACEDROP_PRINCIPAL, drops[i]);
+				if (error != 0)
+					return (error);
+			}
+		}
+
 		/*
-		 * This _really_ shouldn't fail, but it is strictly speaking
-		 * possible for this to return ENOENT if the CPU that called
-		 * the END enabling somehow managed to become unconfigured.
-		 * It's unclear how the user can possibly expect anything
-		 * rational to happen in this case -- the state has been thrown
-		 * out along with the unconfigured CPU -- so we'll just drive
-		 * on...
+		 * Reduce memory usage by re-allocating smaller buffers
+		 * for the "remnants".
 		 */
-		if (errno == ENOENT)
-			return (0);
-
-		return (dt_set_errno(dtp, errno));
+		while (buf = dt_pq_walk(dtp->dt_bufq, &cookie))
+			dt_realloc_buf(dtp, buf, buf->dtbd_size);
 	}
 
-	return (dt_consume_cpu(dtp, fp, dtp->dt_endedon, buf, pf, rf, arg));
+	return (0);
 }

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_decl.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_decl.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_decl.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -21,6 +22,8 @@
  */
 /*
  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013 Joyent, Inc. All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -254,11 +257,6 @@
 	ddp->dd_kind = kind;
 	ddp->dd_name = name;
 
-	if (name != NULL && strchr(name, '`') != NULL) {
-		xyerror(D_DECL_SCOPE, "D scoping operator may not be used "
-		    "in a type name\n");
-	}
-
 	return (dt_decl_check(ddp));
 }
 
@@ -783,7 +781,7 @@
 	yyintdecimal = 0;
 
 	dnp = dt_node_int(value);
-	dt_node_type_assign(dnp, dsp->ds_ctfp, dsp->ds_type);
+	dt_node_type_assign(dnp, dsp->ds_ctfp, dsp->ds_type, B_FALSE);
 
 	if ((inp = malloc(sizeof (dt_idnode_t))) == NULL)
 		longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
@@ -825,6 +823,8 @@
 	char *name;
 	int rv;
 
+	tip->dtt_flags = 0;
+
 	/*
 	 * Based on our current #include depth and decl stack depth, determine
 	 * which dynamic CTF module and scope to use when adding any new types.
@@ -832,6 +832,9 @@
 	dmp = yypcb->pcb_idepth ? dtp->dt_cdefs : dtp->dt_ddefs;
 	flag = yypcb->pcb_dstack.ds_next ? CTF_ADD_NONROOT : CTF_ADD_ROOT;
 
+	if (ddp->dd_attr & DT_DA_USER)
+		tip->dtt_flags = DTT_FL_USER;
+
 	/*
 	 * If we have already cached a CTF type for this decl, then we just
 	 * return the type information for the cached type.

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_decl.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_decl.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_decl.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -23,12 +24,14 @@
  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013 Joyent, Inc. All rights reserved.
+ */
 
 #ifndef	_DT_DECL_H
 #define	_DT_DECL_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <libctf.h>
 #include <dtrace.h>
@@ -59,6 +62,7 @@
 #define	DT_DA_RESTRICT	0x0040		/* qualify type as restrict */
 #define	DT_DA_VOLATILE	0x0080		/* qualify type as volatile */
 #define	DT_DA_PAREN	0x0100		/* parenthesis tag */
+#define	DT_DA_USER	0x0200		/* user-land type specifier */
 
 typedef enum dt_dclass {
 	DT_DC_DEFAULT,			/* no storage class specified */

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dis.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dis.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dis.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -19,12 +20,16 @@
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013 Joyent, Inc. All rights reserved.
+ */
 
 #include <strings.h>
 #include <stdio.h>
@@ -212,12 +217,22 @@
 {
 	static const char *const tnames[] = { "D type", "string" };
 	uint_t type = DIF_INSTR_TYPE(in);
+	const char *pad;
 
-	(void) fprintf(fp, "%-4s DT_TYPE(%u), %%r%u, %%r%u",
-	    name, type, DIF_INSTR_R2(in), DIF_INSTR_RS(in));
+	if (DIF_INSTR_OP(in) == DIF_OP_PUSHTV) {
+		(void) fprintf(fp, "%-4s DT_TYPE(%u), %%r%u",
+		    name, type, DIF_INSTR_RS(in));
+		pad = "\t\t";
+	} else {
+		(void) fprintf(fp, "%-4s DT_TYPE(%u), %%r%u, %%r%u",
+		    name, type, DIF_INSTR_R2(in), DIF_INSTR_RS(in));
+		pad = "\t";
+	}
 
-	if (type < sizeof (tnames) / sizeof (tnames[0]))
-		(void) fprintf(fp, "\t! DT_TYPE(%u) = %s", type, tnames[type]);
+	if (type < sizeof (tnames) / sizeof (tnames[0])) {
+		(void) fprintf(fp, "%s! DT_TYPE(%u) = %s", pad,
+		    type, tnames[type]);
+	}
 }
 
 static void
@@ -299,9 +314,10 @@
 		(void) snprintf(ckind, sizeof (ckind), "0x%x", t->dtdt_ckind);
 	}
 
-	if (t->dtdt_flags & DIF_TF_BYREF) {
-		(void) snprintf(buf, len, "%s (%s) by ref (size %lu)",
-		    kind, ckind, (ulong_t)t->dtdt_size);
+	if (t->dtdt_flags & (DIF_TF_BYREF | DIF_TF_BYUREF)) {
+		(void) snprintf(buf, len, "%s (%s) by %sref (size %lu)",
+		    kind, ckind, (t->dtdt_flags & DIF_TF_BYUREF) ? "user " : "",
+		    (ulong_t)t->dtdt_size);
 	} else {
 		(void) snprintf(buf, len, "%s (%s) (size %lu)",
 		    kind, ckind, (ulong_t)t->dtdt_size);

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -22,15 +23,16 @@
 /*
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2011 by Delphix. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  */
 
 #include <sys/types.h>
-#if defined(sun)
+#ifdef illumos
 #include <sys/sysmacros.h>
 #endif
 
 #include <strings.h>
-#if defined(sun)
+#ifdef illumos
 #include <alloca.h>
 #endif
 #include <assert.h>
@@ -486,7 +488,7 @@
 	return (0);
 }
 
-static void
+static int
 dof_add_provider(dt_dof_t *ddo, const dt_provider_t *pvp)
 {
 	dtrace_hdl_t *dtp = ddo->ddo_hdl;
@@ -497,8 +499,12 @@
 	size_t sz;
 	id_t i;
 
-	if (pvp->pv_flags & DT_PROVIDER_IMPL)
-		return; /* ignore providers that are exported by dtrace(7D) */
+	if (pvp->pv_flags & DT_PROVIDER_IMPL) {
+		/*
+		 * ignore providers that are exported by dtrace(7D)
+		 */
+		return (0);
+	}
 
 	nxr = dt_popcb(pvp->pv_xrefs, pvp->pv_xrmax);
 	dofs = alloca(sizeof (dof_secidx_t) * (nxr + 1));
@@ -525,6 +531,9 @@
 
 	(void) dt_idhash_iter(pvp->pv_probes, dof_add_probe, ddo);
 
+	if (dt_buf_len(&ddo->ddo_probes) == 0)
+		return (dt_set_errno(dtp, EDT_NOPROBES));
+
 	dofpv.dofpv_probes = dof_add_lsect(ddo, NULL, DOF_SECT_PROBES,
 	    sizeof (uint64_t), 0, sizeof (dof_probe_t),
 	    dt_buf_len(&ddo->ddo_probes));
@@ -579,6 +588,8 @@
 		    sizeof (dof_secidx_t), 0, sizeof (dof_secidx_t),
 		    sizeof (dof_secidx_t) * (nxr + 1));
 	}
+
+	return (0);
 }
 
 static int
@@ -822,8 +833,10 @@
 	 */
 	if (flags & DTRACE_D_PROBES) {
 		for (pvp = dt_list_next(&dtp->dt_provlist);
-		    pvp != NULL; pvp = dt_list_next(pvp))
-			dof_add_provider(ddo, pvp);
+		    pvp != NULL; pvp = dt_list_next(pvp)) {
+			if (dof_add_provider(ddo, pvp) != 0)
+				return (NULL);
+		}
 	}
 
 	/*

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_error.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_error.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_error.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -18,11 +19,17 @@
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
 #include <string.h>
 #include <strings.h>
 #include <dt_impl.h>
@@ -37,7 +44,6 @@
 	{ EDT_VERSREDUCED, "Requested version conflicts with earlier setting" },
 	{ EDT_CTF,	"Unexpected libctf error" },
 	{ EDT_COMPILER, "Error in D program compilation" },
-	{ EDT_NOREG,	"Insufficient registers to generate code" },
 	{ EDT_NOTUPREG,	"Insufficient tuple registers to generate code" },
 	{ EDT_NOMEM,	"Memory allocation failure" },
 	{ EDT_INT2BIG,	"Integer constant table limit exceeded" },
@@ -105,7 +111,9 @@
 	{ EDT_BADSTACKPC, "Invalid stack program counter size" },
 	{ EDT_BADAGGVAR, "Invalid aggregation variable identifier" },
 	{ EDT_OVERSION,	"Client requested deprecated version of library" },
-	{ EDT_ENABLING_ERR, "Failed to enable probe" }
+	{ EDT_ENABLING_ERR, "Failed to enable probe" },
+	{ EDT_NOPROBES, "No probe sites found for declared provider" },
+	{ EDT_CANTLOAD, "Failed to load module" },
 };
 
 static const int _dt_nerr = sizeof (_dt_errlist) / sizeof (_dt_errlist[0]);
@@ -138,7 +146,7 @@
 	return (dtp->dt_errno);
 }
 
-#if defined(sun)
+#ifdef illumos
 int
 dt_set_errno(dtrace_hdl_t *dtp, int err)
 {

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_errtags.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_errtags.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_errtags.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -26,7 +27,7 @@
 
  /*
   * Copyright (c) 2011, Joyent, Inc. All rights reserved.
-  * Copyright (c) 2011 by Delphix. All rights reserved.
+  * Copyright (c) 2012 by Delphix. All rights reserved.
   */
 
 #ifndef	_DT_ERRTAGS_H
@@ -190,8 +191,10 @@
 	D_PRINTA_AGGPROTO,		/* printa() aggregation mismatch */
 	D_TRACE_VOID,			/* trace() argument has void type */
 	D_TRACE_DYN,			/* trace() argument has dynamic type */
+	D_TRACE_AGG,			/* trace() argument is an aggregation */
 	D_PRINT_VOID,			/* print() argument has void type */
 	D_PRINT_DYN,			/* print() argument has dynamic type */
+	D_PRINT_AGG,			/* print() argument is an aggregation */
 	D_TRACEMEM_ADDR,		/* tracemem() address bad type */
 	D_TRACEMEM_SIZE,		/* tracemem() size bad type */
 	D_TRACEMEM_ARGS,		/* tracemem() illegal number of args */
@@ -260,6 +263,7 @@
 	D_LLQUANT_FACTOREVEN,		/* llquantize() bad # steps/factor */
 	D_LLQUANT_FACTORSMALL,		/* llquantize() magnitude too small */
 	D_LLQUANT_MAGTOOBIG,		/* llquantize() high mag too large */
+	D_NOREG,			/* no available internal registers */
 	D_PRINTM_ADDR,			/* printm() memref bad type */
 	D_PRINTM_SIZE,			/* printm() size bad type */
 	D_PRINTT_ADDR,			/* printt() typeref bad type */

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_grammar.y
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_grammar.y	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_grammar.y	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 %{
 /*
  * CDDL HEADER START
@@ -23,9 +24,11 @@
  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <dt_impl.h>
 
 #define	OP1(op, c)	dt_node_op1(op, c)
@@ -102,6 +105,7 @@
 %token	DT_KEY_TYPEDEF
 %token	DT_KEY_UNION
 %token	DT_KEY_UNSIGNED
+%token	DT_KEY_USERLAND
 %token	DT_KEY_VOID
 %token	DT_KEY_VOLATILE
 %token	DT_KEY_WHILE
@@ -204,6 +208,8 @@
 %type	<l_tok>		unary_operator
 %type	<l_tok>		struct_or_union
 
+%type	<l_str>		dtrace_keyword_ident
+
 %%
 
 dtrace_program: d_expression DT_TOK_EOF { return (dt_node_root($1)); }
@@ -388,6 +394,9 @@
 	|	postfix_expression DT_TOK_DOT DT_TOK_TNAME {
 			$$ = OP2(DT_TOK_DOT, $1, dt_node_ident($3));
 		}
+	|	postfix_expression DT_TOK_DOT dtrace_keyword_ident {
+			$$ = OP2(DT_TOK_DOT, $1, dt_node_ident($3));
+		}
 	|	postfix_expression DT_TOK_PTR DT_TOK_IDENT {
 			$$ = OP2(DT_TOK_PTR, $1, dt_node_ident($3));
 		}
@@ -394,6 +403,9 @@
 	|	postfix_expression DT_TOK_PTR DT_TOK_TNAME {
 			$$ = OP2(DT_TOK_PTR, $1, dt_node_ident($3));
 		}
+	|	postfix_expression DT_TOK_PTR dtrace_keyword_ident {
+			$$ = OP2(DT_TOK_PTR, $1, dt_node_ident($3));
+		}
 	|	postfix_expression DT_TOK_ADDADD {
 			$$ = OP1(DT_TOK_POSTINC, $1);
 		}
@@ -408,6 +420,10 @@
 		    DT_TOK_TNAME DT_TOK_RPAR {
 			$$ = dt_node_offsetof($3, $5);
 		}
+	|	DT_TOK_OFFSETOF DT_TOK_LPAR type_name DT_TOK_COMMA
+		    dtrace_keyword_ident DT_TOK_RPAR {
+			$$ = dt_node_offsetof($3, $5);
+		}
 	|	DT_TOK_XLATE DT_TOK_LT type_name DT_TOK_GT
 		    DT_TOK_LPAR expression DT_TOK_RPAR {
 			$$ = OP2(DT_TOK_XLATE, dt_node_type($3), $6);
@@ -633,6 +649,7 @@
 	|	DT_KEY_DOUBLE { $$ = dt_decl_spec(CTF_K_FLOAT, DUP("double")); }
 	|	DT_KEY_SIGNED { $$ = dt_decl_attr(DT_DA_SIGNED); }
 	|	DT_KEY_UNSIGNED { $$ = dt_decl_attr(DT_DA_UNSIGNED); }
+	|	DT_KEY_USERLAND { $$ = dt_decl_attr(DT_DA_USER); }
 	|	DT_KEY_STRING {
 			$$ = dt_decl_spec(CTF_K_TYPEDEF, DUP("string"));
 		}
@@ -831,4 +848,15 @@
 	|	parameter_type_list	{ $$ = $1; }
 	;
 
+dtrace_keyword_ident:
+	  DT_KEY_PROBE { $$ = DUP("probe"); }
+	| DT_KEY_PROVIDER { $$ = DUP("provider"); }
+	| DT_KEY_SELF { $$ = DUP("self"); }
+	| DT_KEY_STRING { $$ = DUP("string"); }
+	| DT_TOK_STRINGOF { $$ = DUP("stringof"); }
+	| DT_KEY_USERLAND { $$ = DUP("userland"); }
+	| DT_TOK_XLATE { $$ = DUP("xlate"); }
+	| DT_KEY_XLATOR { $$ = DUP("translator"); }
+	;
+
 %%


Property changes on: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_grammar.y
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_handle.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_handle.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_handle.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -31,7 +32,7 @@
 #include <errno.h>
 #include <unistd.h>
 #include <assert.h>
-#if defined(sun)
+#ifdef illumos
 #include <alloca.h>
 #endif
 

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_ident.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_ident.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_ident.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -22,22 +23,24 @@
 /*
  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013 Joyent, Inc. All rights reserved.
  */
 
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 
-#if defined(sun)
+#ifdef illumos
 #include <sys/sysmacros.h>
 #endif
 #include <strings.h>
 #include <stdlib.h>
-#if defined(sun)
+#ifdef illumos
 #include <alloca.h>
 #endif
 #include <assert.h>
 #include <errno.h>
 #include <ctype.h>
-#if defined(sun)
+#ifdef illumos
 #include <sys/procfs_isa.h>
 #endif
 #include <limits.h>
@@ -104,7 +107,7 @@
 		}
 	}
 
-	dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);
+	dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type, B_FALSE);
 }
 
 /*
@@ -163,7 +166,7 @@
 		if (argc != 0)
 			isp->dis_args[argc - 1].dn_list = NULL;
 
-		dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);
+		dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type, B_FALSE);
 
 	} else {
 		dt_idcook_sign(dnp, idp, argc, args,
@@ -304,7 +307,7 @@
 			}
 
 			dt_node_type_assign(&isp->dis_args[i],
-			    dtt.dtt_ctfp, dtt.dtt_type);
+			    dtt.dtt_ctfp, dtt.dtt_type, B_FALSE);
 		}
 	}
 
@@ -391,7 +394,9 @@
 
 		dt_node_type_assign(dnp,
 		    prp->pr_argv[ap->dn_value].dtt_ctfp,
-		    prp->pr_argv[ap->dn_value].dtt_type);
+		    prp->pr_argv[ap->dn_value].dtt_type,
+		    prp->pr_argv[ap->dn_value].dtt_flags & DTT_FL_USER ?
+		    B_TRUE : B_FALSE);
 
 	} else if ((dxp = dt_xlator_lookup(dtp,
 	    nnp, xnp, DT_XLATE_FUZZY)) != NULL || (
@@ -419,7 +424,8 @@
 		dnp->dn_ident->di_ctfp = xidp->di_ctfp;
 		dnp->dn_ident->di_type = xidp->di_type;
 
-		dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp));
+		dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp),
+		    B_FALSE);
 
 	} else {
 		xyerror(D_ARGS_XLATOR, "translator for %s[%lld] from %s to %s "
@@ -465,7 +471,7 @@
 	idp->di_ctfp = dtt.dtt_ctfp;
 	idp->di_type = dtt.dtt_type;
 
-	dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);
+	dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type, B_FALSE);
 }
 
 /*ARGSUSED*/
@@ -487,7 +493,7 @@
 		idp->di_type = dtt.dtt_type;
 	}
 
-	dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);
+	dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type, B_FALSE);
 }
 
 /*ARGSUSED*/
@@ -495,7 +501,7 @@
 dt_idcook_thaw(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
 {
 	if (idp->di_ctfp != NULL && idp->di_type != CTF_ERR)
-		dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);
+		dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type, B_FALSE);
 }
 
 static void

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_ident.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_ident.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_ident.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -25,8 +26,8 @@
  */
 
 /*
- * Copyright (c) 2011, Joyent, Inc. All rights reserved.
- * Copyright (c) 2011 by Delphix. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
  */
 
 #ifndef	_DT_IMPL_H
@@ -34,7 +35,7 @@
 
 #include <sys/param.h>
 #include <sys/objfs.h>
-#if !defined(sun)
+#ifndef illumos
 #include <sys/bitmap.h>
 #include <sys/utsname.h>
 #include <sys/ioccom.h>
@@ -45,7 +46,7 @@
 #include <libctf.h>
 #include <dtrace.h>
 #include <gelf.h>
-#if defined(sun)
+#ifdef illumos
 #include <synch.h>
 #endif
 
@@ -64,6 +65,7 @@
 #include <dt_proc.h>
 #include <dt_dof.h>
 #include <dt_pcb.h>
+#include <dt_pq.h>
 
 struct dt_module;		/* see below */
 struct dt_pfdict;		/* see <dt_printf.h> */
@@ -141,10 +143,14 @@
 	GElf_Addr dm_bss_va;	/* virtual address of BSS */
 	GElf_Xword dm_bss_size;	/* size in bytes of BSS */
 	dt_idhash_t *dm_extern;	/* external symbol definitions */
-#if !defined(sun)
+#ifndef illumos
 	caddr_t dm_reloc_offset;	/* Symbol relocation offset. */
 	uintptr_t *dm_sec_offsets;
 #endif
+	pid_t dm_pid;		/* pid for this module */
+	uint_t dm_nctflibs;	/* number of ctf children libraries */
+	ctf_file_t **dm_libctfp; /* process library ctf pointers */
+	char **dm_libctfn;	/* names of process ctf containers */
 } dt_module_t;
 
 #define	DT_DM_LOADED	0x1	/* module symbol and type data is loaded */
@@ -188,6 +194,9 @@
 	dtrace_aggvarid_t dtpa_id;	/* aggregation variable of interest */
 	FILE *dtpa_fp;			/* file pointer */
 	int dtpa_allunprint;		/* print only unprinted aggregations */
+	int dtpa_agghist;		/* print aggregation as histogram */
+	int dtpa_agghisthdr;		/* aggregation histogram hdr printed */
+	int dtpa_aggpack;		/* pack quantized aggregations */
 } dt_print_aggdata_t;
 
 typedef struct dt_dirpath {
@@ -239,6 +248,7 @@
 	uint_t dt_provbuckets;	/* number of provider hash buckets */
 	uint_t dt_nprovs;	/* number of providers in hash and list */
 	dt_proc_hash_t *dt_procs; /* hash table of grabbed process handles */
+	char **dt_proc_env;	/* additional environment variables */
 	dt_intdesc_t dt_ints[6]; /* cached integer type descriptions */
 	ctf_id_t dt_type_func;	/* cached CTF identifier for function type */
 	ctf_id_t dt_type_fptr;	/* cached CTF identifier for function pointer */
@@ -257,7 +267,7 @@
 	int dt_maxstrdata;	/* max strdata ID */
 	char **dt_strdata;	/* pointer to strdata array */
 	dt_aggregate_t dt_aggregate; /* aggregate */
-	dtrace_bufdesc_t dt_buf; /* staging buffer */
+	dt_pq_t *dt_bufq;	/* CPU-specific data queue */
 	struct dt_pfdict *dt_pfdict; /* dictionary of printf conversions */
 	dt_version_t dt_vmax;	/* optional ceiling on program API binding */
 	dtrace_attribute_t dt_amin; /* optional floor on program attributes */
@@ -281,12 +291,13 @@
 	uint_t dt_linktype;	/* dtrace link output file type (see below) */
 	uint_t dt_xlatemode;	/* dtrace translator linking mode (see below) */
 	uint_t dt_stdcmode;	/* dtrace stdc compatibility mode (see below) */
+	uint_t dt_encoding;	/* dtrace output encoding (see below) */
 	uint_t dt_treedump;	/* dtrace tree debug bitmap (see below) */
 	uint64_t dt_options[DTRACEOPT_MAX]; /* dtrace run-time options */
 	int dt_version;		/* library version requested by client */
 	int dt_ctferr;		/* error resulting from last CTF failure */
 	int dt_errno;		/* error resulting from last failed operation */
-#if !defined(sun)
+#ifndef illumos
 	const char *dt_errfile;
 	int dt_errline;
 #endif
@@ -295,7 +306,7 @@
 	int dt_fterr;		/* saved errno from failed open of dt_ftfd */
 	int dt_cdefs_fd;	/* file descriptor for C CTF debugging cache */
 	int dt_ddefs_fd;	/* file descriptor for D CTF debugging cache */
-#if defined(sun)
+#ifdef illumos
 	int dt_stdout_fd;	/* file descriptor for saved stdout */
 #else
 	FILE *dt_freopen_fp;	/* file pointer for freopened stdout */
@@ -326,6 +337,11 @@
 	struct utsname dt_uts;	/* uname(2) information for system */
 	dt_list_t dt_lib_dep;	/* scratch linked-list of lib dependencies */
 	dt_list_t dt_lib_dep_sorted;	/* dependency sorted library list */
+	dtrace_flowkind_t dt_flow;	/* flow kind */
+	const char *dt_prefix;	/* recommended flow prefix */
+	int dt_indent;		/* recommended flow indent */
+	dtrace_epid_t dt_last_epid;	/* most recently consumed EPID */
+	uint64_t dt_last_timestamp;	/* most recently consumed timestamp */
 };
 
 /*
@@ -367,6 +383,14 @@
 #define	DT_STDC_XT	3	/* ISO C + K&R C compat with ISO: __STDC__=0 */
 
 /*
+ * Values for the dt_encoding property, which is used to force a particular
+ * character encoding (overriding default behavior and/or automatic detection).
+ */
+#define	DT_ENCODING_UNSET	0
+#define	DT_ENCODING_ASCII	1
+#define	DT_ENCODING_UTF8	2
+
+/*
  * Macro to test whether a given pass bit is set in the dt_treedump bit-vector.
  * If the bit for pass 'p' is set, the D compiler displays the parse tree for
  * the program by printing it to stderr at the end of compiler pass 'p'.
@@ -461,7 +485,6 @@
 	EDT_VERSREDUCED,	/* requested API version has been reduced */
 	EDT_CTF,		/* libctf called failed (dt_ctferr has more) */
 	EDT_COMPILER,		/* error in D program compilation */
-	EDT_NOREG,		/* register allocation failure */
 	EDT_NOTUPREG,		/* tuple register allocation failure */
 	EDT_NOMEM,		/* memory allocation failure */
 	EDT_INT2BIG,		/* integer limit exceeded */
@@ -529,7 +552,9 @@
 	EDT_BADSTACKPC,		/* invalid stack program counter size */
 	EDT_BADAGGVAR,		/* invalid aggregation variable identifier */
 	EDT_OVERSION,		/* client is requesting deprecated version */
-	EDT_ENABLING_ERR	/* failed to enable probe */
+	EDT_ENABLING_ERR,	/* failed to enable probe */
+	EDT_NOPROBES,		/* no probes sites for declared provider */
+	EDT_CANTLOAD		/* failed to load a module */
 };
 
 /*
@@ -572,7 +597,7 @@
 extern char *dt_cpp_add_arg(dtrace_hdl_t *, const char *);
 extern char *dt_cpp_pop_arg(dtrace_hdl_t *);
 
-#if defined(sun)
+#ifdef illumos
 extern int dt_set_errno(dtrace_hdl_t *, int);
 #else
 int _dt_set_errno(dtrace_hdl_t *, int, const char *, int);
@@ -582,7 +607,7 @@
 extern void dt_set_errmsg(dtrace_hdl_t *, const char *, const char *,
     const char *, int, const char *, va_list);
 
-#if defined(sun)
+#ifdef illumos
 extern int dt_ioctl(dtrace_hdl_t *, int, void *);
 #else
 extern int dt_ioctl(dtrace_hdl_t *, u_long, void *);

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_inttab.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_inttab.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_inttab.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_inttab.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_inttab.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_inttab.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_lex.l
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_lex.l	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_lex.l	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 %{
 /*
  * CDDL HEADER START
@@ -23,6 +24,10 @@
 /*
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  */
+/*
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
 
 #include <string.h>
 #include <stdlib.h>
@@ -40,7 +45,7 @@
  * We need to undefine lex's input and unput macros so that references to these
  * call the functions provided at the end of this source file.
  */
-#if defined(sun)
+#ifdef illumos
 #undef input
 #undef unput
 #else
@@ -75,7 +80,7 @@
 #endif
 
 static int id_or_type(const char *);
-#if defined(sun)
+#ifdef illumos
 static int input(void);
 static void unput(int);
 #endif
@@ -93,13 +98,17 @@
 %}
 
 %e 1500		/* maximum nodes */
-%p 3700		/* maximum positions */
+%p 4900		/* maximum positions */
 %n 600		/* maximum states */
+%a 3000		/* maximum transitions */
 
 %s S0 S1 S2 S3 S4
 
 RGX_AGG		"@"[a-zA-Z_][0-9a-zA-Z_]*
 RGX_PSPEC	[-$:a-zA-Z_.?*\\\[\]!][-$:0-9a-zA-Z_.`?*\\\[\]!]*
+RGX_ALTIDENT	[a-zA-Z_][0-9a-zA-Z_]*
+RGX_LMID	LM[0-9a-fA-F]+`
+RGX_MOD_IDENT	[a-zA-Z_`][0-9a-z.A-Z_`]*`
 RGX_IDENT	[a-zA-Z_`][0-9a-zA-Z_`]*
 RGX_INT		([0-9]+|0[xX][0-9A-Fa-f]+)[uU]?[lL]?[lL]?
 RGX_FP		([0-9]+("."?)[0-9]*|"."[0-9]+)((e|E)("+"|-)?[0-9]+)?[fFlL]?
@@ -169,6 +178,7 @@
 <S0>typedef	return (DT_KEY_TYPEDEF);
 <S0>union	return (DT_KEY_UNION);
 <S0>unsigned	return (DT_KEY_UNSIGNED);
+<S0>userland	return (DT_KEY_USERLAND);
 <S0>void	return (DT_KEY_VOID);
 <S0>volatile	return (DT_KEY_VOLATILE);
 <S0>while	return (DT_KEY_WHILE);
@@ -347,7 +357,9 @@
 			return (DT_TOK_INT);
 		}
 
-<S0>{RGX_IDENT}	{
+<S0>{RGX_IDENT} |
+<S0>{RGX_MOD_IDENT}{RGX_IDENT} |
+<S0>{RGX_MOD_IDENT} {
 			return (id_or_type(yytext));
 		}
 
@@ -729,9 +741,10 @@
 	yypcb = pcb;
 	yylineno = 1;
 	yypragma = NULL;
-#if defined(sun)
+#ifdef illumos
 	yysptr = yysbuf;
 #endif
+	YY_FLUSH_BUFFER;
 }
 
 /*
@@ -827,7 +840,7 @@
 	return (ttok);
 }
 
-#if defined(sun)
+#ifdef illumos
 static int
 input(void)
 {
@@ -869,4 +882,4 @@
 	*yysptr++ = c;
 	yytchar = c;
 }
-#endif
+#endif /* illumos */


Property changes on: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_lex.l
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -30,7 +31,7 @@
 #include <elf.h>
 
 #include <sys/types.h>
-#if defined(sun)
+#ifdef illumos
 #include <sys/sysmacros.h>
 #else
 #define	P2ROUNDUP(x, align)		(-(-(x) & -(align)))
@@ -38,7 +39,7 @@
 
 #include <unistd.h>
 #include <strings.h>
-#if defined(sun)
+#ifdef illumos
 #include <alloca.h>
 #endif
 #include <limits.h>
@@ -47,7 +48,7 @@
 #include <stdio.h>
 #include <fcntl.h>
 #include <errno.h>
-#if defined(sun)
+#ifdef illumos
 #include <wait.h>
 #else
 #include <sys/wait.h>
@@ -242,8 +243,14 @@
 /* XXX */
 printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
 #elif defined(__powerpc__)
-/* XXX */
-printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
+			/*
+			 * Add 4 bytes to hit the low half of this 64-bit
+			 * big-endian address.
+			 */
+			rel->r_offset = s->dofs_offset +
+			    dofr[j].dofr_offset + 4;
+			rel->r_info = ELF32_R_INFO(count + dep->de_global,
+			    R_PPC_REL32);
 #elif defined(__sparc)
 			/*
 			 * Add 4 bytes to hit the low half of this 64-bit
@@ -423,7 +430,10 @@
 #elif defined(__mips__)
 /* XXX */
 #elif defined(__powerpc__)
-/* XXX */
+			rel->r_offset = s->dofs_offset +
+			    dofr[j].dofr_offset;
+			rel->r_info = ELF64_R_INFO(count + dep->de_global,
+			    R_PPC64_REL64);
 #elif defined(__i386) || defined(__amd64)
 			rel->r_offset = s->dofs_offset +
 			    dofr[j].dofr_offset;
@@ -824,12 +834,84 @@
 	return (0);
 }
 #elif defined(__powerpc__)
+/* The sentinel is 'xor r3,r3,r3'. */
+#define DT_OP_XOR_R3	0x7c631a78
+
+#define DT_OP_NOP		0x60000000
+#define DT_OP_BLR		0x4e800020
+
+/* This captures all forms of branching to address. */
+#define DT_IS_BRANCH(inst)	((inst & 0xfc000000) == 0x48000000)
+#define DT_IS_BL(inst)	(DT_IS_BRANCH(inst) && (inst & 0x01))
+
 /* XXX */
 static int
 dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
     uint32_t *off)
 {
-printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
+	uint32_t *ip;
+
+	if ((rela->r_offset & (sizeof (uint32_t) - 1)) != 0)
+		return (-1);
+
+	/*LINTED*/
+	ip = (uint32_t *)(p + rela->r_offset);
+
+	/*
+	 * We only know about some specific relocation types.
+	 */
+	if (GELF_R_TYPE(rela->r_info) != R_PPC_REL24 &&
+	    GELF_R_TYPE(rela->r_info) != R_PPC_PLTREL24)
+		return (-1);
+
+	/*
+	 * We may have already processed this object file in an earlier linker
+	 * invocation. Check to see if the present instruction sequence matches
+	 * the one we would install below.
+	 */
+	if (isenabled) {
+		if (ip[0] == DT_OP_XOR_R3) {
+			(*off) += sizeof (ip[0]);
+			return (0);
+		}
+	} else {
+		if (ip[0] == DT_OP_NOP) {
+			(*off) += sizeof (ip[0]);
+			return (0);
+		}
+	}
+
+	/*
+	 * We only expect branch to address instructions.
+	 */
+	if (!DT_IS_BRANCH(ip[0])) {
+		dt_dprintf("found %x instead of a branch instruction at %llx\n",
+		    ip[0], (u_longlong_t)rela->r_offset);
+		return (-1);
+	}
+
+	if (isenabled) {
+		/*
+		 * It would necessarily indicate incorrect usage if an is-
+		 * enabled probe were tail-called so flag that as an error.
+		 * It's also potentially (very) tricky to handle gracefully,
+		 * but could be done if this were a desired use scenario.
+		 */
+		if (!DT_IS_BL(ip[0])) {
+			dt_dprintf("tail call to is-enabled probe at %llx\n",
+			    (u_longlong_t)rela->r_offset);
+			return (-1);
+		}
+
+		ip[0] = DT_OP_XOR_R3;
+		(*off) += sizeof (ip[0]);
+	} else {
+		if (DT_IS_BL(ip[0]))
+			ip[0] = DT_OP_NOP;
+		else
+			ip[0] = DT_OP_BLR;
+	}
+
 	return (0);
 }
 
@@ -1528,7 +1610,7 @@
 				return (dt_link_error(dtp, elf, fd, bufs,
 				    "failed to allocate space for probe"));
 			}
-#if !defined(sun)
+#ifndef illumos
 			/*
 			 * Our linker doesn't understand the SUNW_IGNORE ndx and
 			 * will try to use this relocation when we build the
@@ -1539,10 +1621,17 @@
 			 * the executable file as the symbol is going to be
 			 * change from UND to ABS.
 			 */
-			rela.r_offset = 0;
-			rela.r_info  = 0;
-			rela.r_addend = 0;
-			(void) gelf_update_rela(data_rel, i, &rela);
+			if (shdr_rel.sh_type == SHT_RELA) {
+				rela.r_offset = 0;
+				rela.r_info  = 0;
+				rela.r_addend = 0;
+				(void) gelf_update_rela(data_rel, i, &rela);
+			} else {
+				GElf_Rel rel;
+				rel.r_offset = 0;
+				rel.r_info = 0;
+				(void) gelf_update_rel(data_rel, i, &rel);
+			}
 #endif
 
 			mod = 1;
@@ -1555,7 +1644,7 @@
 			 * already been processed by an earlier link
 			 * invocation.
 			 */
-#if !defined(sun)
+#ifndef illumos
 #define SHN_SUNW_IGNORE	SHN_ABS
 #endif
 			if (rsym.st_shndx != SHN_SUNW_IGNORE) {
@@ -1571,7 +1660,7 @@
 	(void) elf_end(elf);
 	(void) close(fd);
 
-#if !defined(sun)
+#ifndef illumos
 	if (nsym > 0)
 #endif
 	while ((pair = bufs) != NULL) {
@@ -1592,7 +1681,7 @@
 dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
     const char *file, int objc, char *const objv[])
 {
-#if !defined(sun)
+#ifndef illumos
 	char tfile[PATH_MAX];
 	Elf *e;
 	Elf_Scn *scn;
@@ -1615,7 +1704,7 @@
 	size_t len;
 	int eprobes = 0, ret = 0;
 
-#if !defined(sun)
+#ifndef illumos
 	if (access(file, R_OK) == 0) {
 		fprintf(stderr, "dtrace: target object (%s) already exists. "
 		    "Please remove the target\ndtrace: object and rebuild all "
@@ -1693,7 +1782,7 @@
 	if ((dof = dtrace_dof_create(dtp, pgp, dflags)) == NULL)
 		return (-1); /* errno is set for us */
 
-#if defined(sun)
+#ifdef illumos
 	/*
 	 * Create a temporary file and then unlink it if we're going to
 	 * combine it with drti.o later.  We can still refer to it in child
@@ -1737,12 +1826,12 @@
 	}
 
 
-#if defined(sun)
+#ifdef illumos
 	if (!dtp->dt_lazyload)
 		(void) unlink(file);
 #endif
 
-#if defined(sun)
+#ifdef illumos
 	if (dtp->dt_oflags & DTRACE_O_LP64)
 		status = dump_elf64(dtp, dof, fd);
 	else
@@ -1758,7 +1847,7 @@
 	}
 
 	if (!dtp->dt_lazyload) {
-#if defined(sun)
+#ifdef illumos
 		const char *fmt = "%s -o %s -r -Blocal -Breduce /dev/fd/%d %s";
 
 		if (dtp->dt_oflags & DTRACE_O_LP64) {
@@ -1783,7 +1872,7 @@
 		 * Arches which default to 64-bit need to explicitly use
 		 * the 32-bit library path.
 		 */
-		int use_32 = !(dtp->dt_oflags & DTRACE_O_LP64);
+		int use_32 = (dtp->dt_oflags & DTRACE_O_ILP32);
 #else
 		/*
 		 * Arches which are 32-bit only just use the normal
@@ -1798,9 +1887,7 @@
 		len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file, tfile,
 		    drti) + 1;
 
-#if !defined(sun)
 		len *= 2;
-#endif
 		cmd = alloca(len);
 
 		(void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file,
@@ -1826,8 +1913,7 @@
 			    file, dtp->dt_ld_path, WEXITSTATUS(status));
 			goto done;
 		}
-#if !defined(sun)
-#define BROKEN_LIBELF
+#ifndef illumos
 		/*
 		 * FreeBSD's ld(1) is not instructed to interpret and add
 		 * correctly the SUNW_dof section present in tfile.
@@ -1851,9 +1937,6 @@
 		/*
 		 * Add the string '.SUWN_dof' to the shstrtab section.
 		 */
-#ifdef BROKEN_LIBELF
-		elf_flagelf(e, ELF_C_SET, ELF_F_LAYOUT);
-#endif
 		elf_getshdrstrndx(e, &stridx);
 		scn = elf_getscn(e, stridx);
 		gelf_getshdr(scn, &shdr);
@@ -1865,54 +1948,6 @@
 		loc = shdr.sh_size;
 		shdr.sh_size += data->d_size;
 		gelf_update_shdr(scn, &shdr);
-#ifdef BROKEN_LIBELF
-		off = shdr.sh_offset;
-		rc = shdr.sh_offset + shdr.sh_size;
-		gelf_getehdr(e, &ehdr);
-		if (ehdr.e_shoff > off) {
-			off = ehdr.e_shoff + ehdr.e_shnum * ehdr.e_shentsize;
-			rc = roundup(rc, 8);
-			ehdr.e_shoff = rc;
-			gelf_update_ehdr(e, &ehdr);
-			rc += ehdr.e_shnum * ehdr.e_shentsize;
-		}
-		for (;;) {
-			scn0 = NULL;
-			scn = NULL;
-			while ((scn = elf_nextscn(e, scn)) != NULL) {
-				gelf_getshdr(scn, &shdr);
-				if (shdr.sh_type == SHT_NOBITS ||
-				    shdr.sh_offset < off)
-					continue;
-				/* Find the immediately adjcent section. */
-				if (scn0 == NULL ||
-				    shdr.sh_offset < shdr0.sh_offset) {
-					scn0 = scn;
-					gelf_getshdr(scn0, &shdr0);
-				}
-			}
-			if (scn0 == NULL)
-				break;
-			/* Load section data to work around another bug */
-			elf_getdata(scn0, NULL);
-			/* Update section header, assure section alignment */
-			off = shdr0.sh_offset + shdr0.sh_size;
-			rc = roundup(rc, shdr0.sh_addralign);
-			shdr0.sh_offset = rc;
-			gelf_update_shdr(scn0, &shdr0);
-			rc += shdr0.sh_size;
-		}
-		if (elf_update(e, ELF_C_WRITE) < 0) {
-			ret = dt_link_error(dtp, NULL, -1, NULL,
-			    "failed to add append the shstrtab section: %s",
-			    elf_errmsg(elf_errno()));
-			elf_end(e);
-			close(efd);
-			goto done;
-		}
-		elf_end(e);
-		e = elf_begin(efd, ELF_C_RDWR, NULL);
-#endif
 		/*
 		 * Construct the .SUNW_dof section.
 		 */
@@ -1965,7 +2000,7 @@
 done:
 	dtrace_dof_destroy(dtp, dof);
 
-#if !defined(sun)
+#ifndef illumos
 	unlink(tfile);
 #endif
 	return (ret);

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_list.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_list.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_list.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_list.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_list.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_list.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_map.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_map.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_map.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -39,7 +40,7 @@
 static int
 dt_strdata_add(dtrace_hdl_t *dtp, dtrace_recdesc_t *rec, void ***data, int *max)
 {
-	int maxformat;
+	int maxformat, rval;
 	dtrace_fmtdesc_t fmt;
 	void *result;
 
@@ -63,8 +64,9 @@
 		return (dt_set_errno(dtp, EDT_NOMEM));
 
 	if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {
+		rval = dt_set_errno(dtp, errno);
 		free(fmt.dtfd_string);
-		return (dt_set_errno(dtp, errno));
+		return (rval);
 	}
 
 	while (rec->dtrd_format > (maxformat = *max)) {
@@ -155,7 +157,7 @@
 	enabled->dtepd_epid = id;
 	enabled->dtepd_nrecs = 1;
 
-#if defined(sun)
+#ifdef illumos
 	if (dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled) == -1) {
 #else
 	if (dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled) == -1) {
@@ -179,7 +181,7 @@
 		if ((enabled = nenabled) == NULL)
 			return (dt_set_errno(dtp, EDT_NOMEM));
 
-#if defined(sun)
+#ifdef illumos
 		rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled);
 #else
 		rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled);
@@ -355,7 +357,7 @@
 		agg->dtagd_id = id;
 		agg->dtagd_nrecs = 1;
 
-#if defined(sun)
+#ifdef illumos
 		if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg) == -1) {
 #else
 		if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg) == -1) {
@@ -378,7 +380,7 @@
 			if ((agg = nagg) == NULL)
 				return (dt_set_errno(dtp, EDT_NOMEM));
 
-#if defined(sun)
+#ifdef illumos
 			rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg);
 #else
 			rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg);

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -22,9 +23,13 @@
 /*
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  */
+/*
+ * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
+ * Copyright (c) 2016, Pedro Giffuni.  All rights reserved.
+ */
 
 #include <sys/types.h>
-#if defined(sun)
+#ifdef illumos
 #include <sys/modctl.h>
 #include <sys/kobj.h>
 #include <sys/kobj_impl.h>
@@ -38,7 +43,7 @@
 #endif
 
 #include <unistd.h>
-#if defined(sun)
+#ifdef illumos
 #include <project.h>
 #endif
 #include <strings.h>
@@ -48,8 +53,9 @@
 #include <assert.h>
 #include <errno.h>
 #include <dirent.h>
-#if !defined(sun)
+#ifndef illumos
 #include <fcntl.h>
+#include <libproc_compat.h>
 #endif
 
 #include <dt_strtab.h>
@@ -462,6 +468,9 @@
 dt_module_t *
 dt_module_create(dtrace_hdl_t *dtp, const char *name)
 {
+	long pid;
+	char *eptr;
+	dt_ident_t *idp;
 	uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_modbuckets;
 	dt_module_t *dmp;
 
@@ -485,6 +494,32 @@
 	else
 		dmp->dm_ops = &dt_modops_32;
 
+	/*
+	 * Modules for userland processes are special. They always refer to a
+	 * specific process and have a copy of their CTF data from a specific
+	 * instant in time. Any dt_module_t that begins with 'pid' is a module
+	 * for a specific process, much like how any probe description that
+	 * begins with 'pid' is special. pid123 refers to process 123. A module
+	 * that is just 'pid' refers specifically to pid$target. This is
+	 * generally done as D does not currently allow for macros to be
+	 * evaluated when working with types.
+	 */
+	if (strncmp(dmp->dm_name, "pid", 3) == 0) {
+		errno = 0;
+		if (dmp->dm_name[3] == '\0') {
+			idp = dt_idhash_lookup(dtp->dt_macros, "target");
+			if (idp != NULL && idp->di_id != 0)
+				dmp->dm_pid = idp->di_id;
+		} else {
+			pid = strtol(dmp->dm_name + 3, &eptr, 10);
+			if (errno == 0 && *eptr == '\0')
+				dmp->dm_pid = (pid_t)pid;
+			else
+				dt_dprintf("encountered malformed pid "
+				    "module: %s\n", dmp->dm_name);
+		}
+	}
+
 	return (dmp);
 }
 
@@ -539,7 +574,7 @@
 	if (sp == NULL || (dp = elf_getdata(sp, NULL)) == NULL)
 		return (0);
 
-#if defined(sun)
+#ifdef illumos
 	ctsp->cts_data = dp->d_buf;
 #else
 	if ((ctsp->cts_data = malloc(dp->d_size)) == NULL)
@@ -554,6 +589,159 @@
 	return (0);
 }
 
+typedef struct dt_module_cb_arg {
+	struct ps_prochandle *dpa_proc;
+	dtrace_hdl_t *dpa_dtp;
+	dt_module_t *dpa_dmp;
+	uint_t dpa_count;
+} dt_module_cb_arg_t;
+
+/* ARGSUSED */
+static int
+dt_module_load_proc_count(void *arg, const prmap_t *prmap, const char *obj)
+{
+	ctf_file_t *fp;
+	dt_module_cb_arg_t *dcp = arg;
+
+	/* Try to grab a ctf container if it exists */
+	fp = Pname_to_ctf(dcp->dpa_proc, obj);
+	if (fp != NULL)
+		dcp->dpa_count++;
+	return (0);
+}
+
+/* ARGSUSED */
+static int
+dt_module_load_proc_build(void *arg, const prmap_t *prmap, const char *obj)
+{
+	ctf_file_t *fp;
+	char buf[MAXPATHLEN], *p;
+	dt_module_cb_arg_t *dcp = arg;
+	int count = dcp->dpa_count;
+	Lmid_t lmid;
+
+	fp = Pname_to_ctf(dcp->dpa_proc, obj);
+	if (fp == NULL)
+		return (0);
+	fp = ctf_dup(fp);
+	if (fp == NULL)
+		return (0);
+	dcp->dpa_dmp->dm_libctfp[count] = fp;
+	/*
+	 * While it'd be nice to simply use objname here, because of our prior
+	 * actions we'll always get a resolved object name to its on disk file.
+	 * Like the pid provider, we need to tell a bit of a lie here. The type
+	 * that the user thinks of is in terms of the libraries they requested,
+	 * eg. libc.so.1, they don't care about the fact that it's
+	 * libc_hwcap.so.1.
+	 */
+	(void) Pobjname(dcp->dpa_proc, prmap->pr_vaddr, buf, sizeof (buf));
+	if ((p = strrchr(buf, '/')) == NULL)
+		p = buf;
+	else
+		p++;
+
+	/*
+	 * If for some reason we can't find a link map id for this module, which
+	 * would be really quite weird. We instead just say the link map id is
+	 * zero.
+	 */
+	if (Plmid(dcp->dpa_proc, prmap->pr_vaddr, &lmid) != 0)
+		lmid = 0;
+
+	if (lmid == 0)
+		dcp->dpa_dmp->dm_libctfn[count] = strdup(p);
+	else
+		(void) asprintf(&dcp->dpa_dmp->dm_libctfn[count],
+		    "LM%x`%s", lmid, p);
+	if (dcp->dpa_dmp->dm_libctfn[count] == NULL)
+		return (1);
+	ctf_setspecific(fp, dcp->dpa_dmp);
+	dcp->dpa_count++;
+	return (0);
+}
+
+/*
+ * We've been asked to load data that belongs to another process. As such we're
+ * going to pgrab it at this instant, load everything that we might ever care
+ * about, and then drive on. The reason for this is that the process that we're
+ * interested in might be changing. As long as we have grabbed it, then this
+ * can't be a problem for us.
+ *
+ * For now, we're actually going to punt on most things and just try to get CTF
+ * data, nothing else. Basically this is only useful as a source of type
+ * information, we can't go and do the stacktrace lookups, etc.
+ */
+static int
+dt_module_load_proc(dtrace_hdl_t *dtp, dt_module_t *dmp)
+{
+	struct ps_prochandle *p;
+	dt_module_cb_arg_t arg;
+
+	/*
+	 * Note that on success we do not release this hold. We must hold this
+	 * for our life time.
+	 */
+	p = dt_proc_grab(dtp, dmp->dm_pid, 0, PGRAB_RDONLY | PGRAB_FORCE);
+	if (p == NULL) {
+		dt_dprintf("failed to grab pid: %d\n", (int)dmp->dm_pid);
+		return (dt_set_errno(dtp, EDT_CANTLOAD));
+	}
+	dt_proc_lock(dtp, p);
+
+	arg.dpa_proc = p;
+	arg.dpa_dtp = dtp;
+	arg.dpa_dmp = dmp;
+	arg.dpa_count = 0;
+	if (Pobject_iter_resolved(p, dt_module_load_proc_count, &arg) != 0) {
+		dt_dprintf("failed to iterate objects\n");
+		dt_proc_unlock(dtp, p);
+		dt_proc_release(dtp, p);
+		return (dt_set_errno(dtp, EDT_CANTLOAD));
+	}
+
+	if (arg.dpa_count == 0) {
+		dt_dprintf("no ctf data present\n");
+		dt_proc_unlock(dtp, p);
+		dt_proc_release(dtp, p);
+		return (dt_set_errno(dtp, EDT_CANTLOAD));
+	}
+
+	dmp->dm_libctfp = calloc(arg.dpa_count, sizeof (ctf_file_t *));
+	if (dmp->dm_libctfp == NULL) {
+		dt_proc_unlock(dtp, p);
+		dt_proc_release(dtp, p);
+		return (dt_set_errno(dtp, EDT_NOMEM));
+	}
+
+	dmp->dm_libctfn = calloc(arg.dpa_count, sizeof (char *));
+	if (dmp->dm_libctfn == NULL) {
+		free(dmp->dm_libctfp);
+		dt_proc_unlock(dtp, p);
+		dt_proc_release(dtp, p);
+		return (dt_set_errno(dtp, EDT_NOMEM));
+	}
+
+	dmp->dm_nctflibs = arg.dpa_count;
+
+	arg.dpa_count = 0;
+	if (Pobject_iter_resolved(p, dt_module_load_proc_build, &arg) != 0) {
+		dt_proc_unlock(dtp, p);
+		dt_module_unload(dtp, dmp);
+		dt_proc_release(dtp, p);
+		return (dt_set_errno(dtp, EDT_CANTLOAD));
+	}
+	assert(arg.dpa_count == dmp->dm_nctflibs);
+	dt_dprintf("loaded %d ctf modules for pid %d\n", arg.dpa_count,
+	    (int)dmp->dm_pid);
+
+	dt_proc_unlock(dtp, p);
+	dt_proc_release(dtp, p);
+	dmp->dm_flags |= DT_DM_LOADED;
+
+	return (0);
+}
+
 int
 dt_module_load(dtrace_hdl_t *dtp, dt_module_t *dmp)
 {
@@ -560,6 +748,9 @@
 	if (dmp->dm_flags & DT_DM_LOADED)
 		return (0); /* module is already loaded */
 
+	if (dmp->dm_pid != 0)
+		return (dt_module_load_proc(dtp, dmp));
+
 	dmp->dm_ctdata.cts_name = ".SUNW_ctf";
 	dmp->dm_ctdata.cts_type = SHT_PROGBITS;
 	dmp->dm_ctdata.cts_flags = 0;
@@ -610,8 +801,8 @@
 	dmp->dm_nsymbuckets = _dtrace_strbuckets;
 	dmp->dm_symfree = 1;		/* first free element is index 1 */
 
-	dmp->dm_symbuckets = malloc(sizeof (uint_t) * dmp->dm_nsymbuckets);
-	dmp->dm_symchains = malloc(sizeof (dt_sym_t) * dmp->dm_nsymelems + 1);
+	dmp->dm_symbuckets = calloc(dmp->dm_nsymbuckets, sizeof (uint_t));
+	dmp->dm_symchains = calloc(dmp->dm_nsymelems + 1, sizeof (dt_sym_t));
 
 	if (dmp->dm_symbuckets == NULL || dmp->dm_symchains == NULL) {
 		dt_module_unload(dtp, dmp);
@@ -618,9 +809,6 @@
 		return (dt_set_errno(dtp, EDT_NOMEM));
 	}
 
-	bzero(dmp->dm_symbuckets, sizeof (uint_t) * dmp->dm_nsymbuckets);
-	bzero(dmp->dm_symchains, sizeof (dt_sym_t) * dmp->dm_nsymelems + 1);
-
 	/*
 	 * Iterate over the symbol table data buffer and insert each symbol
 	 * name into the name hash if the name and type are valid.  Then
@@ -645,6 +833,14 @@
 	return (0);
 }
 
+int
+dt_module_hasctf(dtrace_hdl_t *dtp, dt_module_t *dmp)
+{
+	if (dmp->dm_pid != 0 && dmp->dm_nctflibs > 0)
+		return (1);
+	return (dt_module_getctf(dtp, dmp) != NULL);
+}
+
 ctf_file_t *
 dt_module_getctf(dtrace_hdl_t *dtp, dt_module_t *dmp)
 {
@@ -718,10 +914,12 @@
 void
 dt_module_unload(dtrace_hdl_t *dtp, dt_module_t *dmp)
 {
+	int i;
+
 	ctf_close(dmp->dm_ctfp);
 	dmp->dm_ctfp = NULL;
 
-#if !defined(sun)
+#ifndef illumos
 	if (dmp->dm_ctdata.cts_data != NULL) {
 		free(dmp->dm_ctdata.cts_data);
 	}
@@ -733,6 +931,17 @@
 	}
 #endif
 
+	if (dmp->dm_libctfp != NULL) {
+		for (i = 0; i < dmp->dm_nctflibs; i++) {
+			ctf_close(dmp->dm_libctfp[i]);
+			free(dmp->dm_libctfn[i]);
+		}
+		free(dmp->dm_libctfp);
+		free(dmp->dm_libctfn);
+		dmp->dm_libctfp = NULL;
+		dmp->dm_nctflibs = 0;
+	}
+
 	bzero(&dmp->dm_ctdata, sizeof (ctf_sect_t));
 	bzero(&dmp->dm_symtab, sizeof (ctf_sect_t));
 	bzero(&dmp->dm_strtab, sizeof (ctf_sect_t));
@@ -778,6 +987,8 @@
 	(void) elf_end(dmp->dm_elf);
 	dmp->dm_elf = NULL;
 
+	dmp->dm_pid = 0;
+
 	dmp->dm_flags &= ~DT_DM_LOADED;
 }
 
@@ -866,6 +1077,34 @@
 		return ("32-bit");
 }
 
+/* ARGSUSED */
+int
+dt_module_getlibid(dtrace_hdl_t *dtp, dt_module_t *dmp, const ctf_file_t *fp)
+{
+	int i;
+
+	for (i = 0; i < dmp->dm_nctflibs; i++) {
+		if (dmp->dm_libctfp[i] == fp)
+			return (i);
+	}
+
+	return (-1);
+}
+
+/* ARGSUSED */
+ctf_file_t *
+dt_module_getctflib(dtrace_hdl_t *dtp, dt_module_t *dmp, const char *name)
+{
+	int i;
+
+	for (i = 0; i < dmp->dm_nctflibs; i++) {
+		if (strcmp(dmp->dm_libctfn[i], name) == 0)
+			return (dmp->dm_libctfp[i]);
+	}
+
+	return (NULL);
+}
+
 /*
  * Update our module cache by adding an entry for the specified module 'name'.
  * We create the dt_module_t and populate it using /system/object/<name>/.
@@ -874,7 +1113,7 @@
  * including the path.
  */
 static void
-#if defined(sun)
+#ifdef illumos
 dt_module_update(dtrace_hdl_t *dtp, const char *name)
 #else
 dt_module_update(dtrace_hdl_t *dtp, struct kld_file_stat *k_stat)
@@ -891,7 +1130,7 @@
 	Elf_Data *dp;
 	Elf_Scn *sp;
 
-#if defined(sun)
+#ifdef illumos
 	(void) snprintf(fname, sizeof (fname),
 	    "%s/%s/object", OBJFS_ROOT, name);
 #else
@@ -970,13 +1209,13 @@
 #if defined(__FreeBSD__)
 		if (sh.sh_size == 0)
 			continue;
-		if (is_elf_obj && (sh.sh_type == SHT_PROGBITS ||
-		    sh.sh_type == SHT_NOBITS)) {
+		if (sh.sh_type == SHT_PROGBITS || sh.sh_type == SHT_NOBITS) {
 			alignmask = sh.sh_addralign - 1;
 			mapbase += alignmask;
 			mapbase &= ~alignmask;
 			sh.sh_addr = mapbase;
-			dmp->dm_sec_offsets[elf_ndxscn(sp)] = sh.sh_addr;
+			if (is_elf_obj)
+				dmp->dm_sec_offsets[elf_ndxscn(sp)] = sh.sh_addr;
 			mapbase += sh.sh_size;
 		}
 #endif
@@ -1001,7 +1240,7 @@
 	}
 
 	dmp->dm_flags |= DT_DM_KERNEL;
-#if defined(sun)
+#ifdef illumos
 	dmp->dm_modid = (int)OBJFS_MODID(st.st_ino);
 #else
 	/*
@@ -1024,7 +1263,7 @@
 		}
 	}
 #endif
-#endif
+#endif /* illumos */
 
 	if (dmp->dm_info.objfs_info_primary)
 		dmp->dm_flags |= DT_DM_PRIMARY;
@@ -1050,7 +1289,7 @@
 	    dmp != NULL; dmp = dt_list_next(dmp))
 		dt_module_unload(dtp, dmp);
 
-#if defined(sun)
+#ifdef illumos
 	/*
 	 * Open /system/object and attempt to create a libdtrace module for
 	 * each kernel module that is loaded on the current system.
@@ -1090,11 +1329,11 @@
 	dt_idhash_lookup(dtp->dt_macros, "pid")->di_id = getpid();
 	dt_idhash_lookup(dtp->dt_macros, "pgid")->di_id = getpgid(0);
 	dt_idhash_lookup(dtp->dt_macros, "ppid")->di_id = getppid();
-#if defined(sun)
+#ifdef illumos
 	dt_idhash_lookup(dtp->dt_macros, "projid")->di_id = getprojid();
 #endif
 	dt_idhash_lookup(dtp->dt_macros, "sid")->di_id = getsid(0);
-#if defined(sun)
+#ifdef illumos
 	dt_idhash_lookup(dtp->dt_macros, "taskid")->di_id = gettaskid();
 #endif
 	dt_idhash_lookup(dtp->dt_macros, "uid")->di_id = getuid();
@@ -1294,8 +1533,10 @@
 	dt_module_t *dmp;
 	int found = 0;
 	ctf_id_t id;
-	uint_t n;
+	uint_t n, i;
 	int justone;
+	ctf_file_t *fp;
+	char *buf, *p, *q;
 
 	uint_t mask = 0; /* mask of dt_module flags to match */
 	uint_t bits = 0; /* flag bits that must be present */
@@ -1310,7 +1551,6 @@
 			return (-1); /* dt_errno is set for us */
 		n = 1;
 		justone = 1;
-
 	} else {
 		if (object == DTRACE_OBJ_KMODS)
 			mask = bits = DT_DM_KERNEL;
@@ -1334,7 +1574,7 @@
 		 * module.  If our search was scoped to only one module then
 		 * return immediately leaving dt_errno unmodified.
 		 */
-		if (dt_module_getctf(dtp, dmp) == NULL) {
+		if (dt_module_hasctf(dtp, dmp) == 0) {
 			if (justone)
 				return (-1);
 			continue;
@@ -1346,13 +1586,38 @@
 		 * 'tip' and keep going in the hope that we will locate the
 		 * underlying structure definition.  Otherwise just return.
 		 */
-		if ((id = ctf_lookup_by_name(dmp->dm_ctfp, name)) != CTF_ERR) {
+		if (dmp->dm_pid == 0) {
+			id = ctf_lookup_by_name(dmp->dm_ctfp, name);
+			fp = dmp->dm_ctfp;
+		} else {
+			if ((p = strchr(name, '`')) != NULL) {
+				buf = strdup(name);
+				if (buf == NULL)
+					return (dt_set_errno(dtp, EDT_NOMEM));
+				p = strchr(buf, '`');
+				if ((q = strchr(p + 1, '`')) != NULL)
+					p = q;
+				*p = '\0';
+				fp = dt_module_getctflib(dtp, dmp, buf);
+				if (fp == NULL || (id = ctf_lookup_by_name(fp,
+				    p + 1)) == CTF_ERR)
+					id = CTF_ERR;
+				free(buf);
+			} else {
+				for (i = 0; i < dmp->dm_nctflibs; i++) {
+					fp = dmp->dm_libctfp[i];
+					id = ctf_lookup_by_name(fp, name);
+					if (id != CTF_ERR)
+						break;
+				}
+			}
+		}
+		if (id != CTF_ERR) {
 			tip->dtt_object = dmp->dm_name;
-			tip->dtt_ctfp = dmp->dm_ctfp;
+			tip->dtt_ctfp = fp;
 			tip->dtt_type = id;
-
-			if (ctf_type_kind(dmp->dm_ctfp, ctf_type_resolve(
-			    dmp->dm_ctfp, id)) != CTF_K_FORWARD)
+			if (ctf_type_kind(fp, ctf_type_resolve(fp, id)) !=
+			    CTF_K_FORWARD)
 				return (0);
 
 			found++;
@@ -1374,6 +1639,7 @@
 	tip->dtt_object = NULL;
 	tip->dtt_ctfp = NULL;
 	tip->dtt_type = CTF_ERR;
+	tip->dtt_flags = 0;
 
 	if ((dmp = dt_module_lookup_by_name(dtp, sip->dts_object)) == NULL)
 		return (dt_set_errno(dtp, EDT_NOMOD));

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -23,12 +24,13 @@
  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
+ */
 
 #ifndef	_DT_MODULE_H
 #define	_DT_MODULE_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <dt_impl.h>
 
 #ifdef	__cplusplus
@@ -43,11 +45,16 @@
 extern dt_module_t *dt_module_lookup_by_name(dtrace_hdl_t *, const char *);
 extern dt_module_t *dt_module_lookup_by_ctf(dtrace_hdl_t *, ctf_file_t *);
 
+extern int dt_module_hasctf(dtrace_hdl_t *, dt_module_t *);
 extern ctf_file_t *dt_module_getctf(dtrace_hdl_t *, dt_module_t *);
 extern dt_ident_t *dt_module_extern(dtrace_hdl_t *, dt_module_t *,
     const char *, const dtrace_typeinfo_t *);
 
 extern const char *dt_module_modelname(dt_module_t *);
+extern int dt_module_getlibid(dtrace_hdl_t *, dt_module_t *,
+    const ctf_file_t *);
+extern ctf_file_t *dt_module_getctflib(dtrace_hdl_t *, dt_module_t *,
+    const char *);
 
 #ifdef	__cplusplus
 }

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -21,12 +22,12 @@
 
 /*
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, Joyent, Inc. All rights reserved.
- * Copyright (c) 2011 by Delphix. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
  */
 
 #include <sys/types.h>
-#if defined(sun)
+#ifdef illumos
 #include <sys/modctl.h>
 #include <sys/systeminfo.h>
 #endif
@@ -34,7 +35,7 @@
 
 #include <libelf.h>
 #include <strings.h>
-#if defined(sun)
+#ifdef illumos
 #include <alloca.h>
 #endif
 #include <limits.h>
@@ -55,7 +56,7 @@
 #include <dt_printf.h>
 #include <dt_string.h>
 #include <dt_provider.h>
-#if !defined(sun)
+#ifndef illumos
 #include <sys/sysctl.h>
 #include <string.h>
 #endif
@@ -92,7 +93,7 @@
 
 /*
  * The version number should be increased for every customer visible release
- * of Solaris. The major number should be incremented when a fundamental
+ * of DTrace. The major number should be incremented when a fundamental
  * change has been made that would affect all consumers, and would reflect
  * sweeping changes to DTrace or the D language. The minor number should be
  * incremented when a change is introduced that could break scripts that had
@@ -121,8 +122,13 @@
 #define	DT_VERS_1_8	DT_VERSION_NUMBER(1, 8, 0)
 #define	DT_VERS_1_8_1	DT_VERSION_NUMBER(1, 8, 1)
 #define	DT_VERS_1_9	DT_VERSION_NUMBER(1, 9, 0)
-#define	DT_VERS_LATEST	DT_VERS_1_9
-#define	DT_VERS_STRING	"Sun D 1.9"
+#define	DT_VERS_1_9_1	DT_VERSION_NUMBER(1, 9, 1)
+#define	DT_VERS_1_10	DT_VERSION_NUMBER(1, 10, 0)
+#define	DT_VERS_1_11	DT_VERSION_NUMBER(1, 11, 0)
+#define	DT_VERS_1_12	DT_VERSION_NUMBER(1, 12, 0)
+#define	DT_VERS_1_12_1	DT_VERSION_NUMBER(1, 12, 1)
+#define	DT_VERS_LATEST	DT_VERS_1_12_1
+#define	DT_VERS_STRING	"Sun D 1.12.1"
 
 const dt_version_t _dtrace_versions[] = {
 	DT_VERS_1_0,	/* D API 1.0.0 (PSARC 2001/466) Solaris 10 FCS */
@@ -143,6 +149,11 @@
 	DT_VERS_1_8,	/* D API 1.8 */
 	DT_VERS_1_8_1,	/* D API 1.8.1 */
 	DT_VERS_1_9,	/* D API 1.9 */
+	DT_VERS_1_9_1,	/* D API 1.9.1 */
+	DT_VERS_1_10,	/* D API 1.10 */
+	DT_VERS_1_11,	/* D API 1.11 */
+	DT_VERS_1_12,	/* D API 1.12 */
+	DT_VERS_1_12_1,	/* D API 1.12.1 */
 	0
 };
 
@@ -149,7 +160,7 @@
 /*
  * Global variables that are formatted on FreeBSD based on the kernel file name.
  */
-#if !defined(sun)
+#ifndef illumos
 static char	curthread_str[MAXPATHLEN];
 static char	intmtx_str[MAXPATHLEN];
 static char	threadmtx_str[MAXPATHLEN];
@@ -231,7 +242,7 @@
 { "curthread", DT_IDENT_SCALAR, 0, DIF_VAR_CURTHREAD,
 	{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_PRIVATE,
 	DTRACE_CLASS_COMMON }, DT_VERS_1_0,
-#if defined(sun)
+#ifdef illumos
 	&dt_idops_type, "genunix`kthread_t *" },
 #else
 	&dt_idops_type, curthread_str },
@@ -273,6 +284,8 @@
 	&dt_idops_func, "uint64_t(uint64_t)" },
 { "htons", DT_IDENT_FUNC, 0, DIF_SUBR_HTONS, DT_ATTR_EVOLCMN, DT_VERS_1_3,
 	&dt_idops_func, "uint16_t(uint16_t)" },
+{ "getf", DT_IDENT_FUNC, 0, DIF_SUBR_GETF, DT_ATTR_STABCMN, DT_VERS_1_10,
+	&dt_idops_func, "file_t *(int)" },
 { "gid", DT_IDENT_SCALAR, 0, DIF_VAR_GID, DT_ATTR_STABCMN, DT_VERS_1_0,
 	&dt_idops_type, "gid_t" },
 { "id", DT_IDENT_SCALAR, 0, DIF_VAR_ID, DT_ATTR_STABCMN, DT_VERS_1_0,
@@ -280,13 +293,13 @@
 { "index", DT_IDENT_FUNC, 0, DIF_SUBR_INDEX, DT_ATTR_STABCMN, DT_VERS_1_1,
 	&dt_idops_func, "int(const char *, const char *, [int])" },
 { "inet_ntoa", DT_IDENT_FUNC, 0, DIF_SUBR_INET_NTOA, DT_ATTR_STABCMN,
-#if defined(sun)
+#ifdef illumos
 	DT_VERS_1_5, &dt_idops_func, "string(ipaddr_t *)" },
 #else
 	DT_VERS_1_5, &dt_idops_func, "string(in_addr_t *)" },
 #endif
 { "inet_ntoa6", DT_IDENT_FUNC, 0, DIF_SUBR_INET_NTOA6, DT_ATTR_STABCMN,
-#if defined(sun)
+#ifdef illumos
 	DT_VERS_1_5, &dt_idops_func, "string(in6_addr_t *)" },
 #else
 	DT_VERS_1_5, &dt_idops_func, "string(struct in6_addr *)" },
@@ -295,6 +308,8 @@
 	DT_VERS_1_5, &dt_idops_func, "string(int, void *)" },
 { "ipl", DT_IDENT_SCALAR, 0, DIF_VAR_IPL, DT_ATTR_STABCMN, DT_VERS_1_0,
 	&dt_idops_type, "uint_t" },
+{ "json", DT_IDENT_FUNC, 0, DIF_SUBR_JSON, DT_ATTR_STABCMN, DT_VERS_1_11,
+	&dt_idops_func, "string(const char *, const char *)" },
 { "jstack", DT_IDENT_ACTFUNC, 0, DT_ACT_JSTACK, DT_ATTR_STABCMN, DT_VERS_1_0,
 	&dt_idops_func, "stack(...)" },
 { "lltostr", DT_IDENT_FUNC, 0, DIF_SUBR_LLTOSTR, DT_ATTR_STABCMN, DT_VERS_1_0,
@@ -309,6 +324,10 @@
 	&dt_idops_func, "void(@)" },
 { "memref", DT_IDENT_FUNC, 0, DIF_SUBR_MEMREF, DT_ATTR_STABCMN, DT_VERS_1_1,
 	&dt_idops_func, "uintptr_t *(void *, size_t)" },
+#ifndef illumos
+{ "memstr", DT_IDENT_FUNC, 0, DIF_SUBR_MEMSTR, DT_ATTR_STABCMN, DT_VERS_1_0,
+	&dt_idops_func, "string(void *, char, size_t)" },
+#endif
 { "min", DT_IDENT_AGGFUNC, 0, DTRACEAGG_MIN, DT_ATTR_STABCMN, DT_VERS_1_0,
 	&dt_idops_func, "void(@)" },
 { "mod", DT_IDENT_ACTFUNC, 0, DT_ACT_MOD, DT_ATTR_STABCMN,
@@ -319,7 +338,7 @@
 { "msgsize", DT_IDENT_FUNC, 0, DIF_SUBR_MSGSIZE,
 	DT_ATTR_STABCMN, DT_VERS_1_0,
 	&dt_idops_func, "size_t(mblk_t *)" },
-#if defined(sun)
+#ifdef illumos
 { "mutex_owned", DT_IDENT_FUNC, 0, DIF_SUBR_MUTEX_OWNED,
 	DT_ATTR_EVOLCMN, DT_VERS_1_0,
 	&dt_idops_func, "int(genunix`kmutex_t *)" },
@@ -390,7 +409,7 @@
 	&dt_idops_func, "int()" },
 { "rindex", DT_IDENT_FUNC, 0, DIF_SUBR_RINDEX, DT_ATTR_STABCMN, DT_VERS_1_1,
 	&dt_idops_func, "int(const char *, const char *, [int])" },
-#if defined(sun)
+#ifdef illumos
 { "rw_iswriter", DT_IDENT_FUNC, 0, DIF_SUBR_RW_ISWRITER,
 	DT_ATTR_EVOLCMN, DT_VERS_1_0,
 	&dt_idops_func, "int(genunix`krwlock_t *)" },
@@ -442,11 +461,13 @@
 	&dt_idops_func, "string(const char *, const char *)" },
 { "strtok", DT_IDENT_FUNC, 0, DIF_SUBR_STRTOK, DT_ATTR_STABCMN, DT_VERS_1_1,
 	&dt_idops_func, "string(const char *, const char *)" },
+{ "strtoll", DT_IDENT_FUNC, 0, DIF_SUBR_STRTOLL, DT_ATTR_STABCMN, DT_VERS_1_11,
+	&dt_idops_func, "int64_t(const char *, [int])" },
 { "substr", DT_IDENT_FUNC, 0, DIF_SUBR_SUBSTR, DT_ATTR_STABCMN, DT_VERS_1_1,
 	&dt_idops_func, "string(const char *, int, [int])" },
 { "sum", DT_IDENT_AGGFUNC, 0, DTRACEAGG_SUM, DT_ATTR_STABCMN, DT_VERS_1_0,
 	&dt_idops_func, "void(@)" },
-#if !defined(sun)
+#ifndef illumos
 { "sx_isexclusive", DT_IDENT_FUNC, 0, DIF_SUBR_SX_ISEXCLUSIVE,
 	DT_ATTR_EVOLCMN, DT_VERS_1_0,
 	&dt_idops_func, sxlock_str },
@@ -481,22 +502,16 @@
 	DT_VERS_1_0, &dt_idops_func, "void(...)" },
 { "typeref", DT_IDENT_FUNC, 0, DIF_SUBR_TYPEREF, DT_ATTR_STABCMN, DT_VERS_1_1,
 	&dt_idops_func, "uintptr_t *(void *, size_t, string, size_t)" },
-#if defined(sun)
 { "uaddr", DT_IDENT_ACTFUNC, 0, DT_ACT_UADDR, DT_ATTR_STABCMN,
 	DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
-#endif
 { "ucaller", DT_IDENT_SCALAR, 0, DIF_VAR_UCALLER, DT_ATTR_STABCMN,
 	DT_VERS_1_2, &dt_idops_type, "uint64_t" },
-#if defined(sun)
 { "ufunc", DT_IDENT_ACTFUNC, 0, DT_ACT_USYM, DT_ATTR_STABCMN,
 	DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
-#endif
 { "uid", DT_IDENT_SCALAR, 0, DIF_VAR_UID, DT_ATTR_STABCMN, DT_VERS_1_0,
 	&dt_idops_type, "uid_t" },
-#if defined(sun)
 { "umod", DT_IDENT_ACTFUNC, 0, DT_ACT_UMOD, DT_ATTR_STABCMN,
 	DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
-#endif
 { "uregs", DT_IDENT_ARRAY, 0, DIF_VAR_UREGS, DT_ATTR_STABCMN, DT_VERS_1_0,
 	&dt_idops_regs, NULL },
 { "ustack", DT_IDENT_ACTFUNC, 0, DT_ACT_USTACK, DT_ATTR_STABCMN, DT_VERS_1_0,
@@ -504,10 +519,8 @@
 { "ustackdepth", DT_IDENT_SCALAR, 0, DIF_VAR_USTACKDEPTH,
 	DT_ATTR_STABCMN, DT_VERS_1_2,
 	&dt_idops_type, "uint32_t" },
-#if defined(sun)
 { "usym", DT_IDENT_ACTFUNC, 0, DT_ACT_USYM, DT_ATTR_STABCMN,
 	DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
-#endif
 { "vtimestamp", DT_IDENT_SCALAR, 0, DIF_VAR_VTIMESTAMP,
 	DT_ATTR_STABCMN, DT_VERS_1_0,
 	&dt_idops_type, "uint64_t" },
@@ -514,12 +527,12 @@
 { "walltimestamp", DT_IDENT_SCALAR, 0, DIF_VAR_WALLTIMESTAMP,
 	DT_ATTR_STABCMN, DT_VERS_1_0,
 	&dt_idops_type, "int64_t" },
-#if defined(sun)
+#ifdef illumos
 { "zonename", DT_IDENT_SCALAR, 0, DIF_VAR_ZONENAME,
 	DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" },
 #endif
 
-#if !defined(sun)
+#ifndef illumos
 { "cpu", DT_IDENT_SCALAR, 0, DIF_VAR_CPU,
 	DT_ATTR_STABCMN, DT_VERS_1_6_3, &dt_idops_type, "int" },
 #endif
@@ -763,7 +776,7 @@
 { DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_COMMON },
 };
 
-#if defined(sun)
+#ifdef illumos
 const char *_dtrace_defcpp = "/usr/ccs/lib/cpp"; /* default cpp(1) to invoke */
 const char *_dtrace_defld = "/usr/ccs/bin/ld";   /* default ld(1) to invoke */
 #else
@@ -772,7 +785,7 @@
 #endif
 
 const char *_dtrace_libdir = "/usr/lib/dtrace"; /* default library directory */
-#if defined(sun)
+#ifdef illumos
 const char *_dtrace_provdir = "/dev/dtrace/provider"; /* provider directory */
 #else
 const char *_dtrace_provdir = "/dev/dtrace"; /* provider directory */
@@ -797,7 +810,7 @@
 	uint_t df_size;		/* size of df_fds[] */
 } dt_fdlist_t;
 
-#if defined(sun)
+#ifdef illumos
 #pragma init(_dtrace_init)
 #else
 void _dtrace_init(void) __attribute__ ((constructor));
@@ -833,7 +846,7 @@
 	dt_provmod_t *prov;
 	char path[PATH_MAX];
 	int fd;
-#if defined(sun)
+#ifdef illumos
 	struct dirent *dp, *ep;
 	DIR *dirp;
 
@@ -880,7 +893,7 @@
 	}
 
 	(void) closedir(dirp);
-#else
+#else	/* !illumos */
 	char	*p;
 	char	*p1;
 	char	*p_providers = NULL;
@@ -965,7 +978,7 @@
 	}
 	if (p_providers != NULL)
 		free(p_providers);
-#endif
+#endif	/* illumos */
 }
 
 static void
@@ -982,7 +995,7 @@
 	*provmod = NULL;
 }
 
-#if defined(sun)
+#ifdef illumos
 static const char *
 dt_get_sysinfo(int cmd, char *buf, size_t len)
 {
@@ -1084,8 +1097,18 @@
 
 	dtfd = open("/dev/dtrace/dtrace", O_RDWR);
 	err = errno; /* save errno from opening dtfd */
-
-#if defined(sun)
+#if defined(__FreeBSD__)
+	/*
+	 * Automatically load the 'dtraceall' module if we couldn't open the
+	 * char device.
+	 */
+	if (err == ENOENT && modfind("dtraceall") < 0) {
+		kldload("dtraceall"); /* ignore the error */
+		dtfd = open("/dev/dtrace/dtrace", O_RDWR);
+		err = errno;
+	}
+#endif
+#ifdef illumos
 	ftfd = open("/dev/dtrace/provider/fasttrap", O_RDWR);
 #else
 	ftfd = open("/dev/dtrace/fasttrap", O_RDWR);
@@ -1127,15 +1150,16 @@
 
 	bzero(dtp, sizeof (dtrace_hdl_t));
 	dtp->dt_oflags = flags;
-#if defined(sun)
+#ifdef illumos
 	dtp->dt_prcmode = DT_PROC_STOP_PREINIT;
 #else
-	dtp->dt_prcmode = DT_PROC_STOP_MAIN;
+	dtp->dt_prcmode = DT_PROC_STOP_POSTINIT;
 #endif
 	dtp->dt_linkmode = DT_LINK_KERNEL;
 	dtp->dt_linktype = DT_LTYP_ELF;
 	dtp->dt_xlatemode = DT_XL_STATIC;
 	dtp->dt_stdcmode = DT_STDC_XA;
+	dtp->dt_encoding = DT_ENCODING_UNSET;
 	dtp->dt_version = version;
 	dtp->dt_fd = dtfd;
 	dtp->dt_ftfd = ftfd;
@@ -1142,7 +1166,7 @@
 	dtp->dt_fterr = fterr;
 	dtp->dt_cdefs_fd = -1;
 	dtp->dt_ddefs_fd = -1;
-#if defined(sun)
+#ifdef illumos
 	dtp->dt_stdout_fd = -1;
 #else
 	dtp->dt_freopen_fp = NULL;
@@ -1174,7 +1198,7 @@
 
 	dtp->dt_cpp_argv[0] = (char *)strbasename(dtp->dt_cpp_path);
 
-#if defined(sun)
+#ifdef illumos
 	(void) snprintf(isadef, sizeof (isadef), "-D__SUNW_D_%u",
 	    (uint_t)(sizeof (void *) * NBBY));
 
@@ -1214,7 +1238,7 @@
 		return (set_open_errno(dtp, errp, EDT_NOMEM));
 #endif
 
-#if defined(sun)
+#ifdef illumos
 #ifdef __x86
 	/*
 	 * On x86 systems, __i386 is defined for <sys/isa_defs.h> for 32-bit
@@ -1254,7 +1278,7 @@
 	 * 'kern.bootfile' sysctl value tells us exactly which file is being
 	 * used as the kernel.
 	 */
-#if !defined(sun)
+#ifndef illumos
 	{
 	char bootfile[MAXPATHLEN];
 	char *p;
@@ -1616,7 +1640,7 @@
 		(void) close(dtp->dt_cdefs_fd);
 	if (dtp->dt_ddefs_fd != -1)
 		(void) close(dtp->dt_ddefs_fd);
-#if defined(sun)
+#ifdef illumos
 	if (dtp->dt_stdout_fd != -1)
 		(void) close(dtp->dt_stdout_fd);
 #else
@@ -1630,7 +1654,6 @@
 	dt_strdata_destroy(dtp);
 	dt_buffered_destroy(dtp);
 	dt_aggregate_destroy(dtp);
-	free(dtp->dt_buf.dtbd_data);
 	dt_pfdict_destroy(dtp);
 	dt_provmod_destroy(&dtp->dt_provmod);
 	dt_dof_fini(dtp);

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_options.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_options.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_options.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -24,7 +25,10 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
 
 #include <sys/resource.h>
 #include <sys/mman.h>
@@ -35,7 +39,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <limits.h>
-#if defined(sun)
+#ifdef illumos
 #include <alloca.h>
 #endif
 #include <errno.h>
@@ -336,6 +340,23 @@
 
 /*ARGSUSED*/
 static int
+dt_opt_encoding(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+	if (arg == NULL)
+		return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+	if (strcmp(arg, "ascii") == 0)
+		dtp->dt_encoding = DT_ENCODING_ASCII;
+	else if (strcmp(arg, "utf8") == 0)
+		dtp->dt_encoding = DT_ENCODING_UTF8;
+	else
+		return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+	return (0);
+}
+
+/*ARGSUSED*/
+static int
 dt_opt_evaltime(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 {
 	if (arg == NULL)
@@ -368,6 +389,61 @@
 	return (0);
 }
 
+static int
+dt_opt_setenv(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+	char **p;
+	char *var;
+	int i;
+
+	/*
+	 * We can't effectively set environment variables from #pragma lines
+	 * since the processes have already been spawned.
+	 */
+	if (dtp->dt_pcb != NULL)
+		return (dt_set_errno(dtp, EDT_BADOPTCTX));
+
+	if (arg == NULL)
+		return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+	if (!option && strchr(arg, '=') != NULL)
+		return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+	for (i = 1, p = dtp->dt_proc_env; *p != NULL; i++, p++)
+		continue;
+
+	for (p = dtp->dt_proc_env; *p != NULL; p++) {
+		var = strchr(*p, '=');
+		if (var == NULL)
+			var = *p + strlen(*p);
+		if (strncmp(*p, arg, var - *p) == 0) {
+			dt_free(dtp, *p);
+			*p = dtp->dt_proc_env[i - 1];
+			dtp->dt_proc_env[i - 1] = NULL;
+			i--;
+		}
+	}
+
+	if (option) {
+		if ((var = strdup(arg)) == NULL)
+			return (dt_set_errno(dtp, EDT_NOMEM));
+
+		if ((p = dt_alloc(dtp, sizeof (char *) * (i + 1))) == NULL) {
+			dt_free(dtp, var);
+			return (dt_set_errno(dtp, EDT_NOMEM));
+		}
+
+		bcopy(dtp->dt_proc_env, p, sizeof (char *) * i);
+		dt_free(dtp, dtp->dt_proc_env);
+		dtp->dt_proc_env = p;
+
+		dtp->dt_proc_env[i - 1] = var;
+		dtp->dt_proc_env[i] = NULL;
+	}
+
+	return (0);
+}
+
 /*ARGSUSED*/
 static int
 dt_opt_stdc(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
@@ -411,7 +487,6 @@
 	return (0);
 }
 
-
 /*ARGSUSED*/
 static int
 dt_opt_tree(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
@@ -797,7 +872,7 @@
 	bzero(&hdr, sizeof (dof_hdr_t));
 	hdr.dofh_loadsz = sizeof (dof_hdr_t);
 
-#if defined(sun)
+#ifdef illumos
 	if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &hdr) == -1)
 #else
 	dof = &hdr;
@@ -815,7 +890,7 @@
 	for (i = 0; i < DTRACEOPT_MAX; i++)
 		dtp->dt_options[i] = DTRACEOPT_UNSET;
 
-#if defined(sun)
+#ifdef illumos
 	if (dt_ioctl(dtp, DTRACEIOC_DOFGET, dof) == -1)
 #else
 	if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &dof) == -1)
@@ -848,30 +923,6 @@
 	return (0);
 }
 
-/*ARGSUSED*/
-static int
-dt_opt_preallocate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
-{
-	dtrace_optval_t size;
-	void *p;
-
-	if (arg == NULL || dt_optval_parse(arg, &size) != 0)
-		return (dt_set_errno(dtp, EDT_BADOPTVAL));
-
-	if (size > SIZE_MAX)
-		size = SIZE_MAX;
-
-	if ((p = dt_zalloc(dtp, size)) == NULL) {
-		do {
-			size /= 2;
-		} while ((p = dt_zalloc(dtp, size)) == NULL);
-	}
-
-	dt_free(dtp, p);
-
-	return (0);
-}
-
 typedef struct dt_option {
 	const char *o_name;
 	int (*o_func)(dtrace_hdl_t *, const char *, uintptr_t);
@@ -896,6 +947,7 @@
 	{ "define", dt_opt_cpp_opts, (uintptr_t)"-D" },
 	{ "droptags", dt_opt_droptags },
 	{ "empty", dt_opt_cflags, DTRACE_C_EMPTY },
+	{ "encoding", dt_opt_encoding },
 	{ "errtags", dt_opt_cflags, DTRACE_C_ETAGS },
 	{ "evaltime", dt_opt_evaltime },
 	{ "incdir", dt_opt_cpp_opts, (uintptr_t)"-I" },
@@ -910,8 +962,8 @@
 	{ "linktype", dt_opt_linktype },
 	{ "nolibs", dt_opt_cflags, DTRACE_C_NOLIBS },
 	{ "pgmax", dt_opt_pgmax },
-	{ "preallocate", dt_opt_preallocate },
 	{ "pspec", dt_opt_cflags, DTRACE_C_PSPEC },
+	{ "setenv", dt_opt_setenv, 1 },
 	{ "stdc", dt_opt_stdc },
 	{ "strip", dt_opt_dflags, DTRACE_D_STRIP },
 	{ "syslibdir", dt_opt_syslibdir },
@@ -920,6 +972,7 @@
 	{ "udefs", dt_opt_invcflags, DTRACE_C_UNODEF },
 	{ "undef", dt_opt_cpp_opts, (uintptr_t)"-U" },
 	{ "unodefs", dt_opt_cflags, DTRACE_C_UNODEF },
+	{ "unsetenv", dt_opt_setenv, 0 },
 	{ "verbose", dt_opt_cflags, DTRACE_C_DIFV },
 	{ "version", dt_opt_version },
 	{ "zdefs", dt_opt_cflags, DTRACE_C_ZDEFS },
@@ -947,6 +1000,7 @@
 	{ "statusrate", dt_opt_rate, DTRACEOPT_STATUSRATE },
 	{ "strsize", dt_opt_strsize, DTRACEOPT_STRSIZE },
 	{ "ustackframes", dt_opt_runtime, DTRACEOPT_USTACKFRAMES },
+	{ "temporal", dt_opt_runtime, DTRACEOPT_TEMPORAL },
 	{ NULL, NULL, 0 }
 };
 
@@ -954,11 +1008,14 @@
  * Dynamic run-time options.
  */
 static const dt_option_t _dtrace_drtoptions[] = {
+	{ "agghist", dt_opt_runtime, DTRACEOPT_AGGHIST },
+	{ "aggpack", dt_opt_runtime, DTRACEOPT_AGGPACK },
 	{ "aggrate", dt_opt_rate, DTRACEOPT_AGGRATE },
 	{ "aggsortkey", dt_opt_runtime, DTRACEOPT_AGGSORTKEY },
 	{ "aggsortkeypos", dt_opt_runtime, DTRACEOPT_AGGSORTKEYPOS },
 	{ "aggsortpos", dt_opt_runtime, DTRACEOPT_AGGSORTPOS },
 	{ "aggsortrev", dt_opt_runtime, DTRACEOPT_AGGSORTREV },
+	{ "aggzoom", dt_opt_runtime, DTRACEOPT_AGGZOOM },
 	{ "flowindent", dt_opt_runtime, DTRACEOPT_FLOWINDENT },
 	{ "quiet", dt_opt_runtime, DTRACEOPT_QUIET },
 	{ "rawbytes", dt_opt_runtime, DTRACEOPT_RAWBYTES },

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -22,7 +23,8 @@
 
 /*
  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
- * Copyright (c) 2011, Joyent Inc. All rights reserved.
+ * Copyright (c) 2013, Joyent Inc. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
  */
 
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
@@ -96,11 +98,12 @@
  */
 
 #include <sys/param.h>
+#include <sys/sysmacros.h>
 #include <limits.h>
 #include <setjmp.h>
 #include <strings.h>
 #include <assert.h>
-#if defined(sun)
+#ifdef illumos
 #include <alloca.h>
 #endif
 #include <stdlib.h>
@@ -195,7 +198,7 @@
 {
 	static const char delimiters[] = " \t\n\r\v\f*`";
 	dtrace_hdl_t *dtp = yypcb->pcb_hdl;
-	const char *p, *q, *end, *obj;
+	const char *p, *q, *r, *end, *obj;
 
 	for (p = s, end = s + strlen(s); *p != '\0'; p = q) {
 		while (isspace(*p))
@@ -223,8 +226,23 @@
 			bcopy(s, type, (size_t)(p - s));
 			bcopy(q + 1, type + (size_t)(p - s), strlen(q + 1) + 1);
 
-			if (strchr(q + 1, '`') != NULL)
-				return (dt_set_errno(dtp, EDT_BADSCOPE));
+			/*
+			 * There may be at most three delimeters. The second
+			 * delimeter is usually used to distinguish the type
+			 * within a given module, however, there could be a link
+			 * map id on the scene in which case that delimeter
+			 * would be the third. We determine presence of the lmid
+			 * if it rouglhly meets the from LM[0-9]
+			 */
+			if ((r = strchr(q + 1, '`')) != NULL &&
+			    ((r = strchr(r + 1, '`')) != NULL)) {
+				if (strchr(r + 1, '`') != NULL)
+					return (dt_set_errno(dtp,
+					    EDT_BADSCOPE));
+				if (q[1] != 'L' || q[2] != 'M')
+					return (dt_set_errno(dtp,
+					    EDT_BADSCOPE));
+			}
 
 			return (dtrace_lookup_by_type(dtp, object, type, tip));
 		}
@@ -254,6 +272,7 @@
 	ctf_file_t *ctfp = tip->dtt_ctfp;
 	ctf_id_t type = tip->dtt_type;
 	ctf_id_t base = ctf_type_resolve(ctfp, type);
+	uint_t bflags = tip->dtt_flags;
 
 	dt_module_t *dmp;
 	ctf_id_t ptr;
@@ -285,6 +304,7 @@
 	tip->dtt_object = dmp->dm_name;
 	tip->dtt_ctfp = dmp->dm_ctfp;
 	tip->dtt_type = ptr;
+	tip->dtt_flags = bflags;
 
 	return (0);
 }
@@ -388,7 +408,7 @@
 dt_node_promote(dt_node_t *lp, dt_node_t *rp, dt_node_t *dnp)
 {
 	dt_type_promote(lp, rp, &dnp->dn_ctfp, &dnp->dn_type);
-	dt_node_type_assign(dnp, dnp->dn_ctfp, dnp->dn_type);
+	dt_node_type_assign(dnp, dnp->dn_ctfp, dnp->dn_type, B_FALSE);
 	dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr));
 }
 
@@ -657,7 +677,8 @@
 }
 
 void
-dt_node_type_assign(dt_node_t *dnp, ctf_file_t *fp, ctf_id_t type)
+dt_node_type_assign(dt_node_t *dnp, ctf_file_t *fp, ctf_id_t type,
+    boolean_t user)
 {
 	ctf_id_t base = ctf_type_resolve(fp, type);
 	uint_t kind = ctf_type_kind(fp, base);
@@ -689,6 +710,9 @@
 	    type == DT_DYN_TYPE(yypcb->pcb_hdl))
 		dnp->dn_flags |= DT_NF_REF;
 
+	if (user)
+		dnp->dn_flags |= DT_NF_USERLAND;
+
 	dnp->dn_flags |= DT_NF_COOKED;
 	dnp->dn_ctfp = fp;
 	dnp->dn_type = type;
@@ -726,6 +750,7 @@
 dt_node_type_size(const dt_node_t *dnp)
 {
 	ctf_id_t base;
+	dtrace_hdl_t *dtp = yypcb->pcb_hdl;
 
 	if (dnp->dn_kind == DT_NODE_STRING)
 		return (strlen(dnp->dn_string) + 1);
@@ -738,6 +763,20 @@
 	if (ctf_type_kind(dnp->dn_ctfp, base) == CTF_K_FORWARD)
 		return (0);
 
+	/*
+	 * Here we have a 32-bit user pointer that is being used with a 64-bit
+	 * kernel. When we're using it and its tagged as a userland reference --
+	 * then we need to keep it as a 32-bit pointer. However, if we are
+	 * referring to it as a kernel address, eg. being used after a copyin()
+	 * then we need to make sure that we actually return the kernel's size
+	 * of a pointer, 8 bytes.
+	 */
+	if (ctf_type_kind(dnp->dn_ctfp, base) == CTF_K_POINTER &&
+	    ctf_getmodel(dnp->dn_ctfp) == CTF_MODEL_ILP32 &&
+	    !(dnp->dn_flags & DT_NF_USERLAND) &&
+	    dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64)
+			return (8);
+
 	return (ctf_type_size(dnp->dn_ctfp, dnp->dn_type));
 }
 
@@ -1224,7 +1263,7 @@
 		if (value <= dtp->dt_ints[i].did_limit) {
 			dt_node_type_assign(dnp,
 			    dtp->dt_ints[i].did_ctfp,
-			    dtp->dt_ints[i].did_type);
+			    dtp->dt_ints[i].did_type, B_FALSE);
 
 			/*
 			 * If a prefix character is present in macro text, add
@@ -1259,7 +1298,7 @@
 	dnp = dt_node_alloc(DT_NODE_STRING);
 	dnp->dn_op = DT_TOK_STRING;
 	dnp->dn_string = string;
-	dt_node_type_assign(dnp, DT_STR_CTFP(dtp), DT_STR_TYPE(dtp));
+	dt_node_type_assign(dnp, DT_STR_CTFP(dtp), DT_STR_TYPE(dtp), B_FALSE);
 
 	return (dnp);
 }
@@ -1335,8 +1374,9 @@
 	dnp = dt_node_alloc(DT_NODE_TYPE);
 	dnp->dn_op = DT_TOK_IDENT;
 	dnp->dn_string = name;
-	dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type);
 
+	dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type, dtt.dtt_flags);
+
 	if (dtt.dtt_ctfp == dtp->dt_cdefs->dm_ctfp ||
 	    dtt.dtt_ctfp == dtp->dt_ddefs->dm_ctfp)
 		dt_node_attr_assign(dnp, _dtrace_defattr);
@@ -1579,7 +1619,8 @@
 		bzero(&idn, sizeof (dt_node_t));
 
 		if (idp != NULL && idp->di_type != CTF_ERR)
-			dt_node_type_assign(&idn, idp->di_ctfp, idp->di_type);
+			dt_node_type_assign(&idn, idp->di_ctfp, idp->di_type,
+			    B_FALSE);
 		else if (idp != NULL)
 			(void) dt_ident_cook(&idn, idp, NULL);
 
@@ -1789,7 +1830,7 @@
 	}
 
 	bzero(&dn, sizeof (dn));
-	dt_node_type_assign(&dn, dtt.dtt_ctfp, ctm.ctm_type);
+	dt_node_type_assign(&dn, dtt.dtt_ctfp, ctm.ctm_type, B_FALSE);
 
 	if (dn.dn_flags & DT_NF_BITFIELD) {
 		xyerror(D_OFFSETOF_BITFIELD,
@@ -1845,7 +1886,8 @@
 		}
 
 		dt_node_type_assign(cp, dtp->dt_ddefs->dm_ctfp,
-		    ctf_lookup_by_name(dtp->dt_ddefs->dm_ctfp, "size_t"));
+		    ctf_lookup_by_name(dtp->dt_ddefs->dm_ctfp, "size_t"),
+		    B_FALSE);
 
 		cp->dn_kind = DT_NODE_INT;
 		cp->dn_op = DT_TOK_INT;
@@ -1862,6 +1904,38 @@
 	return (dnp);
 }
 
+/*
+ * If an integer constant is being cast to another integer type, we can
+ * perform the cast as part of integer constant folding in this pass. We must
+ * take action when the integer is being cast to a smaller type or if it is
+ * changing signed-ness. If so, we first shift rp's bits bits high (losing
+ * excess bits if narrowing) and then shift them down with either a logical
+ * shift (unsigned) or arithmetic shift (signed).
+ */
+static void
+dt_cast(dt_node_t *lp, dt_node_t *rp)
+{
+	size_t srcsize = dt_node_type_size(rp);
+	size_t dstsize = dt_node_type_size(lp);
+
+	if (dstsize < srcsize) {
+		int n = (sizeof (uint64_t) - dstsize) * NBBY;
+		rp->dn_value <<= n;
+		rp->dn_value >>= n;
+	} else if (dstsize > srcsize) {
+		int n = (sizeof (uint64_t) - srcsize) * NBBY;
+		int s = (dstsize - srcsize) * NBBY;
+
+		rp->dn_value <<= n;
+		if (rp->dn_flags & DT_NF_SIGNED) {
+			rp->dn_value = (intmax_t)rp->dn_value >> s;
+			rp->dn_value >>= n - s;
+		} else {
+			rp->dn_value >>= n;
+		}
+	}
+}
+
 dt_node_t *
 dt_node_op2(int op, dt_node_t *lp, dt_node_t *rp)
 {
@@ -1891,17 +1965,17 @@
 		case DT_TOK_LOR:
 			dnp->dn_value = l || r;
 			dt_node_type_assign(dnp,
-			    DT_INT_CTFP(dtp), DT_INT_TYPE(dtp));
+			    DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE);
 			break;
 		case DT_TOK_LXOR:
 			dnp->dn_value = (l != 0) ^ (r != 0);
 			dt_node_type_assign(dnp,
-			    DT_INT_CTFP(dtp), DT_INT_TYPE(dtp));
+			    DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE);
 			break;
 		case DT_TOK_LAND:
 			dnp->dn_value = l && r;
 			dt_node_type_assign(dnp,
-			    DT_INT_CTFP(dtp), DT_INT_TYPE(dtp));
+			    DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE);
 			break;
 		case DT_TOK_BOR:
 			dnp->dn_value = l | r;
@@ -1918,12 +1992,12 @@
 		case DT_TOK_EQU:
 			dnp->dn_value = l == r;
 			dt_node_type_assign(dnp,
-			    DT_INT_CTFP(dtp), DT_INT_TYPE(dtp));
+			    DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE);
 			break;
 		case DT_TOK_NEQ:
 			dnp->dn_value = l != r;
 			dt_node_type_assign(dnp,
-			    DT_INT_CTFP(dtp), DT_INT_TYPE(dtp));
+			    DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE);
 			break;
 		case DT_TOK_LT:
 			dt_node_promote(lp, rp, dnp);
@@ -1932,7 +2006,7 @@
 			else
 				dnp->dn_value = l < r;
 			dt_node_type_assign(dnp,
-			    DT_INT_CTFP(dtp), DT_INT_TYPE(dtp));
+			    DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE);
 			break;
 		case DT_TOK_LE:
 			dt_node_promote(lp, rp, dnp);
@@ -1941,7 +2015,7 @@
 			else
 				dnp->dn_value = l <= r;
 			dt_node_type_assign(dnp,
-			    DT_INT_CTFP(dtp), DT_INT_TYPE(dtp));
+			    DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE);
 			break;
 		case DT_TOK_GT:
 			dt_node_promote(lp, rp, dnp);
@@ -1950,7 +2024,7 @@
 			else
 				dnp->dn_value = l > r;
 			dt_node_type_assign(dnp,
-			    DT_INT_CTFP(dtp), DT_INT_TYPE(dtp));
+			    DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE);
 			break;
 		case DT_TOK_GE:
 			dt_node_promote(lp, rp, dnp);
@@ -1959,7 +2033,7 @@
 			else
 				dnp->dn_value = l >= r;
 			dt_node_type_assign(dnp,
-			    DT_INT_CTFP(dtp), DT_INT_TYPE(dtp));
+			    DT_INT_CTFP(dtp), DT_INT_TYPE(dtp), B_FALSE);
 			break;
 		case DT_TOK_LSH:
 			dnp->dn_value = l << r;
@@ -2011,32 +2085,9 @@
 		}
 	}
 
-	/*
-	 * If an integer constant is being cast to another integer type, we can
-	 * perform the cast as part of integer constant folding in this pass.
-	 * We must take action when the integer is being cast to a smaller type
-	 * or if it is changing signed-ness.  If so, we first shift rp's bits
-	 * bits high (losing excess bits if narrowing) and then shift them down
-	 * with either a logical shift (unsigned) or arithmetic shift (signed).
-	 */
 	if (op == DT_TOK_LPAR && rp->dn_kind == DT_NODE_INT &&
 	    dt_node_is_integer(lp)) {
-		size_t srcsize = dt_node_type_size(rp);
-		size_t dstsize = dt_node_type_size(lp);
-
-		if ((dstsize < srcsize) || ((lp->dn_flags & DT_NF_SIGNED) ^
-		    (rp->dn_flags & DT_NF_SIGNED))) {
-			int n = dstsize < srcsize ?
-			    (sizeof (uint64_t) * NBBY - dstsize * NBBY) :
-			    (sizeof (uint64_t) * NBBY - srcsize * NBBY);
-
-			rp->dn_value <<= n;
-			if (lp->dn_flags & DT_NF_SIGNED)
-				rp->dn_value = (intmax_t)rp->dn_value >> n;
-			else
-				rp->dn_value = rp->dn_value >> n;
-		}
-
+		dt_cast(lp, rp);
 		dt_node_type_propagate(lp, rp);
 		dt_node_attr_assign(rp, dt_attr_min(lp->dn_attr, rp->dn_attr));
 		dt_node_free(lp);
@@ -2223,7 +2274,7 @@
 	 * until we have successfully cooked the right-hand expression, below.
 	 */
 	dnp = dt_node_alloc(DT_NODE_INLINE);
-	dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type);
+	dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type, B_FALSE);
 	dt_node_attr_assign(dnp, _dtrace_defattr);
 
 	if (dt_node_is_void(dnp)) {
@@ -2378,7 +2429,8 @@
 	dnp->dn_membexpr = expr;
 
 	if (ddp != NULL)
-		dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type);
+		dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type,
+		    dtt.dtt_flags);
 
 	return (dnp);
 }
@@ -2409,10 +2461,10 @@
 	}
 
 	bzero(&sn, sizeof (sn));
-	dt_node_type_assign(&sn, src.dtt_ctfp, src.dtt_type);
+	dt_node_type_assign(&sn, src.dtt_ctfp, src.dtt_type, B_FALSE);
 
 	bzero(&dn, sizeof (dn));
-	dt_node_type_assign(&dn, dst.dtt_ctfp, dst.dtt_type);
+	dt_node_type_assign(&dn, dst.dtt_ctfp, dst.dtt_type, B_FALSE);
 
 	if (dt_xlator_lookup(dtp, &sn, &dn, DT_XLATE_EXACT) != NULL) {
 		xyerror(D_XLATE_REDECL,
@@ -2658,7 +2710,7 @@
 			attr = dt_ident_cook(dnp, idp, NULL);
 		else {
 			dt_node_type_assign(dnp,
-			    DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp));
+			    DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp), B_FALSE);
 			attr = idp->di_attr;
 		}
 
@@ -2734,7 +2786,8 @@
 		dnp->dn_ident = idp;
 		dnp->dn_flags |= DT_NF_LVALUE;
 
-		dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type);
+		dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type,
+		    dtt.dtt_flags);
 		dt_node_attr_assign(dnp, _dtrace_symattr);
 
 		if (uref) {
@@ -2782,7 +2835,7 @@
 			attr = dt_ident_cook(dnp, idp, NULL);
 		else {
 			dt_node_type_assign(dnp,
-			    DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp));
+			    DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp), B_FALSE);
 			attr = idp->di_attr;
 		}
 
@@ -2885,7 +2938,8 @@
 			xyerror(D_TYPE_ERR, "failed to lookup int64_t\n");
 
 		dt_ident_type_assign(cp->dn_ident, dtt.dtt_ctfp, dtt.dtt_type);
-		dt_node_type_assign(cp, dtt.dtt_ctfp, dtt.dtt_type);
+		dt_node_type_assign(cp, dtt.dtt_ctfp, dtt.dtt_type,
+		    dtt.dtt_flags);
 	}
 
 	if (cp->dn_kind == DT_NODE_VAR)
@@ -2895,7 +2949,7 @@
 	case DT_TOK_DEREF:
 		/*
 		 * If the deref operator is applied to a translated pointer,
-		 * we can just set our output type to the base translation.
+		 * we set our output type to the output of the translation.
 		 */
 		if ((idp = dt_node_resolve(cp, DT_IDENT_XLPTR)) != NULL) {
 			dt_xlator_t *dxp = idp->di_data;
@@ -2902,7 +2956,8 @@
 
 			dnp->dn_ident = &dxp->dx_souid;
 			dt_node_type_assign(dnp,
-			    DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp));
+			    dnp->dn_ident->di_ctfp, dnp->dn_ident->di_type,
+			    cp->dn_flags & DT_NF_USERLAND);
 			break;
 		}
 
@@ -2922,7 +2977,8 @@
 			    "cannot dereference non-pointer type\n");
 		}
 
-		dt_node_type_assign(dnp, cp->dn_ctfp, type);
+		dt_node_type_assign(dnp, cp->dn_ctfp, type,
+		    cp->dn_flags & DT_NF_USERLAND);
 		base = ctf_type_resolve(cp->dn_ctfp, type);
 		kind = ctf_type_kind(cp->dn_ctfp, base);
 
@@ -2979,7 +3035,8 @@
 			xyerror(D_OP_SCALAR, "operator %s requires an operand "
 			    "of scalar type\n", opstr(dnp->dn_op));
 		}
-		dt_node_type_assign(dnp, DT_INT_CTFP(dtp), DT_INT_TYPE(dtp));
+		dt_node_type_assign(dnp, DT_INT_CTFP(dtp), DT_INT_TYPE(dtp),
+		    B_FALSE);
 		break;
 
 	case DT_TOK_ADDROF:
@@ -3012,10 +3069,8 @@
 			    dt_node_type_name(cp, n, sizeof (n)));
 		}
 
-		dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type);
-
-		if (cp->dn_flags & DT_NF_USERLAND)
-			dnp->dn_flags |= DT_NF_USERLAND;
+		dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type,
+		    cp->dn_flags & DT_NF_USERLAND);
 		break;
 
 	case DT_TOK_SIZEOF:
@@ -3030,7 +3085,8 @@
 		}
 
 		dt_node_type_assign(dnp, dtp->dt_ddefs->dm_ctfp,
-		    ctf_lookup_by_name(dtp->dt_ddefs->dm_ctfp, "size_t"));
+		    ctf_lookup_by_name(dtp->dt_ddefs->dm_ctfp, "size_t"),
+		    B_FALSE);
 		break;
 
 	case DT_TOK_STRINGOF:
@@ -3040,7 +3096,8 @@
 			    "cannot apply stringof to a value of type %s\n",
 			    dt_node_type_name(cp, n, sizeof (n)));
 		}
-		dt_node_type_assign(dnp, DT_STR_CTFP(dtp), DT_STR_TYPE(dtp));
+		dt_node_type_assign(dnp, DT_STR_CTFP(dtp), DT_STR_TYPE(dtp),
+		    cp->dn_flags & DT_NF_USERLAND);
 		break;
 
 	case DT_TOK_PREINC:
@@ -3078,6 +3135,31 @@
 	return (dnp);
 }
 
+static void
+dt_assign_common(dt_node_t *dnp)
+{
+	dt_node_t *lp = dnp->dn_left;
+	dt_node_t *rp = dnp->dn_right;
+	int op = dnp->dn_op;
+
+	if (rp->dn_kind == DT_NODE_INT)
+		dt_cast(lp, rp);
+
+	if (!(lp->dn_flags & DT_NF_LVALUE)) {
+		xyerror(D_OP_LVAL, "operator %s requires modifiable "
+		    "lvalue as an operand\n", opstr(op));
+		/* see K&R[A7.17] */
+	}
+
+	if (!(lp->dn_flags & DT_NF_WRITABLE)) {
+		xyerror(D_OP_WRITE, "operator %s can only be applied "
+		    "to a writable variable\n", opstr(op));
+	}
+
+	dt_node_type_propagate(lp, dnp); /* see K&R[A7.17] */
+	dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr));
+}
+
 static dt_node_t *
 dt_cook_op2(dt_node_t *dnp, uint_t idflags)
 {
@@ -3208,7 +3290,8 @@
 			    "of scalar type\n", opstr(op));
 		}
 
-		dt_node_type_assign(dnp, DT_INT_CTFP(dtp), DT_INT_TYPE(dtp));
+		dt_node_type_assign(dnp, DT_INT_CTFP(dtp), DT_INT_TYPE(dtp),
+		    B_FALSE);
 		dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr));
 		break;
 
@@ -3252,7 +3335,8 @@
 			rp->dn_op = DT_TOK_INT;
 			rp->dn_value = (intmax_t)val;
 
-			dt_node_type_assign(rp, lp->dn_ctfp, lp->dn_type);
+			dt_node_type_assign(rp, lp->dn_ctfp, lp->dn_type,
+			    B_FALSE);
 			dt_node_attr_assign(rp, _dtrace_symattr);
 		}
 
@@ -3284,7 +3368,8 @@
 			    dt_node_type_name(rp, n2, sizeof (n2)));
 		}
 
-		dt_node_type_assign(dnp, DT_INT_CTFP(dtp), DT_INT_TYPE(dtp));
+		dt_node_type_assign(dnp, DT_INT_CTFP(dtp), DT_INT_TYPE(dtp),
+		    B_FALSE);
 		dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr));
 		break;
 
@@ -3332,7 +3417,7 @@
 			    dt_node_type_name(rp, n2, sizeof (n2)));
 		}
 
-		dt_node_type_assign(dnp, ctfp, type);
+		dt_node_type_assign(dnp, ctfp, type, B_FALSE);
 		dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr));
 
 		if (uref)
@@ -3473,7 +3558,7 @@
 		 */
 		if (lp->dn_kind == DT_NODE_VAR &&
 		    dt_ident_unref(lp->dn_ident)) {
-			dt_node_type_assign(lp, ctfp, type);
+			dt_node_type_assign(lp, ctfp, type, B_FALSE);
 			dt_ident_type_assign(lp->dn_ident, ctfp, type);
 
 			if (uref) {
@@ -3556,19 +3641,7 @@
 			}
 		}
 asgn_common:
-		if (!(lp->dn_flags & DT_NF_LVALUE)) {
-			xyerror(D_OP_LVAL, "operator %s requires modifiable "
-			    "lvalue as an operand\n", opstr(op));
-			/* see K&R[A7.17] */
-		}
-
-		if (!(lp->dn_flags & DT_NF_WRITABLE)) {
-			xyerror(D_OP_WRITE, "operator %s can only be applied "
-			    "to a writable variable\n", opstr(op));
-		}
-
-		dt_node_type_propagate(lp, dnp); /* see K&R[A7.17] */
-		dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr));
+		dt_assign_common(dnp);
 		break;
 
 	case DT_TOK_PTR:
@@ -3699,7 +3772,7 @@
 		type = ctf_type_resolve(ctfp, m.ctm_type);
 		kind = ctf_type_kind(ctfp, type);
 
-		dt_node_type_assign(dnp, ctfp, m.ctm_type);
+		dt_node_type_assign(dnp, ctfp, m.ctm_type, B_FALSE);
 		dt_node_attr_assign(dnp, lp->dn_attr);
 
 		if (op == DT_TOK_PTR && (kind != CTF_K_ARRAY ||
@@ -3825,7 +3898,8 @@
 		}
 
 		dnp->dn_ident = dt_xlator_ident(dxp, lp->dn_ctfp, lp->dn_type);
-		dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp));
+		dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp),
+		    B_FALSE);
 		dt_node_attr_assign(dnp,
 		    dt_attr_min(rp->dn_attr, dnp->dn_ident->di_attr));
 		break;
@@ -3873,6 +3947,14 @@
 
 		dt_node_type_propagate(lp, dnp); /* see K&R[A7.5] */
 		dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr));
+
+		/*
+		 * If it's a pointer then should be able to (attempt to)
+		 * assign to it.
+		 */
+		if (lkind == CTF_K_POINTER)
+			dnp->dn_flags |= DT_NF_WRITABLE;
+
 		break;
 	}
 
@@ -3982,7 +4064,7 @@
 		    "used in a conditional context\n");
 	}
 
-	dt_node_type_assign(dnp, ctfp, type);
+	dt_node_type_assign(dnp, ctfp, type, B_FALSE);
 	dt_node_attr_assign(dnp, dt_attr_min(dnp->dn_expr->dn_attr,
 	    dt_attr_min(lp->dn_attr, rp->dn_attr)));
 
@@ -4015,7 +4097,8 @@
 		dt_node_attr_assign(dnp, dt_ident_cook(dnp,
 		    dnp->dn_ident, &dnp->dn_aggtup));
 	} else {
-		dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp));
+		dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp),
+		    B_FALSE);
 		dt_node_attr_assign(dnp, dnp->dn_ident->di_attr);
 	}
 
@@ -4217,7 +4300,8 @@
 		}
 
 		(void) dt_node_cook(mnp, DT_IDFLG_REF);
-		dt_node_type_assign(mnp, dxp->dx_dst_ctfp, ctm.ctm_type);
+		dt_node_type_assign(mnp, dxp->dx_dst_ctfp, ctm.ctm_type,
+		    B_FALSE);
 		attr = dt_attr_min(attr, mnp->dn_attr);
 
 		if (dt_node_is_argcompat(mnp, mnp->dn_membexpr) == 0) {
@@ -4236,7 +4320,7 @@
 	dxp->dx_souid.di_attr = attr;
 	dxp->dx_ptrid.di_attr = attr;
 
-	dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp));
+	dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp), B_FALSE);
 	dt_node_attr_assign(dnp, _dtrace_defattr);
 
 	return (dnp);
@@ -4529,7 +4613,9 @@
 		    ctf_type_resolve(dnp->dn_ctfp, dnp->dn_type));
 	}
 
-	tp->dtdt_flags = (dnp->dn_flags & DT_NF_REF) ? DIF_TF_BYREF : 0;
+	tp->dtdt_flags = (dnp->dn_flags & DT_NF_REF) ?
+	    (dnp->dn_flags & DT_NF_USERLAND) ? DIF_TF_BYUREF :
+	    DIF_TF_BYREF : 0;
 	tp->dtdt_pad = 0;
 	tp->dtdt_size = ctf_type_size(dnp->dn_ctfp, dnp->dn_type);
 }

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -22,12 +23,14 @@
  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013 Joyent, Inc. All rights reserved.
+ */
 
 #ifndef	_DT_PARSER_H
 #define	_DT_PARSER_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <sys/dtrace.h>
 
@@ -223,7 +226,7 @@
 extern void dt_node_link_free(dt_node_t **);
 
 extern void dt_node_attr_assign(dt_node_t *, dtrace_attribute_t);
-extern void dt_node_type_assign(dt_node_t *, ctf_file_t *, ctf_id_t);
+extern void dt_node_type_assign(dt_node_t *, ctf_file_t *, ctf_id_t, boolean_t);
 extern void dt_node_type_propagate(const dt_node_t *, dt_node_t *);
 extern const char *dt_node_type_name(const dt_node_t *, char *, size_t);
 extern size_t dt_node_type_size(const dt_node_t *);

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pcb.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pcb.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pcb.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pcb.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pcb.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pcb.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -23,6 +24,9 @@
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
+ */
 
 #include <assert.h>
 #include <strings.h>
@@ -30,19 +34,21 @@
 #include <stdio.h>
 #include <errno.h>
 #include <ctype.h>
-#if defined(sun)
+#ifdef illumos
 #include <alloca.h>
 #endif
 #include <libgen.h>
 #include <stddef.h>
+#include <sys/sysmacros.h>
 
 #include <dt_impl.h>
 #include <dt_program.h>
 #include <dt_pid.h>
 #include <dt_string.h>
-#if !defined(sun)
+#ifndef illumos
 #include <libproc_compat.h>
 #endif
+#include <dt_module.h>
 
 typedef struct dt_pid_probe {
 	dtrace_hdl_t *dpp_dtp;
@@ -69,7 +75,7 @@
 static void
 dt_pid_objname(char *buf, size_t len, Lmid_t lmid, const char *obj)
 {
-#if defined(sun)
+#ifdef illumos
 	if (lmid == LM_ID_BASE)
 		(void) strncpy(buf, obj, len);
 	else
@@ -121,7 +127,7 @@
 	int isdash = strcmp("-", func) == 0;
 	pid_t pid;
 
-#if defined(sun)
+#ifdef illumos
 	pid = Pstatus(pp->dpp_pr)->pr_pid;
 #else
 	pid = proc_getpid(pp->dpp_pr);
@@ -265,7 +271,7 @@
 	if (obj == NULL)
 		return (0);
 
-#if defined(sun)
+#ifdef illumos
 	(void) Plmid(pp->dpp_pr, pmp->pr_vaddr, &pp->dpp_lmid);
 #endif
 	
@@ -274,7 +280,7 @@
 		pp->dpp_obj = obj;
 	else
 		pp->dpp_obj++;
-#if defined(sun)
+#ifdef illumos
 	if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj, ".stret1", &sym,
 	    NULL) == 0)
 		pp->dpp_stret[0] = sym.st_value;
@@ -332,7 +338,7 @@
 				    GELF_ST_INFO(STB_LOCAL, STT_FUNC);
 				sym.st_other = 0;
 				sym.st_value = 0;
-#if defined(sun)
+#ifdef illumos
 				sym.st_size = Pstatus(pp->dpp_pr)->pr_dmodel ==
 				    PR_MODEL_ILP32 ? -1U : -1ULL;
 #else
@@ -399,7 +405,7 @@
 	if (gmatch(obj, pp->dpp_mod))
 		return (dt_pid_per_mod(pp, pmp, obj));
 
-#if defined(sun)
+#ifdef illumos
 	(void) Plmid(pp->dpp_pr, pmp->pr_vaddr, &pp->dpp_lmid);
 #else
 	pp->dpp_lmid = 0;
@@ -413,7 +419,7 @@
 	if (gmatch(pp->dpp_obj, pp->dpp_mod))
 		return (dt_pid_per_mod(pp, pmp, obj));
 
-#if defined(sun)
+#ifdef illumos
 	(void) Plmid(pp->dpp_pr, pmp->pr_vaddr, &pp->dpp_lmid);
 #endif
 
@@ -429,7 +435,7 @@
 dt_pid_fix_mod(dtrace_probedesc_t *pdp, struct ps_prochandle *P)
 {
 	char m[MAXPATHLEN];
-#if defined(sun)
+#ifdef illumos
 	Lmid_t lmid = PR_LMID_EVERY;
 #else
 	Lmid_t lmid = 0;
@@ -437,7 +443,7 @@
 	const char *obj;
 	const prmap_t *pmp;
 
-#if defined(sun)
+#ifdef illumos
 	/*
 	 * Pick apart the link map from the library name.
 	 */
@@ -465,7 +471,7 @@
 	if ((pmp = Plmid_to_map(P, lmid, obj)) == NULL)
 		return (NULL);
 
-#if defined(sun)
+#ifdef illumos
 	(void) Pobjname(P, pmp->pr_vaddr, m, sizeof (m));
 	if ((obj = strrchr(m, '/')) == NULL)
 		obj = &m[0];
@@ -566,7 +572,7 @@
 {
 	struct ps_prochandle *P = data;
 	GElf_Sym sym;
-#if defined(sun)
+#ifdef illumos
 	prsyminfo_t sip;
 #endif
 	dof_helper_t dh;
@@ -604,13 +610,13 @@
 		dh.dofhp_addr = (e_type == ET_EXEC) ? 0 : pmp->pr_vaddr;
 
 		dt_pid_objname(dh.dofhp_mod, sizeof (dh.dofhp_mod),
-#if defined(sun)
+#ifdef illumos
 		    sip.prs_lmid, mname);
 #else
 		    0, mname);
 #endif
 
-#if defined(sun)
+#ifdef illumos
 		if (fd == -1 &&
 		    (fd = pr_open(P, "/dev/dtrace/helper", O_RDWR, 0)) < 0) {
 			dt_dprintf("pr_open of helper device failed: %s\n",
@@ -623,7 +629,7 @@
 #endif
 	}
 
-#if defined(sun)
+#ifdef illumos
 	if (fd != -1)
 		(void) pr_close(P, fd);
 #endif
@@ -639,13 +645,13 @@
 	int ret = 0;
 
 	assert(DT_MUTEX_HELD(&dpr->dpr_lock));
-#if defined(sun)
+#ifdef illumos
 	(void) Pupdate_maps(P);
 	if (Pobject_iter(P, dt_pid_usdt_mapping, P) != 0) {
 		ret = -1;
 		(void) dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_USDT,
 		    "failed to instantiate probes for pid %d: %s",
-#if defined(sun)
+#ifdef illumos
 		    (int)Pstatus(P)->pr_pid, strerror(errno));
 #else
 		    (int)proc_getpid(P), strerror(errno));
@@ -827,3 +833,170 @@
 
 	return (ret);
 }
+
+/*
+ * libdtrace has a backroom deal with us to ask us for type information on
+ * behalf of pid provider probes when fasttrap doesn't return any type
+ * information. Instead we'll look up the module and see if there is type
+ * information available. However, if there is no type information available due
+ * to a lack of CTF data, then we want to make sure that DTrace still carries on
+ * in face of that. As such we don't have a meaningful exit code about failure.
+ * We emit information about why we failed to the dtrace debug log so someone
+ * can figure it out by asking nicely for DTRACE_DEBUG.
+ */
+void
+dt_pid_get_types(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp,
+    dtrace_argdesc_t *adp, int *nargs)
+{
+	dt_module_t *dmp;
+	ctf_file_t *fp;
+	ctf_funcinfo_t f;
+	ctf_id_t argv[32];
+	GElf_Sym sym;
+#ifdef illumos
+	prsyminfo_t si;
+#else
+	void *si;
+#endif
+	struct ps_prochandle *p;
+	int i, args;
+	char buf[DTRACE_ARGTYPELEN];
+	const char *mptr;
+	char *eptr;
+	int ret = 0;
+	int argc = sizeof (argv) / sizeof (ctf_id_t);
+	Lmid_t lmid;
+
+	/* Set up a potential outcome */
+	args = *nargs;
+	*nargs = 0;
+
+	/*
+	 * If we don't have an entry or return probe then we can just stop right
+	 * now as we don't have arguments for offset probes.
+	 */
+	if (strcmp(pdp->dtpd_name, "entry") != 0 &&
+	    strcmp(pdp->dtpd_name, "return") != 0)
+		return;
+
+	dmp = dt_module_create(dtp, pdp->dtpd_provider);
+	if (dmp == NULL) {
+		dt_dprintf("failed to find module for %s\n",
+		    pdp->dtpd_provider);
+		return;
+	}
+	if (dt_module_load(dtp, dmp) != 0) {
+		dt_dprintf("failed to load module for %s\n",
+		    pdp->dtpd_provider);
+		return;
+	}
+
+	/*
+	 * We may be working with a module that doesn't have ctf. If that's the
+	 * case then we just return now and move on with life.
+	 */
+	fp = dt_module_getctflib(dtp, dmp, pdp->dtpd_mod);
+	if (fp == NULL) {
+		dt_dprintf("no ctf container for  %s\n",
+		    pdp->dtpd_mod);
+		return;
+	}
+	p = dt_proc_grab(dtp, dmp->dm_pid, 0, PGRAB_RDONLY | PGRAB_FORCE);
+	if (p == NULL) {
+		dt_dprintf("failed to grab pid\n");
+		return;
+	}
+	dt_proc_lock(dtp, p);
+
+	/*
+	 * Check to see if the D module has a link map ID and separate that out
+	 * for properly interrogating libproc.
+	 */
+	if ((mptr = strchr(pdp->dtpd_mod, '`')) != NULL) {
+		if (strlen(pdp->dtpd_mod) < 3) {
+			dt_dprintf("found weird modname with linkmap, "
+			    "aborting: %s\n", pdp->dtpd_mod);
+			goto out;
+		}
+		if (pdp->dtpd_mod[0] != 'L' || pdp->dtpd_mod[1] != 'M') {
+			dt_dprintf("missing leading 'LM', "
+			    "aborting: %s\n", pdp->dtpd_mod);
+			goto out;
+		}
+		errno = 0;
+		lmid = strtol(pdp->dtpd_mod + 2, &eptr, 16);
+		if (errno == ERANGE || eptr != mptr) {
+			dt_dprintf("failed to parse out lmid, aborting: %s\n",
+			    pdp->dtpd_mod);
+			goto out;
+		}
+		mptr++;
+	} else {
+		mptr = pdp->dtpd_mod;
+		lmid = 0;
+	}
+
+	if (Pxlookup_by_name(p, lmid, mptr, pdp->dtpd_func,
+	    &sym, &si) != 0) {
+		dt_dprintf("failed to find function %s in %s`%s\n",
+		    pdp->dtpd_func, pdp->dtpd_provider, pdp->dtpd_mod);
+		goto out;
+	}
+#ifdef illumos
+	if (ctf_func_info(fp, si.prs_id, &f) == CTF_ERR) {
+		dt_dprintf("failed to get ctf information for %s in %s`%s\n",
+		    pdp->dtpd_func, pdp->dtpd_provider, pdp->dtpd_mod);
+		goto out;
+	}
+#endif
+
+	(void) snprintf(buf, sizeof (buf), "%s`%s", pdp->dtpd_provider,
+	    pdp->dtpd_mod);
+
+	if (strcmp(pdp->dtpd_name, "return") == 0) {
+		if (args < 2)
+			goto out;
+
+		bzero(adp, sizeof (dtrace_argdesc_t));
+		adp->dtargd_ndx = 0;
+		adp->dtargd_id = pdp->dtpd_id;
+		adp->dtargd_mapping = adp->dtargd_ndx;
+		/*
+		 * We explicitly leave out the library here, we only care that
+		 * it is some int. We are assuming that there is no ctf
+		 * container in here that is lying about what an int is.
+		 */
+		(void) snprintf(adp->dtargd_native, DTRACE_ARGTYPELEN,
+		    "user %s`%s", pdp->dtpd_provider, "int");
+		adp++;
+		bzero(adp, sizeof (dtrace_argdesc_t));
+		adp->dtargd_ndx = 1;
+		adp->dtargd_id = pdp->dtpd_id;
+		adp->dtargd_mapping = adp->dtargd_ndx;
+		ret = snprintf(adp->dtargd_native, DTRACE_ARGTYPELEN,
+		    "userland ");
+		(void) ctf_type_qname(fp, f.ctc_return, adp->dtargd_native +
+		    ret, DTRACE_ARGTYPELEN - ret, buf);
+		*nargs = 2;
+#ifdef illumos
+	} else {
+		if (ctf_func_args(fp, si.prs_id, argc, argv) == CTF_ERR)
+			goto out;
+
+		*nargs = MIN(args, f.ctc_argc);
+		for (i = 0; i < *nargs; i++, adp++) {
+			bzero(adp, sizeof (dtrace_argdesc_t));
+			adp->dtargd_ndx = i;
+			adp->dtargd_id = pdp->dtpd_id;
+			adp->dtargd_mapping = adp->dtargd_ndx;
+			ret = snprintf(adp->dtargd_native, DTRACE_ARGTYPELEN,
+			    "userland ");
+			(void) ctf_type_qname(fp, argv[i], adp->dtargd_native +
+			    ret, DTRACE_ARGTYPELEN - ret, buf);
+		}
+#endif
+	}
+out:
+	dt_proc_unlock(dtp, p);
+	dt_proc_release(dtp, p);
+}

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -24,12 +25,13 @@
  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
+ */
 
 #ifndef	_DT_PID_H
 #define	_DT_PID_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <libproc.h>
 #include <sys/fasttrap.h>
 #include <dt_impl.h>
@@ -57,6 +59,9 @@
 extern int dt_pid_create_glob_offset_probes(struct ps_prochandle *,
     dtrace_hdl_t *, fasttrap_probe_spec_t *, const GElf_Sym *, const char *);
 
+extern void dt_pid_get_types(dtrace_hdl_t *, const dtrace_probedesc_t *,
+    dtrace_argdesc_t *, int *);
+
 #ifdef	__cplusplus
 }
 #endif

Added: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pq.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pq.c	                        (rev 0)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pq.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -0,0 +1,158 @@
+/* $MidnightBSD$ */
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+#include <dtrace.h>
+#include <dt_impl.h>
+#include <dt_pq.h>
+#include <assert.h>
+
+/*
+ * Create a new priority queue.
+ *
+ * size is the maximum number of items that will be stored in the priority
+ * queue at one time.
+ */
+dt_pq_t *
+dt_pq_init(dtrace_hdl_t *dtp, uint_t size, dt_pq_value_f value_cb, void *cb_arg)
+{
+	dt_pq_t *p;
+	assert(size > 1);
+
+	if ((p = dt_zalloc(dtp, sizeof (dt_pq_t))) == NULL)
+		return (NULL);
+
+	p->dtpq_items = dt_zalloc(dtp, size * sizeof (p->dtpq_items[0]));
+	if (p->dtpq_items == NULL) {
+		dt_free(dtp, p);
+		return (NULL);
+	}
+
+	p->dtpq_hdl = dtp;
+	p->dtpq_size = size;
+	p->dtpq_last = 1;
+	p->dtpq_value = value_cb;
+	p->dtpq_arg = cb_arg;
+
+	return (p);
+}
+
+void
+dt_pq_fini(dt_pq_t *p)
+{
+	dtrace_hdl_t *dtp = p->dtpq_hdl;
+
+	dt_free(dtp, p->dtpq_items);
+	dt_free(dtp, p);
+}
+
+static uint64_t
+dt_pq_getvalue(dt_pq_t *p, uint_t index)
+{
+	void *item = p->dtpq_items[index];
+	return (p->dtpq_value(item, p->dtpq_arg));
+}
+
+void
+dt_pq_insert(dt_pq_t *p, void *item)
+{
+	uint_t i;
+
+	assert(p->dtpq_last < p->dtpq_size);
+
+	i = p->dtpq_last++;
+	p->dtpq_items[i] = item;
+
+	while (i > 1 && dt_pq_getvalue(p, i) < dt_pq_getvalue(p, i / 2)) {
+		void *tmp = p->dtpq_items[i];
+		p->dtpq_items[i] = p->dtpq_items[i / 2];
+		p->dtpq_items[i / 2] = tmp;
+		i /= 2;
+	}
+}
+
+/*
+ * Return elements from the priority queue.  *cookie should be zero when first
+ * called.  Returns NULL when there are no more elements.
+ */
+void *
+dt_pq_walk(dt_pq_t *p, uint_t *cookie)
+{
+	(*cookie)++;
+	if (*cookie >= p->dtpq_last)
+		return (NULL);
+
+	return (p->dtpq_items[*cookie]);
+}
+
+void *
+dt_pq_pop(dt_pq_t *p)
+{
+	uint_t i = 1;
+	void *ret;
+
+	assert(p->dtpq_last > 0);
+
+	if (p->dtpq_last == 1)
+		return (NULL);
+
+	ret = p->dtpq_items[1];
+
+	p->dtpq_last--;
+	p->dtpq_items[1] = p->dtpq_items[p->dtpq_last];
+	p->dtpq_items[p->dtpq_last] = NULL;
+
+	for (;;) {
+		uint_t lc = i * 2;
+		uint_t rc = i * 2 + 1;
+		uint_t c;
+		uint64_t v;
+		void *tmp;
+
+		if (lc >= p->dtpq_last)
+			break;
+
+		if (rc >= p->dtpq_last) {
+			c = lc;
+			v = dt_pq_getvalue(p, lc);
+		} else {
+			uint64_t lv = dt_pq_getvalue(p, lc);
+			uint64_t rv = dt_pq_getvalue(p, rc);
+
+			if (lv < rv) {
+				c = lc;
+				v = lv;
+			} else {
+				c = rc;
+				v = rv;
+			}
+		}
+
+		if (v >= dt_pq_getvalue(p, i))
+			break;
+
+		tmp = p->dtpq_items[i];
+		p->dtpq_items[i] = p->dtpq_items[c];
+		p->dtpq_items[c] = tmp;
+
+		i = c;
+	}
+
+	return (ret);
+}


Property changes on: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pq.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pq.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pq.h	                        (rev 0)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pq.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -0,0 +1,52 @@
+/* $MidnightBSD$ */
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+#ifndef	_DT_PQ_H
+#define	_DT_PQ_H
+
+#include <dtrace.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef uint64_t (*dt_pq_value_f)(void *, void *);
+
+typedef struct dt_pq {
+	dtrace_hdl_t *dtpq_hdl;		/* dtrace handle */
+	void **dtpq_items;		/* array of elements */
+	uint_t dtpq_size;		/* count of allocated elements */
+	uint_t dtpq_last;		/* next free slot */
+	dt_pq_value_f dtpq_value;	/* callback to get the value */
+	void *dtpq_arg;			/* callback argument */
+} dt_pq_t;
+
+extern dt_pq_t *dt_pq_init(dtrace_hdl_t *, uint_t size, dt_pq_value_f, void *);
+extern void dt_pq_fini(dt_pq_t *);
+
+extern void dt_pq_insert(dt_pq_t *, void *);
+extern void *dt_pq_pop(dt_pq_t *);
+extern void *dt_pq_walk(dt_pq_t *, uint_t *);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _DT_PQ_H */


Property changes on: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pq.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pragma.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pragma.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pragma.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -28,7 +29,7 @@
 
 #include <assert.h>
 #include <strings.h>
-#if defined(sun)
+#ifdef illumos
 #include <alloca.h>
 #endif
 #include <fcntl.h>

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -167,7 +168,7 @@
 	 * to the lowest 'size' bytes in 'value', and we need to shift based on
 	 * the offset from the end of the data, not the offset of the start.
 	 */
-#ifdef _BIG_ENDIAN
+#if BYTE_ORDER == _BIG_ENDIAN
 	buf += sizeof (value) - size;
 	off += ep->cte_bits;
 #endif
@@ -178,7 +179,7 @@
 	 * Offsets are counted from opposite ends on little- and
 	 * big-endian machines.
 	 */
-#ifdef _BIG_ENDIAN
+#if BYTE_ORDER == _BIG_ENDIAN
 	shift = NBBY - shift;
 #endif
 
@@ -647,12 +648,16 @@
 	dt_printarg_t pa;
 	ctf_id_t id;
 	dt_module_t *dmp;
+	ctf_file_t *ctfp;
+	int libid;
 
 	/*
 	 * Split the fully-qualified type ID (module`id).  This should
 	 * always be the format, but if for some reason we don't find the
 	 * expected value, return 0 to fall back to the generic trace()
-	 * behavior.
+	 * behavior. In the case of userland CTF modules this will actually be
+	 * of the format (module`lib`id). This is due to the fact that those
+	 * modules have multiple CTF containers which `lib` identifies.
 	 */
 	for (s = typename; *s != '\0' && *s != '`'; s++)
 		;
@@ -663,6 +668,20 @@
 	object = alloca(s - typename + 1);
 	bcopy(typename, object, s - typename);
 	object[s - typename] = '\0';
+	dmp = dt_module_lookup_by_name(dtp, object);
+	if (dmp == NULL)
+		return (0);
+
+	if (dmp->dm_pid != 0) {
+		libid = atoi(s + 1);
+		s = strchr(s + 1, '`');
+		if (s == NULL || libid > dmp->dm_nctflibs)
+			return (0);
+		ctfp = dmp->dm_libctfp[libid];
+	} else {
+		ctfp = dt_module_getctf(dtp, dmp);
+	}
+
 	id = atoi(s + 1);
 
 	/*
@@ -670,16 +689,13 @@
 	 * wrong and we can't resolve the ID, bail out and let trace() do the
 	 * work.
 	 */
-	dmp = dt_module_lookup_by_name(dtp, object);
-	if (dmp == NULL || ctf_type_kind(dt_module_getctf(dtp, dmp),
-	    id) == CTF_ERR) {
+	if (ctfp == NULL || ctf_type_kind(ctfp, id) == CTF_ERR)
 		return (0);
-	}
 
 	/* setup the print structure and kick off the main print routine */
 	pa.pa_dtp = dtp;
 	pa.pa_addr = addr;
-	pa.pa_ctfp = dt_module_getctf(dtp, dmp);
+	pa.pa_ctfp = ctfp;
 	pa.pa_nest = 0;
 	pa.pa_depth = 0;
 	pa.pa_file = fp;

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -21,10 +22,11 @@
 
 /*
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
  */
 
-#if defined(sun)
+#ifdef illumos
 #include <sys/sysmacros.h>
 #else
 #define	ABS(a)		((a) < 0 ? -(a) : (a))
@@ -32,7 +34,7 @@
 #include <string.h>
 #include <strings.h>
 #include <stdlib.h>
-#if defined(sun)
+#ifdef illumos
 #include <alloca.h>
 #endif
 #include <assert.h>
@@ -161,7 +163,7 @@
 pfcheck_dint(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
 {
 	if (dnp->dn_flags & DT_NF_SIGNED)
-		pfd->pfd_flags |= DT_PFCONV_SIGNED;
+		pfd->pfd_fmt[strlen(pfd->pfd_fmt) - 1] = 'i';
 	else
 		pfd->pfd_fmt[strlen(pfd->pfd_fmt) - 1] = 'u';
 
@@ -466,7 +468,7 @@
 	 * Below, we turn this into the canonical adb/mdb /[yY] format,
 	 * "1973 Dec  3 17:20:00".
 	 */
-#if defined(sun)
+#ifdef illumos
 	(void) ctime_r(&sec, src, sizeof (src));
 #else
 	(void) ctime_r(&sec, src);
@@ -517,7 +519,7 @@
 	char buf[256];
 	struct servent *sv, res;
 
-#if defined(sun)
+#ifdef illumos
 	if ((sv = getservbyport_r(port, NULL, &res, buf, sizeof (buf))) != NULL)
 #else
 	if (getservbyport_r(port, NULL, &res, buf, sizeof (buf), &sv) > 0)
@@ -543,7 +545,7 @@
 	s[size] = '\0';
 
 	if (strchr(s, ':') == NULL && inet_pton(AF_INET, s, inetaddr) != -1) {
-#if defined(sun)
+#ifdef illumos
 		if ((host = gethostbyaddr_r(inetaddr, NS_INADDRSZ,
 		    AF_INET, &res, buf, sizeof (buf), &e)) != NULL)
 #else
@@ -664,7 +666,7 @@
 { "hu", "u", "unsigned short", pfcheck_type, pfprint_uint },
 { "hx", "x", "short", pfcheck_xshort, pfprint_uint },
 { "hX", "X", "short", pfcheck_xshort, pfprint_uint },
-{ "i", "i", pfproto_xint, pfcheck_dint, pfprint_dint },
+{ "i", "i", pfproto_xint, pfcheck_xint, pfprint_sint },
 { "I", "s", pfproto_cstr, pfcheck_str, pfprint_inetaddr },
 { "k", "s", "stack", pfcheck_stack, pfprint_stack },
 { "lc", "lc", "int", pfcheck_type, pfprint_sint }, /* a.k.a. wint_t */
@@ -693,8 +695,13 @@
 { "S", "s", pfproto_cstr, pfcheck_str, pfprint_estr },
 { "T", "s", "int64_t", pfcheck_time, pfprint_time822 },
 { "u", "u", pfproto_xint, pfcheck_xint, pfprint_uint },
+#ifdef illumos
 { "wc",	"wc", "int", pfcheck_type, pfprint_sint }, /* a.k.a. wchar_t */
 { "ws", "ws", pfproto_wstr, pfcheck_wstr, pfprint_wstr },
+#else
+{ "wc", "lc", "int", pfcheck_type, pfprint_sint }, /* a.k.a. wchar_t */
+{ "ws", "ls", pfproto_wstr, pfcheck_wstr, pfprint_wstr },
+#endif
 { "x", "x", pfproto_xint, pfcheck_xint, pfprint_uint },
 { "X", "X", pfproto_xint, pfcheck_xint, pfprint_uint },
 { "Y", "s", "int64_t", pfcheck_time, pfprint_time },
@@ -1069,7 +1076,7 @@
 		xyerror(D_TYPE_ERR, "failed to lookup agg type %s\n", aggtype);
 
 	bzero(&aggnode, sizeof (aggnode));
-	dt_node_type_assign(&aggnode, dtt.dtt_ctfp, dtt.dtt_type);
+	dt_node_type_assign(&aggnode, dtt.dtt_ctfp, dtt.dtt_type, B_FALSE);
 
 	for (i = 0, j = 0; i < pfv->pfv_argc; i++, pfd = pfd->pfd_next) {
 		const dt_pfconv_t *pfc = pfd->pfd_conv;
@@ -1342,6 +1349,7 @@
 	dtrace_aggdesc_t *agg;
 	caddr_t lim = (caddr_t)buf + len, limit;
 	char format[64] = "%";
+	size_t ret;
 	int i, aggrec, curagg = -1;
 	uint64_t normal;
 
@@ -1373,7 +1381,9 @@
 		int prec = pfd->pfd_prec;
 		int rval;
 
+		const char *start;
 		char *f = format + 1; /* skip initial '%' */
+		size_t fmtsz = sizeof(format) - 1;
 		const dtrace_recdesc_t *rec;
 		dt_pfprint_f *func;
 		caddr_t addr;
@@ -1530,6 +1540,7 @@
 			break;
 		}
 
+		start = f;
 		if (pfd->pfd_flags & DT_PFCONV_ALT)
 			*f++ = '#';
 		if (pfd->pfd_flags & DT_PFCONV_ZPAD)
@@ -1542,6 +1553,7 @@
 			*f++ = '\'';
 		if (pfd->pfd_flags & DT_PFCONV_SPACE)
 			*f++ = ' ';
+		fmtsz -= f - start;
 
 		/*
 		 * If we're printing a stack and DT_PFCONV_LEFT is set, we
@@ -1552,13 +1564,20 @@
 		if (func == pfprint_stack && (pfd->pfd_flags & DT_PFCONV_LEFT))
 			width = 0;
 
-		if (width != 0)
-			f += snprintf(f, sizeof (format), "%d", ABS(width));
+		if (width != 0) {
+			ret = snprintf(f, fmtsz, "%d", ABS(width));
+			f += ret;
+			fmtsz = MAX(0, fmtsz - ret);
+		}
 
-		if (prec > 0)
-			f += snprintf(f, sizeof (format), ".%d", prec);
+		if (prec > 0) {
+			ret = snprintf(f, fmtsz, ".%d", prec);
+			f += ret;
+			fmtsz = MAX(0, fmtsz - ret);
+		}
 
-		(void) strcpy(f, pfd->pfd_fmt);
+		if (strlcpy(f, pfd->pfd_fmt, fmtsz) >= fmtsz)
+			return (dt_set_errno(dtp, EDT_COMPILER));
 		pfd->pfd_rec = rec;
 
 		if (func(dtp, fp, format, pfd, addr, size, normal) < 0)
@@ -1651,7 +1670,7 @@
 	if (rval == -1 || fp == NULL)
 		return (rval);
 
-#if defined(sun)
+#ifdef illumos
 	if (pfd->pfd_preflen != 0 &&
 	    strcmp(pfd->pfd_prefix, DT_FREOPEN_RESTORE) == 0) {
 		/*
@@ -1733,7 +1752,7 @@
 	}
 
 	(void) fclose(nfp);
-#else
+#else	/* !illumos */
 	/*
 	 * The 'standard output' (which is not necessarily stdout)
 	 * treatment on FreeBSD is implemented differently than on
@@ -1808,7 +1827,7 @@
 
 	/* Remember that the output has been redirected to the new file. */
 	dtp->dt_freopen_fp = nfp;
-#endif
+#endif	/* illumos */
 
 	return (rval);
 }

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_proc.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_proc.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_proc.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -77,7 +78,7 @@
  */
 
 #include <sys/wait.h>
-#if defined(sun)
+#ifdef illumos
 #include <sys/lwp.h>
 #endif
 #include <strings.h>
@@ -89,7 +90,7 @@
 #include <dt_pid.h>
 #include <dt_impl.h>
 
-#if !defined(sun)
+#ifndef illumos
 #include <sys/syscall.h>
 #include <libproc_compat.h>
 #define	SYS_forksys SYS_fork
@@ -143,7 +144,7 @@
 static void
 dt_proc_bpmatch(dtrace_hdl_t *dtp, dt_proc_t *dpr)
 {
-#if defined(sun)
+#ifdef illumos
 	const lwpstatus_t *psp = &Pstatus(dpr->dpr_proc)->pr_lwp;
 #else
 	unsigned long pc;
@@ -152,7 +153,7 @@
 
 	assert(DT_MUTEX_HELD(&dpr->dpr_lock));
 
-#if !defined(sun)
+#ifndef illumos
 	proc_regget(dpr->dpr_proc, REG_PC, &pc);
 	proc_bkptregadj(&pc);
 #endif
@@ -159,7 +160,7 @@
 
 	for (dbp = dt_list_next(&dpr->dpr_bps);
 	    dbp != NULL; dbp = dt_list_next(dbp)) {
-#if defined(sun)
+#ifdef illumos
 		if (psp->pr_reg[R_PC] == dbp->dbp_addr)
 			break;
 #else
@@ -170,7 +171,7 @@
 
 	if (dbp == NULL) {
 		dt_dprintf("pid %d: spurious breakpoint wakeup for %lx\n",
-#if defined(sun)
+#ifdef illumos
 		    (int)dpr->dpr_pid, (ulong_t)psp->pr_reg[R_PC]);
 #else
 		    (int)dpr->dpr_pid, pc);
@@ -342,7 +343,7 @@
 	}
 
 	(void) dt_proc_bpcreate(dpr, rdn.u.bptaddr,
-#if defined(sun)
+#ifdef illumos
 	    (dt_bkpt_f *)dt_proc_rdevent, (void *)evname);
 #else
 	    /* XXX ugly */
@@ -357,7 +358,7 @@
 static void
 dt_proc_attach(dt_proc_t *dpr, int exec)
 {
-#if defined(sun)
+#ifdef illumos
 	const pstatus_t *psp = Pstatus(dpr->dpr_proc);
 #endif
 	rd_err_e err;
@@ -366,23 +367,23 @@
 	assert(DT_MUTEX_HELD(&dpr->dpr_lock));
 
 	if (exec) {
-#if defined(sun)
+#ifdef illumos
 		if (psp->pr_lwp.pr_errno != 0)
 			return; /* exec failed: nothing needs to be done */
 #endif
 
 		dt_proc_bpdestroy(dpr, B_FALSE);
-#if defined(sun)
+#ifdef illumos
 		Preset_maps(dpr->dpr_proc);
 #endif
 	}
 	if ((dpr->dpr_rtld = Prd_agent(dpr->dpr_proc)) != NULL &&
 	    (err = rd_event_enable(dpr->dpr_rtld, B_TRUE)) == RD_OK) {
-#if defined(sun)
+#ifdef illumos
 		dt_proc_rdwatch(dpr, RD_PREINIT, "RD_PREINIT");
 #endif
 		dt_proc_rdwatch(dpr, RD_POSTINIT, "RD_POSTINIT");
-#if defined(sun)
+#ifdef illumos
 		dt_proc_rdwatch(dpr, RD_DLACTIVITY, "RD_DLACTIVITY");
 #endif
 	} else {
@@ -507,7 +508,7 @@
 	struct ps_prochandle *P = dpr->dpr_proc;
 	int pid = dpr->dpr_pid;
 
-#if defined(sun)
+#ifdef illumos
 	int pfd = Pctlfd(P);
 
 	const long wstop = PCWSTOP;
@@ -529,7 +530,7 @@
 	 */
 	(void) pthread_mutex_lock(&dpr->dpr_lock);
 
-#if defined(sun)
+#ifdef illumos
 	(void) Punsetflags(P, PR_ASYNC);	/* require synchronous mode */
 	(void) Psetflags(P, PR_BPTADJ);		/* always adjust eip on x86 */
 	(void) Punsetflags(P, PR_FORK);		/* do not inherit on fork */
@@ -562,7 +563,7 @@
 	 * If PR_KLC is set, we created the process; otherwise we grabbed it.
 	 * Check for an appropriate stop request and wait for dt_proc_continue.
 	 */
-#if defined(sun)
+#ifdef illumos
 	if (Pstatus(P)->pr_flags & PR_KLC)
 #else
 	if (proc_getflags(P) & PR_KLC)
@@ -590,7 +591,7 @@
 	while (!dpr->dpr_quit) {
 		const lwpstatus_t *psp;
 
-#if defined(sun)
+#ifdef illumos
 		if (write(pfd, &wstop, sizeof (wstop)) == -1 && errno == EINTR)
 			continue; /* check dpr_quit and continue waiting */
 #else
@@ -602,7 +603,7 @@
 
 		(void) pthread_mutex_lock(&dpr->dpr_lock);
 
-#if defined(sun)
+#ifdef illumos
 pwait_locked:
 		if (Pstopstatus(P, PCNULL, 0) == -1 && errno == EINTR) {
 			(void) pthread_mutex_unlock(&dpr->dpr_lock);
@@ -612,7 +613,7 @@
 
 		switch (Pstate(P)) {
 		case PS_STOP:
-#if defined(sun)
+#ifdef illumos
 			psp = &Pstatus(P)->pr_lwp;
 #else
 			psp = proc_getlwpstatus(P);
@@ -661,7 +662,7 @@
 			break;
 
 		case PS_LOST:
-#if defined(sun)
+#ifdef illumos
 			if (Preopen(P) == 0)
 				goto pwait_locked;
 #endif
@@ -734,7 +735,7 @@
 dt_proc_lookup(dtrace_hdl_t *dtp, struct ps_prochandle *P, int remove)
 {
 	dt_proc_hash_t *dph = dtp->dt_procs;
-#if defined(sun)
+#ifdef illumos
 	pid_t pid = Pstatus(P)->pr_pid;
 #else
 	pid_t pid = proc_getpid(P);
@@ -772,7 +773,7 @@
 	 * an external debugger and we were waiting in dt_proc_waitrun().
 	 * Leave the process in this condition using PRELEASE_HANG.
 	 */
-#if defined(sun)
+#ifdef illumos
 	if (!(Pstatus(dpr->dpr_proc)->pr_flags & (PR_KLC | PR_RLC))) {
 #else
 	if (!(proc_getflags(dpr->dpr_proc) & (PR_KLC | PR_RLC))) {
@@ -779,7 +780,7 @@
 #endif
 		dt_dprintf("abandoning pid %d\n", (int)dpr->dpr_pid);
 		rflag = PRELEASE_HANG;
-#if defined(sun)
+#ifdef illumos
 	} else if (Pstatus(dpr->dpr_proc)->pr_flags & PR_KLC) {
 #else
 	} else if (proc_getflags(dpr->dpr_proc) & PR_KLC) {
@@ -808,7 +809,7 @@
 		 */
 		(void) pthread_mutex_lock(&dpr->dpr_lock);
 		dpr->dpr_quit = B_TRUE;
-#if defined(sun)
+#ifdef illumos
 		(void) _lwp_kill(dpr->dpr_tid, SIGCANCEL);
 #else
 		pthread_kill(dpr->dpr_tid, SIGTHR);
@@ -880,7 +881,7 @@
 
 	(void) sigfillset(&nset);
 	(void) sigdelset(&nset, SIGABRT);	/* unblocked for assert() */
-#if defined(sun)
+#ifdef illumos
 	(void) sigdelset(&nset, SIGCANCEL);	/* see dt_proc_destroy() */
 #else
 	(void) sigdelset(&nset, SIGUSR1);	/* see dt_proc_destroy() */
@@ -912,7 +913,7 @@
 		 * small amount of useful information to help figure it out.
 		 */
 		if (dpr->dpr_done) {
-#if defined(sun)
+#ifdef illumos
 			const psinfo_t *prp = Ppsinfo(dpr->dpr_proc);
 			int stat = prp ? prp->pr_wstat : 0;
 			int pid = dpr->dpr_pid;
@@ -963,7 +964,7 @@
 	(void) pthread_mutex_init(&dpr->dpr_lock, NULL);
 	(void) pthread_cond_init(&dpr->dpr_cv, NULL);
 
-#if defined(sun)
+#ifdef illumos
 	if ((dpr->dpr_proc = Pcreate(file, argv, &err, NULL, 0)) == NULL) {
 #else
 	if ((err = proc_create(file, argv, pcf, child_arg,
@@ -974,7 +975,7 @@
 	}
 
 	dpr->dpr_hdl = dtp;
-#if defined(sun)
+#ifdef illumos
 	dpr->dpr_pid = Pstatus(dpr->dpr_proc)->pr_pid;
 #else
 	dpr->dpr_pid = proc_getpid(dpr->dpr_proc);
@@ -1039,7 +1040,7 @@
 	(void) pthread_mutex_init(&dpr->dpr_lock, NULL);
 	(void) pthread_cond_init(&dpr->dpr_cv, NULL);
 
-#if defined(sun)
+#ifdef illumos
 	if ((dpr->dpr_proc = Pgrab(pid, flags, &err)) == NULL) {
 #else
 	if ((err = proc_attach(pid, flags, &dpr->dpr_proc)) != 0) {
@@ -1174,7 +1175,7 @@
 	struct ps_prochandle *P = dt_proc_create(dtp, file, argv, pcf, child_arg);
 
 	if (P != NULL && idp != NULL && idp->di_id == 0) {
-#if defined(sun)
+#ifdef illumos
 		idp->di_id = Pstatus(P)->pr_pid; /* $target = created pid */
 #else
 		idp->di_id = proc_getpid(P); /* $target = created pid */

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_proc.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_proc.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_proc.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_program.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_program.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_program.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -30,7 +31,7 @@
 #include <errno.h>
 #include <assert.h>
 #include <ctype.h>
-#if defined(sun)
+#ifdef illumos
 #include <alloca.h>
 #endif
 

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_program.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_program.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_program.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -23,11 +24,12 @@
  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
+ */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
-#if defined(sun)
+#ifdef illumos
 #include <sys/sysmacros.h>
 #endif
 
@@ -35,7 +37,7 @@
 #include <limits.h>
 #include <strings.h>
 #include <stdlib.h>
-#if defined(sun)
+#ifdef illumos
 #include <alloca.h>
 #endif
 #include <unistd.h>
@@ -45,6 +47,8 @@
 #include <dt_module.h>
 #include <dt_string.h>
 #include <dt_list.h>
+#include <dt_pid.h>
+#include <dtrace.h>
 
 static dt_provider_t *
 dt_provider_insert(dtrace_hdl_t *dtp, dt_provider_t *pvp, uint_t h)
@@ -273,6 +277,21 @@
 	nc++;
 
 	/*
+	 * The pid provider believes in giving the kernel a break. No reason to
+	 * give the kernel all the ctf containers that we're keeping ourselves
+	 * just to get it back from it. So if we're coming from a pid provider
+	 * probe and the kernel gave us no argument information we'll get some
+	 * here. If for some crazy reason the kernel knows about our userland
+	 * types then we just ignore this.
+	 */
+	if (xc == 0 && nc == 0 &&
+	    strncmp(pvp->pv_desc.dtvd_name, "pid", 3) == 0) {
+		nc = adc;
+		dt_pid_get_types(dtp, pdp, adv, &nc);
+		xc = nc;
+	}
+
+	/*
 	 * Now that we have discovered the number of native and translated
 	 * arguments from the argument descriptions, allocate a new probe ident
 	 * and corresponding dt_probe_t and hash it into the provider.
@@ -318,7 +337,8 @@
 			dtt.dtt_type = CTF_ERR;
 		} else {
 			dt_node_type_assign(prp->pr_nargv[adp->dtargd_mapping],
-			    dtt.dtt_ctfp, dtt.dtt_type);
+			    dtt.dtt_ctfp, dtt.dtt_type,
+			    dtt.dtt_flags & DTT_FL_USER ? B_TRUE : B_FALSE);
 		}
 
 		if (dtt.dtt_type != CTF_ERR && (adp->dtargd_xlate[0] == '\0' ||
@@ -337,7 +357,7 @@
 			dtt.dtt_type = CTF_ERR;
 		} else {
 			dt_node_type_assign(prp->pr_xargv[i],
-			    dtt.dtt_ctfp, dtt.dtt_type);
+			    dtt.dtt_ctfp, dtt.dtt_type, B_FALSE);
 		}
 
 		prp->pr_mapping[i] = adp->dtargd_mapping;
@@ -638,7 +658,7 @@
 	bzero(dnp, sizeof (dt_node_t));
 	dnp->dn_kind = DT_NODE_TYPE;
 
-	dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type);
+	dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type, B_FALSE);
 	dt_node_attr_assign(dnp, _dtrace_defattr);
 
 	return (dnp);

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_regset.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_regset.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_regset.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -19,12 +20,16 @@
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2016 Pedro Giffuni.  All rights reserved.
+ */
 
 #include <sys/types.h>
 #include <sys/bitmap.h>
@@ -33,18 +38,18 @@
 #include <stdlib.h>
 
 #include <dt_regset.h>
+#include <dt_impl.h>
 
 dt_regset_t *
-dt_regset_create(ulong_t size)
+dt_regset_create(ulong_t nregs)
 {
-	ulong_t n = BT_BITOUL(size + 1); /* + 1 for %r0 */
+	ulong_t n = BT_BITOUL(nregs);
 	dt_regset_t *drp = malloc(sizeof (dt_regset_t));
 
 	if (drp == NULL)
 		return (NULL);
 
-	drp->dr_bitmap = malloc(sizeof (ulong_t) * n);
-	drp->dr_size = size + 1;
+	drp->dr_bitmap = calloc(n, sizeof (ulong_t));
 
 	if (drp->dr_bitmap == NULL) {
 		dt_regset_destroy(drp);
@@ -51,7 +56,8 @@
 		return (NULL);
 	}
 
-	bzero(drp->dr_bitmap, sizeof (ulong_t) * n);
+	drp->dr_size = nregs;
+
 	return (drp);
 }
 
@@ -68,6 +74,25 @@
 	bzero(drp->dr_bitmap, sizeof (ulong_t) * BT_BITOUL(drp->dr_size));
 }
 
+void
+dt_regset_assert_free(dt_regset_t *drp)
+{
+	int reg;
+	boolean_t fail = B_FALSE;
+	for (reg = 0; reg < drp->dr_size; reg++) {
+		if (BT_TEST(drp->dr_bitmap, reg) != 0)  {
+			dt_dprintf("%%r%d was left allocated\n", reg);
+			fail = B_TRUE;
+		}
+	}
+
+	/*
+	 * We set this during dtest runs to check for register leaks.
+	 */
+	if (fail && getenv("DTRACE_DEBUG_REGSET") != NULL)
+		abort();
+}
+
 int
 dt_regset_alloc(dt_regset_t *drp)
 {
@@ -95,13 +120,15 @@
 		}
 	}
 
-	return (-1); /* no available registers */
+	xyerror(D_NOREG, "Insufficient registers to generate code");
+	/*NOTREACHED*/
+	return (-1);
 }
 
 void
 dt_regset_free(dt_regset_t *drp, int reg)
 {
-	assert(reg > 0 && reg < drp->dr_size);
+	assert(reg >= 0 && reg < drp->dr_size);
 	assert(BT_TEST(drp->dr_bitmap, reg) != 0);
 	BT_CLEAR(drp->dr_bitmap, reg);
 }

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_regset.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_regset.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_regset.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -19,16 +20,19 @@
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
 #ifndef	_DT_REGSET_H
 #define	_DT_REGSET_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 
 #ifdef	__cplusplus
@@ -45,6 +49,7 @@
 extern void dt_regset_reset(dt_regset_t *);
 extern int dt_regset_alloc(dt_regset_t *);
 extern void dt_regset_free(dt_regset_t *, int);
+extern void dt_regset_assert_free(dt_regset_t *);
 
 #ifdef	__cplusplus
 }

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_string.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_string.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_string.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_string.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_string.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_string.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_strtab.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_strtab.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_strtab.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -24,6 +25,10 @@
  * Use is subject to license terms.
  */
 
+/*
+ * Portions Copyright 2016 Pedro Giffuni.  All rights reserved.
+ */
+ 
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 
 #include <sys/types.h>
@@ -70,12 +75,11 @@
 		return (NULL);
 
 	bzero(sp, sizeof (dt_strtab_t));
-	sp->str_hash = malloc(nbuckets * sizeof (dt_strhash_t *));
+	sp->str_hash = calloc(nbuckets, sizeof (dt_strhash_t *));
 
 	if (sp->str_hash == NULL)
 		goto err;
 
-	bzero(sp->str_hash, nbuckets * sizeof (dt_strhash_t *));
 	sp->str_hashsz = nbuckets;
 	sp->str_bufs = NULL;
 	sp->str_ptr = NULL;

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_strtab.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_strtab.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_strtab.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_subr.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_subr.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_subr.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -21,10 +22,11 @@
 
 /*
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
  * Use is subject to license terms.
  */
 
-#if defined(sun)
+#ifdef illumos
 #include <sys/sysmacros.h>
 #endif
 #include <sys/isa_defs.h>
@@ -37,7 +39,7 @@
 #include <stdio.h>
 #include <errno.h>
 #include <ctype.h>
-#if defined(sun)
+#ifdef illumos
 #include <alloca.h>
 #else
 #include <sys/sysctl.h>
@@ -476,7 +478,7 @@
 }
 
 int
-#if defined(sun)
+#ifdef illumos
 dt_ioctl(dtrace_hdl_t *dtp, int val, void *arg)
 #else
 dt_ioctl(dtrace_hdl_t *dtp, u_long val, void *arg)
@@ -484,7 +486,7 @@
 {
 	const dtrace_vector_t *v = dtp->dt_vector;
 
-#if !defined(sun)
+#ifndef illumos
 	/* Avoid sign extension. */
 	val &= 0xffffffff;
 #endif
@@ -505,7 +507,7 @@
 	const dtrace_vector_t *v = dtp->dt_vector;
 
 	if (v == NULL) {
-#if defined(sun)
+#ifdef illumos
 		return (p_online(cpu, P_STATUS));
 #else
 		int maxid = 0;
@@ -582,7 +584,7 @@
 	va_list ap;
 	int n;
 
-#if !defined(sun)
+#ifndef illumos
 	/*
 	 * On FreeBSD, check if output is currently being re-directed
 	 * to another file. If so, output to that file instead of the
@@ -617,8 +619,8 @@
 		size_t avail;
 
 		/*
-		 * It's not legal to use buffered ouput if there is not a
-		 * handler for buffered output.
+		 * Using buffered output is not allowed if a handler has
+		 * not been installed.
 		 */
 		if (dtp->dt_bufhdlr == NULL) {
 			va_end(ap);
@@ -678,6 +680,7 @@
 
 		dtp->dt_buffered_offs += needed;
 		assert(dtp->dt_buffered_buf[dtp->dt_buffered_offs] == '\0');
+		va_end(ap);
 		return (0);
 	}
 
@@ -732,11 +735,6 @@
 {
 	void *data;
 
-	if (size > 16 * 1024 * 1024) {
-		(void) dt_set_errno(dtp, EDT_NOMEM);
-		return (NULL);
-	}
-
 	if ((data = malloc(size)) == NULL)
 		(void) dt_set_errno(dtp, EDT_NOMEM);
 	else
@@ -750,11 +748,6 @@
 {
 	void *data;
 
-	if (size > 16 * 1024 * 1024) {
-		(void) dt_set_errno(dtp, EDT_NOMEM);
-		return (NULL);
-	}
-
 	if ((data = malloc(size)) == NULL)
 		(void) dt_set_errno(dtp, EDT_NOMEM);
 
@@ -853,7 +846,7 @@
 	return (popc + dt_popc(bp[maxw] & ((1UL << maxb) - 1)));
 }
 
-#if defined(sun)
+#ifdef illumos
 struct _rwlock;
 struct _lwp_mutex;
 
@@ -875,7 +868,7 @@
 int
 dt_mutex_held(pthread_mutex_t *lock)
 {
-#if defined(sun)
+#ifdef illumos
 	extern int _mutex_held(struct _lwp_mutex *);
 	return (_mutex_held((struct _lwp_mutex *)lock));
 #else

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_work.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_work.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_work.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -82,7 +83,7 @@
 		return; /* sleep duration has already past */
 	}
 
-#if defined(sun)
+#ifdef illumos
 	tv.tv_sec = (earliest - now) / NANOSEC;
 	tv.tv_nsec = (earliest - now) % NANOSEC;
 
@@ -184,7 +185,7 @@
 {
 	dtrace_enable_io_t args;
 	void *dof;
-	int err;
+	int error, r;
 
 	if (dtp->dt_active)
 		return (dt_set_errno(dtp, EINVAL));
@@ -206,11 +207,12 @@
 
 	args.dof = dof;
 	args.n_matched = 0;
-	err = dt_ioctl(dtp, DTRACEIOC_ENABLE, &args);
+	r = dt_ioctl(dtp, DTRACEIOC_ENABLE, &args);
+	error = errno;
 	dtrace_dof_destroy(dtp, dof);
 
-	if (err == -1 && (errno != ENOTTY || dtp->dt_vector == NULL))
-		return (dt_set_errno(dtp, errno));
+	if (r == -1 && (error != ENOTTY || dtp->dt_vector == NULL))
+		return (dt_set_errno(dtp, error));
 
 	if (dt_ioctl(dtp, DTRACEIOC_GO, &dtp->dt_beganon) == -1) {
 		if (errno == EACCES)

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_xlator.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_xlator.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_xlator.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -23,9 +24,11 @@
  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013 Joyent, Inc. All rights reserved.
+ */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <strings.h>
 #include <assert.h>
 
@@ -69,7 +72,7 @@
 	enp->dn_op = DT_TOK_XLATE;
 	enp->dn_xlator = dxp;
 	enp->dn_xmember = mnp;
-	dt_node_type_assign(enp, dxp->dx_dst_ctfp, type);
+	dt_node_type_assign(enp, dxp->dx_dst_ctfp, type, B_FALSE);
 
 	/*
 	 * For the member itself, we use a DT_NODE_MEMBER as usual with the
@@ -83,7 +86,7 @@
 
 	mnp->dn_membname = strdup(name);
 	mnp->dn_membexpr = enp;
-	dt_node_type_assign(mnp, dxp->dx_dst_ctfp, type);
+	dt_node_type_assign(mnp, dxp->dx_dst_ctfp, type, B_FALSE);
 
 	if (mnp->dn_membname == NULL)
 		return (dt_set_errno(dtp, EDT_NOMEM));
@@ -318,7 +321,8 @@
 
 	for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL;
 	    dxp = dt_list_next(dxp)) {
-		dt_node_type_assign(&xn, dxp->dx_src_ctfp, dxp->dx_src_type);
+		dt_node_type_assign(&xn, dxp->dx_src_ctfp, dxp->dx_src_type,
+		    B_FALSE);
 		if (ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base,
 		    dst_ctfp, dst_base) && dt_node_is_argcompat(src, &xn))
 			goto out;

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_xlator.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_xlator.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dt_xlator.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -25,7 +26,8 @@
  */
 
 /*
- * Copyright (c) 2011, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  */
 
 #ifndef	_DTRACE_H
@@ -36,7 +38,7 @@
 #include <stdio.h>
 #include <gelf.h>
 #include <libproc.h>
-#if !defined(sun)
+#ifndef illumos
 #include <rtld_db.h>
 #endif
 
@@ -356,7 +358,13 @@
 #define	DTRACE_A_PERCPU		0x0001
 #define	DTRACE_A_KEEPDELTA	0x0002
 #define	DTRACE_A_ANONYMOUS	0x0004
+#define	DTRACE_A_TOTAL		0x0008
+#define	DTRACE_A_MINMAXBIN	0x0010
+#define	DTRACE_A_HASNEGATIVES	0x0020
+#define	DTRACE_A_HASPOSITIVES	0x0040
 
+#define	DTRACE_AGGZOOM_MAX		0.95	/* height of max bar */
+
 #define	DTRACE_AGGWALK_ERROR		-1	/* error while processing */
 #define	DTRACE_AGGWALK_NEXT		0	/* proceed to next element */
 #define	DTRACE_AGGWALK_ABORT		1	/* abort aggregation walk */
@@ -376,6 +384,10 @@
 	caddr_t dtada_delta;			/* delta data, if available */
 	caddr_t *dtada_percpu;			/* per CPU data, if avail */
 	caddr_t *dtada_percpu_delta;		/* per CPU delta, if avail */
+	int64_t dtada_total;			/* per agg total, if avail */
+	uint16_t dtada_minbin;			/* minimum bin, if avail */
+	uint16_t dtada_maxbin;			/* maximum bin, if avail */
+	uint32_t dtada_flags;			/* flags */
 };
 
 typedef int dtrace_aggregate_f(const dtrace_aggdata_t *, void *);
@@ -495,8 +507,11 @@
 	const char *dtt_object;			/* object containing type */
 	ctf_file_t *dtt_ctfp;			/* CTF container handle */
 	ctf_id_t dtt_type;			/* CTF type identifier */
+	uint_t dtt_flags;			/* Misc. flags */
 } dtrace_typeinfo_t;
 
+#define	DTT_FL_USER	0x1			/* user type */
+
 extern int dtrace_lookup_by_type(dtrace_hdl_t *, const char *, const char *,
     dtrace_typeinfo_t *);
 
@@ -540,7 +555,7 @@
  * entry point to obtain a library handle.
  */
 struct dtrace_vector {
-#if defined(sun)
+#ifdef illumos
 	int (*dtv_ioctl)(void *, int, void *);
 #else
 	int (*dtv_ioctl)(void *, u_long, void *);
@@ -591,7 +606,7 @@
 }
 #endif
 
-#if !defined(sun)
+#ifndef illumos
 #define _SC_CPUID_MAX		_SC_NPROCESSORS_CONF
 #define _SC_NPROCESSORS_MAX	_SC_NPROCESSORS_CONF
 #endif

Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/i386/dt_isadep.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/i386/dt_isadep.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/i386/dt_isadep.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -24,6 +25,10 @@
  * Use is subject to license terms.
  */
 
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
 #include <stdlib.h>
 #include <assert.h>
 #include <errno.h>
@@ -35,7 +40,7 @@
 
 #include <dis_tables.h>
 
-#if !defined(sun)
+#ifndef illumos
 #define PR_MODEL_ILP32	1
 #define PR_MODEL_LP64	2
 #include <libproc_compat.h>
@@ -84,7 +89,7 @@
 {
 	ulong_t i;
 	int size;
-#if defined(sun)
+#ifdef illumos
 	pid_t pid = Pstatus(P)->pr_pid;
 	char dmodel = Pstatus(P)->pr_dmodel;
 #else
@@ -140,7 +145,7 @@
 	uint8_t *text;
 	ulong_t i, end;
 	int size;
-#if defined(sun)
+#ifdef illumos
 	pid_t pid = Pstatus(P)->pr_pid;
 	char dmodel = Pstatus(P)->pr_dmodel;
 #else
@@ -301,7 +306,7 @@
 		uint8_t *text;
 		ulong_t i;
 		int size;
-#if defined(sun)
+#ifdef illumos
 		pid_t pid = Pstatus(P)->pr_pid;
 		char dmodel = Pstatus(P)->pr_dmodel;
 #else
@@ -384,7 +389,7 @@
 	uint8_t *text;
 	int size;
 	ulong_t i, end = symp->st_size;
-#if defined(sun)
+#ifdef illumos
 	pid_t pid = Pstatus(P)->pr_pid;
 	char dmodel = Pstatus(P)->pr_dmodel;
 #else
@@ -525,7 +530,8 @@
 	 * another debugger attached to this process. The original instruction
 	 * can't be recovered so this must fail.
 	 */
-	if (x86dis.d86_len == 1 && instr[0] == FASTTRAP_INSTR)
+	if (x86dis.d86_len == 1 &&
+	    (uchar_t)x86dis.d86_bytes[0] == FASTTRAP_INSTR)
 		return (-1);
 
 	return (x86dis.d86_len);

Added: trunk/cddl/contrib/opensolaris/lib/libdtrace/mips/dt_isadep.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/mips/dt_isadep.c	                        (rev 0)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/mips/dt_isadep.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -0,0 +1,76 @@
+/* $MidnightBSD$ */
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <libgen.h>
+
+#include <dt_impl.h>
+#include <dt_pid.h>
+
+/*ARGSUSED*/
+int
+dt_pid_create_entry_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+    fasttrap_probe_spec_t *ftp, const GElf_Sym *symp)
+{
+
+	dt_dprintf("%s: unimplemented\n", __func__);
+	return (DT_PROC_ERR);
+}
+
+int
+dt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+    fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, uint64_t *stret)
+{
+
+	dt_dprintf("%s: unimplemented\n", __func__);
+	return (DT_PROC_ERR);
+}
+
+/*ARGSUSED*/
+int
+dt_pid_create_offset_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+    fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, ulong_t off)
+{
+
+	dt_dprintf("%s: unimplemented\n", __func__);
+	return (DT_PROC_ERR);
+}
+
+/*ARGSUSED*/
+int
+dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+    fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, const char *pattern)
+{
+
+	dt_dprintf("%s: unimplemented\n", __func__);
+	return (DT_PROC_ERR);
+}


Property changes on: trunk/cddl/contrib/opensolaris/lib/libdtrace/mips/dt_isadep.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/cddl/contrib/opensolaris/lib/libdtrace/powerpc/dt_isadep.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/powerpc/dt_isadep.c	                        (rev 0)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/powerpc/dt_isadep.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -0,0 +1,198 @@
+/* $MidnightBSD$ */
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <libgen.h>
+
+#include <dt_impl.h>
+#include <dt_pid.h>
+
+#include <libproc_compat.h>
+
+/*ARGSUSED*/
+int
+dt_pid_create_entry_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+    fasttrap_probe_spec_t *ftp, const GElf_Sym *symp)
+{
+	ftp->ftps_type = DTFTP_ENTRY;
+	ftp->ftps_pc = (uintptr_t)symp->st_value;
+	ftp->ftps_size = (size_t)symp->st_size;
+	ftp->ftps_noffs = 1;
+	ftp->ftps_offs[0] = 0;
+
+	if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+		dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+		    strerror(errno));
+		return (dt_set_errno(dtp, errno));
+	}
+
+	return (1);
+}
+
+int
+dt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+    fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, uint64_t *stret)
+{
+
+	uintptr_t temp;
+	uint32_t *text;
+	int i;
+	int srdepth = 0;
+
+	if ((text = malloc(symp->st_size + 4)) == NULL) {
+		dt_dprintf("mr sparkle: malloc() failed\n");
+		return (DT_PROC_ERR);
+	}
+
+	if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) {
+		dt_dprintf("mr sparkle: Pread() failed\n");
+		free(text);
+		return (DT_PROC_ERR);
+	}
+
+	/*
+	 * Leave a dummy instruction in the last slot to simplify edge
+	 * conditions.
+	 */
+	text[symp->st_size / 4] = 0;
+
+	ftp->ftps_type = DTFTP_RETURN;
+	ftp->ftps_pc = symp->st_value;
+	ftp->ftps_size = symp->st_size;
+	ftp->ftps_noffs = 0;
+
+	for (i = 0; i < symp->st_size / 4; i++) {
+
+		if ((text[i] & 0xfc000001) != 0x48000000 &&
+		    text[i] != 0x4e800020)
+			continue;
+
+		/*
+		 * Check for a jump within this function.  If it's outside this
+		 * function then it's a tail-call, so a return point.
+		 */
+		if ((text[i] & 0xfc000000) == 0x48000000) {
+			temp = (text[i] & 0x03fffffc);
+			/* Bit 30 denotes an absolute address. */
+			if (!(text[i] & 0x02)) {
+				temp += symp->st_value + i * 4;
+			}
+			else {
+				/* Sign extend the absolute address. */
+				if (temp & 0x02000000) {
+					temp |= (UINTPTR_MAX - 0x03ffffff);
+				}
+			}
+			if (temp >= symp->st_value &&
+			    temp <= (symp->st_value + symp->st_size))
+				continue;
+		}
+		dt_dprintf("return at offset %x\n", i * 4);
+		ftp->ftps_offs[ftp->ftps_noffs++] = i * 4;
+	}
+
+	free(text);
+	if (ftp->ftps_noffs > 0) {
+		if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+			dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+			    strerror(errno));
+			return (dt_set_errno(dtp, errno));
+		}
+	}
+
+
+	return (ftp->ftps_noffs);
+}
+
+/*ARGSUSED*/
+int
+dt_pid_create_offset_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+    fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, ulong_t off)
+{
+	if (off & 0x3)
+		return (DT_PROC_ALIGN);
+
+	ftp->ftps_type = DTFTP_OFFSETS;
+	ftp->ftps_pc = (uintptr_t)symp->st_value;
+	ftp->ftps_size = (size_t)symp->st_size;
+	ftp->ftps_noffs = 1;
+	ftp->ftps_offs[0] = off;
+
+	if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+		dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+		    strerror(errno));
+		return (dt_set_errno(dtp, errno));
+	}
+
+	return (1);
+}
+
+/*ARGSUSED*/
+int
+dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp,
+    fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, const char *pattern)
+{
+	ulong_t i;
+
+	ftp->ftps_type = DTFTP_OFFSETS;
+	ftp->ftps_pc = (uintptr_t)symp->st_value;
+	ftp->ftps_size = (size_t)symp->st_size;
+	ftp->ftps_noffs = 0;
+
+	/*
+	 * If we're matching against everything, just iterate through each
+	 * instruction in the function, otherwise look for matching offset
+	 * names by constructing the string and comparing it against the
+	 * pattern.
+	 */
+	if (strcmp("*", pattern) == 0) {
+		for (i = 0; i < symp->st_size; i += 4) {
+			ftp->ftps_offs[ftp->ftps_noffs++] = i;
+		}
+	} else {
+		char name[sizeof (i) * 2 + 1];
+
+		for (i = 0; i < symp->st_size; i += 4) {
+			(void) sprintf(name, "%lx", i);
+			if (gmatch(name, pattern))
+				ftp->ftps_offs[ftp->ftps_noffs++] = i;
+		}
+	}
+
+	if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
+		dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
+		    strerror(errno));
+		return (dt_set_errno(dtp, errno));
+	}
+
+	return (ftp->ftps_noffs);
+}


Property changes on: trunk/cddl/contrib/opensolaris/lib/libdtrace/powerpc/dt_isadep.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/cddl/contrib/opensolaris/lib/libdtrace/sparc/dt_isadep.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libdtrace/sparc/dt_isadep.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libdtrace/sparc/dt_isadep.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libgen/common/gmatch.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libgen/common/gmatch.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libgen/common/gmatch.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -29,7 +30,7 @@
 
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 
-#if defined(sun)
+#ifdef illumos
 #pragma weak gmatch = _gmatch
 
 #include "gen_synonyms.h"
@@ -38,7 +39,7 @@
 #include <libgen.h>
 #include <stdlib.h>
 #include <limits.h>
-#if defined(sun)
+#ifdef illumos
 #include <widec.h>
 #include "_range.h"
 #else

Modified: trunk/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -26,7 +27,7 @@
 #include <solaris.h>
 #include <inttypes.h>
 #include <unistd.h>
-#include <strings.h>
+#include <string.h>
 #include <libintl.h>
 #include <stdarg.h>
 #include "libnvpair.h"
@@ -210,7 +211,7 @@
 NVLIST_PRTFUNC(uint32, uint32_t, uint32_t, "0x%x")
 NVLIST_PRTFUNC(int64, int64_t, longlong_t, "%lld")
 NVLIST_PRTFUNC(uint64, uint64_t, u_longlong_t, "0x%llx")
-NVLIST_PRTFUNC(double, double, double, "0x%llf")
+NVLIST_PRTFUNC(double, double, double, "0x%f")
 NVLIST_PRTFUNC(string, char *, char *, "%s")
 NVLIST_PRTFUNC(hrtime, hrtime_t, hrtime_t, "0x%llx")
 
@@ -793,6 +794,7 @@
 {
 	nvpair_t	*elem = NULL;
 	boolean_t	bool_value;
+	boolean_t	*bool_array_value;
 	nvlist_t	*nvlist_value;
 	nvlist_t	**nvlist_array_value;
 	uint_t		i, count;
@@ -853,6 +855,16 @@
 			NVP(elem, string, char *, char *, "'%s'");
 			break;
 
+		case DATA_TYPE_BOOLEAN_ARRAY:
+			(void) nvpair_value_boolean_array(elem,
+			    &bool_array_value, &count);
+			for (i = 0; i < count; i++) {
+				(void) printf("%*s%s[%d]: %s\n", indent, "",
+				    nvpair_name(elem), i,
+				    bool_array_value[i] ? "true" : "false");
+			}
+			break;
+
 		case DATA_TYPE_BYTE_ARRAY:
 			NVPA(elem, byte_array, uchar_t, int, "%u");
 			break;
@@ -1217,7 +1229,8 @@
 		break;
 	}
 	case DATA_TYPE_BOOLEAN_VALUE: {
-		boolean_t val, val_arg;
+		int32_t val_arg;
+		boolean_t val;
 
 		/* scanf boolean_t from value and check for match */
 		sr = sscanf(value, "%"SCNi32, &val_arg);
@@ -1228,7 +1241,8 @@
 		break;
 	}
 	case DATA_TYPE_BOOLEAN_ARRAY: {
-		boolean_t *val_array, val_arg;
+		boolean_t *val_array;
+		int32_t val_arg;
 
 		/* check indexed value of array for match */
 		sr = sscanf(value, "%"SCNi32, &val_arg);

Modified: trunk/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -20,6 +21,7 @@
  */
 /*
  * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  */
 
 #ifndef	_LIBNVPAIR_H
@@ -46,6 +48,7 @@
     char **);
 
 extern void nvlist_print(FILE *, nvlist_t *);
+extern int nvlist_print_json(FILE *, nvlist_t *);
 extern void dump_nvlist(nvlist_t *, int);
 
 /*

Modified: trunk/cddl/contrib/opensolaris/lib/libnvpair/nvpair_alloc_system.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libnvpair/nvpair_alloc_system.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libnvpair/nvpair_alloc_system.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Added: trunk/cddl/contrib/opensolaris/lib/libnvpair/nvpair_json.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libnvpair/nvpair_json.c	                        (rev 0)
+++ trunk/cddl/contrib/opensolaris/lib/libnvpair/nvpair_json.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -0,0 +1,404 @@
+/* $MidnightBSD$ */
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+/*
+ * Copyright (c) 2014, Joyent, Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <wchar.h>
+#include <sys/debug.h>
+
+#include "libnvpair.h"
+
+#define	FPRINTF(fp, ...)				\
+	do {						\
+		if (fprintf(fp, __VA_ARGS__) < 0)	\
+			return (-1);			\
+	} while (0)
+
+/*
+ * When formatting a string for JSON output we must escape certain characters,
+ * as described in RFC4627.  This applies to both member names and
+ * DATA_TYPE_STRING values.
+ *
+ * This function will only operate correctly if the following conditions are
+ * met:
+ *
+ *       1. The input String is encoded in the current locale.
+ *
+ *       2. The current locale includes the Basic Multilingual Plane (plane 0)
+ *          as defined in the Unicode standard.
+ *
+ * The output will be entirely 7-bit ASCII (as a subset of UTF-8) with all
+ * representable Unicode characters included in their escaped numeric form.
+ */
+static int
+nvlist_print_json_string(FILE *fp, const char *input)
+{
+	mbstate_t mbr;
+	wchar_t c;
+	size_t sz;
+
+	bzero(&mbr, sizeof (mbr));
+
+	FPRINTF(fp, "\"");
+	while ((sz = mbrtowc(&c, input, MB_CUR_MAX, &mbr)) > 0) {
+		switch (c) {
+		case '"':
+			FPRINTF(fp, "\\\"");
+			break;
+		case '\n':
+			FPRINTF(fp, "\\n");
+			break;
+		case '\r':
+			FPRINTF(fp, "\\r");
+			break;
+		case '\\':
+			FPRINTF(fp, "\\\\");
+			break;
+		case '\f':
+			FPRINTF(fp, "\\f");
+			break;
+		case '\t':
+			FPRINTF(fp, "\\t");
+			break;
+		case '\b':
+			FPRINTF(fp, "\\b");
+			break;
+		default:
+			if ((c >= 0x00 && c <= 0x1f) ||
+			    (c > 0x7f && c <= 0xffff)) {
+				/*
+				 * Render both Control Characters and Unicode
+				 * characters in the Basic Multilingual Plane
+				 * as JSON-escaped multibyte characters.
+				 */
+				FPRINTF(fp, "\\u%04x", (int)(0xffff & c));
+			} else if (c >= 0x20 && c <= 0x7f) {
+				/*
+				 * Render other 7-bit ASCII characters directly
+				 * and drop other, unrepresentable characters.
+				 */
+				FPRINTF(fp, "%c", (int)(0xff & c));
+			}
+			break;
+		}
+		input += sz;
+	}
+
+	if (sz == (size_t)-1 || sz == (size_t)-2) {
+		/*
+		 * We last read an invalid multibyte character sequence,
+		 * so return an error.
+		 */
+		return (-1);
+	}
+
+	FPRINTF(fp, "\"");
+	return (0);
+}
+
+/*
+ * Dump a JSON-formatted representation of an nvlist to the provided FILE *.
+ * This routine does not output any new-lines or additional whitespace other
+ * than that contained in strings, nor does it call fflush(3C).
+ */
+int
+nvlist_print_json(FILE *fp, nvlist_t *nvl)
+{
+	nvpair_t *curr;
+	boolean_t first = B_TRUE;
+
+	FPRINTF(fp, "{");
+
+	for (curr = nvlist_next_nvpair(nvl, NULL); curr;
+	    curr = nvlist_next_nvpair(nvl, curr)) {
+		data_type_t type = nvpair_type(curr);
+
+		if (!first)
+			FPRINTF(fp, ",");
+		else
+			first = B_FALSE;
+
+		if (nvlist_print_json_string(fp, nvpair_name(curr)) == -1)
+			return (-1);
+		FPRINTF(fp, ":");
+
+		switch (type) {
+		case DATA_TYPE_STRING: {
+			char *string = fnvpair_value_string(curr);
+			if (nvlist_print_json_string(fp, string) == -1)
+				return (-1);
+			break;
+		}
+
+		case DATA_TYPE_BOOLEAN: {
+			FPRINTF(fp, "true");
+			break;
+		}
+
+		case DATA_TYPE_BOOLEAN_VALUE: {
+			FPRINTF(fp, "%s", fnvpair_value_boolean_value(curr) ==
+			    B_TRUE ? "true" : "false");
+			break;
+		}
+
+		case DATA_TYPE_BYTE: {
+			FPRINTF(fp, "%hhu", fnvpair_value_byte(curr));
+			break;
+		}
+
+		case DATA_TYPE_INT8: {
+			FPRINTF(fp, "%hhd", fnvpair_value_int8(curr));
+			break;
+		}
+
+		case DATA_TYPE_UINT8: {
+			FPRINTF(fp, "%hhu", fnvpair_value_uint8_t(curr));
+			break;
+		}
+
+		case DATA_TYPE_INT16: {
+			FPRINTF(fp, "%hd", fnvpair_value_int16(curr));
+			break;
+		}
+
+		case DATA_TYPE_UINT16: {
+			FPRINTF(fp, "%hu", fnvpair_value_uint16(curr));
+			break;
+		}
+
+		case DATA_TYPE_INT32: {
+			FPRINTF(fp, "%d", fnvpair_value_int32(curr));
+			break;
+		}
+
+		case DATA_TYPE_UINT32: {
+			FPRINTF(fp, "%u", fnvpair_value_uint32(curr));
+			break;
+		}
+
+		case DATA_TYPE_INT64: {
+			FPRINTF(fp, "%lld",
+			    (long long)fnvpair_value_int64(curr));
+			break;
+		}
+
+		case DATA_TYPE_UINT64: {
+			FPRINTF(fp, "%llu",
+			    (unsigned long long)fnvpair_value_uint64(curr));
+			break;
+		}
+
+		case DATA_TYPE_HRTIME: {
+			hrtime_t val;
+			VERIFY0(nvpair_value_hrtime(curr, &val));
+			FPRINTF(fp, "%llu", (unsigned long long)val);
+			break;
+		}
+
+		case DATA_TYPE_DOUBLE: {
+			double val;
+			VERIFY0(nvpair_value_double(curr, &val));
+			FPRINTF(fp, "%f", val);
+			break;
+		}
+
+		case DATA_TYPE_NVLIST: {
+			if (nvlist_print_json(fp,
+			    fnvpair_value_nvlist(curr)) == -1)
+				return (-1);
+			break;
+		}
+
+		case DATA_TYPE_STRING_ARRAY: {
+			char **val;
+			uint_t valsz, i;
+			VERIFY0(nvpair_value_string_array(curr, &val, &valsz));
+			FPRINTF(fp, "[");
+			for (i = 0; i < valsz; i++) {
+				if (i > 0)
+					FPRINTF(fp, ",");
+				if (nvlist_print_json_string(fp, val[i]) == -1)
+					return (-1);
+			}
+			FPRINTF(fp, "]");
+			break;
+		}
+
+		case DATA_TYPE_NVLIST_ARRAY: {
+			nvlist_t **val;
+			uint_t valsz, i;
+			VERIFY0(nvpair_value_nvlist_array(curr, &val, &valsz));
+			FPRINTF(fp, "[");
+			for (i = 0; i < valsz; i++) {
+				if (i > 0)
+					FPRINTF(fp, ",");
+				if (nvlist_print_json(fp, val[i]) == -1)
+					return (-1);
+			}
+			FPRINTF(fp, "]");
+			break;
+		}
+
+		case DATA_TYPE_BOOLEAN_ARRAY: {
+			boolean_t *val;
+			uint_t valsz, i;
+			VERIFY0(nvpair_value_boolean_array(curr, &val, &valsz));
+			FPRINTF(fp, "[");
+			for (i = 0; i < valsz; i++) {
+				if (i > 0)
+					FPRINTF(fp, ",");
+				FPRINTF(fp, val[i] == B_TRUE ?
+				    "true" : "false");
+			}
+			FPRINTF(fp, "]");
+			break;
+		}
+
+		case DATA_TYPE_BYTE_ARRAY: {
+			uchar_t *val;
+			uint_t valsz, i;
+			VERIFY0(nvpair_value_byte_array(curr, &val, &valsz));
+			FPRINTF(fp, "[");
+			for (i = 0; i < valsz; i++) {
+				if (i > 0)
+					FPRINTF(fp, ",");
+				FPRINTF(fp, "%hhu", val[i]);
+			}
+			FPRINTF(fp, "]");
+			break;
+		}
+
+		case DATA_TYPE_UINT8_ARRAY: {
+			uint8_t *val;
+			uint_t valsz, i;
+			VERIFY0(nvpair_value_uint8_array(curr, &val, &valsz));
+			FPRINTF(fp, "[");
+			for (i = 0; i < valsz; i++) {
+				if (i > 0)
+					FPRINTF(fp, ",");
+				FPRINTF(fp, "%hhu", val[i]);
+			}
+			FPRINTF(fp, "]");
+			break;
+		}
+
+		case DATA_TYPE_INT8_ARRAY: {
+			int8_t *val;
+			uint_t valsz, i;
+			VERIFY0(nvpair_value_int8_array(curr, &val, &valsz));
+			FPRINTF(fp, "[");
+			for (i = 0; i < valsz; i++) {
+				if (i > 0)
+					FPRINTF(fp, ",");
+				FPRINTF(fp, "%hhd", val[i]);
+			}
+			FPRINTF(fp, "]");
+			break;
+		}
+
+		case DATA_TYPE_UINT16_ARRAY: {
+			uint16_t *val;
+			uint_t valsz, i;
+			VERIFY0(nvpair_value_uint16_array(curr, &val, &valsz));
+			FPRINTF(fp, "[");
+			for (i = 0; i < valsz; i++) {
+				if (i > 0)
+					FPRINTF(fp, ",");
+				FPRINTF(fp, "%hu", val[i]);
+			}
+			FPRINTF(fp, "]");
+			break;
+		}
+
+		case DATA_TYPE_INT16_ARRAY: {
+			int16_t *val;
+			uint_t valsz, i;
+			VERIFY0(nvpair_value_int16_array(curr, &val, &valsz));
+			FPRINTF(fp, "[");
+			for (i = 0; i < valsz; i++) {
+				if (i > 0)
+					FPRINTF(fp, ",");
+				FPRINTF(fp, "%hd", val[i]);
+			}
+			FPRINTF(fp, "]");
+			break;
+		}
+
+		case DATA_TYPE_UINT32_ARRAY: {
+			uint32_t *val;
+			uint_t valsz, i;
+			VERIFY0(nvpair_value_uint32_array(curr, &val, &valsz));
+			FPRINTF(fp, "[");
+			for (i = 0; i < valsz; i++) {
+				if (i > 0)
+					FPRINTF(fp, ",");
+				FPRINTF(fp, "%u", val[i]);
+			}
+			FPRINTF(fp, "]");
+			break;
+		}
+
+		case DATA_TYPE_INT32_ARRAY: {
+			int32_t *val;
+			uint_t valsz, i;
+			VERIFY0(nvpair_value_int32_array(curr, &val, &valsz));
+			FPRINTF(fp, "[");
+			for (i = 0; i < valsz; i++) {
+				if (i > 0)
+					FPRINTF(fp, ",");
+				FPRINTF(fp, "%d", val[i]);
+			}
+			FPRINTF(fp, "]");
+			break;
+		}
+
+		case DATA_TYPE_UINT64_ARRAY: {
+			uint64_t *val;
+			uint_t valsz, i;
+			VERIFY0(nvpair_value_uint64_array(curr, &val, &valsz));
+			FPRINTF(fp, "[");
+			for (i = 0; i < valsz; i++) {
+				if (i > 0)
+					FPRINTF(fp, ",");
+				FPRINTF(fp, "%llu",
+				    (unsigned long long)val[i]);
+			}
+			FPRINTF(fp, "]");
+			break;
+		}
+
+		case DATA_TYPE_INT64_ARRAY: {
+			int64_t *val;
+			uint_t valsz, i;
+			VERIFY0(nvpair_value_int64_array(curr, &val, &valsz));
+			FPRINTF(fp, "[");
+			for (i = 0; i < valsz; i++) {
+				if (i > 0)
+					FPRINTF(fp, ",");
+				FPRINTF(fp, "%lld", (long long)val[i]);
+			}
+			FPRINTF(fp, "]");
+			break;
+		}
+
+		case DATA_TYPE_UNKNOWN:
+			return (-1);
+		}
+	}
+
+	FPRINTF(fp, "}");
+	return (0);
+}


Property changes on: trunk/cddl/contrib/opensolaris/lib/libnvpair/nvpair_json.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/cddl/contrib/opensolaris/lib/libuutil/common/libuutil.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libuutil/common/libuutil.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libuutil/common/libuutil.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libuutil/common/libuutil_common.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libuutil/common/libuutil_common.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libuutil/common/libuutil_common.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libuutil/common/libuutil_impl.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libuutil/common/libuutil_impl.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libuutil/common/libuutil_impl.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_alloc.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_alloc.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_alloc.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_avl.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_avl.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_avl.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -128,6 +129,7 @@
 	pp->uap_next->uap_prev = pp->uap_prev;
 	pp->uap_prev->uap_next = pp->uap_next;
 	(void) pthread_mutex_unlock(&uu_apool_list_lock);
+	(void) pthread_mutex_destroy(&pp->uap_lock);
 	pp->uap_prev = NULL;
 	pp->uap_next = NULL;
 	uu_free(pp);

Modified: trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_dprintf.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_dprintf.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_dprintf.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_ident.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_ident.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_ident.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_list.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_list.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_list.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_misc.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_misc.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_misc.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_open.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_open.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_open.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_pname.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_pname.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_pname.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_string.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_string.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_string.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_strtoint.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_strtoint.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libuutil/common/uu_strtoint.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -21,13 +22,13 @@
 
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2011 Pawel Jakub Dawidek <pawel at dawidek.net>.
- * All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2011 Pawel Jakub Dawidek. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
  * Copyright (c) 2012 Martin Matuska <mm at FreeBSD.org>. All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
+ * Copyright (c) 2014 Integros [integros.com]
+ * Copyright 2016 Nexenta Systems, Inc.
  */
 
 #ifndef	_LIBZFS_H
@@ -42,6 +43,7 @@
 #include <sys/fs/zfs.h>
 #include <sys/avl.h>
 #include <sys/zfs_ioctl.h>
+#include <libzfs_core.h>
 
 #ifdef	__cplusplus
 extern "C" {
@@ -50,8 +52,6 @@
 /*
  * Miscellaneous ZFS constants
  */
-#define	ZFS_MAXNAMELEN		MAXNAMELEN
-#define	ZPOOL_MAXNAMELEN	MAXNAMELEN
 #define	ZFS_MAXPROPLEN		MAXPATHLEN
 #define	ZPOOL_MAXPROPLEN	MAXPATHLEN
 
@@ -193,6 +193,7 @@
 extern int libzfs_errno(libzfs_handle_t *);
 extern const char *libzfs_error_action(libzfs_handle_t *);
 extern const char *libzfs_error_description(libzfs_handle_t *);
+extern int zfs_standard_error(libzfs_handle_t *, int, const char *);
 extern void libzfs_mnttab_init(libzfs_handle_t *);
 extern void libzfs_mnttab_fini(libzfs_handle_t *);
 extern void libzfs_mnttab_cache(libzfs_handle_t *, boolean_t);
@@ -213,6 +214,7 @@
 extern const char *zpool_state_to_name(vdev_state_t, vdev_aux_t);
 extern const char *zpool_pool_state_to_name(pool_state_t);
 extern void zpool_free_handles(libzfs_handle_t *);
+extern int zpool_nextboot(libzfs_handle_t *, uint64_t, uint64_t, const char *);
 
 /*
  * Iterate over all active pools in the system.
@@ -219,6 +221,7 @@
  */
 typedef int (*zpool_iter_f)(zpool_handle_t *, void *);
 extern int zpool_iter(libzfs_handle_t *, zpool_iter_f, void *);
+extern boolean_t zpool_skip_pool(const char *);
 
 /*
  * Functions to create and destroy pools
@@ -269,7 +272,7 @@
  */
 extern int zpool_set_prop(zpool_handle_t *, const char *, const char *);
 extern int zpool_get_prop(zpool_handle_t *, zpool_prop_t, char *,
-    size_t proplen, zprop_source_t *);
+    size_t proplen, zprop_source_t *, boolean_t);
 extern uint64_t zpool_get_prop_int(zpool_handle_t *, zpool_prop_t,
     zprop_source_t *);
 
@@ -324,8 +327,9 @@
 	ZPOOL_STATUS_VERSION_OLDER,	/* older legacy on-disk version */
 	ZPOOL_STATUS_FEAT_DISABLED,	/* supported features are disabled */
 	ZPOOL_STATUS_RESILVERING,	/* device being resilvered */
-	ZPOOL_STATUS_OFFLINE_DEV,	/* device online */
+	ZPOOL_STATUS_OFFLINE_DEV,	/* device offline */
 	ZPOOL_STATUS_REMOVED_DEV,	/* removed device */
+	ZPOOL_STATUS_NON_NATIVE_ASHIFT,	/* (e.g. 512e dev with ashift of 9) */
 
 	/*
 	 * Finally, the following indicates a healthy pool.
@@ -408,6 +412,7 @@
 extern zfs_type_t zfs_get_type(const zfs_handle_t *);
 extern const char *zfs_get_name(const zfs_handle_t *);
 extern zpool_handle_t *zfs_get_pool_handle(const zfs_handle_t *);
+extern const char *zfs_get_pool_name(const zfs_handle_t *);
 
 /*
  * Property management functions.  Some functions are shared with the kernel,
@@ -423,10 +428,11 @@
 extern boolean_t zfs_prop_align_right(zfs_prop_t);
 
 extern nvlist_t *zfs_valid_proplist(libzfs_handle_t *, zfs_type_t,
-    nvlist_t *, uint64_t, zfs_handle_t *, const char *);
+    nvlist_t *, uint64_t, zfs_handle_t *, zpool_handle_t *, const char *);
 
 extern const char *zfs_prop_to_name(zfs_prop_t);
 extern int zfs_prop_set(zfs_handle_t *, const char *, const char *);
+extern int zfs_prop_set_list(zfs_handle_t *, nvlist_t *);
 extern int zfs_prop_get(zfs_handle_t *, zfs_prop_t, char *, size_t,
     zprop_source_t *, char *, size_t, boolean_t);
 extern int zfs_prop_get_recvd(zfs_handle_t *, const char *, char *, size_t,
@@ -462,7 +468,8 @@
 	boolean_t	pl_fixed;
 } zprop_list_t;
 
-extern int zfs_expand_proplist(zfs_handle_t *, zprop_list_t **, boolean_t);
+extern int zfs_expand_proplist(zfs_handle_t *, zprop_list_t **, boolean_t,
+    boolean_t);
 extern void zfs_prune_proplist(zfs_handle_t *, uint8_t *);
 
 #define	ZFS_MOUNTPOINT_NONE	"none"
@@ -535,6 +542,7 @@
 extern int zfs_iter_snapshots(zfs_handle_t *, boolean_t, zfs_iter_f, void *);
 extern int zfs_iter_snapshots_sorted(zfs_handle_t *, zfs_iter_f, void *);
 extern int zfs_iter_snapspec(zfs_handle_t *, const char *, zfs_iter_f, void *);
+extern int zfs_iter_bookmarks(zfs_handle_t *, zfs_iter_f, void *);
 
 typedef struct get_all_cb {
 	zfs_handle_t	**cb_handles;
@@ -603,6 +611,12 @@
 
 	/* show progress (ie. -v) */
 	boolean_t progress;
+
+	/* large blocks (>128K) are permitted */
+	boolean_t largeblock;
+
+	/* WRITE_EMBEDDED records of type DATA are permitted */
+	boolean_t embed_data;
 } sendflags_t;
 
 typedef boolean_t (snapfilter_cb_t)(zfs_handle_t *, void *);
@@ -609,6 +623,11 @@
 
 extern int zfs_send(zfs_handle_t *, const char *, const char *,
     sendflags_t *, int, snapfilter_cb_t, void *, nvlist_t **);
+extern int zfs_send_one(zfs_handle_t *, const char *, int, enum lzc_send_flags);
+extern int zfs_send_resume(libzfs_handle_t *, sendflags_t *, int outfd,
+    const char *);
+extern nvlist_t *zfs_send_resume_token_to_nvlist(libzfs_handle_t *hdl,
+    const char *token);
 
 extern int zfs_promote(zfs_handle_t *);
 extern int zfs_hold(zfs_handle_t *, const char *, const char *,
@@ -649,6 +668,12 @@
 	/* set "canmount=off" on all modified filesystems */
 	boolean_t canmountoff;
 
+	/*
+	 * Mark the file systems as "resumable" and do not destroy them if the
+	 * receive is interrupted
+	 */
+	boolean_t resumable;
+
 	/* byteswap flag is used internally; callers need not specify */
 	boolean_t byteswap;
 
@@ -656,8 +681,8 @@
 	boolean_t nomount;
 } recvflags_t;
 
-extern int zfs_receive(libzfs_handle_t *, const char *, recvflags_t *,
-    int, avl_tree_t *);
+extern int zfs_receive(libzfs_handle_t *, const char *, nvlist_t *,
+    recvflags_t *, int, avl_tree_t *);
 
 typedef enum diff_flags {
 	ZFS_DIFF_PARSEABLE = 0x1,
@@ -678,6 +703,7 @@
 extern boolean_t zfs_dataset_exists(libzfs_handle_t *, const char *,
     zfs_type_t);
 extern int zfs_spa_version(zfs_handle_t *, int *);
+extern boolean_t zfs_bookmark_exists(const char *path);
 
 /*
  * Mount support functions.
@@ -776,10 +802,10 @@
 extern boolean_t libzfs_fru_notself(libzfs_handle_t *, const char *);
 extern int zpool_fru_set(zpool_handle_t *, uint64_t, const char *);
 
-#ifndef sun
+#ifndef illumos
 extern int zmount(const char *, const char *, int, char *, char *, int, char *,
     int);
-#endif	/* !sun */
+#endif
 
 #ifdef	__cplusplus
 }

Modified: trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_changelist.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_changelist.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_changelist.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -24,9 +25,10 @@
  * Use is subject to license terms.
  *
  * Portions Copyright 2007 Ramprakash Jelari
- *
  * Copyright (c) 2011 Pawel Jakub Dawidek <pawel at dawidek.net>.
  * All rights reserved.
+ * Copyright (c) 2014, 2015 by Delphix. All rights reserved.
+ * Copyright 2016 Igor Kozhukhov <ikozhukhov at gmail.com>
  */
 
 #include <libintl.h>
@@ -136,6 +138,9 @@
 			case ZFS_PROP_SHARESMB:
 				(void) zfs_unshare_smb(cn->cn_handle, NULL);
 				break;
+
+			default:
+				break;
 			}
 		}
 	}
@@ -293,7 +298,7 @@
 changelist_rename(prop_changelist_t *clp, const char *src, const char *dst)
 {
 	prop_changenode_t *cn;
-	char newname[ZFS_MAXNAMELEN];
+	char newname[ZFS_MAX_DATASET_NAME_LEN];
 
 	for (cn = uu_list_first(clp->cl_list); cn != NULL;
 	    cn = uu_list_next(clp->cl_list, cn)) {

Modified: trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER SART
  *
@@ -72,16 +73,32 @@
 	if (zfs_ioctl_version == ZFS_IOCVER_UNDEF)
 		zfs_ioctl_version = get_zfs_ioctl_version();
 
-	if (zfs_ioctl_version == ZFS_IOCVER_LZC)
-		cflag = ZFS_CMD_COMPAT_LZC;
-	else if (zfs_ioctl_version == ZFS_IOCVER_DEADMAN)
-		cflag = ZFS_CMD_COMPAT_DEADMAN;
-
-	/*
-	 * If vfs.zfs.version.ioctl is not defined, assume we have v28
-	 * compatible binaries and use vfs.zfs.version.spa to test for v15
-	 */
-	if (zfs_ioctl_version < ZFS_IOCVER_DEADMAN) {
+	if (zfs_ioctl_version >= ZFS_IOCVER_DEADMAN) {
+		switch (zfs_ioctl_version) {
+		case ZFS_IOCVER_INLANES:
+			cflag = ZFS_CMD_COMPAT_INLANES;
+			break;
+		case ZFS_IOCVER_RESUME:
+			cflag = ZFS_CMD_COMPAT_RESUME;
+			break;
+		case ZFS_IOCVER_EDBP:
+			cflag = ZFS_CMD_COMPAT_EDBP;
+			break;
+		case ZFS_IOCVER_ZCMD:
+			cflag = ZFS_CMD_COMPAT_ZCMD;
+			break;
+		case ZFS_IOCVER_LZC:
+			cflag = ZFS_CMD_COMPAT_LZC;
+			break;
+		case ZFS_IOCVER_DEADMAN:
+			cflag = ZFS_CMD_COMPAT_DEADMAN;
+			break;
+		}
+	} else {
+		/*
+		 * If vfs.zfs.version.ioctl is not defined, assume we have v28
+		 * compatible binaries and use vfs.zfs.version.spa to test for v15
+		 */
 		cflag = ZFS_CMD_COMPAT_V28;
 
 		if (zfs_spa_version < 0)

Modified: trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER SART
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_config.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_config.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_config.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -26,6 +27,8 @@
 
 /*
  * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2015 by Syneto S.R.L. All rights reserved.
+ * Copyright 2016 Nexenta Systems, Inc.
  */
 
 /*
@@ -246,8 +249,9 @@
 		config = zpool_get_config(zhp, NULL);
 	}
 
-	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_FEATURE_STATS,
-	    &features) == 0);
+	if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_FEATURE_STATS,
+	    &features) != 0)
+		return (NULL);
 
 	return (features);
 }
@@ -316,8 +320,7 @@
 		verify(nvlist_lookup_uint64(config,
 		    ZPOOL_CONFIG_POOL_TXG, &newtxg) == 0);
 
-		if (zhp->zpool_old_config != NULL)
-			nvlist_free(zhp->zpool_old_config);
+		nvlist_free(zhp->zpool_old_config);
 
 		if (oldtxg != newtxg) {
 			nvlist_free(zhp->zpool_config);
@@ -337,33 +340,47 @@
 }
 
 /*
- * If the __ZFS_POOL_RESTRICT environment variable is set we only iterate over
- * pools it lists.
+ * The following environment variables are undocumented
+ * and should be used for testing purposes only:
  *
- * This is an undocumented feature for use during testing only.
+ * __ZFS_POOL_EXCLUDE - don't iterate over the pools it lists
+ * __ZFS_POOL_RESTRICT - iterate only over the pools it lists
  *
  * This function returns B_TRUE if the pool should be skipped
  * during iteration.
  */
-static boolean_t
-check_restricted(const char *poolname)
+boolean_t
+zpool_skip_pool(const char *poolname)
 {
 	static boolean_t initialized = B_FALSE;
-	static char *restricted = NULL;
+	static const char *exclude = NULL;
+	static const char *restricted = NULL;
 
 	const char *cur, *end;
-	int len, namelen;
+	int len;
+	int namelen = strlen(poolname);
 
 	if (!initialized) {
 		initialized = B_TRUE;
+		exclude = getenv("__ZFS_POOL_EXCLUDE");
 		restricted = getenv("__ZFS_POOL_RESTRICT");
 	}
 
+	if (exclude != NULL) {
+		cur = exclude;
+		do {
+			end = strchr(cur, ' ');
+			len = (NULL == end) ? strlen(cur) : (end - cur);
+			if (len == namelen && 0 == strncmp(cur, poolname, len))
+				return (B_TRUE);
+			cur += (len + 1);
+		} while (NULL != end);
+	}
+
 	if (NULL == restricted)
 		return (B_FALSE);
 
 	cur = restricted;
-	namelen = strlen(poolname);
 	do {
 		end = strchr(cur, ' ');
 		len = (NULL == end) ? strlen(cur) : (end - cur);
@@ -401,7 +418,7 @@
 	for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
 	    cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
 
-		if (check_restricted(cn->cn_name))
+		if (zpool_skip_pool(cn->cn_name))
 			continue;
 
 		if (zpool_open_silent(hdl, cn->cn_name, &zhp) != 0) {
@@ -439,7 +456,7 @@
 	for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
 	    cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
 
-		if (check_restricted(cn->cn_name))
+		if (zpool_skip_pool(cn->cn_name))
 			continue;
 
 		if ((zhp = make_dataset_handle(hdl, cn->cn_name)) == NULL)

Modified: trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -21,13 +22,15 @@
 
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
  * Copyright (c) 2012 DEY Storage Systems, Inc.  All rights reserved.
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2011-2012 Pawel Jakub Dawidek <pawel at dawidek.net>.
- * All rights reserved.
- * Copyright (c) 2012 Martin Matuska <mm at FreeBSD.org>. All rights reserved.
+ * Copyright (c) 2011-2012 Pawel Jakub Dawidek. All rights reserved.
+ * Copyright (c) 2013 Martin Matuska. All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
+ * Copyright (c) 2014 Integros [integros.com]
+ * Copyright 2016 Igor Kozhukhov <ikozhukhov at gmail.com>
+ * Copyright 2016 Nexenta Systems, Inc.
  */
 
 #include <ctype.h>
@@ -77,6 +80,12 @@
 		return (dgettext(TEXT_DOMAIN, "snapshot"));
 	case ZFS_TYPE_VOLUME:
 		return (dgettext(TEXT_DOMAIN, "volume"));
+	case ZFS_TYPE_POOL:
+		return (dgettext(TEXT_DOMAIN, "pool"));
+	case ZFS_TYPE_BOOKMARK:
+		return (dgettext(TEXT_DOMAIN, "bookmark"));
+	default:
+		assert(!"unhandled zfs_type_t");
 	}
 
 	return (NULL);
@@ -83,49 +92,6 @@
 }
 
 /*
- * Given a path and mask of ZFS types, return a string describing this dataset.
- * This is used when we fail to open a dataset and we cannot get an exact type.
- * We guess what the type would have been based on the path and the mask of
- * acceptable types.
- */
-static const char *
-path_to_str(const char *path, int types)
-{
-	/*
-	 * When given a single type, always report the exact type.
-	 */
-	if (types == ZFS_TYPE_SNAPSHOT)
-		return (dgettext(TEXT_DOMAIN, "snapshot"));
-	if (types == ZFS_TYPE_FILESYSTEM)
-		return (dgettext(TEXT_DOMAIN, "filesystem"));
-	if (types == ZFS_TYPE_VOLUME)
-		return (dgettext(TEXT_DOMAIN, "volume"));
-
-	/*
-	 * The user is requesting more than one type of dataset.  If this is the
-	 * case, consult the path itself.  If we're looking for a snapshot, and
-	 * a '@' is found, then report it as "snapshot".  Otherwise, remove the
-	 * snapshot attribute and try again.
-	 */
-	if (types & ZFS_TYPE_SNAPSHOT) {
-		if (strchr(path, '@') != NULL)
-			return (dgettext(TEXT_DOMAIN, "snapshot"));
-		return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT));
-	}
-
-	/*
-	 * The user has requested either filesystems or volumes.
-	 * We have no way of knowing a priori what type this would be, so always
-	 * report it as "filesystem" or "volume", our two primitive types.
-	 */
-	if (types & ZFS_TYPE_FILESYSTEM)
-		return (dgettext(TEXT_DOMAIN, "filesystem"));
-
-	assert(types & ZFS_TYPE_VOLUME);
-	return (dgettext(TEXT_DOMAIN, "volume"));
-}
-
-/*
  * Validate a ZFS path.  This is used even before trying to open the dataset, to
  * provide a more meaningful error message.  We call zfs_error_aux() to
  * explain exactly why the name was not valid.
@@ -186,6 +152,11 @@
 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 				    "reserved disk name"));
 				break;
+
+			default:
+				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+				    "(%d) not defined"), why);
+				break;
 			}
 		}
 
@@ -295,7 +266,7 @@
 	int len;
 	zpool_handle_t *zph;
 
-	len = strcspn(zhp->zfs_name, "/@") + 1;
+	len = strcspn(zhp->zfs_name, "/@#") + 1;
 	pool_name = zfs_alloc(zhp->zfs_hdl, len);
 	(void) strlcpy(pool_name, zhp->zfs_name, len);
 
@@ -579,6 +550,70 @@
 	return (zhp);
 }
 
+boolean_t
+zfs_bookmark_exists(const char *path)
+{
+	nvlist_t *bmarks;
+	nvlist_t *props;
+	char fsname[ZFS_MAX_DATASET_NAME_LEN];
+	char *bmark_name;
+	char *pound;
+	int err;
+	boolean_t rv;
+
+
+	(void) strlcpy(fsname, path, sizeof (fsname));
+	pound = strchr(fsname, '#');
+	if (pound == NULL)
+		return (B_FALSE);
+
+	*pound = '\0';
+	bmark_name = pound + 1;
+	props = fnvlist_alloc();
+	err = lzc_get_bookmarks(fsname, props, &bmarks);
+	nvlist_free(props);
+	if (err != 0) {
+		nvlist_free(bmarks);
+		return (B_FALSE);
+	}
+
+	rv = nvlist_exists(bmarks, bmark_name);
+	nvlist_free(bmarks);
+	return (rv);
+}
+
+zfs_handle_t *
+make_bookmark_handle(zfs_handle_t *parent, const char *path,
+    nvlist_t *bmark_props)
+{
+	zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
+
+	if (zhp == NULL)
+		return (NULL);
+
+	/* Fill in the name. */
+	zhp->zfs_hdl = parent->zfs_hdl;
+	(void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
+
+	/* Set the property lists. */
+	if (nvlist_dup(bmark_props, &zhp->zfs_props, 0) != 0) {
+		free(zhp);
+		return (NULL);
+	}
+
+	/* Set the types. */
+	zhp->zfs_head_type = parent->zfs_head_type;
+	zhp->zfs_type = ZFS_TYPE_BOOKMARK;
+
+	if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL) {
+		nvlist_free(zhp->zfs_props);
+		free(zhp);
+		return (NULL);
+	}
+
+	return (zhp);
+}
+
 /*
  * Opens the given snapshot, filesystem, or volume.   The 'types'
  * argument is a mask of acceptable types.  The function will print an
@@ -704,7 +739,8 @@
 	void *cookie = NULL;
 	mnttab_node_t *mtn;
 
-	while (mtn = avl_destroy_nodes(&hdl->libzfs_mnttab_cache, &cookie)) {
+	while ((mtn = avl_destroy_nodes(&hdl->libzfs_mnttab_cache, &cookie))
+	    != NULL) {
 		free(mtn->mtn_mt.mnt_special);
 		free(mtn->mtn_mt.mnt_mountp);
 		free(mtn->mtn_mt.mnt_fstype);
@@ -776,7 +812,8 @@
 	mnttab_node_t *ret;
 
 	find.mtn_mt.mnt_special = (char *)fsname;
-	if (ret = avl_find(&hdl->libzfs_mnttab_cache, (void *)&find, NULL)) {
+	if ((ret = avl_find(&hdl->libzfs_mnttab_cache, (void *)&find, NULL))
+	    != NULL) {
 		avl_remove(&hdl->libzfs_mnttab_cache, ret);
 		free(ret->mtn_mt.mnt_special);
 		free(ret->mtn_mt.mnt_mountp);
@@ -825,7 +862,8 @@
  */
 nvlist_t *
 zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
-    uint64_t zoned, zfs_handle_t *zhp, const char *errbuf)
+    uint64_t zoned, zfs_handle_t *zhp, zpool_handle_t *zpool_hdl,
+    const char *errbuf)
 {
 	nvpair_t *elem;
 	uint64_t intval;
@@ -1015,24 +1053,39 @@
 			break;
 		}
 
+		case ZFS_PROP_VOLBLOCKSIZE:
 		case ZFS_PROP_RECORDSIZE:
-		case ZFS_PROP_VOLBLOCKSIZE:
-			/* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */
+		{
+			int maxbs = SPA_MAXBLOCKSIZE;
+			if (zpool_hdl != NULL) {
+				maxbs = zpool_get_prop_int(zpool_hdl,
+				    ZPOOL_PROP_MAXBLOCKSIZE, NULL);
+			}
+			/*
+			 * Volumes are limited to a volblocksize of 128KB,
+			 * because they typically service workloads with
+			 * small random writes, which incur a large performance
+			 * penalty with large blocks.
+			 */
+			if (prop == ZFS_PROP_VOLBLOCKSIZE)
+				maxbs = SPA_OLD_MAXBLOCKSIZE;
+			/*
+			 * The value must be a power of two between
+			 * SPA_MINBLOCKSIZE and maxbs.
+			 */
 			if (intval < SPA_MINBLOCKSIZE ||
-			    intval > SPA_MAXBLOCKSIZE || !ISP2(intval)) {
+			    intval > maxbs || !ISP2(intval)) {
 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
-				    "'%s' must be power of 2 from %u "
-				    "to %uk"), propname,
-				    (uint_t)SPA_MINBLOCKSIZE,
-				    (uint_t)SPA_MAXBLOCKSIZE >> 10);
+				    "'%s' must be power of 2 from 512B "
+				    "to %uKB"), propname, maxbs >> 10);
 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
 				goto error;
 			}
 			break;
-
+		}
 		case ZFS_PROP_MLSLABEL:
 		{
-#ifdef sun
+#ifdef illumos
 			/*
 			 * Verify the mlslabel string and convert to
 			 * internal hex label string.
@@ -1081,11 +1134,11 @@
 			    "invalid mlslabel '%s'"), strval);
 			(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
 			m_label_free(new_sl);	/* OK if null */
-#else	/* !sun */
+#else	/* !illumos */
 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 			    "mlslabel is not supported on FreeBSD"));
 			(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
-#endif	/* !sun */
+#endif	/* illumos */
 			goto error;
 
 		}
@@ -1112,6 +1165,13 @@
 					    "component of '%s' is too long"),
 					    propname);
 					break;
+
+				default:
+					zfs_error_aux(hdl,
+					    dgettext(TEXT_DOMAIN,
+					    "(%d) not defined"),
+					    why);
+					break;
 				}
 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
 				goto error;
@@ -1230,12 +1290,17 @@
 			}
 
 			break;
+
 		case ZFS_PROP_UTF8ONLY:
 			chosen_utf = (int)intval;
 			break;
+
 		case ZFS_PROP_NORMALIZE:
 			chosen_normal = (int)intval;
 			break;
+
+		default:
+			break;
 		}
 
 		/*
@@ -1284,6 +1349,9 @@
 					goto error;
 				}
 				break;
+
+			default:
+				break;
 			}
 		}
 	}
@@ -1323,6 +1391,7 @@
 	uint64_t old_reservation;
 	uint64_t new_reservation;
 	zfs_prop_t resv_prop;
+	nvlist_t *props;
 
 	/*
 	 * If this is an existing volume, and someone is setting the volsize,
@@ -1332,16 +1401,25 @@
 	if (zfs_which_resv_prop(zhp, &resv_prop) < 0)
 		return (-1);
 	old_reservation = zfs_prop_get_int(zhp, resv_prop);
-	if ((zvol_volsize_to_reservation(old_volsize, zhp->zfs_props) !=
-	    old_reservation) || nvlist_lookup_uint64(nvl,
-	    zfs_prop_to_name(resv_prop), &new_reservation) != ENOENT) {
+
+	props = fnvlist_alloc();
+	fnvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
+	    zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE));
+
+	if ((zvol_volsize_to_reservation(old_volsize, props) !=
+	    old_reservation) || nvlist_exists(nvl,
+	    zfs_prop_to_name(resv_prop))) {
+		fnvlist_free(props);
 		return (0);
 	}
 	if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE),
-	    &new_volsize) != 0)
+	    &new_volsize) != 0) {
+		fnvlist_free(props);
 		return (-1);
-	new_reservation = zvol_volsize_to_reservation(new_volsize,
-	    zhp->zfs_props);
+	}
+	new_reservation = zvol_volsize_to_reservation(new_volsize, props);
+	fnvlist_free(props);
+
 	if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop),
 	    new_reservation) != 0) {
 		(void) no_memory(zhp->zfs_hdl);
@@ -1400,11 +1478,19 @@
 		break;
 
 	case ERANGE:
-		if (prop == ZFS_PROP_COMPRESSION) {
+	case EDOM:
+		if (prop == ZFS_PROP_COMPRESSION ||
+		    prop == ZFS_PROP_RECORDSIZE) {
 			(void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 			    "property setting is not allowed on "
 			    "bootable datasets"));
 			(void) zfs_error(hdl, EZFS_NOTSUP, errbuf);
+		} else if (prop == ZFS_PROP_CHECKSUM ||
+		    prop == ZFS_PROP_DEDUP) {
+			(void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+			    "property setting is not allowed on "
+			    "root pools"));
+			(void) zfs_error(hdl, EZFS_NOTSUP, errbuf);
 		} else {
 			(void) zfs_standard_error(hdl, err, errbuf);
 		}
@@ -1440,15 +1526,10 @@
 int
 zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
 {
-	zfs_cmd_t zc = { 0 };
 	int ret = -1;
-	prop_changelist_t *cl = NULL;
 	char errbuf[1024];
 	libzfs_handle_t *hdl = zhp->zfs_hdl;
-	nvlist_t *nvl = NULL, *realprops;
-	zfs_prop_t prop;
-	boolean_t do_prefix = B_TRUE;
-	int added_resv;
+	nvlist_t *nvl = NULL;
 
 	(void) snprintf(errbuf, sizeof (errbuf),
 	    dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
@@ -1460,79 +1541,150 @@
 		goto error;
 	}
 
-	if ((realprops = zfs_valid_proplist(hdl, zhp->zfs_type, nvl,
-	    zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL)
-		goto error;
+	ret = zfs_prop_set_list(zhp, nvl);
 
+error:
 	nvlist_free(nvl);
-	nvl = realprops;
+	return (ret);
+}
 
-	prop = zfs_name_to_prop(propname);
 
-	/* We don't support those properties on FreeBSD. */
-	switch (prop) {
-	case ZFS_PROP_DEVICES:
-	case ZFS_PROP_ISCSIOPTIONS:
-	case ZFS_PROP_XATTR:
-	case ZFS_PROP_VSCAN:
-	case ZFS_PROP_NBMAND:
-	case ZFS_PROP_MLSLABEL:
-		(void) snprintf(errbuf, sizeof (errbuf),
-		    "property '%s' not supported on FreeBSD", propname);
-		ret = zfs_error(hdl, EZFS_PERM, errbuf);
-		goto error;
-	}
 
-	if (prop == ZFS_PROP_VOLSIZE) {
-		if ((added_resv = zfs_add_synthetic_resv(zhp, nvl)) == -1)
-			goto error;
-	}
+/*
+ * Given an nvlist of property names and values, set the properties for the
+ * given dataset.
+ */
+int
+zfs_prop_set_list(zfs_handle_t *zhp, nvlist_t *props)
+{
+	zfs_cmd_t zc = { 0 };
+	int ret = -1;
+	prop_changelist_t **cls = NULL;
+	int cl_idx;
+	char errbuf[1024];
+	libzfs_handle_t *hdl = zhp->zfs_hdl;
+	nvlist_t *nvl;
+	int nvl_len;
+	int added_resv = 0;
 
-	if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL)
-		goto error;
+	(void) snprintf(errbuf, sizeof (errbuf),
+	    dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
+	    zhp->zfs_name);
 
-	if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) {
-		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
-		    "child dataset with inherited mountpoint is used "
-		    "in a non-global zone"));
-		ret = zfs_error(hdl, EZFS_ZONED, errbuf);
+	if ((nvl = zfs_valid_proplist(hdl, zhp->zfs_type, props,
+	    zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, zhp->zpool_hdl,
+	    errbuf)) == NULL)
 		goto error;
-	}
 
 	/*
-	 * We don't want to unmount & remount the dataset when changing
-	 * its canmount property to 'on' or 'noauto'.  We only use
-	 * the changelist logic to unmount when setting canmount=off.
+	 * We have to check for any extra properties which need to be added
+	 * before computing the length of the nvlist.
 	 */
-	if (prop == ZFS_PROP_CANMOUNT) {
-		uint64_t idx;
-		int err = zprop_string_to_index(prop, propval, &idx,
-		    ZFS_TYPE_DATASET);
-		if (err == 0 && idx != ZFS_CANMOUNT_OFF)
-			do_prefix = B_FALSE;
+	for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL);
+	    elem != NULL;
+	    elem = nvlist_next_nvpair(nvl, elem)) {
+		if (zfs_name_to_prop(nvpair_name(elem)) == ZFS_PROP_VOLSIZE &&
+		    (added_resv = zfs_add_synthetic_resv(zhp, nvl)) == -1) {
+			goto error;
+		}
 	}
-
-	if (do_prefix && (ret = changelist_prefix(cl)) != 0)
+	/*
+	 * Check how many properties we're setting and allocate an array to
+	 * store changelist pointers for postfix().
+	 */
+	nvl_len = 0;
+	for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL);
+	    elem != NULL;
+	    elem = nvlist_next_nvpair(nvl, elem))
+		nvl_len++;
+	if ((cls = calloc(nvl_len, sizeof (prop_changelist_t *))) == NULL)
 		goto error;
 
+	cl_idx = 0;
+	for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL);
+	    elem != NULL;
+	    elem = nvlist_next_nvpair(nvl, elem)) {
+
+		zfs_prop_t prop = zfs_name_to_prop(nvpair_name(elem));
+
+		assert(cl_idx < nvl_len);
+		/*
+		 * We don't want to unmount & remount the dataset when changing
+		 * its canmount property to 'on' or 'noauto'.  We only use
+		 * the changelist logic to unmount when setting canmount=off.
+		 */
+		if (prop != ZFS_PROP_CANMOUNT ||
+		    (fnvpair_value_uint64(elem) == ZFS_CANMOUNT_OFF &&
+		     zfs_is_mounted(zhp, NULL))) {
+			cls[cl_idx] = changelist_gather(zhp, prop, 0, 0);
+			if (cls[cl_idx] == NULL)
+				goto error;
+		}
+
+		if (prop == ZFS_PROP_MOUNTPOINT &&
+		    changelist_haszonedchild(cls[cl_idx])) {
+			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+			    "child dataset with inherited mountpoint is used "
+			    "in a non-global zone"));
+			ret = zfs_error(hdl, EZFS_ZONED, errbuf);
+			goto error;
+		}
+
+		/* We don't support those properties on FreeBSD. */
+		switch (prop) {
+		case ZFS_PROP_DEVICES:
+		case ZFS_PROP_ISCSIOPTIONS:
+		case ZFS_PROP_XATTR:
+		case ZFS_PROP_VSCAN:
+		case ZFS_PROP_NBMAND:
+		case ZFS_PROP_MLSLABEL:
+			(void) snprintf(errbuf, sizeof (errbuf),
+			    "property '%s' not supported on FreeBSD",
+			    nvpair_name(elem));
+			ret = zfs_error(hdl, EZFS_PERM, errbuf);
+			goto error;
+		}
+
+		if (cls[cl_idx] != NULL &&
+		    (ret = changelist_prefix(cls[cl_idx])) != 0)
+			goto error;
+
+		cl_idx++;
+	}
+	assert(cl_idx == nvl_len);
+
 	/*
-	 * Execute the corresponding ioctl() to set this property.
+	 * Execute the corresponding ioctl() to set this list of properties.
 	 */
 	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
 
-	if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0)
+	if ((ret = zcmd_write_src_nvlist(hdl, &zc, nvl)) != 0 ||
+	    (ret = zcmd_alloc_dst_nvlist(hdl, &zc, 0)) != 0)
 		goto error;
 
 	ret = zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc);
 
 	if (ret != 0) {
-		zfs_setprop_error(hdl, prop, errno, errbuf);
+		/* Get the list of unset properties back and report them. */
+		nvlist_t *errorprops = NULL;
+		if (zcmd_read_dst_nvlist(hdl, &zc, &errorprops) != 0)
+			goto error;
+		for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL);
+		    elem != NULL;
+		    elem = nvlist_next_nvpair(nvl, elem)) {
+			zfs_prop_t prop = zfs_name_to_prop(nvpair_name(elem));
+			zfs_setprop_error(hdl, prop, errno, errbuf);
+		}
+		nvlist_free(errorprops);
+
 		if (added_resv && errno == ENOSPC) {
 			/* clean up the volsize property we tried to set */
 			uint64_t old_volsize = zfs_prop_get_int(zhp,
 			    ZFS_PROP_VOLSIZE);
 			nvlist_free(nvl);
+			nvl = NULL;
 			zcmd_free_nvlists(&zc);
+
 			if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
 				goto error;
 			if (nvlist_add_uint64(nvl,
@@ -1544,8 +1696,13 @@
 			(void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc);
 		}
 	} else {
-		if (do_prefix)
-			ret = changelist_postfix(cl);
+		for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) {
+			if (cls[cl_idx] != NULL) {
+				int clp_err = changelist_postfix(cls[cl_idx]);
+				if (clp_err != 0)
+					ret = clp_err;
+			}
+		}
 
 		/*
 		 * Refresh the statistics so the new property value
@@ -1558,8 +1715,13 @@
 error:
 	nvlist_free(nvl);
 	zcmd_free_nvlists(&zc);
-	if (cl)
-		changelist_free(cl);
+	if (cls != NULL) {
+		for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) {
+			if (cls[cl_idx] != NULL)
+				changelist_free(cls[cl_idx]);
+		}
+		free(cls);
+	}
 	return (ret);
 }
 
@@ -1690,22 +1852,21 @@
 	return (value);
 }
 
-static char *
+static const char *
 getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
 {
 	nvlist_t *nv;
-	char *value;
+	const char *value;
 
 	*source = NULL;
 	if (nvlist_lookup_nvlist(zhp->zfs_props,
 	    zfs_prop_to_name(prop), &nv) == 0) {
-		verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0);
+		value = fnvlist_lookup_string(nv, ZPROP_VALUE);
 		(void) nvlist_lookup_string(nv, ZPROP_SOURCE, source);
 	} else {
 		verify(!zhp->zfs_props_table ||
 		    zhp->zfs_props_table[prop] == B_TRUE);
-		if ((value = (char *)zfs_prop_default_string(prop)) == NULL)
-			value = "";
+		value = zfs_prop_default_string(prop);
 		*source = "";
 	}
 
@@ -1789,6 +1950,9 @@
 		mntopt_on = MNTOPT_NBMAND;
 		mntopt_off = MNTOPT_NONBMAND;
 		break;
+
+	default:
+		break;
 	}
 
 	/*
@@ -1846,6 +2010,10 @@
 	case ZFS_PROP_REFQUOTA:
 	case ZFS_PROP_RESERVATION:
 	case ZFS_PROP_REFRESERVATION:
+	case ZFS_PROP_FILESYSTEM_LIMIT:
+	case ZFS_PROP_SNAPSHOT_LIMIT:
+	case ZFS_PROP_FILESYSTEM_COUNT:
+	case ZFS_PROP_SNAPSHOT_COUNT:
 		*val = getprop_uint64(zhp, prop, source);
 
 		if (*source == NULL) {
@@ -1880,11 +2048,14 @@
 			zcmd_free_nvlists(&zc);
 			return (-1);
 		}
-		if (zplprops)
-			nvlist_free(zplprops);
+		nvlist_free(zplprops);
 		zcmd_free_nvlists(&zc);
 		break;
 
+	case ZFS_PROP_INCONSISTENT:
+		*val = zhp->zfs_dmustats.dds_inconsistent;
+		break;
+
 	default:
 		switch (zfs_prop_get_type(prop)) {
 		case PROP_TYPE_NUMBER:
@@ -1898,6 +2069,7 @@
 			if (zfs_prop_readonly(prop) &&
 			    *source != NULL && (*source)[0] == '\0') {
 				*source = NULL;
+				return (-1);
 			}
 			break;
 
@@ -2000,7 +2172,7 @@
 	uint64_t numclones;
 	nvlist_t *value;
 	const char *origin;
-	char buf[ZFS_MAXNAMELEN];
+	char buf[ZFS_MAX_DATASET_NAME_LEN];
 };
 
 int
@@ -2055,7 +2227,7 @@
 
 		if (gca.numclones != 0) {
 			zfs_handle_t *root;
-			char pool[ZFS_MAXNAMELEN];
+			char pool[ZFS_MAX_DATASET_NAME_LEN];
 			char *cp = pool;
 
 			/* get the pool name */
@@ -2099,7 +2271,7 @@
 {
 	char *source = NULL;
 	uint64_t val;
-	char *str;
+	const char *str;
 	const char *strval;
 	boolean_t received = zfs_is_recvd_props_mode(zhp);
 
@@ -2169,8 +2341,8 @@
 			}
 
 			if ((zpool_get_prop(zhp->zpool_hdl,
-			    ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL)) ||
-			    (strcmp(root, "-") == 0))
+			    ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL,
+			    B_FALSE)) || (strcmp(root, "-") == 0))
 				root[0] = '\0';
 			/*
 			 * Special case an alternate root of '/'. This will
@@ -2204,14 +2376,10 @@
 		break;
 
 	case ZFS_PROP_ORIGIN:
-		(void) strlcpy(propbuf, getprop_string(zhp, prop, &source),
-		    proplen);
-		/*
-		 * If there is no parent at all, return failure to indicate that
-		 * it doesn't apply to this dataset.
-		 */
-		if (propbuf[0] == '\0')
+		str = getprop_string(zhp, prop, &source);
+		if (str == NULL)
 			return (-1);
+		(void) strlcpy(propbuf, str, proplen);
 		break;
 
 	case ZFS_PROP_CLONES:
@@ -2247,6 +2415,30 @@
 		}
 		break;
 
+	case ZFS_PROP_FILESYSTEM_LIMIT:
+	case ZFS_PROP_SNAPSHOT_LIMIT:
+	case ZFS_PROP_FILESYSTEM_COUNT:
+	case ZFS_PROP_SNAPSHOT_COUNT:
+
+		if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
+			return (-1);
+
+		/*
+		 * If limit is UINT64_MAX, we translate this into 'none' (unless
+		 * literal is set), and indicate that it's the default value.
+		 * Otherwise, we print the number nicely and indicate that it's
+		 * set locally.
+		 */
+		if (literal) {
+			(void) snprintf(propbuf, proplen, "%llu",
+			    (u_longlong_t)val);
+		} else if (val == UINT64_MAX) {
+			(void) strlcpy(propbuf, "none", proplen);
+		} else {
+			zfs_nicenum(val, propbuf, proplen);
+		}
+		break;
+
 	case ZFS_PROP_REFRATIO:
 	case ZFS_PROP_COMPRESSRATIO:
 		if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
@@ -2267,6 +2459,9 @@
 		case ZFS_TYPE_SNAPSHOT:
 			str = "snapshot";
 			break;
+		case ZFS_TYPE_BOOKMARK:
+			str = "bookmark";
+			break;
 		default:
 			abort();
 		}
@@ -2300,7 +2495,7 @@
 
 	case ZFS_PROP_MLSLABEL:
 		{
-#ifdef sun
+#ifdef illumos
 			m_label_t *new_sl = NULL;
 			char *ascii = NULL;	/* human readable label */
 
@@ -2334,9 +2529,9 @@
 
 			(void) strlcpy(propbuf, ascii, proplen);
 			free(ascii);
-#else	/* !sun */
+#else	/* !illumos */
 			propbuf[0] = '\0';
-#endif	/* !sun */
+#endif	/* illumos */
 		}
 		break;
 
@@ -2365,8 +2560,10 @@
 			break;
 
 		case PROP_TYPE_STRING:
-			(void) strlcpy(propbuf,
-			    getprop_string(zhp, prop, &source), proplen);
+			str = getprop_string(zhp, prop, &source);
+			if (str == NULL)
+				return (-1);
+			(void) strlcpy(propbuf, str, proplen);
 			break;
 
 		case PROP_TYPE_INDEX:
@@ -2446,7 +2643,7 @@
 idmap_id_to_numeric_domain_rid(uid_t id, boolean_t isuser,
     char **domainp, idmap_rid_t *ridp)
 {
-#ifdef sun
+#ifdef illumos
 	idmap_get_handle_t *get_hdl = NULL;
 	idmap_stat status;
 	int err = EINVAL;
@@ -2471,9 +2668,10 @@
 	if (get_hdl)
 		idmap_get_destroy(get_hdl);
 	return (err);
-#else	/* !sun */
+#else	/* !illumos */
 	assert(!"invalid code path");
-#endif	/* !sun */
+	return (EINVAL); // silence compiler warning
+#endif	/* illumos */
 }
 
 /*
@@ -2491,7 +2689,7 @@
 	boolean_t isuser;
 
 	domain[0] = '\0';
-
+	*ridp = 0;
 	/* Figure out the property type ({user|group}{quota|space}) */
 	for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++) {
 		if (strncmp(propname, zfs_userquota_prop_prefixes[type],
@@ -2508,43 +2706,69 @@
 	cp = strchr(propname, '@') + 1;
 
 	if (strchr(cp, '@')) {
-#ifdef sun
+#ifdef illumos
 		/*
 		 * It's a SID name (eg "user at domain") that needs to be
 		 * turned into S-1-domainID-RID.
 		 */
-		directory_error_t e;
+		int flag = 0;
+		idmap_stat stat, map_stat;
+		uid_t pid;
+		idmap_rid_t rid;
+		idmap_get_handle_t *gh = NULL;
+
+		stat = idmap_get_create(&gh);
+		if (stat != IDMAP_SUCCESS) {
+			idmap_get_destroy(gh);
+			return (ENOMEM);
+		}
 		if (zoned && getzoneid() == GLOBAL_ZONEID)
 			return (ENOENT);
 		if (isuser) {
-			e = directory_sid_from_user_name(NULL,
-			    cp, &numericsid);
+			stat = idmap_getuidbywinname(cp, NULL, flag, &pid);
+			if (stat < 0)
+				return (ENOENT);
+			stat = idmap_get_sidbyuid(gh, pid, flag, &numericsid,
+			    &rid, &map_stat);
 		} else {
-			e = directory_sid_from_group_name(NULL,
-			    cp, &numericsid);
+			stat = idmap_getgidbywinname(cp, NULL, flag, &pid);
+			if (stat < 0)
+				return (ENOENT);
+			stat = idmap_get_sidbygid(gh, pid, flag, &numericsid,
+			    &rid, &map_stat);
 		}
-		if (e != NULL) {
-			directory_error_free(e);
+		if (stat < 0) {
+			idmap_get_destroy(gh);
 			return (ENOENT);
 		}
+		stat = idmap_get_mappings(gh);
+		idmap_get_destroy(gh);
+
+		if (stat < 0) {
+			return (ENOENT);
+		}
 		if (numericsid == NULL)
 			return (ENOENT);
 		cp = numericsid;
+		*ridp = rid;
 		/* will be further decoded below */
-#else	/* !sun */
+#else	/* !illumos */
 		return (ENOENT);
-#endif	/* !sun */
+#endif	/* illumos */
 	}
 
 	if (strncmp(cp, "S-1-", 4) == 0) {
 		/* It's a numeric SID (eg "S-1-234-567-89") */
 		(void) strlcpy(domain, cp, domainlen);
-		cp = strrchr(domain, '-');
-		*cp = '\0';
-		cp++;
-
 		errno = 0;
-		*ridp = strtoull(cp, &end, 10);
+		if (*ridp == 0) {
+			cp = strrchr(domain, '-');
+			*cp = '\0';
+			cp++;
+			*ridp = strtoull(cp, &end, 10);
+		} else {
+			end = "";
+		}
 		if (numericsid) {
 			free(numericsid);
 			numericsid = NULL;
@@ -2718,6 +2942,15 @@
 }
 
 /*
+ * Returns the name of the parent pool for the given zfs handle.
+ */
+const char *
+zfs_get_pool_name(const zfs_handle_t *zhp)
+{
+	return (zhp->zpool_hdl->zpool_name);
+}
+
+/*
  * Returns the type of the given zfs handle.
  */
 zfs_type_t
@@ -2779,7 +3012,7 @@
     boolean_t accept_ancestor, int *prefixlen)
 {
 	zfs_cmd_t zc = { 0 };
-	char parent[ZFS_MAXNAMELEN];
+	char parent[ZFS_MAX_DATASET_NAME_LEN];
 	char *slash;
 	zfs_handle_t *zhp;
 	char errbuf[1024];
@@ -2907,7 +3140,7 @@
 	 * up to the prefixlen-long one.
 	 */
 	for (cp = target + prefixlen + 1;
-	    cp = strchr(cp, '/'); *cp = '/', cp++) {
+	    (cp = strchr(cp, '/')) != NULL; *cp = '/', cp++) {
 
 		*cp = '\0';
 
@@ -2959,7 +3192,7 @@
 {
 	int prefix;
 	char *path_copy;
-	int rc;
+	int rc = 0;
 
 	if (check_parents(hdl, path, NULL, B_TRUE, &prefix) != 0)
 		return (-1);
@@ -2986,7 +3219,7 @@
 	uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE);
 	char errbuf[1024];
 	uint64_t zoned;
-	dmu_objset_type_t ost;
+	enum lzc_dataset_type ost;
 
 	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
 	    "cannot create '%s'"), path);
@@ -3013,13 +3246,27 @@
 	}
 
 	if (type == ZFS_TYPE_VOLUME)
-		ost = DMU_OST_ZVOL;
+		ost = LZC_DATSET_TYPE_ZVOL;
 	else
-		ost = DMU_OST_ZFS;
+		ost = LZC_DATSET_TYPE_ZFS;
 
+	/* open zpool handle for prop validation */
+	char pool_path[ZFS_MAX_DATASET_NAME_LEN];
+	(void) strlcpy(pool_path, path, sizeof (pool_path));
+
+	/* truncate pool_path at first slash */
+	char *p = strchr(pool_path, '/');
+	if (p != NULL)
+		*p = '\0';
+
+	zpool_handle_t *zpool_handle = zpool_open(hdl, pool_path);
+
 	if (props && (props = zfs_valid_proplist(hdl, type, props,
-	    zoned, NULL, errbuf)) == 0)
+	    zoned, NULL, zpool_handle, errbuf)) == 0) {
+		zpool_close(zpool_handle);
 		return (-1);
+	}
+	zpool_close(zpool_handle);
 
 	if (type == ZFS_TYPE_VOLUME) {
 		/*
@@ -3073,7 +3320,7 @@
 
 	/* check for failure */
 	if (ret != 0) {
-		char parent[ZFS_MAXNAMELEN];
+		char parent[ZFS_MAX_DATASET_NAME_LEN];
 		(void) parent_name(path, parent, sizeof (parent));
 
 		switch (errno) {
@@ -3087,15 +3334,6 @@
 			    "parent '%s' is not a filesystem"), parent);
 			return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
 
-		case EDOM:
-			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
-			    "volume block size must be power of 2 from "
-			    "%u to %uk"),
-			    (uint_t)SPA_MINBLOCKSIZE,
-			    (uint_t)SPA_MAXBLOCKSIZE >> 10);
-
-			return (zfs_error(hdl, EZFS_BADPROP, errbuf));
-
 		case ENOTSUP:
 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 			    "pool must be upgraded to set this "
@@ -3129,6 +3367,19 @@
 {
 	zfs_cmd_t zc = { 0 };
 
+	if (zhp->zfs_type == ZFS_TYPE_BOOKMARK) {
+		nvlist_t *nv = fnvlist_alloc();
+		fnvlist_add_boolean(nv, zhp->zfs_name);
+		int error = lzc_destroy_bookmarks(nv, NULL);
+		fnvlist_free(nv);
+		if (error != 0) {
+			return (zfs_standard_error_fmt(zhp->zfs_hdl, errno,
+			    dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
+			    zhp->zfs_name));
+		}
+		return (0);
+	}
+
 	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
 
 	if (ZFS_IS_VOLUME(zhp)) {
@@ -3159,7 +3410,7 @@
 zfs_check_snap_cb(zfs_handle_t *zhp, void *arg)
 {
 	struct destroydata *dd = arg;
-	char name[ZFS_MAXNAMELEN];
+	char name[ZFS_MAX_DATASET_NAME_LEN];
 	int rv = 0;
 
 	(void) snprintf(name, sizeof (name),
@@ -3204,12 +3455,14 @@
 zfs_destroy_snaps_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, boolean_t defer)
 {
 	int ret;
-	nvlist_t *errlist;
+	nvlist_t *errlist = NULL;
 
 	ret = lzc_destroy_snaps(snaps, defer, &errlist);
 
-	if (ret == 0)
+	if (ret == 0) {
+		nvlist_free(errlist);
 		return (0);
+	}
 
 	if (nvlist_empty(errlist)) {
 		char errbuf[1024];
@@ -3237,6 +3490,7 @@
 		}
 	}
 
+	nvlist_free(errlist);
 	return (ret);
 }
 
@@ -3246,7 +3500,7 @@
 int
 zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
 {
-	char parent[ZFS_MAXNAMELEN];
+	char parent[ZFS_MAX_DATASET_NAME_LEN];
 	int ret;
 	char errbuf[1024];
 	libzfs_handle_t *hdl = zhp->zfs_hdl;
@@ -3277,7 +3531,7 @@
 			type = ZFS_TYPE_FILESYSTEM;
 		}
 		if ((props = zfs_valid_proplist(hdl, type, props, zoned,
-		    zhp, errbuf)) == NULL)
+		    zhp, zhp->zpool_hdl, errbuf)) == NULL)
 			return (-1);
 	}
 
@@ -3376,16 +3630,19 @@
 zfs_snapshot_cb(zfs_handle_t *zhp, void *arg)
 {
 	snapdata_t *sd = arg;
-	char name[ZFS_MAXNAMELEN];
+	char name[ZFS_MAX_DATASET_NAME_LEN];
 	int rv = 0;
 
-	(void) snprintf(name, sizeof (name),
-	    "%s@%s", zfs_get_name(zhp), sd->sd_snapname);
+	if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) == 0) {
+		(void) snprintf(name, sizeof (name),
+		    "%s@%s", zfs_get_name(zhp), sd->sd_snapname);
 
-	fnvlist_add_boolean(sd->sd_nvl, name);
+		fnvlist_add_boolean(sd->sd_nvl, name);
 
-	rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd);
+		rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd);
+	}
 	zfs_close(zhp);
+
 	return (rv);
 }
 
@@ -3418,11 +3675,23 @@
 		}
 	}
 
+	/*
+	 * get pool handle for prop validation. assumes all snaps are in the
+	 * same pool, as does lzc_snapshot (below).
+	 */
+	char pool[ZFS_MAX_DATASET_NAME_LEN];
+	elem = nvlist_next_nvpair(snaps, NULL);
+	(void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
+	pool[strcspn(pool, "/@")] = '\0';
+	zpool_handle_t *zpool_hdl = zpool_open(hdl, pool);
+
 	if (props != NULL &&
 	    (props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT,
-	    props, B_FALSE, NULL, errbuf)) == NULL) {
+	    props, B_FALSE, NULL, zpool_hdl, errbuf)) == NULL) {
+		zpool_close(zpool_hdl);
 		return (-1);
 	}
+	zpool_close(zpool_hdl);
 
 	ret = lzc_snapshot(snaps, props, &errors);
 
@@ -3464,7 +3733,7 @@
 {
 	int ret;
 	snapdata_t sd = { 0 };
-	char fsname[ZFS_MAXNAMELEN];
+	char fsname[ZFS_MAX_DATASET_NAME_LEN];
 	char *cp;
 	zfs_handle_t *zhp;
 	char errbuf[1024];
@@ -3508,45 +3777,44 @@
 	const char	*cb_target;		/* the snapshot */
 	uint64_t	cb_create;		/* creation time reference */
 	boolean_t	cb_error;
-	boolean_t	cb_dependent;
 	boolean_t	cb_force;
 } rollback_data_t;
 
 static int
-rollback_destroy(zfs_handle_t *zhp, void *data)
+rollback_destroy_dependent(zfs_handle_t *zhp, void *data)
 {
 	rollback_data_t *cbp = data;
+	prop_changelist_t *clp;
 
-	if (!cbp->cb_dependent) {
-		if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 &&
-		    zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT &&
-		    zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) >
-		    cbp->cb_create) {
+	/* We must destroy this clone; first unmount it */
+	clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
+	    cbp->cb_force ? MS_FORCE: 0);
+	if (clp == NULL || changelist_prefix(clp) != 0) {
+		cbp->cb_error = B_TRUE;
+		zfs_close(zhp);
+		return (0);
+	}
+	if (zfs_destroy(zhp, B_FALSE) != 0)
+		cbp->cb_error = B_TRUE;
+	else
+		changelist_remove(clp, zhp->zfs_name);
+	(void) changelist_postfix(clp);
+	changelist_free(clp);
 
-			cbp->cb_dependent = B_TRUE;
-			cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE,
-			    rollback_destroy, cbp);
-			cbp->cb_dependent = B_FALSE;
+	zfs_close(zhp);
+	return (0);
+}
 
-			cbp->cb_error |= zfs_destroy(zhp, B_FALSE);
-		}
-	} else {
-		/* We must destroy this clone; first unmount it */
-		prop_changelist_t *clp;
+static int
+rollback_destroy(zfs_handle_t *zhp, void *data)
+{
+	rollback_data_t *cbp = data;
 
-		clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
-		    cbp->cb_force ? MS_FORCE: 0);
-		if (clp == NULL || changelist_prefix(clp) != 0) {
-			cbp->cb_error = B_TRUE;
-			zfs_close(zhp);
-			return (0);
-		}
-		if (zfs_destroy(zhp, B_FALSE) != 0)
-			cbp->cb_error = B_TRUE;
-		else
-			changelist_remove(clp, zhp->zfs_name);
-		(void) changelist_postfix(clp);
-		changelist_free(clp);
+	if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > cbp->cb_create) {
+		cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE,
+		    rollback_destroy_dependent, cbp);
+
+		cbp->cb_error |= zfs_destroy(zhp, B_FALSE);
 	}
 
 	zfs_close(zhp);
@@ -3557,8 +3825,8 @@
  * Given a dataset, rollback to a specific snapshot, discarding any
  * data changes since then and making it the active dataset.
  *
- * Any snapshots more recent than the target are destroyed, along with
- * their dependents.
+ * Any snapshots and bookmarks more recent than the target are
+ * destroyed, along with their dependents (i.e. clones).
  */
 int
 zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force)
@@ -3565,9 +3833,8 @@
 {
 	rollback_data_t cb = { 0 };
 	int err;
-	zfs_cmd_t zc = { 0 };
 	boolean_t restore_resv = 0;
-	uint64_t old_volsize, new_volsize;
+	uint64_t old_volsize = 0, new_volsize;
 	zfs_prop_t resv_prop;
 
 	assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM ||
@@ -3579,7 +3846,8 @@
 	cb.cb_force = force;
 	cb.cb_target = snap->zfs_name;
 	cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG);
-	(void) zfs_iter_children(zhp, rollback_destroy, &cb);
+	(void) zfs_iter_snapshots(zhp, B_FALSE, rollback_destroy, &cb);
+	(void) zfs_iter_bookmarks(zhp, rollback_destroy, &cb);
 
 	if (cb.cb_error)
 		return (-1);
@@ -3597,13 +3865,6 @@
 		    (old_volsize == zfs_prop_get_int(zhp, resv_prop));
 	}
 
-	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
-
-	if (ZFS_IS_VOLUME(zhp))
-		zc.zc_objset_type = DMU_OST_ZVOL;
-	else
-		zc.zc_objset_type = DMU_OST_ZFS;
-
 	/*
 	 * We rely on zfs_iter_children() to verify that there are no
 	 * newer snapshots for the given dataset.  Therefore, we can
@@ -3610,9 +3871,9 @@
 	 * simply pass the name on to the ioctl() call.  There is still
 	 * an unlikely race condition where the user has taken a
 	 * snapshot since we verified that this was the most recent.
-	 *
 	 */
-	if ((err = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_ROLLBACK, &zc)) != 0) {
+	err = lzc_rollback(zhp->zfs_name, NULL, 0);
+	if (err != 0) {
 		(void) zfs_standard_error_fmt(zhp->zfs_hdl, errno,
 		    dgettext(TEXT_DOMAIN, "cannot rollback '%s'"),
 		    zhp->zfs_name);
@@ -3645,13 +3906,13 @@
 zfs_rename(zfs_handle_t *zhp, const char *source, const char *target,
     renameflags_t flags)
 {
-	int ret;
+	int ret = 0;
 	zfs_cmd_t zc = { 0 };
 	char *delim;
 	prop_changelist_t *cl = NULL;
 	zfs_handle_t *zhrp = NULL;
 	char *parentname = NULL;
-	char parent[ZFS_MAXNAMELEN];
+	char parent[ZFS_MAX_DATASET_NAME_LEN];
 	char property[ZFS_MAXPROPLEN];
 	libzfs_handle_t *hdl = zhp->zfs_hdl;
 	char errbuf[1024];
@@ -3764,7 +4025,6 @@
 	     strcmp(property, "none") == 0)) {
 		flags.nounmount = B_TRUE;
 	}
-
 	if (flags.recurse) {
 
 		parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name);
@@ -3779,8 +4039,7 @@
 			ret = -1;
 			goto error;
 		}
-
-	} else {
+	} else if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT) {
 		if ((cl = changelist_gather(zhp, ZFS_PROP_NAME,
 		    flags.nounmount ? CL_GATHER_DONT_UNMOUNT : 0,
 		    flags.forceunmount ? MS_FORCE : 0)) == NULL) {
@@ -3792,6 +4051,7 @@
 			    "child dataset with inherited mountpoint is used "
 			    "in a non-global zone"));
 			(void) zfs_error(hdl, EZFS_ZONED, errbuf);
+			ret = -1;
 			goto error;
 		}
 
@@ -3832,10 +4092,10 @@
 		 * On failure, we still want to remount any filesystems that
 		 * were previously mounted, so we don't alter the system state.
 		 */
-		if (!flags.recurse)
+		if (cl != NULL)
 			(void) changelist_postfix(cl);
 	} else {
-		if (!flags.recurse) {
+		if (cl != NULL) {
 			changelist_rename(cl, zfs_get_name(zhp), target);
 			ret = changelist_postfix(cl);
 		}
@@ -3842,13 +4102,13 @@
 	}
 
 error:
-	if (parentname) {
+	if (parentname != NULL) {
 		free(parentname);
 	}
-	if (zhrp) {
+	if (zhrp != NULL) {
 		zfs_close(zhrp);
 	}
-	if (cl) {
+	if (cl != NULL) {
 		changelist_free(cl);
 	}
 	return (ret);
@@ -3883,7 +4143,8 @@
  *        of the RECEIVED column.
  */
 int
-zfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t received)
+zfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t received,
+    boolean_t literal)
 {
 	libzfs_handle_t *hdl = zhp->zfs_hdl;
 	zprop_list_t *entry;
@@ -3945,18 +4206,18 @@
 	 * Now go through and check the width of any non-fixed columns
 	 */
 	for (entry = *plp; entry != NULL; entry = entry->pl_next) {
-		if (entry->pl_fixed)
+		if (entry->pl_fixed && !literal)
 			continue;
 
 		if (entry->pl_prop != ZPROP_INVAL) {
 			if (zfs_prop_get(zhp, entry->pl_prop,
-			    buf, sizeof (buf), NULL, NULL, 0, B_FALSE) == 0) {
+			    buf, sizeof (buf), NULL, NULL, 0, literal) == 0) {
 				if (strlen(buf) > entry->pl_width)
 					entry->pl_width = strlen(buf);
 			}
 			if (received && zfs_prop_get_recvd(zhp,
 			    zfs_prop_to_name(entry->pl_prop),
-			    buf, sizeof (buf), B_FALSE) == 0)
+			    buf, sizeof (buf), literal) == 0)
 				if (strlen(buf) > entry->pl_recvd_width)
 					entry->pl_recvd_width = strlen(buf);
 		} else {
@@ -3969,7 +4230,7 @@
 			}
 			if (received && zfs_prop_get_recvd(zhp,
 			    entry->pl_user_prop,
-			    buf, sizeof (buf), B_FALSE) == 0)
+			    buf, sizeof (buf), literal) == 0)
 				if (strlen(buf) > entry->pl_recvd_width)
 					entry->pl_recvd_width = strlen(buf);
 		}
@@ -4029,7 +4290,7 @@
 	}
 }
 
-#ifdef sun
+#ifdef illumos
 static int
 zfs_smb_acl_mgmt(libzfs_handle_t *hdl, char *dataset, char *path,
     zfs_smb_acl_op_t cmd, char *resource1, char *resource2)
@@ -4045,7 +4306,7 @@
 	if (cmd == ZFS_SMB_ACL_RENAME) {
 		if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) != 0) {
 			(void) no_memory(hdl);
-			return (NULL);
+			return (0);
 		}
 	}
 
@@ -4076,8 +4337,7 @@
 		return (-1);
 	}
 	error = ioctl(hdl->libzfs_fd, ZFS_IOC_SMB_ACL, &zc);
-	if (nvlist)
-		nvlist_free(nvlist);
+	nvlist_free(nvlist);
 	return (error);
 }
 
@@ -4111,7 +4371,7 @@
 	return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_RENAME,
 	    oldname, newname));
 }
-#endif	/* sun */
+#endif	/* illumos */
 
 int
 zfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type,
@@ -4166,7 +4426,7 @@
 zfs_hold_one(zfs_handle_t *zhp, void *arg)
 {
 	struct holdarg *ha = arg;
-	char name[ZFS_MAXNAMELEN];
+	char name[ZFS_MAX_DATASET_NAME_LEN];
 	int rv = 0;
 
 	(void) snprintf(name, sizeof (name),
@@ -4285,7 +4545,7 @@
 zfs_release_one(zfs_handle_t *zhp, void *arg)
 {
 	struct holdarg *ha = arg;
-	char name[ZFS_MAXNAMELEN];
+	char name[ZFS_MAX_DATASET_NAME_LEN];
 	int rv = 0;
 	nvlist_t *existing_holds;
 
@@ -4414,7 +4674,7 @@
 	zc.zc_nvlist_dst_size = nvsz;
 	zc.zc_nvlist_dst = (uintptr_t)nvbuf;
 
-	(void) strlcpy(zc.zc_name, zhp->zfs_name, ZFS_MAXNAMELEN);
+	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
 
 	if (ioctl(hdl->libzfs_fd, ZFS_IOC_GET_FSACL, &zc) != 0) {
 		(void) snprintf(errbuf, sizeof (errbuf),
@@ -4606,7 +4866,7 @@
 		    dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name);
 	} else {
 		(void) snprintf(errbuf, sizeof (errbuf),
-		    dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name);
+		    dgettext(TEXT_DOMAIN, "cannot unjail '%s'"), zhp->zfs_name);
 	}
 
 	switch (zhp->zfs_type) {

Modified: trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_diff.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_diff.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_diff.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -21,6 +22,10 @@
 
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2015 by Delphix. All rights reserved.
+ * Copyright 2016 Joyent, Inc.
+ * Copyright 2016 Igor Kozhukhov <ikozhukhov at gmail.com>
  */
 
 /*
@@ -51,15 +56,6 @@
 #define	ZDIFF_REMOVED	'-'
 #define	ZDIFF_RENAMED	'R'
 
-static boolean_t
-do_name_cmp(const char *fpath, const char *tpath)
-{
-	char *fname, *tname;
-	fname = strrchr(fpath, '/') + 1;
-	tname = strrchr(tpath, '/') + 1;
-	return (strcmp(fname, tname) == 0);
-}
-
 typedef struct differ_info {
 	zfs_handle_t *zhp;
 	char *fromsnap;
@@ -135,12 +131,13 @@
 static void
 stream_bytes(FILE *fp, const char *string)
 {
-	while (*string) {
-		if (*string > ' ' && *string != '\\' && *string < '\177')
-			(void) fprintf(fp, "%c", *string++);
-		else {
-			(void) fprintf(fp, "\\%03hho",
-			    (unsigned char)*string++);
+	char c;
+
+	while ((c = *string++) != '\0') {
+		if (c > ' ' && c != '\\' && c < '\177') {
+			(void) fprintf(fp, "%c", c);
+		} else {
+			(void) fprintf(fp, "\\%03o", (uint8_t)c);
 		}
 	}
 }
@@ -257,7 +254,6 @@
 write_inuse_diffs_one(FILE *fp, differ_info_t *di, uint64_t dobj)
 {
 	struct zfs_stat fsb, tsb;
-	boolean_t same_name;
 	mode_t fmode, tmode;
 	char fobjname[MAXPATHLEN], tobjname[MAXPATHLEN];
 	int fobjerr, tobjerr;
@@ -318,7 +314,6 @@
 
 	if (fmode != tmode && fsb.zs_gen == tsb.zs_gen)
 		tsb.zs_gen++;	/* Force a generational difference */
-	same_name = do_name_cmp(fobjname, tobjname);
 
 	/* Simple modification or no change */
 	if (fsb.zs_gen == tsb.zs_gen) {
@@ -329,7 +324,7 @@
 		if (change) {
 			print_link_change(fp, di, change,
 			    change > 0 ? fobjname : tobjname, &tsb);
-		} else if (same_name) {
+		} else if (strcmp(fobjname, tobjname) == 0) {
 			print_file(fp, di, ZDIFF_MODIFIED, fobjname, &tsb);
 		} else {
 			print_rename(fp, di, fobjname, tobjname, &tsb);
@@ -350,7 +345,7 @@
 	int err;
 
 	for (o = dr->ddr_first; o <= dr->ddr_last; o++) {
-		if (err = write_inuse_diffs_one(fp, di, o))
+		if ((err = write_inuse_diffs_one(fp, di, o)) != 0)
 			return (err);
 	}
 	return (0);
@@ -494,7 +489,7 @@
 	(void) strlcat(fullpath, ZDIFF_SHARESDIR, MAXPATHLEN);
 
 	if (stat64(fullpath, &sb) != 0) {
-#ifdef sun
+#ifdef illumos
 		(void) snprintf(di->errbuf, sizeof (di->errbuf),
 		    dgettext(TEXT_DOMAIN, "Cannot stat %s"), fullpath);
 		return (zfs_error(di->zhp->zfs_hdl, EZFS_DIFF, di->errbuf));
@@ -614,7 +609,7 @@
 		 * not the same dataset name, might be okay if
 		 * tosnap is a clone of a fromsnap descendant.
 		 */
-		char origin[ZFS_MAXNAMELEN];
+		char origin[ZFS_MAX_DATASET_NAME_LEN];
 		zprop_source_t src;
 		zfs_handle_t *zhp;
 
@@ -624,9 +619,12 @@
 
 		zhp = zfs_open(hdl, di->ds, ZFS_TYPE_FILESYSTEM);
 		while (zhp != NULL) {
-			(void) zfs_prop_get(zhp, ZFS_PROP_ORIGIN,
-			    origin, sizeof (origin), &src, NULL, 0, B_FALSE);
-
+			if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin,
+			    sizeof (origin), &src, NULL, 0, B_FALSE) != 0) {
+				(void) zfs_close(zhp);
+				zhp = NULL;
+				break;
+			}
 			if (strncmp(origin, fromsnap, fsnlen) == 0)
 				break;
 

Modified: trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_fru.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_fru.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_fru.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -282,7 +283,7 @@
 
 	if (hdl->libzfs_fru_hash == NULL &&
 	    (hdl->libzfs_fru_hash =
-	    calloc(ZFS_FRU_HASH_SIZE * sizeof (void *), 1)) == NULL)
+	    calloc(ZFS_FRU_HASH_SIZE, sizeof (void *))) == NULL)
 		return;
 
 	/*

Modified: trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER SART
  *
@@ -21,9 +22,8 @@
 
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011 Pawel Jakub Dawidek <pawel at dawidek.net>.
- * All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2011 Pawel Jakub Dawidek. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  * Copyright (c) 2013 Martin Matuska <mm at FreeBSD.org>. All rights reserved.
  */
 
@@ -30,11 +30,11 @@
 #ifndef	_LIBZFS_IMPL_H
 #define	_LIBZFS_IMPL_H
 
-#include <sys/dmu.h>
 #include <sys/fs/zfs.h>
-#include <sys/zfs_ioctl.h>
 #include <sys/spa.h>
 #include <sys/nvpair.h>
+#include <sys/dmu.h>
+#include <sys/zfs_ioctl.h>
 
 #include <libshare.h>
 #include <libuutil.h>
@@ -87,7 +87,7 @@
 struct zfs_handle {
 	libzfs_handle_t *zfs_hdl;
 	zpool_handle_t *zpool_hdl;
-	char zfs_name[ZFS_MAXNAMELEN];
+	char zfs_name[ZFS_MAX_DATASET_NAME_LEN];
 	zfs_type_t zfs_type; /* type including snapshot */
 	zfs_type_t zfs_head_type; /* type excluding snapshot */
 	dmu_objset_stats_t zfs_dmustats;
@@ -108,7 +108,7 @@
 struct zpool_handle {
 	libzfs_handle_t *zpool_hdl;
 	zpool_handle_t *zpool_next;
-	char zpool_name[ZPOOL_MAXNAMELEN];
+	char zpool_name[ZFS_MAX_DATASET_NAME_LEN];
 	int zpool_state;
 	size_t zpool_config_size;
 	nvlist_t *zpool_config;
@@ -191,6 +191,8 @@
 boolean_t isa_child_of(const char *dataset, const char *parent);
 
 zfs_handle_t *make_dataset_handle(libzfs_handle_t *, const char *);
+zfs_handle_t *make_bookmark_handle(zfs_handle_t *, const char *,
+    nvlist_t *props);
 
 int zpool_open_silent(libzfs_handle_t *, const char *, zpool_handle_t **);
 

Modified: trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -18,10 +19,12 @@
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
+ * Copyright 2015 RackTop Systems.
+ * Copyright 2016 Nexenta Systems, Inc.
  */
 
 /*
@@ -94,6 +97,7 @@
 static char *
 get_devid(const char *path)
 {
+#ifdef have_devid
 	int fd;
 	ddi_devid_t devid;
 	char *minor, *ret;
@@ -113,6 +117,9 @@
 	(void) close(fd);
 
 	return (ret);
+#else
+	return (NULL);
+#endif
 }
 
 
@@ -194,8 +201,10 @@
 	if ((devid = get_devid(best->ne_name)) == NULL) {
 		(void) nvlist_remove_all(nv, ZPOOL_CONFIG_DEVID);
 	} else {
-		if (nvlist_add_string(nv, ZPOOL_CONFIG_DEVID, devid) != 0)
+		if (nvlist_add_string(nv, ZPOOL_CONFIG_DEVID, devid) != 0) {
+			devid_str_free(devid);
 			return (-1);
+		}
 		devid_str_free(devid);
 	}
 
@@ -432,12 +441,12 @@
 	pool_entry_t *pe;
 	vdev_entry_t *ve;
 	config_entry_t *ce;
-	nvlist_t *ret = NULL, *config = NULL, *tmp, *nvtop, *nvroot;
+	nvlist_t *ret = NULL, *config = NULL, *tmp = NULL, *nvtop, *nvroot;
 	nvlist_t **spares, **l2cache;
 	uint_t i, nspares, nl2cache;
 	boolean_t config_seen;
 	uint64_t best_txg;
-	char *name, *hostname;
+	char *name, *hostname = NULL;
 	uint64_t guid;
 	uint_t children = 0;
 	nvlist_t **child = NULL;
@@ -661,8 +670,10 @@
 				    nvlist_add_uint64(holey,
 				    ZPOOL_CONFIG_ID, c) != 0 ||
 				    nvlist_add_uint64(holey,
-				    ZPOOL_CONFIG_GUID, 0ULL) != 0)
+				    ZPOOL_CONFIG_GUID, 0ULL) != 0) {
+					nvlist_free(holey);
 					goto nomem;
+				}
 				child[c] = holey;
 			}
 		}
@@ -854,6 +865,7 @@
 /*
  * Given a file descriptor, read the label information and return an nvlist
  * describing the configuration, if there is one.
+ * Return 0 on success, or -1 on failure
  */
 int
 zpool_read_label(int fd, nvlist_t **config)
@@ -866,7 +878,7 @@
 	*config = NULL;
 
 	if (fstat64(fd, &statbuf) == -1)
-		return (0);
+		return (-1);
 	size = P2ALIGN_TYPED(statbuf.st_size, sizeof (vdev_label_t), uint64_t);
 
 	if ((label = malloc(sizeof (vdev_label_t))) == NULL)
@@ -900,7 +912,8 @@
 
 	free(label);
 	*config = NULL;
-	return (0);
+	errno = ENOENT;
+	return (-1);
 }
 
 typedef struct rdsk_node {
@@ -948,7 +961,7 @@
 	return (rv > 0 ? 1 : -1);
 }
 
-#ifdef sun
+#ifdef illumos
 static void
 check_one_slice(avl_tree_t *r, char *diskname, uint_t partno,
     diskaddr_t size, uint_t blksz)
@@ -971,12 +984,12 @@
 	    (node = avl_find(r, &tmpnode, NULL)))
 		node->rn_nozpool = B_TRUE;
 }
-#endif	/* sun */
+#endif	/* illumos */
 
 static void
 nozpool_all_slices(avl_tree_t *r, const char *sname)
 {
-#ifdef sun
+#ifdef illumos
 	char diskname[MAXNAMELEN];
 	char *ptr;
 	int i;
@@ -992,13 +1005,13 @@
 	ptr[0] = 'p';
 	for (i = 0; i <= FD_NUMPART; i++)
 		check_one_slice(r, diskname, i, 0, 1);
-#endif	/* sun */
+#endif	/* illumos */
 }
 
+#ifdef illumos
 static void
 check_slices(avl_tree_t *r, int fd, const char *sname)
 {
-#ifdef sun
 	struct extvtoc vtoc;
 	struct dk_gpt *gpt;
 	char diskname[MAXNAMELEN];
@@ -1028,8 +1041,8 @@
 			check_one_slice(r, diskname, i, 0, 1);
 		efi_free(gpt);
 	}
-#endif	/* sun */
 }
+#endif	/* illumos */
 
 static void
 zpool_open_func(void *arg)
@@ -1059,6 +1072,7 @@
 		return;
 	}
 	/* this file is too small to hold a zpool */
+#ifdef illumos
 	if (S_ISREG(statbuf.st_mode) &&
 	    statbuf.st_size < SPA_MINDEVSIZE) {
 		(void) close(fd);
@@ -1070,8 +1084,14 @@
 		 */
 		check_slices(rn->rn_avl, fd, rn->rn_name);
 	}
+#else	/* !illumos */
+	if (statbuf.st_size < SPA_MINDEVSIZE) {
+		(void) close(fd);
+		return;
+	}
+#endif	/* illumos */
 
-	if ((zpool_read_label(fd, &config)) != 0) {
+	if ((zpool_read_label(fd, &config)) != 0 && errno == ENOMEM) {
 		(void) close(fd);
 		(void) no_memory(rn->rn_hdl);
 		return;
@@ -1078,17 +1098,11 @@
 	}
 	(void) close(fd);
 
-
 	rn->rn_config = config;
-	if (config != NULL) {
-		assert(rn->rn_nozpool == B_FALSE);
-	}
 }
 
 /*
- * Given a file descriptor, clear (zero) the label information.  This function
- * is used in the appliance stack as part of the ZFS sysevent module and
- * to implement the "zpool labelclear" command.
+ * Given a file descriptor, clear (zero) the label information.
  */
 int
 zpool_clear_label(int fd)
@@ -1107,8 +1121,10 @@
 
 	for (l = 0; l < VDEV_LABELS; l++) {
 		if (pwrite64(fd, label, sizeof (vdev_label_t),
-		    label_offset(size, l)) != sizeof (vdev_label_t))
+		    label_offset(size, l)) != sizeof (vdev_label_t)) {
+			free(label);
 			return (-1);
+		}
 	}
 
 	free(label);
@@ -1126,7 +1142,6 @@
 zpool_find_import_impl(libzfs_handle_t *hdl, importargs_t *iarg)
 {
 	int i, dirs = iarg->paths;
-	DIR *dirp = NULL;
 	struct dirent64 *dp;
 	char path[MAXPATHLEN];
 	char *end, **dir = iarg->path;
@@ -1154,8 +1169,10 @@
 	 */
 	for (i = 0; i < dirs; i++) {
 		tpool_t *t;
-		char *rdsk;
+		char rdsk[MAXPATHLEN];
 		int dfd;
+		boolean_t config_failed = B_FALSE;
+		DIR *dirp;
 
 		/* use realpath to normalize the path */
 		if (realpath(dir[i], path) == 0) {
@@ -1168,18 +1185,22 @@
 		*end = 0;
 		pathleft = &path[sizeof (path)] - end;
 
+#ifdef illumos
 		/*
 		 * Using raw devices instead of block devices when we're
 		 * reading the labels skips a bunch of slow operations during
 		 * close(2) processing, so we replace /dev/dsk with /dev/rdsk.
 		 */
-		if (strcmp(path, "/dev/dsk/") == 0)
-			rdsk = "/dev/";
+		if (strcmp(path, ZFS_DISK_ROOTD) == 0)
+			(void) strlcpy(rdsk, ZFS_RDISK_ROOTD, sizeof (rdsk));
 		else
-			rdsk = path;
+#endif
+			(void) strlcpy(rdsk, path, sizeof (rdsk));
 
 		if ((dfd = open64(rdsk, O_RDONLY)) < 0 ||
 		    (dirp = fdopendir(dfd)) == NULL) {
+			if (dfd >= 0)
+				(void) close(dfd);
 			zfs_error_aux(hdl, strerror(errno));
 			(void) zfs_error_fmt(hdl, EZFS_BADPATH,
 			    dgettext(TEXT_DOMAIN, "cannot open '%s'"),
@@ -1261,7 +1282,7 @@
 		cookie = NULL;
 		while ((slice = avl_destroy_nodes(&slice_cache,
 		    &cookie)) != NULL) {
-			if (slice->rn_config != NULL) {
+			if (slice->rn_config != NULL && !config_failed) {
 				nvlist_t *config = slice->rn_config;
 				boolean_t matched = B_TRUE;
 
@@ -1282,13 +1303,16 @@
 				}
 				if (!matched) {
 					nvlist_free(config);
-					config = NULL;
-					continue;
+				} else {
+					/*
+					 * use the non-raw path for the config
+					 */
+					(void) strlcpy(end, slice->rn_name,
+					    pathleft);
+					if (add_config(hdl, &pools, path,
+					    config) != 0)
+						config_failed = B_TRUE;
 				}
-				/* use the non-raw path for the config */
-				(void) strlcpy(end, slice->rn_name, pathleft);
-				if (add_config(hdl, &pools, path, config) != 0)
-					goto error;
 			}
 			free(slice->rn_name);
 			free(slice);
@@ -1296,7 +1320,9 @@
 		avl_destroy(&slice_cache);
 
 		(void) closedir(dirp);
-		dirp = NULL;
+
+		if (config_failed)
+			goto error;
 	}
 
 	ret = get_configs(hdl, &pools, iarg->can_be_active);
@@ -1308,8 +1334,7 @@
 			venext = ve->ve_next;
 			for (ce = ve->ve_configs; ce != NULL; ce = cenext) {
 				cenext = ce->ce_next;
-				if (ce->ce_config)
-					nvlist_free(ce->ce_config);
+				nvlist_free(ce->ce_config);
 				free(ce);
 			}
 			free(ve);
@@ -1319,14 +1344,10 @@
 
 	for (ne = pools.names; ne != NULL; ne = nenext) {
 		nenext = ne->ne_next;
-		if (ne->ne_name)
-			free(ne->ne_name);
+		free(ne->ne_name);
 		free(ne);
 	}
 
-	if (dirp)
-		(void) closedir(dirp);
-
 	return (ret);
 }
 
@@ -1415,21 +1436,15 @@
 
 	elem = NULL;
 	while ((elem = nvlist_next_nvpair(raw, elem)) != NULL) {
-		verify(nvpair_value_nvlist(elem, &src) == 0);
+		src = fnvpair_value_nvlist(elem);
 
-		verify(nvlist_lookup_string(src, ZPOOL_CONFIG_POOL_NAME,
-		    &name) == 0);
+		name = fnvlist_lookup_string(src, ZPOOL_CONFIG_POOL_NAME);
 		if (poolname != NULL && strcmp(poolname, name) != 0)
 			continue;
 
-		verify(nvlist_lookup_uint64(src, ZPOOL_CONFIG_POOL_GUID,
-		    &this_guid) == 0);
-		if (guid != 0) {
-			verify(nvlist_lookup_uint64(src, ZPOOL_CONFIG_POOL_GUID,
-			    &this_guid) == 0);
-			if (guid != this_guid)
-				continue;
-		}
+		this_guid = fnvlist_lookup_uint64(src, ZPOOL_CONFIG_POOL_GUID);
+		if (guid != 0 && guid != this_guid)
+			continue;
 
 		if (pool_active(hdl, name, this_guid, &active) != 0) {
 			nvlist_free(raw);
@@ -1577,7 +1592,7 @@
 
 	*inuse = B_FALSE;
 
-	if (zpool_read_label(fd, &config) != 0) {
+	if (zpool_read_label(fd, &config) != 0 && errno == ENOMEM) {
 		(void) no_memory(hdl);
 		return (-1);
 	}
@@ -1606,10 +1621,17 @@
 		 * its state to active.
 		 */
 		if (pool_active(hdl, name, guid, &isactive) == 0 && isactive &&
-		    (zhp = zpool_open_canfail(hdl, name)) != NULL &&
-		    zpool_get_prop_int(zhp, ZPOOL_PROP_READONLY, NULL))
-			stateval = POOL_STATE_ACTIVE;
+		    (zhp = zpool_open_canfail(hdl, name)) != NULL) {
+			if (zpool_get_prop_int(zhp, ZPOOL_PROP_READONLY, NULL))
+				stateval = POOL_STATE_ACTIVE;
 
+			/*
+			 * All we needed the zpool handle for is the
+			 * readonly prop check.
+			 */
+			zpool_close(zhp);
+		}
+
 		ret = B_TRUE;
 		break;
 
@@ -1683,9 +1705,9 @@
 		cb.cb_type = ZPOOL_CONFIG_SPARES;
 		if (zpool_iter(hdl, find_aux, &cb) == 1) {
 			name = (char *)zpool_get_name(cb.cb_zhp);
-			ret = TRUE;
+			ret = B_TRUE;
 		} else {
-			ret = FALSE;
+			ret = B_FALSE;
 		}
 		break;
 
@@ -1699,9 +1721,9 @@
 		cb.cb_type = ZPOOL_CONFIG_L2CACHE;
 		if (zpool_iter(hdl, find_aux, &cb) == 1) {
 			name = (char *)zpool_get_name(cb.cb_zhp);
-			ret = TRUE;
+			ret = B_TRUE;
 		} else {
-			ret = FALSE;
+			ret = B_FALSE;
 		}
 		break;
 

Modified: trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -21,10 +22,9 @@
 
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
- * Copyright (c) 2012 Pawel Jakub Dawidek <pawel at dawidek.net>.
- * All rights reserved.
+ * Copyright (c) 2013, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2012 Pawel Jakub Dawidek. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  */
 
 #include <stdio.h>
@@ -146,7 +146,8 @@
 	zfs_handle_t *nzhp;
 	int ret;
 
-	if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT)
+	if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT ||
+	    zhp->zfs_type == ZFS_TYPE_BOOKMARK)
 		return (0);
 
 	zc.zc_simple = simple;
@@ -173,6 +174,56 @@
 }
 
 /*
+ * Iterate over all bookmarks
+ */
+int
+zfs_iter_bookmarks(zfs_handle_t *zhp, zfs_iter_f func, void *data)
+{
+	zfs_handle_t *nzhp;
+	nvlist_t *props = NULL;
+	nvlist_t *bmarks = NULL;
+	int err;
+
+	if ((zfs_get_type(zhp) & (ZFS_TYPE_SNAPSHOT | ZFS_TYPE_BOOKMARK)) != 0)
+		return (0);
+
+	/* Setup the requested properties nvlist. */
+	props = fnvlist_alloc();
+	fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_GUID));
+	fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_CREATETXG));
+	fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_CREATION));
+
+	if ((err = lzc_get_bookmarks(zhp->zfs_name, props, &bmarks)) != 0)
+		goto out;
+
+	for (nvpair_t *pair = nvlist_next_nvpair(bmarks, NULL);
+	    pair != NULL; pair = nvlist_next_nvpair(bmarks, pair)) {
+		char name[ZFS_MAX_DATASET_NAME_LEN];
+		char *bmark_name;
+		nvlist_t *bmark_props;
+
+		bmark_name = nvpair_name(pair);
+		bmark_props = fnvpair_value_nvlist(pair);
+
+		(void) snprintf(name, sizeof (name), "%s#%s", zhp->zfs_name,
+		    bmark_name);
+
+		nzhp = make_bookmark_handle(zhp, name, bmark_props);
+		if (nzhp == NULL)
+			continue;
+
+		if ((err = func(nzhp, data)) != 0)
+			goto out;
+	}
+
+out:
+	fnvlist_free(props);
+	fnvlist_free(bmarks);
+
+	return (err);
+}
+
+/*
  * Routines for dealing with the sorted snapshot functionality
  */
 typedef struct zfs_node {
@@ -264,7 +315,8 @@
 } snapspec_arg_t;
 
 static int
-snapspec_cb(zfs_handle_t *zhp, void *arg) {
+snapspec_cb(zfs_handle_t *zhp, void *arg)
+{
 	snapspec_arg_t *ssa = arg;
 	char *shortsnapname;
 	int err = 0;
@@ -334,7 +386,7 @@
 			 * exists.
 			 */
 			if (ssa.ssa_last[0] != '\0') {
-				char snapname[ZFS_MAXNAMELEN];
+				char snapname[ZFS_MAX_DATASET_NAME_LEN];
 				(void) snprintf(snapname, sizeof (snapname),
 				    "%s@%s", zfs_get_name(fs_zhp),
 				    ssa.ssa_last);
@@ -354,7 +406,7 @@
 				ret = ENOENT;
 			}
 		} else {
-			char snapname[ZFS_MAXNAMELEN];
+			char snapname[ZFS_MAX_DATASET_NAME_LEN];
 			zfs_handle_t *snap_zhp;
 			(void) snprintf(snapname, sizeof (snapname), "%s@%s",
 			    zfs_get_name(fs_zhp), comma_separated);
@@ -406,13 +458,13 @@
 iter_dependents_cb(zfs_handle_t *zhp, void *arg)
 {
 	iter_dependents_arg_t *ida = arg;
-	int err;
+	int err = 0;
 	boolean_t first = ida->first;
 	ida->first = B_FALSE;
 
 	if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
 		err = zfs_iter_clones(zhp, iter_dependents_cb, ida);
-	} else {
+	} else if (zhp->zfs_type != ZFS_TYPE_BOOKMARK) {
 		iter_stack_frame_t isf;
 		iter_stack_frame_t *f;
 
@@ -452,8 +504,12 @@
 		}
 		ida->stack = isf.next;
 	}
+
 	if (!first && err == 0)
 		err = ida->func(zhp, ida->data);
+	else
+		zfs_close(zhp);
+
 	return (err);
 }
 

Modified: trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_mount.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_mount.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_mount.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -20,7 +21,11 @@
  */
 
 /*
+ * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014 by Delphix. All rights reserved.
+ * Copyright 2016 Igor Kozhukhov <ikozhukhov at gmail.com>
+ * Copyright 2017 RackTop Systems.
  */
 
 /*
@@ -85,7 +90,7 @@
     zfs_share_proto_t);
 
 /*
- * The share protocols table must be in the same order as the zfs_share_prot_t
+ * The share protocols table must be in the same order as the zfs_share_proto_t
  * enum in libzfs_impl.h
  */
 typedef struct {
@@ -138,7 +143,7 @@
 
 		*tab = '\0';
 		if (strcmp(buf, mountpoint) == 0) {
-#ifdef sun
+#ifdef illumos
 			/*
 			 * the protocol field is the third field
 			 * skip over second field
@@ -171,7 +176,7 @@
 	return (SHARED_NOT_SHARED);
 }
 
-#ifdef sun
+#ifdef illumos
 /*
  * Returns true if the specified directory is empty.  If we can't open the
  * directory at all, return true so that the mount can fail with a more
@@ -234,7 +239,7 @@
 zfs_is_mountable(zfs_handle_t *zhp, char *buf, size_t buflen,
     zprop_source_t *source)
 {
-	char sourceloc[ZFS_MAXNAMELEN];
+	char sourceloc[MAXNAMELEN];
 	zprop_source_t sourcetype;
 
 	if (!zfs_prop_valid_for_type(ZFS_PROP_MOUNTPOINT, zhp->zfs_type))
@@ -296,7 +301,7 @@
 		}
 	}
 
-#ifdef sun	/* FreeBSD: overlay mounts are not checked. */
+#ifdef illumos	/* FreeBSD: overlay mounts are not checked. */
 	/*
 	 * Determine if the mountpoint is empty.  If so, refuse to perform the
 	 * mount.  We don't perform this check if MS_OVERLAY is specified, which
@@ -474,7 +479,8 @@
 	if (!zfs_is_mounted(zhp, &mountpoint))
 		return (SHARED_NOT_SHARED);
 
-	if (rc = is_shared(zhp->zfs_hdl, mountpoint, proto)) {
+	if ((rc = is_shared(zhp->zfs_hdl, mountpoint, proto))
+	    != SHARED_NOT_SHARED) {
 		if (where != NULL)
 			*where = mountpoint;
 		else
@@ -506,7 +512,7 @@
  * initialized in _zfs_init_libshare() are actually present.
  */
 
-#ifdef sun
+#ifdef illumos
 static sa_handle_t (*_sa_init)(int);
 static void (*_sa_fini)(sa_handle_t);
 static sa_share_t (*_sa_find_share)(sa_handle_t, char *);
@@ -533,7 +539,7 @@
 static void
 _zfs_init_libshare(void)
 {
-#ifdef sun
+#ifdef illumos
 	void *libshare;
 	char path[MAXPATHLEN];
 	char isa[MAXISALEN];
@@ -604,7 +610,7 @@
 {
 	int ret = SA_OK;
 
-#ifdef sun
+#ifdef illumos
 	if (_sa_init == NULL)
 		ret = SA_CONFIG_ERR;
 
@@ -645,7 +651,7 @@
 zfs_uninit_libshare(libzfs_handle_t *zhandle)
 {
 	if (zhandle != NULL && zhandle->libzfs_sharehdl != NULL) {
-#ifdef sun
+#ifdef illumos
 		if (_sa_fini != NULL)
 			_sa_fini(zhandle->libzfs_sharehdl);
 #endif
@@ -662,7 +668,7 @@
 int
 zfs_parse_options(char *options, zfs_share_proto_t proto)
 {
-#ifdef sun
+#ifdef illumos
 	if (_sa_parse_legacy_options != NULL) {
 		return (_sa_parse_legacy_options(NULL, options,
 		    proto_table[proto].p_name));
@@ -673,7 +679,7 @@
 #endif
 }
 
-#ifdef sun
+#ifdef illumos
 /*
  * zfs_sa_find_share(handle, path)
  *
@@ -715,7 +721,7 @@
 		return (_sa_disable_share(share, proto));
 	return (SA_CONFIG_ERR);
 }
-#endif	/* sun */
+#endif	/* illumos */
 
 /*
  * Share the given filesystem according to the options in the specified
@@ -736,16 +742,6 @@
 	if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
 		return (0);
 
-#ifdef sun
-	if ((ret = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) {
-		(void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
-		    dgettext(TEXT_DOMAIN, "cannot share '%s': %s"),
-		    zfs_get_name(zhp), _sa_errorstr != NULL ?
-		    _sa_errorstr(ret) : "");
-		return (-1);
-	}
-#endif
-
 	for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) {
 		/*
 		 * Return success if there are no share options.
@@ -756,6 +752,17 @@
 		    strcmp(shareopts, "off") == 0)
 			continue;
 
+#ifdef illumos
+		ret = zfs_init_libshare(hdl, SA_INIT_SHARE_API);
+		if (ret != SA_OK) {
+			(void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
+			    dgettext(TEXT_DOMAIN, "cannot share '%s': %s"),
+			    zfs_get_name(zhp), _sa_errorstr != NULL ?
+			    _sa_errorstr(ret) : "");
+			return (-1);
+		}
+#endif
+
 		/*
 		 * If the 'zoned' property is set, then zfs_is_mountable()
 		 * will have already bailed out if we are in the global zone.
@@ -765,7 +772,7 @@
 		if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED))
 			continue;
 
-#ifdef sun
+#ifdef illumos
 		share = zfs_sa_find_share(hdl->libzfs_sharehdl, mountpoint);
 		if (share == NULL) {
 			/*
@@ -854,7 +861,7 @@
 unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint,
     zfs_share_proto_t proto)
 {
-#ifdef sun
+#ifdef illumos
 	sa_share_t share;
 	int err;
 	char *mntpt;
@@ -868,7 +875,7 @@
 	/* make sure libshare initialized */
 	if ((err = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) {
 		free(mntpt);	/* don't need the copy anymore */
-		return (zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
+		return (zfs_error_fmt(hdl, proto_table[proto].p_unshare_err,
 		    dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"),
 		    name, _sa_errorstr(err)));
 	}
@@ -879,12 +886,13 @@
 	if (share != NULL) {
 		err = zfs_sa_disable_share(share, proto_table[proto].p_name);
 		if (err != SA_OK) {
-			return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED,
+			return (zfs_error_fmt(hdl,
+			    proto_table[proto].p_unshare_err,
 			    dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"),
 			    name, _sa_errorstr(err)));
 		}
 	} else {
-		return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED,
+		return (zfs_error_fmt(hdl, proto_table[proto].p_unshare_err,
 		    dgettext(TEXT_DOMAIN, "cannot unshare '%s': not found"),
 		    name));
 	}
@@ -1070,6 +1078,17 @@
 		return (0);
 	}
 
+	/*
+	 * If this filesystem is inconsistent and has a receive resume
+	 * token, we can not mount it.
+	 */
+	if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) &&
+	    zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
+	    NULL, 0, NULL, NULL, 0, B_TRUE) == 0) {
+		zfs_close(zhp);
+		return (0);
+	}
+
 	libzfs_add_handle(cbp, zhp);
 	if (zfs_iter_filesystems(zhp, mount_cb, cbp) != 0) {
 		zfs_close(zhp);

Modified: trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -21,8 +22,10 @@
 
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright 2016 Nexenta Systems, Inc.
+ * Copyright 2016 Igor Kozhukhov <ikozhukhov at gmail.com>
  */
 
 #include <sys/types.h>
@@ -48,8 +51,6 @@
 
 static int read_efi_label(nvlist_t *config, diskaddr_t *sb);
 
-#define	DISK_ROOT	"/dev/dsk"
-#define	RDISK_ROOT	"/dev/rdsk"
 #define	BACKUP_SLICE	"s2"
 
 typedef struct prop_flags {
@@ -200,6 +201,9 @@
 		return (gettext("DEGRADED"));
 	case VDEV_STATE_HEALTHY:
 		return (gettext("ONLINE"));
+
+	default:
+		break;
 	}
 
 	return (gettext("UNKNOWN"));
@@ -239,7 +243,7 @@
  */
 int
 zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len,
-    zprop_source_t *srctype)
+    zprop_source_t *srctype, boolean_t literal)
 {
 	uint64_t intval;
 	const char *strval;
@@ -255,7 +259,8 @@
 			break;
 
 		case ZPOOL_PROP_HEALTH:
-			(void) strlcpy(buf, "FAULTED", len);
+			(void) strlcpy(buf,
+			    zpool_pool_state_to_name(POOL_STATE_UNAVAIL), len);
 			break;
 
 		case ZPOOL_PROP_GUID:
@@ -271,9 +276,7 @@
 				(void) strlcpy(buf,
 				    zpool_get_prop_string(zhp, prop, &src),
 				    len);
-				if (srctype != NULL)
-					*srctype = src;
-				return (0);
+				break;
 			}
 			/* FALLTHROUGH */
 		default:
@@ -304,21 +307,46 @@
 		case ZPOOL_PROP_ALLOCATED:
 		case ZPOOL_PROP_FREE:
 		case ZPOOL_PROP_FREEING:
+		case ZPOOL_PROP_LEAKED:
+			if (literal) {
+				(void) snprintf(buf, len, "%llu",
+				    (u_longlong_t)intval);
+			} else {
+				(void) zfs_nicenum(intval, buf, len);
+			}
+			break;
 		case ZPOOL_PROP_EXPANDSZ:
-			(void) zfs_nicenum(intval, buf, len);
+			if (intval == 0) {
+				(void) strlcpy(buf, "-", len);
+			} else if (literal) {
+				(void) snprintf(buf, len, "%llu",
+				    (u_longlong_t)intval);
+			} else {
+				(void) zfs_nicenum(intval, buf, len);
+			}
 			break;
-
 		case ZPOOL_PROP_CAPACITY:
-			(void) snprintf(buf, len, "%llu%%",
-			    (u_longlong_t)intval);
+			if (literal) {
+				(void) snprintf(buf, len, "%llu",
+				    (u_longlong_t)intval);
+			} else {
+				(void) snprintf(buf, len, "%llu%%",
+				    (u_longlong_t)intval);
+			}
 			break;
-
+		case ZPOOL_PROP_FRAGMENTATION:
+			if (intval == UINT64_MAX) {
+				(void) strlcpy(buf, "-", len);
+			} else {
+				(void) snprintf(buf, len, "%llu%%",
+				    (u_longlong_t)intval);
+			}
+			break;
 		case ZPOOL_PROP_DEDUPRATIO:
 			(void) snprintf(buf, len, "%llu.%02llux",
 			    (u_longlong_t)(intval / 100),
 			    (u_longlong_t)(intval % 100));
 			break;
-
 		case ZPOOL_PROP_HEALTH:
 			verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
 			    ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
@@ -377,36 +405,13 @@
 	return (B_FALSE);
 }
 
-/*
- * Inspect the configuration to determine if any of the devices contain
- * an EFI label.
- */
-static boolean_t
-pool_uses_efi(nvlist_t *config)
-{
-#ifdef sun
-	nvlist_t **child;
-	uint_t c, children;
-
-	if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN,
-	    &child, &children) != 0)
-		return (read_efi_label(config, NULL) >= 0);
-
-	for (c = 0; c < children; c++) {
-		if (pool_uses_efi(child[c]))
-			return (B_TRUE);
-	}
-#endif	/* sun */
-	return (B_FALSE);
-}
-
 boolean_t
 zpool_is_bootable(zpool_handle_t *zhp)
 {
-	char bootfs[ZPOOL_MAXNAMELEN];
+	char bootfs[ZFS_MAX_DATASET_NAME_LEN];
 
 	return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs,
-	    sizeof (bootfs), NULL) == 0 && strncmp(bootfs, "-",
+	    sizeof (bootfs), NULL, B_FALSE) == 0 && strncmp(bootfs, "-",
 	    sizeof (bootfs)) != 0);
 }
 
@@ -428,7 +433,6 @@
 	char *slash, *check;
 	struct stat64 statbuf;
 	zpool_handle_t *zhp;
-	nvlist_t *nvroot;
 
 	if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) {
 		(void) no_memory(hdl);
@@ -442,10 +446,9 @@
 		prop = zpool_name_to_prop(propname);
 		if (prop == ZPROP_INVAL && zpool_prop_feature(propname)) {
 			int err;
-			zfeature_info_t *feature;
 			char *fname = strchr(propname, '@') + 1;
 
-			err = zfeature_lookup_name(fname, &feature);
+			err = zfeature_lookup_name(fname, NULL);
 			if (err != 0) {
 				ASSERT3U(err, ==, ENOENT);
 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
@@ -548,23 +551,6 @@
 				(void) zfs_error(hdl, EZFS_OPENFAILED, errbuf);
 				goto error;
 			}
-			verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
-			    ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
-
-#ifdef sun
-			/*
-			 * bootfs property cannot be set on a disk which has
-			 * been EFI labeled.
-			 */
-			if (pool_uses_efi(nvroot)) {
-				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
-				    "property '%s' not supported on "
-				    "EFI labeled devices"), propname);
-				(void) zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf);
-				zpool_close(zhp);
-				goto error;
-			}
-#endif	/* sun */
 			zpool_close(zhp);
 			break;
 
@@ -645,6 +631,7 @@
 				goto error;
 			}
 			break;
+
 		case ZPOOL_PROP_READONLY:
 			if (!flags.import) {
 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
@@ -654,6 +641,21 @@
 				goto error;
 			}
 			break;
+
+		case ZPOOL_PROP_TNAME:
+			if (!flags.create) {
+				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+				    "property '%s' can only be set at "
+				    "creation time"), propname);
+				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+				goto error;
+			}
+			break;
+
+		default:
+			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+			    "property '%s'(%d) not defined"), propname, prop);
+			break;
 		}
 	}
 
@@ -806,7 +808,7 @@
 
 		if (entry->pl_prop != ZPROP_INVAL &&
 		    zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf),
-		    NULL) == 0) {
+		    NULL, B_FALSE) == 0) {
 			if (strlen(buf) > entry->pl_width)
 				entry->pl_width = strlen(buf);
 		}
@@ -838,14 +840,14 @@
 	 */
 	if (supported) {
 		int ret;
-		zfeature_info_t *fi;
+		spa_feature_t fid;
 
-		ret = zfeature_lookup_name(feature, &fi);
+		ret = zfeature_lookup_name(feature, &fid);
 		if (ret != 0) {
 			(void) strlcpy(buf, "-", len);
 			return (ENOTSUP);
 		}
-		feature = fi->fi_guid;
+		feature = spa_feature_table[fid].fi_guid;
 	}
 
 	if (nvlist_lookup_uint64(features, feature, &refcount) == 0)
@@ -962,6 +964,10 @@
 				    "multiple '@' delimiters in name"));
 				break;
 
+			default:
+				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+				    "(%d) not defined"), why);
+				break;
 			}
 		}
 		return (B_FALSE);
@@ -1071,12 +1077,9 @@
 void
 zpool_close(zpool_handle_t *zhp)
 {
-	if (zhp->zpool_config)
-		nvlist_free(zhp->zpool_config);
-	if (zhp->zpool_old_config)
-		nvlist_free(zhp->zpool_old_config);
-	if (zhp->zpool_props)
-		nvlist_free(zhp->zpool_props);
+	nvlist_free(zhp->zpool_config);
+	nvlist_free(zhp->zpool_old_config);
+	nvlist_free(zhp->zpool_props);
 	free(zhp);
 }
 
@@ -1140,8 +1143,8 @@
 		    zfs_prop_to_name(ZFS_PROP_ZONED), &zonestr) == 0) &&
 		    strcmp(zonestr, "on") == 0);
 
-		if ((zc_fsprops = zfs_valid_proplist(hdl,
-		    ZFS_TYPE_FILESYSTEM, fsprops, zoned, NULL, msg)) == NULL) {
+		if ((zc_fsprops = zfs_valid_proplist(hdl, ZFS_TYPE_FILESYSTEM,
+		    fsprops, zoned, NULL, NULL, msg)) == NULL) {
 			goto create_failed;
 		}
 		if (!zc_props &&
@@ -1177,6 +1180,21 @@
 			    "one or more vdevs refer to the same device"));
 			return (zfs_error(hdl, EZFS_BADDEV, msg));
 
+		case ERANGE:
+			/*
+			 * This happens if the record size is smaller or larger
+			 * than the allowed size range, or not a power of 2.
+			 *
+			 * NOTE: although zfs_valid_proplist is called earlier,
+			 * this case may have slipped through since the
+			 * pool does not exist yet and it is therefore
+			 * impossible to read properties e.g. max blocksize
+			 * from the pool.
+			 */
+			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+			    "record size invalid"));
+			return (zfs_error(hdl, EZFS_BADPROP, msg));
+
 		case EOVERFLOW:
 			/*
 			 * This occurs when one of the devices is below
@@ -1287,25 +1305,6 @@
 		return (zfs_error(hdl, EZFS_BADVERSION, msg));
 	}
 
-	if (zpool_is_bootable(zhp) && nvlist_lookup_nvlist_array(nvroot,
-	    ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0) {
-		uint64_t s;
-
-		for (s = 0; s < nspares; s++) {
-			char *path;
-
-			if (nvlist_lookup_string(spares[s], ZPOOL_CONFIG_PATH,
-			    &path) == 0 && pool_uses_efi(spares[s])) {
-				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
-				    "device '%s' contains an EFI label and "
-				    "cannot be used on root pools."),
-				    zpool_vdev_name(hdl, NULL, spares[s],
-				    B_FALSE));
-				return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg));
-			}
-		}
-	}
-
 	if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) <
 	    SPA_VERSION_L2CACHE &&
 	    nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
@@ -1598,8 +1597,7 @@
 
 	ret = zpool_import_props(hdl, config, newname, props,
 	    ZFS_IMPORT_NORMAL);
-	if (props)
-		nvlist_free(props);
+	nvlist_free(props);
 	return (ret);
 }
 
@@ -1691,7 +1689,7 @@
 		thename = origname;
 	}
 
-	if (props) {
+	if (props != NULL) {
 		uint64_t version;
 		prop_flags_t flags = { .create = B_FALSE, .import = B_TRUE };
 
@@ -1699,12 +1697,13 @@
 		    &version) == 0);
 
 		if ((props = zpool_valid_proplist(hdl, origname,
-		    props, version, flags, errbuf)) == NULL) {
+		    props, version, flags, errbuf)) == NULL)
 			return (-1);
-		} else if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) {
+		if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) {
 			nvlist_free(props);
 			return (-1);
 		}
+		nvlist_free(props);
 	}
 
 	(void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name));
@@ -1713,11 +1712,11 @@
 	    &zc.zc_guid) == 0);
 
 	if (zcmd_write_conf_nvlist(hdl, &zc, config) != 0) {
-		nvlist_free(props);
+		zcmd_free_nvlists(&zc);
 		return (-1);
 	}
 	if (zcmd_alloc_dst_nvlist(hdl, &zc, zc.zc_nvlist_conf_size * 2) != 0) {
-		nvlist_free(props);
+		zcmd_free_nvlists(&zc);
 		return (-1);
 	}
 
@@ -1733,6 +1732,9 @@
 		error = errno;
 
 	(void) zcmd_read_dst_nvlist(hdl, &zc, &nv);
+
+	zcmd_free_nvlists(&zc);
+
 	zpool_get_rewind_policy(config, &policy);
 
 	if (error) {
@@ -1809,7 +1811,12 @@
 		case EEXIST:
 			(void) zpool_standard_error(hdl, error, desc);
 			break;
-
+		case ENAMETOOLONG:
+			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+			    "new name of at least one dataset is longer than "
+			    "the maximum allowable length"));
+			(void) zfs_error(hdl, EZFS_NAMETOOLONG, desc);
+			break;
 		default:
 			(void) zpool_standard_error(hdl, error, desc);
 			zpool_explain_recover(hdl,
@@ -1838,9 +1845,6 @@
 		return (0);
 	}
 
-	zcmd_free_nvlists(&zc);
-	nvlist_free(props);
-
 	return (ret);
 }
 
@@ -1892,6 +1896,7 @@
 	}
 }
 
+#ifdef illumos
 /*
  * This provides a very minimal check whether a given string is likely a
  * c#t#d# style string.  Users of this are expected to do their own
@@ -1904,7 +1909,8 @@
  * and the like.
  */
 static int
-ctd_check_path(char *str) {
+ctd_check_path(char *str)
+{
 	/*
 	 * If it starts with a slash, check the last component.
 	 */
@@ -1923,6 +1929,7 @@
 	}
 	return (CTD_CHECK(str));
 }
+#endif
 
 /*
  * Find a vdev that matches the search criteria specified. We use the
@@ -1978,6 +1985,7 @@
 		 *
 		 * Otherwise, all other searches are simple string compares.
 		 */
+#ifdef illumos
 		if (strcmp(srchkey, ZPOOL_CONFIG_PATH) == 0 &&
 		    ctd_check_path(val)) {
 			uint64_t wholedisk = 0;
@@ -2017,6 +2025,9 @@
 				break;
 			}
 		} else if (strcmp(srchkey, ZPOOL_CONFIG_TYPE) == 0 && val) {
+#else
+		if (strcmp(srchkey, ZPOOL_CONFIG_TYPE) == 0 && val) {
+#endif
 			char *type, *idx, *end, *p;
 			uint64_t id, vdev_id;
 
@@ -2273,6 +2284,7 @@
 				return (ret);
 		}
 	} else if (strcmp(type, VDEV_TYPE_MIRROR) == 0 ||
+	    strcmp(type, VDEV_TYPE_RAIDZ) == 0 ||
 	    strcmp(type, VDEV_TYPE_REPLACING) == 0 ||
 	    (is_spare = (strcmp(type, VDEV_TYPE_SPARE) == 0))) {
 		nvlist_t **child;
@@ -2319,11 +2331,9 @@
 		return (EZFS_INVALCONFIG);
 
 	/*
-	 * root pool can not have EFI labeled disks and can only have
-	 * a single top-level vdev.
+	 * root pool can only have a single top-level vdev.
 	 */
-	if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1 ||
-	    pool_uses_efi(vdev_root))
+	if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1)
 		return (EZFS_POOL_INVALARG);
 
 	(void) vdev_get_physpaths(child[0], physpath, phypath_size, &rsz,
@@ -2354,7 +2364,7 @@
 static int
 zpool_relabel_disk(libzfs_handle_t *hdl, const char *name)
 {
-#ifdef sun
+#ifdef illumos
 	char path[MAXPATHLEN];
 	char errbuf[1024];
 	int fd, error;
@@ -2364,7 +2374,7 @@
 	    "efi_use_whole_disk")) == NULL)
 		return (-1);
 
-	(void) snprintf(path, sizeof (path), "%s/%s", RDISK_ROOT, name);
+	(void) snprintf(path, sizeof (path), "%s/%s", ZFS_RDISK_ROOT, name);
 
 	if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) {
 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot "
@@ -2384,7 +2394,7 @@
 		    "relabel '%s': unable to read disk capacity"), name);
 		return (zfs_error(hdl, EZFS_NOCAP, errbuf));
 	}
-#endif	/* sun */
+#endif	/* illumos */
 	return (0);
 }
 
@@ -2440,7 +2450,7 @@
 		}
 
 		if (wholedisk) {
-			pathname += strlen(DISK_ROOT) + 1;
+			pathname += strlen(ZFS_DISK_ROOT) + 1;
 			(void) zpool_relabel_disk(hdl, pathname);
 		}
 	}
@@ -2627,16 +2637,6 @@
 		(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
 		    "cannot attach %s to %s"), new_disk, old_disk);
 
-	/*
-	 * If this is a root pool, make sure that we're not attaching an
-	 * EFI labeled device.
-	 */
-	if (rootpool && pool_uses_efi(nvroot)) {
-		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
-		    "EFI labeled devices are not supported on root pools."));
-		return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg));
-	}
-
 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
 	if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache,
 	    &islog)) == 0)
@@ -2926,8 +2926,7 @@
 	    &children) != 0) {
 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 		    "Source pool is missing vdev tree"));
-		if (zc_props)
-			nvlist_free(zc_props);
+		nvlist_free(zc_props);
 		return (-1);
 	}
 
@@ -3075,10 +3074,8 @@
 		free(varray);
 	}
 	zcmd_free_nvlists(&zc);
-	if (zc_props)
-		nvlist_free(zc_props);
-	if (newconfig)
-		nvlist_free(newconfig);
+	nvlist_free(zc_props);
+	nvlist_free(newconfig);
 	if (freelist) {
 		nvlist_free(*newroot);
 		*newroot = NULL;
@@ -3302,8 +3299,10 @@
 	if (ret != 0)
 		return (NULL);
 
-	if ((path = strdup(list[0].devname)) == NULL)
-		return (NULL);
+	/*
+	 * In a case the strdup() fails, we will just return NULL below.
+	 */
+	path = strdup(list[0].devname);
 
 	devid_free_nmlist(list);
 
@@ -3316,6 +3315,7 @@
 static char *
 path_to_devid(const char *path)
 {
+#ifdef have_devid
 	int fd;
 	ddi_devid_t devid;
 	char *minor, *ret;
@@ -3335,6 +3335,9 @@
 	(void) close(fd);
 
 	return (ret);
+#else
+	return (NULL);
+#endif
 }
 
 /*
@@ -3436,9 +3439,9 @@
 				devid_str_free(newdevid);
 		}
 
-#ifdef sun
-		if (strncmp(path, "/dev/dsk/", 9) == 0)
-			path += 9;
+#ifdef illumos
+		if (strncmp(path, ZFS_DISK_ROOTD, strlen(ZFS_DISK_ROOTD)) == 0)
+			path += strlen(ZFS_DISK_ROOTD);
 
 		if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
 		    &value) == 0 && value) {
@@ -3461,10 +3464,10 @@
 			}
 			return (tmp);
 		}
-#else	/* !sun */
+#else	/* !illumos */
 		if (strncmp(path, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
 			path += sizeof(_PATH_DEV) - 1;
-#endif	/* !sun */
+#endif	/* illumos */
 	} else {
 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0);
 
@@ -3498,9 +3501,9 @@
 }
 
 static int
-zbookmark_compare(const void *a, const void *b)
+zbookmark_mem_compare(const void *a, const void *b)
 {
-	return (memcmp(a, b, sizeof (zbookmark_t)));
+	return (memcmp(a, b, sizeof (zbookmark_phys_t)));
 }
 
 /*
@@ -3512,7 +3515,7 @@
 {
 	zfs_cmd_t zc = { 0 };
 	uint64_t count;
-	zbookmark_t *zb = NULL;
+	zbookmark_phys_t *zb = NULL;
 	int i;
 
 	/*
@@ -3525,7 +3528,7 @@
 	if (count == 0)
 		return (0);
 	if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl,
-	    count * sizeof (zbookmark_t))) == (uintptr_t)NULL)
+	    count * sizeof (zbookmark_phys_t))) == (uintptr_t)NULL)
 		return (-1);
 	zc.zc_nvlist_dst_size = count;
 	(void) strcpy(zc.zc_name, zhp->zpool_name);
@@ -3534,11 +3537,14 @@
 		    &zc) != 0) {
 			free((void *)(uintptr_t)zc.zc_nvlist_dst);
 			if (errno == ENOMEM) {
+				void *dst;
+
 				count = zc.zc_nvlist_dst_size;
-				if ((zc.zc_nvlist_dst = (uintptr_t)
-				    zfs_alloc(zhp->zpool_hdl, count *
-				    sizeof (zbookmark_t))) == (uintptr_t)NULL)
+				dst = zfs_alloc(zhp->zpool_hdl, count *
+				    sizeof (zbookmark_phys_t));
+				if (dst == NULL)
 					return (-1);
+				zc.zc_nvlist_dst = (uintptr_t)dst;
 			} else {
 				return (-1);
 			}
@@ -3554,11 +3560,11 @@
 	 * _not_ copied as part of the process.  So we point the start of our
 	 * array appropriate and decrement the total number of elements.
 	 */
-	zb = ((zbookmark_t *)(uintptr_t)zc.zc_nvlist_dst) +
+	zb = ((zbookmark_phys_t *)(uintptr_t)zc.zc_nvlist_dst) +
 	    zc.zc_nvlist_dst_size;
 	count -= zc.zc_nvlist_dst_size;
 
-	qsort(zb, count, sizeof (zbookmark_t), zbookmark_compare);
+	qsort(zb, count, sizeof (zbookmark_phys_t), zbookmark_mem_compare);
 
 	verify(nvlist_alloc(nverrlistp, 0, KM_SLEEP) == 0);
 
@@ -3736,7 +3742,9 @@
 	return (0);
 }
 
-#define	HIS_BUF_LEN	(128*1024)
+/* from spa_history.c: spa_history_create_obj() */
+#define	HIS_BUF_LEN_DEF	(128 << 10)
+#define	HIS_BUF_LEN_MAX	(1 << 30)
 
 /*
  * Retrieve the command history of a pool.
@@ -3744,14 +3752,18 @@
 int
 zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp)
 {
-	char buf[HIS_BUF_LEN];
+	char *buf;
+	uint64_t buflen = HIS_BUF_LEN_DEF;
 	uint64_t off = 0;
 	nvlist_t **records = NULL;
 	uint_t numrecords = 0;
 	int err, i;
 
+	buf = malloc(buflen);
+	if (buf == NULL)
+		return (ENOMEM);
 	do {
-		uint64_t bytes_read = sizeof (buf);
+		uint64_t bytes_read = buflen;
 		uint64_t leftover;
 
 		if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0)
@@ -3758,7 +3770,7 @@
 			break;
 
 		/* if nothing else was read in, we're at EOF, just return */
-		if (!bytes_read)
+		if (bytes_read == 0)
 			break;
 
 		if ((err = zpool_history_unpack(buf, bytes_read,
@@ -3765,10 +3777,26 @@
 		    &leftover, &records, &numrecords)) != 0)
 			break;
 		off -= leftover;
+		if (leftover == bytes_read) {
+			/*
+			 * no progress made, because buffer is not big enough
+			 * to hold this record; resize and retry.
+			 */
+			buflen *= 2;
+			free(buf);
+			buf = NULL;
+			if ((buflen >= HIS_BUF_LEN_MAX) ||
+			    ((buf = malloc(buflen)) == NULL)) {
+				err = ENOMEM;
+				break;
+			}
+		}
 
 		/* CONSTCOND */
 	} while (1);
 
+	free(buf);
+
 	if (!err) {
 		verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0);
 		verify(nvlist_add_nvlist_array(*nvhisp, ZPOOL_HIST_RECORD,
@@ -3788,7 +3816,7 @@
 	zfs_cmd_t zc = { 0 };
 	boolean_t mounted = B_FALSE;
 	char *mntpnt = NULL;
-	char dsname[MAXNAMELEN];
+	char dsname[ZFS_MAX_DATASET_NAME_LEN];
 
 	if (dsobj == 0) {
 		/* special case for the MOS */
@@ -3829,7 +3857,7 @@
 	free(mntpnt);
 }
 
-#ifdef sun
+#ifdef illumos
 /*
  * Read the EFI label from the config, if a label does not exist then
  * pass back the error to the caller. If the caller has passed a non-NULL
@@ -3847,7 +3875,7 @@
 	if (nvlist_lookup_string(config, ZPOOL_CONFIG_PATH, &path) != 0)
 		return (err);
 
-	(void) snprintf(diskname, sizeof (diskname), "%s%s", RDISK_ROOT,
+	(void) snprintf(diskname, sizeof (diskname), "%s%s", ZFS_RDISK_ROOT,
 	    strrchr(path, '/'));
 	if ((fd = open(diskname, O_RDONLY|O_NDELAY)) >= 0) {
 		struct dk_gpt *vtoc;
@@ -3894,7 +3922,7 @@
 	}
 	return (MAXOFFSET_T);
 }
-#endif /* sun */
+#endif /* illumos */
 
 /*
  * Label an individual disk.  The name provided is the short name,
@@ -3903,7 +3931,7 @@
 int
 zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, const char *name)
 {
-#ifdef sun
+#ifdef illumos
 	char path[MAXPATHLEN];
 	struct dk_gpt *vtoc;
 	int fd;
@@ -3919,13 +3947,6 @@
 	if (zhp) {
 		nvlist_t *nvroot;
 
-		if (zpool_is_bootable(zhp)) {
-			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
-			    "EFI labeled devices are not supported on root "
-			    "pools."));
-			return (zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf));
-		}
-
 		verify(nvlist_lookup_nvlist(zhp->zpool_config,
 		    ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
 
@@ -3939,7 +3960,7 @@
 		start_block = NEW_START_BLOCK;
 	}
 
-	(void) snprintf(path, sizeof (path), "%s/%s%s", RDISK_ROOT, name,
+	(void) snprintf(path, sizeof (path), "%s/%s%s", ZFS_RDISK_ROOT, name,
 	    BACKUP_SLICE);
 
 	if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) {
@@ -4008,7 +4029,7 @@
 
 	(void) close(fd);
 	efi_free(vtoc);
-#endif /* sun */
+#endif /* illumos */
 	return (0);
 }
 
@@ -4020,9 +4041,7 @@
 	uint_t children, c;
 
 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_TYPE, &type) == 0);
-	if (strcmp(type, VDEV_TYPE_RAIDZ) == 0 ||
-	    strcmp(type, VDEV_TYPE_FILE) == 0 ||
-	    strcmp(type, VDEV_TYPE_LOG) == 0 ||
+	if (strcmp(type, VDEV_TYPE_FILE) == 0 ||
 	    strcmp(type, VDEV_TYPE_HOLE) == 0 ||
 	    strcmp(type, VDEV_TYPE_MISSING) == 0) {
 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
@@ -4041,8 +4060,12 @@
 }
 
 /*
- * check if this zvol is allowable for use as a dump device; zero if
- * it is, > 0 if it isn't, < 0 if it isn't a zvol
+ * Check if this zvol is allowable for use as a dump device; zero if
+ * it is, > 0 if it isn't, < 0 if it isn't a zvol.
+ *
+ * Allowable storage configurations include mirrors, all raidz variants, and
+ * pools with log, cache, and spare devices.  Pools which are backed by files or
+ * have missing/hole vdevs are not suitable.
  */
 int
 zvol_check_dump_config(char *arg)
@@ -4054,7 +4077,7 @@
 	uint_t toplevels;
 	libzfs_handle_t *hdl;
 	char errbuf[1024];
-	char poolname[ZPOOL_MAXNAMELEN];
+	char poolname[ZFS_MAX_DATASET_NAME_LEN];
 	int pathlen = strlen(ZVOL_FULL_DEV_DIR);
 	int ret = 1;
 
@@ -4077,7 +4100,7 @@
 		    "malformed dataset name"));
 		(void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
 		return (1);
-	} else if (p - volname >= ZFS_MAXNAMELEN) {
+	} else if (p - volname >= ZFS_MAX_DATASET_NAME_LEN) {
 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 		    "dataset name is too long"));
 		(void) zfs_error(hdl, EZFS_NAMETOOLONG, errbuf);
@@ -4104,12 +4127,6 @@
 
 	verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
 	    &top, &toplevels) == 0);
-	if (toplevels != 1) {
-		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
-		    "'%s' has multiple top level vdevs"), poolname);
-		(void) zfs_error(hdl, EZFS_DEVOVERFLOW, errbuf);
-		goto out;
-	}
 
 	if (!supported_dump_vdev_type(hdl, top[0], errbuf)) {
 		goto out;
@@ -4122,3 +4139,25 @@
 	libzfs_fini(hdl);
 	return (ret);
 }
+
+int
+zpool_nextboot(libzfs_handle_t *hdl, uint64_t pool_guid, uint64_t dev_guid,
+    const char *command)
+{
+	zfs_cmd_t zc = { 0 };
+	nvlist_t *args;
+	char *packed;
+	size_t size;
+	int error;
+
+	args = fnvlist_alloc();
+	fnvlist_add_uint64(args, ZPOOL_CONFIG_POOL_GUID, pool_guid);
+	fnvlist_add_uint64(args, ZPOOL_CONFIG_GUID, dev_guid);
+	fnvlist_add_string(args, "command", command);
+	error = zcmd_write_src_nvlist(hdl, &zc, args);
+	if (error == 0)
+		error = ioctl(hdl->libzfs_fd, ZFS_IOC_NEXTBOOT, &zc);
+	zcmd_free_nvlists(&zc);
+	nvlist_free(args);
+	return (error);
+}

Modified: trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -21,11 +22,13 @@
 
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
- * Copyright (c) 2012 Pawel Jakub Dawidek <pawel at dawidek.net>.
- * All rights reserved.
+ * Copyright (c) 2012 Pawel Jakub Dawidek. All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
+ * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
+ * Copyright (c) 2014 Integros [integros.com]
+ * Copyright 2016 Igor Kozhukhov <ikozhukhov at gmail.com>
  */
 
 #include <assert.h>
@@ -45,11 +48,13 @@
 #include <time.h>
 
 #include <libzfs.h>
+#include <libzfs_core.h>
 
 #include "zfs_namecheck.h"
 #include "zfs_prop.h"
 #include "zfs_fletcher.h"
 #include "libzfs_impl.h"
+#include <zlib.h>
 #include <sha2.h>
 #include <sys/zio_checksum.h>
 #include <sys/ddt.h>
@@ -63,8 +68,11 @@
 /* We need to use something for ENODATA. */
 #define	ENODATA	EIDRM
 
-static int zfs_receive_impl(libzfs_handle_t *, const char *, recvflags_t *,
-    int, const char *, nvlist_t *, avl_tree_t *, char **, int, uint64_t *);
+static int zfs_receive_impl(libzfs_handle_t *, const char *, const char *,
+    recvflags_t *, int, const char *, nvlist_t *, avl_tree_t *, char **, int,
+    uint64_t *, const char *);
+static int guid_to_name(libzfs_handle_t *, const char *,
+    uint64_t, boolean_t, char *);
 
 static const zio_cksum_t zero_cksum = { 0 };
 
@@ -187,10 +195,28 @@
 }
 
 static int
-cksum_and_write(const void *buf, uint64_t len, zio_cksum_t *zc, int outfd)
+dump_record(dmu_replay_record_t *drr, void *payload, int payload_len,
+    zio_cksum_t *zc, int outfd)
 {
-	fletcher_4_incremental_native(buf, len, zc);
-	return (write(outfd, buf, len));
+	ASSERT3U(offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum),
+	    ==, sizeof (dmu_replay_record_t) - sizeof (zio_cksum_t));
+	fletcher_4_incremental_native(drr,
+	    offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum), zc);
+	if (drr->drr_type != DRR_BEGIN) {
+		ASSERT(ZIO_CHECKSUM_IS_ZERO(&drr->drr_u.
+		    drr_checksum.drr_checksum));
+		drr->drr_u.drr_checksum.drr_checksum = *zc;
+	}
+	fletcher_4_incremental_native(&drr->drr_u.drr_checksum.drr_checksum,
+	    sizeof (zio_cksum_t), zc);
+	if (write(outfd, drr, sizeof (*drr)) == -1)
+		return (errno);
+	if (payload_len != 0) {
+		fletcher_4_incremental_native(payload, payload_len, zc);
+		if (write(outfd, payload, payload_len) == -1)
+			return (errno);
+	}
+	return (0);
 }
 
 /*
@@ -214,18 +240,11 @@
 cksummer(void *arg)
 {
 	dedup_arg_t *dda = arg;
-	char *buf = malloc(1<<20);
+	char *buf = zfs_alloc(dda->dedup_hdl, SPA_MAXBLOCKSIZE);
 	dmu_replay_record_t thedrr;
 	dmu_replay_record_t *drr = &thedrr;
-	struct drr_begin *drrb = &thedrr.drr_u.drr_begin;
-	struct drr_end *drre = &thedrr.drr_u.drr_end;
-	struct drr_object *drro = &thedrr.drr_u.drr_object;
-	struct drr_write *drrw = &thedrr.drr_u.drr_write;
-	struct drr_spill *drrs = &thedrr.drr_u.drr_spill;
 	FILE *ofp;
 	int outfd;
-	dmu_replay_record_t wbr_drr = {0};
-	struct drr_write_byref *wbr_drrr = &wbr_drr.drr_u.drr_write_byref;
 	dedup_table_t ddt;
 	zio_cksum_t stream_cksum;
 	uint64_t physmem = sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE);
@@ -232,10 +251,10 @@
 	uint64_t numbuckets;
 
 	ddt.max_ddt_size =
-	    MAX((physmem * MAX_DDT_PHYSMEM_PERCENT)/100,
-	    SMALLEST_POSSIBLE_MAX_DDT_MB<<20);
+	    MAX((physmem * MAX_DDT_PHYSMEM_PERCENT) / 100,
+	    SMALLEST_POSSIBLE_MAX_DDT_MB << 20);
 
-	numbuckets = ddt.max_ddt_size/(sizeof (dedup_entry_t));
+	numbuckets = ddt.max_ddt_size / (sizeof (dedup_entry_t));
 
 	/*
 	 * numbuckets must be a power of 2.  Increase number to
@@ -251,20 +270,20 @@
 	ddt.numhashbits = high_order_bit(numbuckets) - 1;
 	ddt.ddt_full = B_FALSE;
 
-	/* Initialize the write-by-reference block. */
-	wbr_drr.drr_type = DRR_WRITE_BYREF;
-	wbr_drr.drr_payloadlen = 0;
-
 	outfd = dda->outputfd;
 	ofp = fdopen(dda->inputfd, "r");
-	while (ssread(drr, sizeof (dmu_replay_record_t), ofp) != 0) {
+	while (ssread(drr, sizeof (*drr), ofp) != 0) {
 
 		switch (drr->drr_type) {
 		case DRR_BEGIN:
 		{
-			int	fflags;
+			struct drr_begin *drrb = &drr->drr_u.drr_begin;
+			int fflags;
+			int sz = 0;
 			ZIO_SET_CHECKSUM(&stream_cksum, 0, 0, 0, 0);
 
+			ASSERT3U(drrb->drr_magic, ==, DMU_BACKUP_MAGIC);
+
 			/* set the DEDUP feature flag for this stream */
 			fflags = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo);
 			fflags |= (DMU_BACKUP_FEATURE_DEDUP |
@@ -271,35 +290,30 @@
 			    DMU_BACKUP_FEATURE_DEDUPPROPS);
 			DMU_SET_FEATUREFLAGS(drrb->drr_versioninfo, fflags);
 
-			if (cksum_and_write(drr, sizeof (dmu_replay_record_t),
-			    &stream_cksum, outfd) == -1)
-				goto out;
-			if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
-			    DMU_COMPOUNDSTREAM && drr->drr_payloadlen != 0) {
-				int sz = drr->drr_payloadlen;
+			if (drr->drr_payloadlen != 0) {
+				sz = drr->drr_payloadlen;
 
-				if (sz > 1<<20) {
-					free(buf);
-					buf = malloc(sz);
+				if (sz > SPA_MAXBLOCKSIZE) {
+					buf = zfs_realloc(dda->dedup_hdl, buf,
+					    SPA_MAXBLOCKSIZE, sz);
 				}
 				(void) ssread(buf, sz, ofp);
 				if (ferror(stdin))
 					perror("fread");
-				if (cksum_and_write(buf, sz, &stream_cksum,
-				    outfd) == -1)
-					goto out;
 			}
+			if (dump_record(drr, buf, sz, &stream_cksum,
+			    outfd) != 0)
+				goto out;
 			break;
 		}
 
 		case DRR_END:
 		{
+			struct drr_end *drre = &drr->drr_u.drr_end;
 			/* use the recalculated checksum */
-			ZIO_SET_CHECKSUM(&drre->drr_checksum,
-			    stream_cksum.zc_word[0], stream_cksum.zc_word[1],
-			    stream_cksum.zc_word[2], stream_cksum.zc_word[3]);
-			if ((write(outfd, drr,
-			    sizeof (dmu_replay_record_t))) == -1)
+			drre->drr_checksum = stream_cksum;
+			if (dump_record(drr, NULL, 0, &stream_cksum,
+			    outfd) != 0)
 				goto out;
 			break;
 		}
@@ -306,29 +320,25 @@
 
 		case DRR_OBJECT:
 		{
-			if (cksum_and_write(drr, sizeof (dmu_replay_record_t),
-			    &stream_cksum, outfd) == -1)
-				goto out;
+			struct drr_object *drro = &drr->drr_u.drr_object;
 			if (drro->drr_bonuslen > 0) {
 				(void) ssread(buf,
 				    P2ROUNDUP((uint64_t)drro->drr_bonuslen, 8),
 				    ofp);
-				if (cksum_and_write(buf,
-				    P2ROUNDUP((uint64_t)drro->drr_bonuslen, 8),
-				    &stream_cksum, outfd) == -1)
-					goto out;
 			}
+			if (dump_record(drr, buf,
+			    P2ROUNDUP((uint64_t)drro->drr_bonuslen, 8),
+			    &stream_cksum, outfd) != 0)
+				goto out;
 			break;
 		}
 
 		case DRR_SPILL:
 		{
-			if (cksum_and_write(drr, sizeof (dmu_replay_record_t),
-			    &stream_cksum, outfd) == -1)
-				goto out;
+			struct drr_spill *drrs = &drr->drr_u.drr_spill;
 			(void) ssread(buf, drrs->drr_length, ofp);
-			if (cksum_and_write(buf, drrs->drr_length,
-			    &stream_cksum, outfd) == -1)
+			if (dump_record(drr, buf, drrs->drr_length,
+			    &stream_cksum, outfd) != 0)
 				goto out;
 			break;
 		}
@@ -335,8 +345,8 @@
 
 		case DRR_FREEOBJECTS:
 		{
-			if (cksum_and_write(drr, sizeof (dmu_replay_record_t),
-			    &stream_cksum, outfd) == -1)
+			if (dump_record(drr, NULL, 0, &stream_cksum,
+			    outfd) != 0)
 				goto out;
 			break;
 		}
@@ -343,6 +353,7 @@
 
 		case DRR_WRITE:
 		{
+			struct drr_write *drrw = &drr->drr_u.drr_write;
 			dataref_t	dataref;
 
 			(void) ssread(buf, drrw->drr_length, ofp);
@@ -380,7 +391,13 @@
 			if (ddt_update(dda->dedup_hdl, &ddt,
 			    &drrw->drr_key.ddk_cksum, drrw->drr_key.ddk_prop,
 			    &dataref)) {
+				dmu_replay_record_t wbr_drr = {0};
+				struct drr_write_byref *wbr_drrr =
+				    &wbr_drr.drr_u.drr_write_byref;
+
 				/* block already present in stream */
+				wbr_drr.drr_type = DRR_WRITE_BYREF;
+
 				wbr_drrr->drr_object = drrw->drr_object;
 				wbr_drrr->drr_offset = drrw->drr_offset;
 				wbr_drrr->drr_length = drrw->drr_length;
@@ -400,34 +417,41 @@
 				wbr_drrr->drr_key.ddk_prop =
 				    drrw->drr_key.ddk_prop;
 
-				if (cksum_and_write(&wbr_drr,
-				    sizeof (dmu_replay_record_t), &stream_cksum,
-				    outfd) == -1)
+				if (dump_record(&wbr_drr, NULL, 0,
+				    &stream_cksum, outfd) != 0)
 					goto out;
 			} else {
 				/* block not previously seen */
-				if (cksum_and_write(drr,
-				    sizeof (dmu_replay_record_t), &stream_cksum,
-				    outfd) == -1)
+				if (dump_record(drr, buf, drrw->drr_length,
+				    &stream_cksum, outfd) != 0)
 					goto out;
-				if (cksum_and_write(buf,
-				    drrw->drr_length,
-				    &stream_cksum, outfd) == -1)
-					goto out;
 			}
 			break;
 		}
 
+		case DRR_WRITE_EMBEDDED:
+		{
+			struct drr_write_embedded *drrwe =
+			    &drr->drr_u.drr_write_embedded;
+			(void) ssread(buf,
+			    P2ROUNDUP((uint64_t)drrwe->drr_psize, 8), ofp);
+			if (dump_record(drr, buf,
+			    P2ROUNDUP((uint64_t)drrwe->drr_psize, 8),
+			    &stream_cksum, outfd) != 0)
+				goto out;
+			break;
+		}
+
 		case DRR_FREE:
 		{
-			if (cksum_and_write(drr, sizeof (dmu_replay_record_t),
-			    &stream_cksum, outfd) == -1)
+			if (dump_record(drr, NULL, 0, &stream_cksum,
+			    outfd) != 0)
 				goto out;
 			break;
 		}
 
 		default:
-			(void) printf("INVALID record type 0x%x\n",
+			(void) fprintf(stderr, "INVALID record type 0x%x\n",
 			    drr->drr_type);
 			/* should never happen, so assert */
 			assert(B_FALSE);
@@ -557,13 +581,30 @@
  * Routines for dealing with the giant nvlist of fs-nvlists, etc.
  */
 typedef struct send_data {
+	/*
+	 * assigned inside every recursive call,
+	 * restored from *_save on return:
+	 *
+	 * guid of fromsnap snapshot in parent dataset
+	 * txg of fromsnap snapshot in current dataset
+	 * txg of tosnap snapshot in current dataset
+	 */
+
 	uint64_t parent_fromsnap_guid;
+	uint64_t fromsnap_txg;
+	uint64_t tosnap_txg;
+
+	/* the nvlists get accumulated during depth-first traversal */
 	nvlist_t *parent_snaps;
 	nvlist_t *fss;
 	nvlist_t *snapprops;
+
+	/* send-receive configuration, does not change during traversal */
+	const char *fsname;
 	const char *fromsnap;
 	const char *tosnap;
 	boolean_t recursive;
+	boolean_t verbose;
 
 	/*
 	 * The header nvlist is of the following format:
@@ -596,11 +637,23 @@
 {
 	send_data_t *sd = arg;
 	uint64_t guid = zhp->zfs_dmustats.dds_guid;
+	uint64_t txg = zhp->zfs_dmustats.dds_creation_txg;
 	char *snapname;
 	nvlist_t *nv;
 
 	snapname = strrchr(zhp->zfs_name, '@')+1;
 
+	if (sd->tosnap_txg != 0 && txg > sd->tosnap_txg) {
+		if (sd->verbose) {
+			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+			    "skipping snapshot %s because it was created "
+			    "after the destination snapshot (%s)\n"),
+			    zhp->zfs_name, sd->tosnap);
+		}
+		zfs_close(zhp);
+		return (0);
+	}
+
 	VERIFY(0 == nvlist_add_uint64(sd->parent_snaps, snapname, guid));
 	/*
 	 * NB: if there is no fromsnap here (it's a newly created fs in
@@ -694,6 +747,31 @@
 }
 
 /*
+ * returns snapshot creation txg
+ * and returns 0 if the snapshot does not exist
+ */
+static uint64_t
+get_snap_txg(libzfs_handle_t *hdl, const char *fs, const char *snap)
+{
+	char name[ZFS_MAX_DATASET_NAME_LEN];
+	uint64_t txg = 0;
+
+	if (fs == NULL || fs[0] == '\0' || snap == NULL || snap[0] == '\0')
+		return (txg);
+
+	(void) snprintf(name, sizeof (name), "%s@%s", fs, snap);
+	if (zfs_dataset_exists(hdl, name, ZFS_TYPE_SNAPSHOT)) {
+		zfs_handle_t *zhp = zfs_open(hdl, name, ZFS_TYPE_SNAPSHOT);
+		if (zhp != NULL) {
+			txg = zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG);
+			zfs_close(zhp);
+		}
+	}
+
+	return (txg);
+}
+
+/*
  * recursively generate nvlists describing datasets.  See comment
  * for the data structure send_data_t above for description of contents
  * of the nvlist.
@@ -705,9 +783,48 @@
 	nvlist_t *nvfs, *nv;
 	int rv = 0;
 	uint64_t parent_fromsnap_guid_save = sd->parent_fromsnap_guid;
+	uint64_t fromsnap_txg_save = sd->fromsnap_txg;
+	uint64_t tosnap_txg_save = sd->tosnap_txg;
+	uint64_t txg = zhp->zfs_dmustats.dds_creation_txg;
 	uint64_t guid = zhp->zfs_dmustats.dds_guid;
+	uint64_t fromsnap_txg, tosnap_txg;
 	char guidstring[64];
 
+	fromsnap_txg = get_snap_txg(zhp->zfs_hdl, zhp->zfs_name, sd->fromsnap);
+	if (fromsnap_txg != 0)
+		sd->fromsnap_txg = fromsnap_txg;
+
+	tosnap_txg = get_snap_txg(zhp->zfs_hdl, zhp->zfs_name, sd->tosnap);
+	if (tosnap_txg != 0)
+		sd->tosnap_txg = tosnap_txg;
+
+	/*
+	 * on the send side, if the current dataset does not have tosnap,
+	 * perform two additional checks:
+	 *
+	 * - 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
+	 */
+	if (sd->tosnap != NULL && tosnap_txg == 0) {
+		if (sd->tosnap_txg != 0 && txg > sd->tosnap_txg) {
+			if (sd->verbose) {
+				(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+				    "skipping dataset %s: 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 "
+			    "exist\n"), sd->fsname, sd->tosnap, sd->recursive ?
+			    dgettext(TEXT_DOMAIN, " recursively") : "",
+			    zhp->zfs_name, sd->tosnap);
+			rv = -1;
+		}
+		goto out;
+	}
+
 	VERIFY(0 == nvlist_alloc(&nvfs, NV_UNIQUE_NAME, 0));
 	VERIFY(0 == nvlist_add_string(nvfs, "name", zhp->zfs_name));
 	VERIFY(0 == nvlist_add_uint64(nvfs, "parentfromsnap",
@@ -716,8 +833,10 @@
 	if (zhp->zfs_dmustats.dds_origin[0]) {
 		zfs_handle_t *origin = zfs_open(zhp->zfs_hdl,
 		    zhp->zfs_dmustats.dds_origin, ZFS_TYPE_SNAPSHOT);
-		if (origin == NULL)
-			return (-1);
+		if (origin == NULL) {
+			rv = -1;
+			goto out;
+		}
 		VERIFY(0 == nvlist_add_uint64(nvfs, "origin",
 		    origin->zfs_dmustats.dds_guid));
 	}
@@ -748,7 +867,10 @@
 	if (sd->recursive)
 		rv = zfs_iter_filesystems(zhp, send_iterate_fs, sd);
 
+out:
 	sd->parent_fromsnap_guid = parent_fromsnap_guid_save;
+	sd->fromsnap_txg = fromsnap_txg_save;
+	sd->tosnap_txg = tosnap_txg_save;
 
 	zfs_close(zhp);
 	return (rv);
@@ -756,7 +878,8 @@
 
 static int
 gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap,
-    const char *tosnap, boolean_t recursive, nvlist_t **nvlp, avl_tree_t **avlp)
+    const char *tosnap, boolean_t recursive, boolean_t verbose,
+    nvlist_t **nvlp, avl_tree_t **avlp)
 {
 	zfs_handle_t *zhp;
 	send_data_t sd = { 0 };
@@ -767,9 +890,11 @@
 		return (EZFS_BADTYPE);
 
 	VERIFY(0 == nvlist_alloc(&sd.fss, NV_UNIQUE_NAME, 0));
+	sd.fsname = fsname;
 	sd.fromsnap = fromsnap;
 	sd.tosnap = tosnap;
 	sd.recursive = recursive;
+	sd.verbose = verbose;
 
 	if ((error = send_iterate_fs(zhp, &sd)) != 0) {
 		nvlist_free(sd.fss);
@@ -796,10 +921,11 @@
 	/* these are all just the short snapname (the part after the @) */
 	const char *fromsnap;
 	const char *tosnap;
-	char prevsnap[ZFS_MAXNAMELEN];
+	char prevsnap[ZFS_MAX_DATASET_NAME_LEN];
 	uint64_t prevsnap_obj;
 	boolean_t seenfrom, seento, replicate, doall, fromorigin;
-	boolean_t verbose, dryrun, parsable, progress;
+	boolean_t verbose, dryrun, parsable, progress, embed_data, std_out;
+	boolean_t large_block;
 	int outfd;
 	boolean_t err;
 	nvlist_t *fss;
@@ -808,7 +934,7 @@
 	snapfilter_cb_t *filter_cb;
 	void *filter_cb_arg;
 	nvlist_t *debugnv;
-	char holdtag[ZFS_MAXNAMELEN];
+	char holdtag[ZFS_MAX_DATASET_NAME_LEN];
 	int cleanup_fd;
 	uint64_t size;
 } send_dump_data_t;
@@ -878,7 +1004,8 @@
  */
 static int
 dump_ioctl(zfs_handle_t *zhp, const char *fromsnap, uint64_t fromsnap_obj,
-    boolean_t fromorigin, int outfd, nvlist_t *debugnv)
+    boolean_t fromorigin, int outfd, enum lzc_send_flags flags,
+    nvlist_t *debugnv)
 {
 	zfs_cmd_t zc = { 0 };
 	libzfs_handle_t *hdl = zhp->zfs_hdl;
@@ -892,6 +1019,7 @@
 	zc.zc_obj = fromorigin;
 	zc.zc_sendobj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID);
 	zc.zc_fromobj = fromsnap_obj;
+	zc.zc_flags = flags;
 
 	VERIFY(0 == nvlist_alloc(&thisdbg, NV_UNIQUE_NAME, 0));
 	if (fromsnap && fromsnap[0] != '\0') {
@@ -931,7 +1059,7 @@
 		case EIO:
 		case ENOLINK:
 		case ENOSPC:
-#ifdef sun
+#ifdef illumos
 		case ENOSTR:
 #endif
 		case ENXIO:
@@ -973,17 +1101,14 @@
 send_progress_thread(void *arg)
 {
 	progress_arg_t *pa = arg;
-
 	zfs_cmd_t zc = { 0 };
 	zfs_handle_t *zhp = pa->pa_zhp;
 	libzfs_handle_t *hdl = zhp->zfs_hdl;
 	unsigned long long bytes;
 	char buf[16];
-
 	time_t t;
 	struct tm *tm;
 
-	assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
 	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
 
 	if (!pa->pa_parsable)
@@ -1016,6 +1141,51 @@
 	}
 }
 
+static void
+send_print_verbose(FILE *fout, const char *tosnap, const char *fromsnap,
+    uint64_t size, boolean_t parsable)
+{
+	if (parsable) {
+		if (fromsnap != NULL) {
+			(void) fprintf(fout, "incremental\t%s\t%s",
+			    fromsnap, tosnap);
+		} else {
+			(void) fprintf(fout, "full\t%s",
+			    tosnap);
+		}
+	} else {
+		if (fromsnap != NULL) {
+			if (strchr(fromsnap, '@') == NULL &&
+			    strchr(fromsnap, '#') == NULL) {
+				(void) fprintf(fout, dgettext(TEXT_DOMAIN,
+				    "send from @%s to %s"),
+				    fromsnap, tosnap);
+			} else {
+				(void) fprintf(fout, dgettext(TEXT_DOMAIN,
+				    "send from %s to %s"),
+				    fromsnap, tosnap);
+			}
+		} else {
+			(void) fprintf(fout, dgettext(TEXT_DOMAIN,
+			    "full send of %s"),
+			    tosnap);
+		}
+	}
+
+	if (size != 0) {
+		if (parsable) {
+			(void) fprintf(fout, "\t%llu",
+			    (longlong_t)size);
+		} else {
+			char buf[16];
+			zfs_nicenum(size, buf, sizeof (buf));
+			(void) fprintf(fout, dgettext(TEXT_DOMAIN,
+			    " estimated size is %s"), buf);
+		}
+	}
+	(void) fprintf(fout, "\n");
+}
+
 static int
 dump_snapshot(zfs_handle_t *zhp, void *arg)
 {
@@ -1026,6 +1196,7 @@
 	int err;
 	boolean_t isfromsnap, istosnap, fromorigin;
 	boolean_t exclude = B_FALSE;
+	FILE *fout = sdd->std_out ? stdout : stderr;
 
 	err = 0;
 	thissnap = strchr(zhp->zfs_name, '@') + 1;
@@ -1094,37 +1265,14 @@
 	    (sdd->fromorigin || sdd->replicate);
 
 	if (sdd->verbose) {
-		uint64_t size;
-		err = estimate_ioctl(zhp, sdd->prevsnap_obj,
+		uint64_t size = 0;
+		(void) estimate_ioctl(zhp, sdd->prevsnap_obj,
 		    fromorigin, &size);
 
-		if (sdd->parsable) {
-			if (sdd->prevsnap[0] != '\0') {
-				(void) fprintf(stderr, "incremental\t%s\t%s",
-				    sdd->prevsnap, zhp->zfs_name);
-			} else {
-				(void) fprintf(stderr, "full\t%s",
-				    zhp->zfs_name);
-			}
-		} else {
-			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
-			    "send from @%s to %s"),
-			    sdd->prevsnap, zhp->zfs_name);
-		}
-		if (err == 0) {
-			if (sdd->parsable) {
-				(void) fprintf(stderr, "\t%llu\n",
-				    (longlong_t)size);
-			} else {
-				char buf[16];
-				zfs_nicenum(size, buf, sizeof (buf));
-				(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
-				    " estimated size is %s\n"), buf);
-			}
-			sdd->size += size;
-		} else {
-			(void) fprintf(stderr, "\n");
-		}
+		send_print_verbose(fout, zhp->zfs_name,
+		    sdd->prevsnap[0] ? sdd->prevsnap : NULL,
+		    size, sdd->parsable);
+		sdd->size += size;
 	}
 
 	if (!sdd->dryrun) {
@@ -1137,15 +1285,21 @@
 			pa.pa_fd = sdd->outfd;
 			pa.pa_parsable = sdd->parsable;
 
-			if (err = pthread_create(&tid, NULL,
-			    send_progress_thread, &pa)) {
+			if ((err = pthread_create(&tid, NULL,
+			    send_progress_thread, &pa)) != 0) {
 				zfs_close(zhp);
 				return (err);
 			}
 		}
 
+		enum lzc_send_flags flags = 0;
+		if (sdd->large_block)
+			flags |= LZC_SEND_FLAG_LARGE_BLOCK;
+		if (sdd->embed_data)
+			flags |= LZC_SEND_FLAG_EMBED_DATA;
+
 		err = dump_ioctl(zhp, sdd->prevsnap, sdd->prevsnap_obj,
-		    fromorigin, sdd->outfd, sdd->debugnv);
+		    fromorigin, sdd->outfd, flags, sdd->debugnv);
 
 		if (sdd->progress) {
 			(void) pthread_cancel(tid);
@@ -1329,6 +1483,233 @@
 	return (0);
 }
 
+nvlist_t *
+zfs_send_resume_token_to_nvlist(libzfs_handle_t *hdl, const char *token)
+{
+	unsigned int version;
+	int nread;
+	unsigned long long checksum, packed_len;
+
+	/*
+	 * Decode token header, which is:
+	 *   <token version>-<checksum of payload>-<uncompressed payload length>
+	 * Note that the only supported token version is 1.
+	 */
+	nread = sscanf(token, "%u-%llx-%llx-",
+	    &version, &checksum, &packed_len);
+	if (nread != 3) {
+		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+		    "resume token is corrupt (invalid format)"));
+		return (NULL);
+	}
+
+	if (version != ZFS_SEND_RESUME_TOKEN_VERSION) {
+		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+		    "resume token is corrupt (invalid version %u)"),
+		    version);
+		return (NULL);
+	}
+
+	/* convert hexadecimal representation to binary */
+	token = strrchr(token, '-') + 1;
+	int len = strlen(token) / 2;
+	unsigned char *compressed = zfs_alloc(hdl, len);
+	for (int i = 0; i < len; i++) {
+		nread = sscanf(token + i * 2, "%2hhx", compressed + i);
+		if (nread != 1) {
+			free(compressed);
+			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+			    "resume token is corrupt "
+			    "(payload is not hex-encoded)"));
+			return (NULL);
+		}
+	}
+
+	/* verify checksum */
+	zio_cksum_t cksum;
+	fletcher_4_native(compressed, len, NULL, &cksum);
+	if (cksum.zc_word[0] != checksum) {
+		free(compressed);
+		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+		    "resume token is corrupt (incorrect checksum)"));
+		return (NULL);
+	}
+
+	/* uncompress */
+	void *packed = zfs_alloc(hdl, packed_len);
+	uLongf packed_len_long = packed_len;
+	if (uncompress(packed, &packed_len_long, compressed, len) != Z_OK ||
+	    packed_len_long != packed_len) {
+		free(packed);
+		free(compressed);
+		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+		    "resume token is corrupt (decompression failed)"));
+		return (NULL);
+	}
+
+	/* unpack nvlist */
+	nvlist_t *nv;
+	int error = nvlist_unpack(packed, packed_len, &nv, KM_SLEEP);
+	free(packed);
+	free(compressed);
+	if (error != 0) {
+		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+		    "resume token is corrupt (nvlist_unpack failed)"));
+		return (NULL);
+	}
+	return (nv);
+}
+
+int
+zfs_send_resume(libzfs_handle_t *hdl, sendflags_t *flags, int outfd,
+    const char *resume_token)
+{
+	char errbuf[1024];
+	char *toname;
+	char *fromname = NULL;
+	uint64_t resumeobj, resumeoff, toguid, fromguid, bytes;
+	zfs_handle_t *zhp;
+	int error = 0;
+	char name[ZFS_MAX_DATASET_NAME_LEN];
+	enum lzc_send_flags lzc_flags = 0;
+
+	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+	    "cannot resume send"));
+
+	nvlist_t *resume_nvl =
+	    zfs_send_resume_token_to_nvlist(hdl, resume_token);
+	if (resume_nvl == NULL) {
+		/*
+		 * zfs_error_aux has already been set by
+		 * zfs_send_resume_token_to_nvlist
+		 */
+		return (zfs_error(hdl, EZFS_FAULT, errbuf));
+	}
+	if (flags->verbose) {
+		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+		    "resume token contents:\n"));
+		nvlist_print(stderr, resume_nvl);
+	}
+
+	if (nvlist_lookup_string(resume_nvl, "toname", &toname) != 0 ||
+	    nvlist_lookup_uint64(resume_nvl, "object", &resumeobj) != 0 ||
+	    nvlist_lookup_uint64(resume_nvl, "offset", &resumeoff) != 0 ||
+	    nvlist_lookup_uint64(resume_nvl, "bytes", &bytes) != 0 ||
+	    nvlist_lookup_uint64(resume_nvl, "toguid", &toguid) != 0) {
+		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+		    "resume token is corrupt"));
+		return (zfs_error(hdl, EZFS_FAULT, errbuf));
+	}
+	fromguid = 0;
+	(void) nvlist_lookup_uint64(resume_nvl, "fromguid", &fromguid);
+
+	if (flags->embed_data || nvlist_exists(resume_nvl, "embedok"))
+		lzc_flags |= LZC_SEND_FLAG_EMBED_DATA;
+
+	if (guid_to_name(hdl, toname, toguid, B_FALSE, name) != 0) {
+		if (zfs_dataset_exists(hdl, toname, ZFS_TYPE_DATASET)) {
+			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+			    "'%s' is no longer the same snapshot used in "
+			    "the initial send"), toname);
+		} else {
+			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+			    "'%s' used in the initial send no longer exists"),
+			    toname);
+		}
+		return (zfs_error(hdl, EZFS_BADPATH, errbuf));
+	}
+	zhp = zfs_open(hdl, name, ZFS_TYPE_DATASET);
+	if (zhp == NULL) {
+		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+		    "unable to access '%s'"), name);
+		return (zfs_error(hdl, EZFS_BADPATH, errbuf));
+	}
+
+	if (fromguid != 0) {
+		if (guid_to_name(hdl, toname, fromguid, B_TRUE, name) != 0) {
+			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+			    "incremental source %#llx no longer exists"),
+			    (longlong_t)fromguid);
+			return (zfs_error(hdl, EZFS_BADPATH, errbuf));
+		}
+		fromname = name;
+	}
+
+	if (flags->verbose) {
+		uint64_t size = 0;
+		error = lzc_send_space(zhp->zfs_name, fromname, &size);
+		if (error == 0)
+			size = MAX(0, (int64_t)(size - bytes));
+		send_print_verbose(stderr, zhp->zfs_name, fromname,
+		    size, flags->parsable);
+	}
+
+	if (!flags->dryrun) {
+		progress_arg_t pa = { 0 };
+		pthread_t tid;
+		/*
+		 * If progress reporting is requested, spawn a new thread to
+		 * poll ZFS_IOC_SEND_PROGRESS at a regular interval.
+		 */
+		if (flags->progress) {
+			pa.pa_zhp = zhp;
+			pa.pa_fd = outfd;
+			pa.pa_parsable = flags->parsable;
+
+			error = pthread_create(&tid, NULL,
+			    send_progress_thread, &pa);
+			if (error != 0) {
+				zfs_close(zhp);
+				return (error);
+			}
+		}
+
+		error = lzc_send_resume(zhp->zfs_name, fromname, outfd,
+		    lzc_flags, resumeobj, resumeoff);
+
+		if (flags->progress) {
+			(void) pthread_cancel(tid);
+			(void) pthread_join(tid, NULL);
+		}
+
+		char errbuf[1024];
+		(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+		    "warning: cannot send '%s'"), zhp->zfs_name);
+
+		zfs_close(zhp);
+
+		switch (error) {
+		case 0:
+			return (0);
+		case EXDEV:
+		case ENOENT:
+		case EDQUOT:
+		case EFBIG:
+		case EIO:
+		case ENOLINK:
+		case ENOSPC:
+#ifdef illumos
+		case ENOSTR:
+#endif
+		case ENXIO:
+		case EPIPE:
+		case ERANGE:
+		case EFAULT:
+		case EROFS:
+			zfs_error_aux(hdl, strerror(errno));
+			return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));
+
+		default:
+			return (zfs_standard_error(hdl, errno, errbuf));
+		}
+	}
+
+
+	zfs_close(zhp);
+
+	return (error);
+}
+
 /*
  * Generate a send stream for the dataset identified by the argument zhp.
  *
@@ -1361,6 +1742,7 @@
 	int pipefd[2];
 	dedup_arg_t dda = { 0 };
 	int featureflags = 0;
+	FILE *fout;
 
 	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
 	    "cannot send '%s'"), zhp->zfs_name);
@@ -1382,7 +1764,7 @@
 	if (flags->dedup && !flags->dryrun) {
 		featureflags |= (DMU_BACKUP_FEATURE_DEDUP |
 		    DMU_BACKUP_FEATURE_DEDUPPROPS);
-		if (err = pipe(pipefd)) {
+		if ((err = pipe(pipefd)) != 0) {
 			zfs_error_aux(zhp->zfs_hdl, strerror(errno));
 			return (zfs_error(zhp->zfs_hdl, EZFS_PIPEFAILED,
 			    errbuf));
@@ -1390,7 +1772,7 @@
 		dda.outputfd = outfd;
 		dda.inputfd = pipefd[1];
 		dda.dedup_hdl = zhp->zfs_hdl;
-		if (err = pthread_create(&tid, NULL, cksummer, &dda)) {
+		if ((err = pthread_create(&tid, NULL, cksummer, &dda)) != 0) {
 			(void) close(pipefd[0]);
 			(void) close(pipefd[1]);
 			zfs_error_aux(zhp->zfs_hdl, strerror(errno));
@@ -1420,7 +1802,8 @@
 			}
 
 			err = gather_nvlist(zhp->zfs_hdl, zhp->zfs_name,
-			    fromsnap, tosnap, flags->replicate, &fss, &fsavl);
+			    fromsnap, tosnap, flags->replicate, flags->verbose,
+			    &fss, &fsavl);
 			if (err)
 				goto err_out;
 			VERIFY(0 == nvlist_add_nvlist(hdrnv, "fss", fss));
@@ -1446,18 +1829,11 @@
 			    sizeof (drr.drr_u.drr_begin.drr_toname),
 			    "%s@%s", zhp->zfs_name, tosnap);
 			drr.drr_payloadlen = buflen;
-			err = cksum_and_write(&drr, sizeof (drr), &zc, outfd);
 
-			/* write header nvlist */
-			if (err != -1 && packbuf != NULL) {
-				err = cksum_and_write(packbuf, buflen, &zc,
-				    outfd);
-			}
+			err = dump_record(&drr, packbuf, buflen, &zc, outfd);
 			free(packbuf);
-			if (err == -1) {
-				err = errno;
+			if (err != 0)
 				goto stderr_out;
-			}
 
 			/* write end record */
 			bzero(&drr, sizeof (drr));
@@ -1489,10 +1865,15 @@
 	sdd.parsable = flags->parsable;
 	sdd.progress = flags->progress;
 	sdd.dryrun = flags->dryrun;
+	sdd.large_block = flags->largeblock;
+	sdd.embed_data = flags->embed_data;
 	sdd.filter_cb = filter_func;
 	sdd.filter_cb_arg = cb_arg;
 	if (debugnvp)
 		sdd.debugnv = *debugnvp;
+	if (sdd.verbose && sdd.dryrun)
+		sdd.std_out = B_TRUE;
+	fout = sdd.std_out ? stdout : stderr;
 
 	/*
 	 * Some flags require that we place user holds on the datasets that are
@@ -1532,12 +1913,12 @@
 
 		if (flags->verbose) {
 			if (flags->parsable) {
-				(void) fprintf(stderr, "size\t%llu\n",
+				(void) fprintf(fout, "size\t%llu\n",
 				    (longlong_t)sdd.size);
 			} else {
 				char buf[16];
 				zfs_nicenum(sdd.size, buf, sizeof (buf));
-				(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+				(void) fprintf(fout, dgettext(TEXT_DOMAIN,
 				    "total estimated size is %s\n"), buf);
 			}
 		}
@@ -1619,6 +2000,63 @@
 	return (err);
 }
 
+int
+zfs_send_one(zfs_handle_t *zhp, const char *from, int fd,
+    enum lzc_send_flags flags)
+{
+	int err;
+	libzfs_handle_t *hdl = zhp->zfs_hdl;
+
+	char errbuf[1024];
+	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+	    "warning: cannot send '%s'"), zhp->zfs_name);
+
+	err = lzc_send(zhp->zfs_name, from, fd, flags);
+	if (err != 0) {
+		switch (errno) {
+		case EXDEV:
+			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+			    "not an earlier snapshot from the same fs"));
+			return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
+
+		case ENOENT:
+		case ESRCH:
+			if (lzc_exists(zhp->zfs_name)) {
+				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+				    "incremental source (%s) does not exist"),
+				    from);
+			}
+			return (zfs_error(hdl, EZFS_NOENT, errbuf));
+
+		case EBUSY:
+			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+			    "target is busy; if a filesystem, "
+			    "it must not be mounted"));
+			return (zfs_error(hdl, EZFS_BUSY, errbuf));
+
+		case EDQUOT:
+		case EFBIG:
+		case EIO:
+		case ENOLINK:
+		case ENOSPC:
+#ifdef illumos
+		case ENOSTR:
+#endif
+		case ENXIO:
+		case EPIPE:
+		case ERANGE:
+		case EFAULT:
+		case EROFS:
+			zfs_error_aux(hdl, strerror(errno));
+			return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));
+
+		default:
+			return (zfs_standard_error(hdl, errno, errbuf));
+		}
+	}
+	return (err != 0);
+}
+
 /*
  * Routines specific to "zfs recv"
  */
@@ -1631,6 +2069,8 @@
 	int rv;
 	int len = ilen;
 
+	assert(ilen <= SPA_MAXBLOCKSIZE);
+
 	do {
 		rv = read(fd, cp, len);
 		cp += rv;
@@ -1724,8 +2164,8 @@
 	if (err != 0 && strncmp(name + baselen, "recv-", 5) != 0) {
 		seq++;
 
-		(void) snprintf(newname, ZFS_MAXNAMELEN, "%.*srecv-%u-%u",
-		    baselen, name, getpid(), seq);
+		(void) snprintf(newname, ZFS_MAX_DATASET_NAME_LEN,
+		    "%.*srecv-%u-%u", baselen, name, getpid(), seq);
 		(void) strlcpy(zc.zc_value, newname, sizeof (zc.zc_value));
 
 		if (flags->verbose) {
@@ -1810,6 +2250,7 @@
 
 typedef struct guid_to_name_data {
 	uint64_t guid;
+	boolean_t bookmark_ok;
 	char *name;
 	char *skip;
 } guid_to_name_data_t;
@@ -1818,14 +2259,17 @@
 guid_to_name_cb(zfs_handle_t *zhp, void *arg)
 {
 	guid_to_name_data_t *gtnd = arg;
+	const char *slash;
 	int err;
 
 	if (gtnd->skip != NULL &&
-	    strcmp(zhp->zfs_name, gtnd->skip) == 0) {
+	    (slash = strrchr(zhp->zfs_name, '/')) != NULL &&
+	    strcmp(slash + 1, gtnd->skip) == 0) {
+		zfs_close(zhp);
 		return (0);
 	}
 
-	if (zhp->zfs_dmustats.dds_guid == gtnd->guid) {
+	if (zfs_prop_get_int(zhp, ZFS_PROP_GUID) == gtnd->guid) {
 		(void) strcpy(gtnd->name, zhp->zfs_name);
 		zfs_close(zhp);
 		return (EEXIST);
@@ -1832,6 +2276,8 @@
 	}
 
 	err = zfs_iter_children(zhp, guid_to_name_cb, gtnd);
+	if (err != EEXIST && gtnd->bookmark_ok)
+		err = zfs_iter_bookmarks(zhp, guid_to_name_cb, gtnd);
 	zfs_close(zhp);
 	return (err);
 }
@@ -1845,45 +2291,48 @@
  */
 static int
 guid_to_name(libzfs_handle_t *hdl, const char *parent, uint64_t guid,
-    char *name)
+    boolean_t bookmark_ok, char *name)
 {
-	/* exhaustive search all local snapshots */
-	char pname[ZFS_MAXNAMELEN];
+	char pname[ZFS_MAX_DATASET_NAME_LEN];
 	guid_to_name_data_t gtnd;
-	int err = 0;
-	zfs_handle_t *zhp;
-	char *cp;
 
 	gtnd.guid = guid;
+	gtnd.bookmark_ok = bookmark_ok;
 	gtnd.name = name;
 	gtnd.skip = NULL;
 
-	(void) strlcpy(pname, parent, sizeof (pname));
-
 	/*
-	 * Search progressively larger portions of the hierarchy.  This will
+	 * Search progressively larger portions of the hierarchy, starting
+	 * with the filesystem specified by 'parent'.  This will
 	 * select the "most local" version of the origin snapshot in the case
 	 * that there are multiple matching snapshots in the system.
 	 */
-	while ((cp = strrchr(pname, '/')) != NULL) {
-
+	(void) strlcpy(pname, parent, sizeof (pname));
+	char *cp = strrchr(pname, '@');
+	if (cp == NULL)
+		cp = strchr(pname, '\0');
+	for (; cp != NULL; cp = strrchr(pname, '/')) {
 		/* Chop off the last component and open the parent */
 		*cp = '\0';
-		zhp = make_dataset_handle(hdl, pname);
+		zfs_handle_t *zhp = make_dataset_handle(hdl, pname);
 
 		if (zhp == NULL)
 			continue;
-
-		err = zfs_iter_children(zhp, guid_to_name_cb, &gtnd);
+		int err = guid_to_name_cb(zfs_handle_dup(zhp), &gtnd);
+		if (err != EEXIST)
+			err = zfs_iter_children(zhp, guid_to_name_cb, &gtnd);
+		if (err != EEXIST && bookmark_ok)
+			err = zfs_iter_bookmarks(zhp, guid_to_name_cb, &gtnd);
 		zfs_close(zhp);
 		if (err == EEXIST)
 			return (0);
 
 		/*
-		 * Remember the dataset that we already searched, so we
-		 * skip it next time through.
+		 * Remember the last portion of the dataset so we skip it next
+		 * time through (as we've already searched that portion of the
+		 * hierarchy).
 		 */
-		gtnd.skip = pname;
+		gtnd.skip = strrchr(pname, '/') + 1;
 	}
 
 	return (ENOENT);
@@ -1899,7 +2348,7 @@
 {
 	nvlist_t *nvfs;
 	char *fsname, *snapname;
-	char buf[ZFS_MAXNAMELEN];
+	char buf[ZFS_MAX_DATASET_NAME_LEN];
 	int rv;
 	zfs_handle_t *guid1hdl, *guid2hdl;
 	uint64_t create1, create2;
@@ -1950,7 +2399,7 @@
 	avl_tree_t *local_avl;
 	nvpair_t *fselem, *nextfselem;
 	char *fromsnap;
-	char newname[ZFS_MAXNAMELEN];
+	char newname[ZFS_MAX_DATASET_NAME_LEN];
 	char guidname[32];
 	int error;
 	boolean_t needagain, progress, recursive;
@@ -1970,7 +2419,7 @@
 	VERIFY(0 == nvlist_alloc(&deleted, NV_UNIQUE_NAME, 0));
 
 	if ((error = gather_nvlist(hdl, tofs, fromsnap, NULL,
-	    recursive, &local_nv, &local_avl)) != 0)
+	    recursive, B_FALSE, &local_nv, &local_avl)) != 0)
 		return (error);
 
 	/*
@@ -2069,7 +2518,7 @@
 
 			/* check for delete */
 			if (found == NULL) {
-				char name[ZFS_MAXNAMELEN];
+				char name[ZFS_MAX_DATASET_NAME_LEN];
 
 				if (!flags->force)
 					continue;
@@ -2109,8 +2558,8 @@
 			/* check for different snapname */
 			if (strcmp(nvpair_name(snapelem),
 			    stream_snapname) != 0) {
-				char name[ZFS_MAXNAMELEN];
-				char tryname[ZFS_MAXNAMELEN];
+				char name[ZFS_MAX_DATASET_NAME_LEN];
+				char tryname[ZFS_MAX_DATASET_NAME_LEN];
 
 				(void) snprintf(name, sizeof (name), "%s@%s",
 				    fsname, nvpair_name(snapelem));
@@ -2192,7 +2641,7 @@
 		    ((flags->isprefix || strcmp(tofs, fsname) != 0) &&
 		    (s1 != NULL) && (s2 != NULL) && strcmp(s1, s2) != 0)) {
 			nvlist_t *parent;
-			char tryname[ZFS_MAXNAMELEN];
+			char tryname[ZFS_MAX_DATASET_NAME_LEN];
 
 			parent = fsavl_find(local_avl,
 			    stream_parent_fromsnap_guid, NULL);
@@ -2258,9 +2707,10 @@
 	nvlist_t *stream_nv = NULL;
 	avl_tree_t *stream_avl = NULL;
 	char *fromsnap = NULL;
+	char *sendsnap = NULL;
 	char *cp;
-	char tofs[ZFS_MAXNAMELEN];
-	char sendfs[ZFS_MAXNAMELEN];
+	char tofs[ZFS_MAX_DATASET_NAME_LEN];
+	char sendfs[ZFS_MAX_DATASET_NAME_LEN];
 	char errbuf[1024];
 	dmu_replay_record_t drre;
 	int error;
@@ -2344,7 +2794,7 @@
 			nvlist_t *renamed = NULL;
 			nvpair_t *pair = NULL;
 
-			(void) strlcpy(tofs, destname, ZFS_MAXNAMELEN);
+			(void) strlcpy(tofs, destname, sizeof (tofs));
 			if (flags->isprefix) {
 				struct drr_begin *drrb = &drr->drr_u.drr_begin;
 				int i;
@@ -2353,7 +2803,7 @@
 					cp = strrchr(drrb->drr_toname, '/');
 					if (cp == NULL) {
 						(void) strlcat(tofs, "/",
-						    ZFS_MAXNAMELEN);
+						    sizeof (tofs));
 						i = 0;
 					} else {
 						i = (cp - drrb->drr_toname);
@@ -2363,7 +2813,7 @@
 				}
 				/* zfs_receive_one() will create_parents() */
 				(void) strlcat(tofs, &drrb->drr_toname[i],
-				    ZFS_MAXNAMELEN);
+				    sizeof (tofs));
 				*strchr(tofs, '@') = '\0';
 			}
 
@@ -2405,9 +2855,17 @@
 	 * zfs_receive_one().
 	 */
 	(void) strlcpy(sendfs, drr->drr_u.drr_begin.drr_toname,
-	    ZFS_MAXNAMELEN);
-	if ((cp = strchr(sendfs, '@')) != NULL)
+	    sizeof (sendfs));
+	if ((cp = strchr(sendfs, '@')) != NULL) {
 		*cp = '\0';
+		/*
+		 * Find the "sendsnap", the final snapshot in a replication
+		 * stream.  zfs_receive_one() handles certain errors
+		 * differently, depending on if the contained stream is the
+		 * last one or not.
+		 */
+		sendsnap = (cp + 1);
+	}
 
 	/* Finally, receive each contained stream */
 	do {
@@ -2418,9 +2876,9 @@
 		 * zfs_receive_one() will take care of it (ie,
 		 * recv_skip() and return 0).
 		 */
-		error = zfs_receive_impl(hdl, destname, flags, fd,
+		error = zfs_receive_impl(hdl, destname, NULL, flags, fd,
 		    sendfs, stream_nv, stream_avl, top_zfs, cleanup_fd,
-		    action_handlep);
+		    action_handlep, sendsnap);
 		if (error == ENODATA) {
 			error = 0;
 			break;
@@ -2439,8 +2897,7 @@
 
 out:
 	fsavl_destroy(stream_avl);
-	if (stream_nv)
-		nvlist_free(stream_nv);
+	nvlist_free(stream_nv);
 	if (softerr)
 		error = -2;
 	if (anyerr)
@@ -2465,7 +2922,7 @@
 recv_skip(libzfs_handle_t *hdl, int fd, boolean_t byteswap)
 {
 	dmu_replay_record_t *drr;
-	void *buf = malloc(1<<20);
+	void *buf = zfs_alloc(hdl, SPA_MAXBLOCKSIZE);
 	char errbuf[1024];
 
 	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
@@ -2481,11 +2938,9 @@
 
 		switch (drr->drr_type) {
 		case DRR_BEGIN:
-			/* NB: not to be used on v2 stream packages */
 			if (drr->drr_payloadlen != 0) {
-				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
-				    "invalid substream header"));
-				return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
+				(void) recv_read(hdl, fd, buf,
+				    drr->drr_payloadlen, B_FALSE, NULL);
 			}
 			break;
 
@@ -2514,12 +2969,22 @@
 			break;
 		case DRR_SPILL:
 			if (byteswap) {
-				drr->drr_u.drr_write.drr_length =
+				drr->drr_u.drr_spill.drr_length =
 				    BSWAP_64(drr->drr_u.drr_spill.drr_length);
 			}
 			(void) recv_read(hdl, fd, buf,
 			    drr->drr_u.drr_spill.drr_length, B_FALSE, NULL);
 			break;
+		case DRR_WRITE_EMBEDDED:
+			if (byteswap) {
+				drr->drr_u.drr_write_embedded.drr_psize =
+				    BSWAP_32(drr->drr_u.drr_write_embedded.
+				    drr_psize);
+			}
+			(void) recv_read(hdl, fd, buf,
+			    P2ROUNDUP(drr->drr_u.drr_write_embedded.drr_psize,
+			    8), B_FALSE, NULL);
+			break;
 		case DRR_WRITE_BYREF:
 		case DRR_FREEOBJECTS:
 		case DRR_FREE:
@@ -2536,15 +3001,49 @@
 	return (-1);
 }
 
+static void
+recv_ecksum_set_aux(libzfs_handle_t *hdl, const char *target_snap,
+    boolean_t resumable)
+{
+	char target_fs[ZFS_MAX_DATASET_NAME_LEN];
+
+	zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+	    "checksum mismatch or incomplete stream"));
+
+	if (!resumable)
+		return;
+	(void) strlcpy(target_fs, target_snap, sizeof (target_fs));
+	*strchr(target_fs, '@') = '\0';
+	zfs_handle_t *zhp = zfs_open(hdl, target_fs,
+	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+	if (zhp == NULL)
+		return;
+
+	char token_buf[ZFS_MAXPROPLEN];
+	int error = zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
+	    token_buf, sizeof (token_buf),
+	    NULL, NULL, 0, B_TRUE);
+	if (error == 0) {
+		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+		    "checksum mismatch or incomplete stream.\n"
+		    "Partially received snapshot is saved.\n"
+		    "A resuming stream can be generated on the sending "
+		    "system by running:\n"
+		    "    zfs send -t %s"),
+		    token_buf);
+	}
+	zfs_close(zhp);
+}
+
 /*
  * Restores a backup of tosnap from the file descriptor specified by infd.
  */
 static int
 zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
-    recvflags_t *flags, dmu_replay_record_t *drr,
-    dmu_replay_record_t *drr_noswap, const char *sendfs,
-    nvlist_t *stream_nv, avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
-    uint64_t *action_handlep)
+    const char *originsnap, recvflags_t *flags, dmu_replay_record_t *drr,
+    dmu_replay_record_t *drr_noswap, const char *sendfs, nvlist_t *stream_nv,
+    avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
+    uint64_t *action_handlep, const char *finalsnap)
 {
 	zfs_cmd_t zc = { 0 };
 	time_t begin_time;
@@ -2561,6 +3060,7 @@
 	nvlist_t *snapprops_nvlist = NULL;
 	zprop_errflags_t prop_errflags;
 	boolean_t recursive;
+	char *snapname = NULL;
 
 	begin_time = time(NULL);
 
@@ -2571,7 +3071,6 @@
 	    ENOENT);
 
 	if (stream_avl != NULL) {
-		char *snapname;
 		nvlist_t *fs = fsavl_find(stream_avl, drrb->drr_toguid,
 		    &snapname);
 		nvlist_t *props;
@@ -2697,9 +3196,14 @@
 	/*
 	 * Determine the name of the origin snapshot, store in zc_string.
 	 */
-	if (drrb->drr_flags & DRR_FLAG_CLONE) {
+	if (originsnap) {
+		(void) strncpy(zc.zc_string, originsnap, sizeof (zc.zc_string));
+		if (flags->verbose)
+			(void) printf("using provided clone origin %s\n",
+			    zc.zc_string);
+	} else if (drrb->drr_flags & DRR_FLAG_CLONE) {
 		if (guid_to_name(hdl, zc.zc_value,
-		    drrb->drr_fromguid, zc.zc_string) != 0) {
+		    drrb->drr_fromguid, B_FALSE, zc.zc_string) != 0) {
 			zcmd_free_nvlists(&zc);
 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 			    "local origin for clone %s does not exist"),
@@ -2710,8 +3214,10 @@
 			(void) printf("found clone origin %s\n", zc.zc_string);
 	}
 
+	boolean_t resuming = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &
+	    DMU_BACKUP_FEATURE_RESUMING;
 	stream_wantsnewfs = (drrb->drr_fromguid == 0 ||
-	    (drrb->drr_flags & DRR_FLAG_CLONE));
+	    (drrb->drr_flags & DRR_FLAG_CLONE) || originsnap) && !resuming;
 
 	if (stream_wantsnewfs) {
 		/*
@@ -2727,10 +3233,10 @@
 			*cp = '\0';
 		if (cp &&
 		    !zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) {
-			char suffix[ZFS_MAXNAMELEN];
+			char suffix[ZFS_MAX_DATASET_NAME_LEN];
 			(void) strcpy(suffix, strrchr(zc.zc_value, '/'));
 			if (guid_to_name(hdl, zc.zc_name, parent_snapguid,
-			    zc.zc_value) == 0) {
+			    B_FALSE, zc.zc_value) == 0) {
 				*strchr(zc.zc_value, '@') = '\0';
 				(void) strcat(zc.zc_value, suffix);
 			}
@@ -2754,10 +3260,10 @@
 		if ((flags->isprefix || (*(chopprefix = drrb->drr_toname +
 		    strlen(sendfs)) != '\0' && *chopprefix != '@')) &&
 		    !zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) {
-			char snap[ZFS_MAXNAMELEN];
+			char snap[ZFS_MAX_DATASET_NAME_LEN];
 			(void) strcpy(snap, strchr(zc.zc_value, '@'));
 			if (guid_to_name(hdl, zc.zc_name, drrb->drr_fromguid,
-			    zc.zc_value) == 0) {
+			    B_FALSE, zc.zc_value) == 0) {
 				*strchr(zc.zc_value, '@') = '\0';
 				(void) strcat(zc.zc_value, snap);
 			}
@@ -2771,11 +3277,12 @@
 		zfs_handle_t *zhp;
 
 		/*
-		 * Destination fs exists.  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).
+		 * Destination fs exists.  It must be one of these cases:
+		 *  - an incremental send stream
+		 *  - the stream specifies a new fs (full stream or clone)
+		 *    and they want us to blow away the existing fs (and
+		 *    have therefore specified -F and removed any snapshots)
+		 *  - we are resuming a failed receive.
 		 */
 		if (stream_wantsnewfs) {
 			if (!flags->force) {
@@ -2830,6 +3337,18 @@
 				return (-1);
 			}
 		}
+
+		/*
+		 * If we are resuming a newfs, set newfs here so that we will
+		 * mount it if the recv succeeds this time.  We can tell
+		 * that it was a newfs on the first recv because the fs
+		 * itself will be inconsistent (if the fs existed when we
+		 * did the first recv, we would have received it into
+		 * .../%recv).
+		 */
+		if (resuming && zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT))
+			newfs = B_TRUE;
+
 		zfs_close(zhp);
 	} else {
 		/*
@@ -2862,9 +3381,10 @@
 		newfs = B_TRUE;
 	}
 
-	zc.zc_begin_record = drr_noswap->drr_u.drr_begin;
+	zc.zc_begin_record = *drr_noswap;
 	zc.zc_cookie = infd;
 	zc.zc_guid = flags->force;
+	zc.zc_resumable = flags->resumable;
 	if (flags->verbose) {
 		(void) printf("%s %s stream of %s into %s\n",
 		    flags->dryrun ? "would receive" : "receiving",
@@ -2906,7 +3426,21 @@
 			    ZPROP_N_MORE_ERRORS) == 0) {
 				trunc_prop_errs(intval);
 				break;
-			} else {
+			} else if (snapname == NULL || finalsnap == NULL ||
+			    strcmp(finalsnap, snapname) == 0 ||
+			    strcmp(nvpair_name(prop_err),
+			    zfs_prop_to_name(ZFS_PROP_REFQUOTA)) != 0) {
+				/*
+				 * Skip the special case of, for example,
+				 * "refquota", errors on intermediate
+				 * snapshots leading up to a final one.
+				 * That's why we have all of the checks above.
+				 *
+				 * See zfs_ioctl.c's extract_delay_props() for
+				 * a list of props which can fail on
+				 * intermediate snapshots, but shouldn't
+				 * affect the overall receive.
+				 */
 				(void) snprintf(tbuf, sizeof (tbuf),
 				    dgettext(TEXT_DOMAIN,
 				    "cannot receive %s property on %s"),
@@ -2949,7 +3483,7 @@
 		 */
 		*cp = '\0';
 		if (gather_nvlist(hdl, zc.zc_value, NULL, NULL, B_FALSE,
-		    &local_nv, &local_avl) == 0) {
+		    B_FALSE, &local_nv, &local_avl) == 0) {
 			*cp = '@';
 			fs = fsavl_find(local_avl, drrb->drr_toguid, NULL);
 			fsavl_destroy(local_avl);
@@ -3001,8 +3535,7 @@
 			(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);
 			break;
 		case ECKSUM:
-			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
-			    "invalid stream (checksum mismatch)"));
+			recv_ecksum_set_aux(hdl, zc.zc_value, flags->resumable);
 			(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);
 			break;
 		case ENOTSUP:
@@ -3049,7 +3582,8 @@
 	}
 
 	if (clp) {
-		err |= changelist_postfix(clp);
+		if (!flags->nomount)
+			err |= changelist_postfix(clp);
 		changelist_free(clp);
 	}
 
@@ -3089,9 +3623,10 @@
 }
 
 static int
-zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap, recvflags_t *flags,
-    int infd, const char *sendfs, nvlist_t *stream_nv, avl_tree_t *stream_avl,
-    char **top_zfs, int cleanup_fd, uint64_t *action_handlep)
+zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap,
+    const char *originsnap, recvflags_t *flags, int infd, const char *sendfs,
+    nvlist_t *stream_nv, avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
+    uint64_t *action_handlep, const char *finalsnap)
 {
 	int err;
 	dmu_replay_record_t drr, drr_noswap;
@@ -3110,6 +3645,12 @@
 		    "(%s) does not exist"), tosnap);
 		return (zfs_error(hdl, EZFS_NOENT, errbuf));
 	}
+	if (originsnap &&
+	    !zfs_dataset_exists(hdl, originsnap, ZFS_TYPE_DATASET)) {
+		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "specified origin fs "
+		    "(%s) does not exist"), originsnap);
+		return (zfs_error(hdl, EZFS_NOENT, errbuf));
+	}
 
 	/* read in the BEGIN record */
 	if (0 != (err = recv_read(hdl, infd, &drr, sizeof (drr), B_FALSE,
@@ -3169,7 +3710,7 @@
 	}
 
 	if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) == DMU_SUBSTREAM) {
-		char nonpackage_sendfs[ZFS_MAXNAMELEN];
+		char nonpackage_sendfs[ZFS_MAX_DATASET_NAME_LEN];
 		if (sendfs == NULL) {
 			/*
 			 * We were not called from zfs_receive_package(). Get
@@ -3177,19 +3718,21 @@
 			 */
 			char *cp;
 			(void) strlcpy(nonpackage_sendfs,
-			    drr.drr_u.drr_begin.drr_toname, ZFS_MAXNAMELEN);
+			    drr.drr_u.drr_begin.drr_toname,
+			    sizeof (nonpackage_sendfs));
 			if ((cp = strchr(nonpackage_sendfs, '@')) != NULL)
 				*cp = '\0';
 			sendfs = nonpackage_sendfs;
+			VERIFY(finalsnap == NULL);
 		}
-		return (zfs_receive_one(hdl, infd, tosnap, flags,
-		    &drr, &drr_noswap, sendfs, stream_nv, stream_avl,
-		    top_zfs, cleanup_fd, action_handlep));
+		return (zfs_receive_one(hdl, infd, tosnap, originsnap, flags,
+		    &drr, &drr_noswap, sendfs, stream_nv, stream_avl, top_zfs,
+		    cleanup_fd, action_handlep, finalsnap));
 	} else {
 		assert(DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
 		    DMU_COMPOUNDSTREAM);
-		return (zfs_receive_package(hdl, infd, tosnap, flags,
-		    &drr, &zcksum, top_zfs, cleanup_fd, action_handlep));
+		return (zfs_receive_package(hdl, infd, tosnap, flags, &drr,
+		    &zcksum, top_zfs, cleanup_fd, action_handlep));
 	}
 }
 
@@ -3197,22 +3740,29 @@
  * Restores a backup of tosnap from the file descriptor specified by infd.
  * Return 0 on total success, -2 if some things couldn't be
  * destroyed/renamed/promoted, -1 if some things couldn't be received.
- * (-1 will override -2).
+ * (-1 will override -2, if -1 and the resumable flag was specified the
+ * transfer can be resumed if the sending side supports it).
  */
 int
-zfs_receive(libzfs_handle_t *hdl, const char *tosnap, recvflags_t *flags,
-    int infd, avl_tree_t *stream_avl)
+zfs_receive(libzfs_handle_t *hdl, const char *tosnap, nvlist_t *props,
+    recvflags_t *flags, int infd, avl_tree_t *stream_avl)
 {
 	char *top_zfs = NULL;
 	int err;
 	int cleanup_fd;
 	uint64_t action_handle = 0;
+	char *originsnap = NULL;
+	if (props) {
+		err = nvlist_lookup_string(props, "origin", &originsnap);
+		if (err && err != ENOENT)
+			return (err);
+	}
 
 	cleanup_fd = open(ZFS_DEV, O_RDWR|O_EXCL);
 	VERIFY(cleanup_fd >= 0);
 
-	err = zfs_receive_impl(hdl, tosnap, flags, infd, NULL, NULL,
-	    stream_avl, &top_zfs, cleanup_fd, &action_handle);
+	err = zfs_receive_impl(hdl, tosnap, originsnap, flags, infd, NULL, NULL,
+	    stream_avl, &top_zfs, cleanup_fd, &action_handle, NULL);
 
 	VERIFY(0 == close(cleanup_fd));
 

Modified: trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_status.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_status.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_status.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -73,57 +74,66 @@
 
 /* ARGSUSED */
 static int
-vdev_missing(uint64_t state, uint64_t aux, uint64_t errs)
+vdev_missing(vdev_stat_t *vs, uint_t vsc)
 {
-	return (state == VDEV_STATE_CANT_OPEN &&
-	    aux == VDEV_AUX_OPEN_FAILED);
+	return (vs->vs_state == VDEV_STATE_CANT_OPEN &&
+	    vs->vs_aux == VDEV_AUX_OPEN_FAILED);
 }
 
 /* ARGSUSED */
 static int
-vdev_faulted(uint64_t state, uint64_t aux, uint64_t errs)
+vdev_faulted(vdev_stat_t *vs, uint_t vsc)
 {
-	return (state == VDEV_STATE_FAULTED);
+	return (vs->vs_state == VDEV_STATE_FAULTED);
 }
 
 /* ARGSUSED */
 static int
-vdev_errors(uint64_t state, uint64_t aux, uint64_t errs)
+vdev_errors(vdev_stat_t *vs, uint_t vsc)
 {
-	return (state == VDEV_STATE_DEGRADED || errs != 0);
+	return (vs->vs_state == VDEV_STATE_DEGRADED ||
+	    vs->vs_read_errors != 0 || vs->vs_write_errors != 0 ||
+	    vs->vs_checksum_errors != 0);
 }
 
 /* ARGSUSED */
 static int
-vdev_broken(uint64_t state, uint64_t aux, uint64_t errs)
+vdev_broken(vdev_stat_t *vs, uint_t vsc)
 {
-	return (state == VDEV_STATE_CANT_OPEN);
+	return (vs->vs_state == VDEV_STATE_CANT_OPEN);
 }
 
 /* ARGSUSED */
 static int
-vdev_offlined(uint64_t state, uint64_t aux, uint64_t errs)
+vdev_offlined(vdev_stat_t *vs, uint_t vsc)
 {
-	return (state == VDEV_STATE_OFFLINE);
+	return (vs->vs_state == VDEV_STATE_OFFLINE);
 }
 
 /* ARGSUSED */
 static int
-vdev_removed(uint64_t state, uint64_t aux, uint64_t errs)
+vdev_removed(vdev_stat_t *vs, uint_t vsc)
 {
-	return (state == VDEV_STATE_REMOVED);
+	return (vs->vs_state == VDEV_STATE_REMOVED);
 }
 
+static int
+vdev_non_native_ashift(vdev_stat_t *vs, uint_t vsc)
+{
+	return (VDEV_STAT_VALID(vs_physical_ashift, vsc) &&
+	    vs->vs_configured_ashift < vs->vs_physical_ashift);
+}
+
 /*
  * Detect if any leaf devices that have seen errors or could not be opened.
  */
 static boolean_t
-find_vdev_problem(nvlist_t *vdev, int (*func)(uint64_t, uint64_t, uint64_t))
+find_vdev_problem(nvlist_t *vdev, int (*func)(vdev_stat_t *, uint_t),
+    boolean_t ignore_replacing)
 {
 	nvlist_t **child;
 	vdev_stat_t *vs;
-	uint_t c, children;
-	char *type;
+	uint_t c, vsc, children;
 
 	/*
 	 * Ignore problems within a 'replacing' vdev, since we're presumably in
@@ -131,23 +141,25 @@
 	 * out again.  We'll pick up the fact that a resilver is happening
 	 * later.
 	 */
-	verify(nvlist_lookup_string(vdev, ZPOOL_CONFIG_TYPE, &type) == 0);
-	if (strcmp(type, VDEV_TYPE_REPLACING) == 0)
-		return (B_FALSE);
+	if (ignore_replacing == B_TRUE) {
+		char *type;
 
+		verify(nvlist_lookup_string(vdev, ZPOOL_CONFIG_TYPE,
+		    &type) == 0);
+		if (strcmp(type, VDEV_TYPE_REPLACING) == 0)
+			return (B_FALSE);
+	}
+
 	if (nvlist_lookup_nvlist_array(vdev, ZPOOL_CONFIG_CHILDREN, &child,
 	    &children) == 0) {
 		for (c = 0; c < children; c++)
-			if (find_vdev_problem(child[c], func))
+			if (find_vdev_problem(child[c], func, ignore_replacing))
 				return (B_TRUE);
 	} else {
 		verify(nvlist_lookup_uint64_array(vdev, ZPOOL_CONFIG_VDEV_STATS,
-		    (uint64_t **)&vs, &c) == 0);
+		    (uint64_t **)&vs, &vsc) == 0);
 
-		if (func(vs->vs_state, vs->vs_aux,
-		    vs->vs_read_errors +
-		    vs->vs_write_errors +
-		    vs->vs_checksum_errors))
+		if (func(vs, vsc) != 0)
 			return (B_TRUE);
 	}
 
@@ -157,7 +169,7 @@
 	if (nvlist_lookup_nvlist_array(vdev, ZPOOL_CONFIG_L2CACHE, &child,
 	    &children) == 0) {
 		for (c = 0; c < children; c++)
-			if (find_vdev_problem(child[c], func))
+			if (find_vdev_problem(child[c], func, ignore_replacing))
 				return (B_TRUE);
 	}
 
@@ -270,15 +282,15 @@
 	 * Bad devices in non-replicated config.
 	 */
 	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
-	    find_vdev_problem(nvroot, vdev_faulted))
+	    find_vdev_problem(nvroot, vdev_faulted, B_TRUE))
 		return (ZPOOL_STATUS_FAULTED_DEV_NR);
 
 	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
-	    find_vdev_problem(nvroot, vdev_missing))
+	    find_vdev_problem(nvroot, vdev_missing, B_TRUE))
 		return (ZPOOL_STATUS_MISSING_DEV_NR);
 
 	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
-	    find_vdev_problem(nvroot, vdev_broken))
+	    find_vdev_problem(nvroot, vdev_broken, B_TRUE))
 		return (ZPOOL_STATUS_CORRUPT_LABEL_NR);
 
 	/*
@@ -300,32 +312,38 @@
 	/*
 	 * Missing devices in a replicated config.
 	 */
-	if (find_vdev_problem(nvroot, vdev_faulted))
+	if (find_vdev_problem(nvroot, vdev_faulted, B_TRUE))
 		return (ZPOOL_STATUS_FAULTED_DEV_R);
-	if (find_vdev_problem(nvroot, vdev_missing))
+	if (find_vdev_problem(nvroot, vdev_missing, B_TRUE))
 		return (ZPOOL_STATUS_MISSING_DEV_R);
-	if (find_vdev_problem(nvroot, vdev_broken))
+	if (find_vdev_problem(nvroot, vdev_broken, B_TRUE))
 		return (ZPOOL_STATUS_CORRUPT_LABEL_R);
 
 	/*
 	 * Devices with errors
 	 */
-	if (!isimport && find_vdev_problem(nvroot, vdev_errors))
+	if (!isimport && find_vdev_problem(nvroot, vdev_errors, B_TRUE))
 		return (ZPOOL_STATUS_FAILING_DEV);
 
 	/*
 	 * Offlined devices
 	 */
-	if (find_vdev_problem(nvroot, vdev_offlined))
+	if (find_vdev_problem(nvroot, vdev_offlined, B_TRUE))
 		return (ZPOOL_STATUS_OFFLINE_DEV);
 
 	/*
 	 * Removed device
 	 */
-	if (find_vdev_problem(nvroot, vdev_removed))
+	if (find_vdev_problem(nvroot, vdev_removed, B_TRUE))
 		return (ZPOOL_STATUS_REMOVED_DEV);
 
 	/*
+	 * Suboptimal, but usable, ashift configuration.
+	 */
+	if (find_vdev_problem(nvroot, vdev_non_native_ashift, B_FALSE))
+		return (ZPOOL_STATUS_NON_NATIVE_ASHIFT);
+
+	/*
 	 * Outdated, but usable, version
 	 */
 	if (SPA_VERSION_IS_SUPPORTED(version) && version != SPA_VERSION)

Modified: trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -21,7 +22,9 @@
 
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
+ * Copyright 2016 Igor Kozhukhov <ikozhukhov at gmail.com>
  */
 
 /*
@@ -46,6 +49,7 @@
 #include <sys/mnttab.h>
 #include <sys/mntent.h>
 #include <sys/types.h>
+#include <libcmdutils.h>
 
 #include <libzfs.h>
 #include <libzfs_core.h>
@@ -54,7 +58,6 @@
 #include "zfs_prop.h"
 #include "zfeature_common.h"
 
-int aok;
 
 int
 libzfs_errno(libzfs_handle_t *hdl)
@@ -369,6 +372,7 @@
 	case ENOSPC:
 	case EDQUOT:
 		zfs_verror(hdl, EZFS_NOSPC, fmt, ap);
+		va_end(ap);
 		return (-1);
 
 	case EEXIST:
@@ -468,6 +472,7 @@
 	case ENOSPC:
 	case EDQUOT:
 		zfs_verror(hdl, EZFS_NOSPC, fmt, ap);
+		va_end(ap);
 		return (-1);
 
 	case EAGAIN:
@@ -572,42 +577,7 @@
 void
 zfs_nicenum(uint64_t num, char *buf, size_t buflen)
 {
-	uint64_t n = num;
-	int index = 0;
-	char u;
-
-	while (n >= 1024) {
-		n /= 1024;
-		index++;
-	}
-
-	u = " KMGTPE"[index];
-
-	if (index == 0) {
-		(void) snprintf(buf, buflen, "%llu", n);
-	} else if ((num & ((1ULL << 10 * index) - 1)) == 0) {
-		/*
-		 * If this is an even multiple of the base, always display
-		 * without any decimal precision.
-		 */
-		(void) snprintf(buf, buflen, "%llu%c", n, u);
-	} else {
-		/*
-		 * We want to choose a precision that reflects the best choice
-		 * for fitting in 5 characters.  This can get rather tricky when
-		 * we have numbers that are very close to an order of magnitude.
-		 * For example, when displaying 10239 (which is really 9.999K),
-		 * we want only a single place of precision for 10.0K.  We could
-		 * develop some complex heuristics for this, but it's much
-		 * easier just to try each combination in turn.
-		 */
-		int i;
-		for (i = 2; i >= 0; i--) {
-			if (snprintf(buf, buflen, "%.*f%c", i,
-			    (double)num / (1ULL << 10 * index), u) <= 5)
-				break;
-		}
-	}
+	nicenum(num, buf, buflen);
 }
 
 void
@@ -684,7 +654,7 @@
 		(void) fclose(hdl->libzfs_sharetab);
 	zfs_uninit_libshare(hdl);
 	zpool_free_handles(hdl);
-#ifdef sun
+#ifdef illumos
 	libzfs_fru_clear(hdl, B_TRUE);
 #endif
 	namespace_clear(hdl);
@@ -736,7 +706,7 @@
 		return (NULL);
 	}
 
-#ifdef sun
+#ifdef illumos
 	rewind(hdl->libzfs_mnttab);
 	while ((ret = getextmntent(hdl->libzfs_mnttab, &entry, 0)) == 0) {
 		if (makedevice(entry.mnt_major, entry.mnt_minor) ==
@@ -756,7 +726,7 @@
 			    strerror(errno));
 		}
 	}
-#endif	/* sun */
+#endif	/* illumos */
 	if (ret != 0) {
 		return (NULL);
 	}
@@ -780,8 +750,9 @@
 	if (len == 0)
 		len = 16 * 1024;
 	zc->zc_nvlist_dst_size = len;
-	if ((zc->zc_nvlist_dst = (uint64_t)(uintptr_t)
-	    zfs_alloc(hdl, zc->zc_nvlist_dst_size)) == 0)
+	zc->zc_nvlist_dst =
+	    (uint64_t)(uintptr_t)zfs_alloc(hdl, zc->zc_nvlist_dst_size);
+	if (zc->zc_nvlist_dst == 0)
 		return (-1);
 
 	return (0);
@@ -796,9 +767,9 @@
 zcmd_expand_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc)
 {
 	free((void *)(uintptr_t)zc->zc_nvlist_dst);
-	if ((zc->zc_nvlist_dst = (uint64_t)(uintptr_t)
-	    zfs_alloc(hdl, zc->zc_nvlist_dst_size))
-	    == 0)
+	zc->zc_nvlist_dst =
+	    (uint64_t)(uintptr_t)zfs_alloc(hdl, zc->zc_nvlist_dst_size);
+	if (zc->zc_nvlist_dst == 0)
 		return (-1);
 
 	return (0);
@@ -813,6 +784,9 @@
 	free((void *)(uintptr_t)zc->zc_nvlist_conf);
 	free((void *)(uintptr_t)zc->zc_nvlist_src);
 	free((void *)(uintptr_t)zc->zc_nvlist_dst);
+	zc->zc_nvlist_conf = NULL;
+	zc->zc_nvlist_src = NULL;
+	zc->zc_nvlist_dst = NULL;
 }
 
 static int
@@ -1004,7 +978,7 @@
     const char *source, const char *recvd_value)
 {
 	int i;
-	const char *str;
+	const char *str = NULL;
 	char buf[128];
 
 	/*
@@ -1056,6 +1030,10 @@
 			case ZPROP_SRC_RECEIVED:
 				str = "received";
 				break;
+
+			default:
+				str = NULL;
+				assert(!"unhandled zprop_source_t");
 			}
 			break;
 
@@ -1266,6 +1244,16 @@
 			    "use 'none' to disable quota/refquota"));
 			goto error;
 		}
+
+		/*
+		 * Special handling for "*_limit=none". In this case it's not
+		 * 0 but UINT64_MAX.
+		 */
+		if ((type & ZFS_TYPE_DATASET) && isnone &&
+		    (prop == ZFS_PROP_FILESYSTEM_LIMIT ||
+		    prop == ZFS_PROP_SNAPSHOT_LIMIT)) {
+			*ivalp = UINT64_MAX;
+		}
 		break;
 
 	case PROP_TYPE_INDEX:

Modified: trunk/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -20,8 +21,9 @@
  */
 
 /*
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
+ * Copyright (c) 2014 Integros [integros.com]
  */
 
 /*
@@ -217,11 +219,11 @@
 }
 
 int
-lzc_create(const char *fsname, dmu_objset_type_t type, nvlist_t *props)
+lzc_create(const char *fsname, enum lzc_dataset_type type, nvlist_t *props)
 {
 	int error;
 	nvlist_t *args = fnvlist_alloc();
-	fnvlist_add_int32(args, "type", type);
+	fnvlist_add_int32(args, "type", (dmu_objset_type_t)type);
 	if (props != NULL)
 		fnvlist_add_nvlist(args, "props", props);
 	error = lzc_ioctl(ZFS_IOC_CREATE, fsname, args, NULL);
@@ -264,7 +266,7 @@
 	nvpair_t *elem;
 	nvlist_t *args;
 	int error;
-	char pool[MAXNAMELEN];
+	char pool[ZFS_MAX_DATASET_NAME_LEN];
 
 	*errlist = NULL;
 
@@ -316,7 +318,7 @@
 	nvpair_t *elem;
 	nvlist_t *args;
 	int error;
-	char pool[MAXNAMELEN];
+	char pool[ZFS_MAX_DATASET_NAME_LEN];
 
 	/* determine the pool name */
 	elem = nvlist_next_nvpair(snaps, NULL);
@@ -343,7 +345,7 @@
 	nvlist_t *args;
 	nvlist_t *result;
 	int err;
-	char fs[MAXNAMELEN];
+	char fs[ZFS_MAX_DATASET_NAME_LEN];
 	char *atp;
 
 	/* determine the fs name */
@@ -408,7 +410,7 @@
 int
 lzc_hold(nvlist_t *holds, int cleanup_fd, nvlist_t **errlist)
 {
-	char pool[MAXNAMELEN];
+	char pool[ZFS_MAX_DATASET_NAME_LEN];
 	nvlist_t *args;
 	nvpair_t *elem;
 	int error;
@@ -455,7 +457,7 @@
 int
 lzc_release(nvlist_t *holds, nvlist_t **errlist)
 {
-	char pool[MAXNAMELEN];
+	char pool[ZFS_MAX_DATASET_NAME_LEN];
 	nvpair_t *elem;
 
 	/* determine the pool name */
@@ -486,18 +488,57 @@
 }
 
 /*
- * If fromsnap is NULL, a full (non-incremental) stream will be sent.
+ * Generate a zfs send stream for the specified snapshot and write it to
+ * the specified file descriptor.
+ *
+ * "snapname" is the full name of the snapshot to send (e.g. "pool/fs at snap")
+ *
+ * If "from" is NULL, a full (non-incremental) stream will be sent.
+ * If "from" is non-NULL, it must be the full name of a snapshot or
+ * bookmark to send an incremental from (e.g. "pool/fs at earlier_snap" or
+ * "pool/fs#earlier_bmark").  If non-NULL, the specified snapshot or
+ * bookmark must represent an earlier point in the history of "snapname").
+ * It can be an earlier snapshot in the same filesystem or zvol as "snapname",
+ * or it can be the origin of "snapname"'s filesystem, or an earlier
+ * snapshot in the origin, etc.
+ *
+ * "fd" is the file descriptor to write the send stream to.
+ *
+ * If "flags" contains LZC_SEND_FLAG_LARGE_BLOCK, the stream is permitted
+ * to contain DRR_WRITE records with drr_length > 128K, and DRR_OBJECT
+ * records with drr_blksz > 128K.
+ *
+ * If "flags" contains LZC_SEND_FLAG_EMBED_DATA, the stream is permitted
+ * to contain DRR_WRITE_EMBEDDED records with drr_etype==BP_EMBEDDED_TYPE_DATA,
+ * which the receiving system must support (as indicated by support
+ * for the "embedded_data" feature).
  */
 int
-lzc_send(const char *snapname, const char *fromsnap, int fd)
+lzc_send(const char *snapname, const char *from, int fd,
+    enum lzc_send_flags flags)
 {
+	return (lzc_send_resume(snapname, from, fd, flags, 0, 0));
+}
+
+int
+lzc_send_resume(const char *snapname, const char *from, int fd,
+    enum lzc_send_flags flags, uint64_t resumeobj, uint64_t resumeoff)
+{
 	nvlist_t *args;
 	int err;
 
 	args = fnvlist_alloc();
 	fnvlist_add_int32(args, "fd", fd);
-	if (fromsnap != NULL)
-		fnvlist_add_string(args, "fromsnap", fromsnap);
+	if (from != NULL)
+		fnvlist_add_string(args, "fromsnap", from);
+	if (flags & LZC_SEND_FLAG_LARGE_BLOCK)
+		fnvlist_add_boolean(args, "largeblockok");
+	if (flags & LZC_SEND_FLAG_EMBED_DATA)
+		fnvlist_add_boolean(args, "embedok");
+	if (resumeobj != 0 || resumeoff != 0) {
+		fnvlist_add_uint64(args, "resume_object", resumeobj);
+		fnvlist_add_uint64(args, "resume_offset", resumeoff);
+	}
 	err = lzc_ioctl(ZFS_IOC_SEND_NEW, snapname, args, NULL);
 	nvlist_free(args);
 	return (err);
@@ -504,10 +545,22 @@
 }
 
 /*
- * If fromsnap is NULL, a full (non-incremental) stream will be estimated.
+ * "from" can be NULL, a snapshot, or a bookmark.
+ *
+ * If from is NULL, a full (non-incremental) stream will be estimated.  This
+ * is calculated very efficiently.
+ *
+ * If from is a snapshot, lzc_send_space uses the deadlists attached to
+ * each snapshot to efficiently estimate the stream size.
+ *
+ * If from is a bookmark, the indirect blocks in the destination snapshot
+ * are traversed, looking for blocks with a birth time since the creation TXG of
+ * the snapshot this bookmark was created from.  This will result in
+ * significantly more I/O and be less efficient than a send space estimation on
+ * an equivalent snapshot.
  */
 int
-lzc_send_space(const char *snapname, const char *fromsnap, uint64_t *spacep)
+lzc_send_space(const char *snapname, const char *from, uint64_t *spacep)
 {
 	nvlist_t *args;
 	nvlist_t *result;
@@ -514,8 +567,8 @@
 	int err;
 
 	args = fnvlist_alloc();
-	if (fromsnap != NULL)
-		fnvlist_add_string(args, "fromsnap", fromsnap);
+	if (from != NULL)
+		fnvlist_add_string(args, "from", from);
 	err = lzc_ioctl(ZFS_IOC_SEND_SPACE, snapname, args, &result);
 	nvlist_free(args);
 	if (err == 0)
@@ -543,22 +596,10 @@
 	return (0);
 }
 
-/*
- * The simplest receive case: receive from the specified fd, creating the
- * specified snapshot.  Apply the specified properties a "received" properties
- * (which can be overridden by locally-set properties).  If the stream is a
- * clone, its origin snapshot must be specified by 'origin'.  The 'force'
- * flag will cause the target filesystem to be rolled back or destroyed if
- * necessary to receive.
- *
- * Return 0 on success or an errno on failure.
- *
- * Note: this interface does not work on dedup'd streams
- * (those with DMU_BACKUP_FEATURE_DEDUP).
- */
-int
-lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
-    boolean_t force, int fd)
+static int
+recv_impl(const char *snapname, nvlist_t *props, const char *origin,
+    boolean_t force, boolean_t resumable, int fd,
+    const dmu_replay_record_t *begin_record)
 {
 	/*
 	 * The receive ioctl is still legacy, so we need to construct our own
@@ -568,7 +609,6 @@
 	char *atp;
 	char *packed = NULL;
 	size_t size;
-	dmu_replay_record_t drr;
 	int error;
 
 	ASSERT3S(g_refcount, >, 0);
@@ -604,10 +644,14 @@
 		(void) strlcpy(zc.zc_string, origin, sizeof (zc.zc_string));
 
 	/* zc_begin_record is non-byteswapped BEGIN record */
-	error = recv_read(fd, &drr, sizeof (drr));
-	if (error != 0)
-		goto out;
-	zc.zc_begin_record = drr.drr_u.drr_begin;
+	if (begin_record == NULL) {
+		error = recv_read(fd, &zc.zc_begin_record,
+		    sizeof (zc.zc_begin_record));
+		if (error != 0)
+			goto out;
+	} else {
+		zc.zc_begin_record = *begin_record;
+	}
 
 	/* zc_cookie is fd to read from */
 	zc.zc_cookie = fd;
@@ -615,6 +659,8 @@
 	/* zc guid is force flag */
 	zc.zc_guid = force;
 
+	zc.zc_resumable = resumable;
+
 	/* zc_cleanup_fd is unused */
 	zc.zc_cleanup_fd = -1;
 
@@ -628,3 +674,176 @@
 	free((void*)(uintptr_t)zc.zc_nvlist_dst);
 	return (error);
 }
+
+/*
+ * The simplest receive case: receive from the specified fd, creating the
+ * specified snapshot.  Apply the specified properties as "received" properties
+ * (which can be overridden by locally-set properties).  If the stream is a
+ * clone, its origin snapshot must be specified by 'origin'.  The 'force'
+ * flag will cause the target filesystem to be rolled back or destroyed if
+ * necessary to receive.
+ *
+ * Return 0 on success or an errno on failure.
+ *
+ * Note: this interface does not work on dedup'd streams
+ * (those with DMU_BACKUP_FEATURE_DEDUP).
+ */
+int
+lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
+    boolean_t force, int fd)
+{
+	return (recv_impl(snapname, props, origin, force, B_FALSE, fd, NULL));
+}
+
+/*
+ * Like lzc_receive, but if the receive fails due to premature stream
+ * termination, the intermediate state will be preserved on disk.  In this
+ * case, ECKSUM will be returned.  The receive may subsequently be resumed
+ * with a resuming send stream generated by lzc_send_resume().
+ */
+int
+lzc_receive_resumable(const char *snapname, nvlist_t *props, const char *origin,
+    boolean_t force, int fd)
+{
+	return (recv_impl(snapname, props, origin, force, B_TRUE, fd, NULL));
+}
+
+/*
+ * Like lzc_receive, but allows the caller to read the begin record and then to
+ * pass it in.  That could be useful if the caller wants to derive, for example,
+ * the snapname or the origin parameters based on the information contained in
+ * the begin record.
+ * The begin record must be in its original form as read from the stream,
+ * in other words, it should not be byteswapped.
+ *
+ * The 'resumable' parameter allows to obtain the same behavior as with
+ * lzc_receive_resumable.
+ */
+int
+lzc_receive_with_header(const char *snapname, nvlist_t *props,
+    const char *origin, boolean_t force, boolean_t resumable, int fd,
+    const dmu_replay_record_t *begin_record)
+{
+	if (begin_record == NULL)
+		return (EINVAL);
+	return (recv_impl(snapname, props, origin, force, resumable, fd,
+	    begin_record));
+}
+
+/*
+ * Roll back this filesystem or volume to its most recent snapshot.
+ * If snapnamebuf is not NULL, it will be filled in with the name
+ * of the most recent snapshot.
+ *
+ * Return 0 on success or an errno on failure.
+ */
+int
+lzc_rollback(const char *fsname, char *snapnamebuf, int snapnamelen)
+{
+	nvlist_t *args;
+	nvlist_t *result;
+	int err;
+
+	args = fnvlist_alloc();
+	err = lzc_ioctl(ZFS_IOC_ROLLBACK, fsname, args, &result);
+	nvlist_free(args);
+	if (err == 0 && snapnamebuf != NULL) {
+		const char *snapname = fnvlist_lookup_string(result, "target");
+		(void) strlcpy(snapnamebuf, snapname, snapnamelen);
+	}
+	return (err);
+}
+
+/*
+ * Creates bookmarks.
+ *
+ * The bookmarks nvlist maps from name of the bookmark (e.g. "pool/fs#bmark") to
+ * the name of the snapshot (e.g. "pool/fs at snap").  All the bookmarks and
+ * snapshots must be in the same pool.
+ *
+ * The returned results nvlist will have an entry for each bookmark that failed.
+ * The value will be the (int32) error code.
+ *
+ * The return value will be 0 if all bookmarks were created, otherwise it will
+ * be the errno of a (undetermined) bookmarks that failed.
+ */
+int
+lzc_bookmark(nvlist_t *bookmarks, nvlist_t **errlist)
+{
+	nvpair_t *elem;
+	int error;
+	char pool[ZFS_MAX_DATASET_NAME_LEN];
+
+	/* determine the pool name */
+	elem = nvlist_next_nvpair(bookmarks, NULL);
+	if (elem == NULL)
+		return (0);
+	(void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
+	pool[strcspn(pool, "/#")] = '\0';
+
+	error = lzc_ioctl(ZFS_IOC_BOOKMARK, pool, bookmarks, errlist);
+
+	return (error);
+}
+
+/*
+ * Retrieve bookmarks.
+ *
+ * Retrieve the list of bookmarks for the given file system. The props
+ * parameter is an nvlist of property names (with no values) that will be
+ * returned for each bookmark.
+ *
+ * The following are valid properties on bookmarks, all of which are numbers
+ * (represented as uint64 in the nvlist)
+ *
+ * "guid" - globally unique identifier of the snapshot it refers to
+ * "createtxg" - txg when the snapshot it refers to was created
+ * "creation" - timestamp when the snapshot it refers to was created
+ *
+ * The format of the returned nvlist as follows:
+ * <short name of bookmark> -> {
+ *     <name of property> -> {
+ *         "value" -> uint64
+ *     }
+ *  }
+ */
+int
+lzc_get_bookmarks(const char *fsname, nvlist_t *props, nvlist_t **bmarks)
+{
+	return (lzc_ioctl(ZFS_IOC_GET_BOOKMARKS, fsname, props, bmarks));
+}
+
+/*
+ * Destroys bookmarks.
+ *
+ * The keys in the bmarks nvlist are the bookmarks to be destroyed.
+ * They must all be in the same pool.  Bookmarks are specified as
+ * <fs>#<bmark>.
+ *
+ * Bookmarks that do not exist will be silently ignored.
+ *
+ * The return value will be 0 if all bookmarks that existed were destroyed.
+ *
+ * Otherwise the return value will be the errno of a (undetermined) bookmark
+ * that failed, no bookmarks will be destroyed, and the errlist will have an
+ * entry for each bookmarks that failed.  The value in the errlist will be
+ * the (int32) error code.
+ */
+int
+lzc_destroy_bookmarks(nvlist_t *bmarks, nvlist_t **errlist)
+{
+	nvpair_t *elem;
+	int error;
+	char pool[ZFS_MAX_DATASET_NAME_LEN];
+
+	/* determine the pool name */
+	elem = nvlist_next_nvpair(bmarks, NULL);
+	if (elem == NULL)
+		return (0);
+	(void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
+	pool[strcspn(pool, "/#")] = '\0';
+
+	error = lzc_ioctl(ZFS_IOC_DESTROY_BOOKMARKS, pool, bmarks, errlist);
+
+	return (error);
+}

Modified: trunk/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -20,7 +21,7 @@
  */
 
 /*
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
  * Copyright (c) 2013 by Martin Matuska <mm at FreeBSD.org>. All rights reserved.
  */
 
@@ -30,7 +31,6 @@
 #include <libnvpair.h>
 #include <sys/param.h>
 #include <sys/types.h>
-#include <sys/fs/zfs.h>
 
 #ifdef	__cplusplus
 extern "C" {
@@ -39,27 +39,50 @@
 int libzfs_core_init(void);
 void libzfs_core_fini(void);
 
-int lzc_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t **errlist);
-int lzc_create(const char *fsname, dmu_objset_type_t type, nvlist_t *props);
-int lzc_clone(const char *fsname, const char *origin, nvlist_t *props);
-int lzc_destroy_snaps(nvlist_t *snaps, boolean_t defer, nvlist_t **errlist);
+/*
+ * NB: this type should be kept binary compatible with dmu_objset_type_t.
+ */
+enum lzc_dataset_type {
+	LZC_DATSET_TYPE_ZFS = 2,
+	LZC_DATSET_TYPE_ZVOL
+};
 
-int lzc_snaprange_space(const char *firstsnap, const char *lastsnap,
-    uint64_t *usedp);
+int lzc_snapshot(nvlist_t *, nvlist_t *, nvlist_t **);
+int lzc_create(const char *, enum lzc_dataset_type, nvlist_t *);
+int lzc_clone(const char *, const char *, nvlist_t *);
+int lzc_destroy_snaps(nvlist_t *, boolean_t, nvlist_t **);
+int lzc_bookmark(nvlist_t *, nvlist_t **);
+int lzc_get_bookmarks(const char *, nvlist_t *, nvlist_t **);
+int lzc_destroy_bookmarks(nvlist_t *, nvlist_t **);
 
-int lzc_hold(nvlist_t *holds, int cleanup_fd, nvlist_t **errlist);
-int lzc_release(nvlist_t *holds, nvlist_t **errlist);
-int lzc_get_holds(const char *snapname, nvlist_t **holdsp);
+int lzc_snaprange_space(const char *, const char *, uint64_t *);
 
-int lzc_send(const char *snapname, const char *fromsnap, int fd);
-int lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
-    boolean_t force, int fd);
-int lzc_send_space(const char *snapname, const char *fromsnap,
-    uint64_t *result);
+int lzc_hold(nvlist_t *, int, nvlist_t **);
+int lzc_release(nvlist_t *, nvlist_t **);
+int lzc_get_holds(const char *, nvlist_t **);
 
-boolean_t lzc_exists(const char *dataset);
+enum lzc_send_flags {
+	LZC_SEND_FLAG_EMBED_DATA = 1 << 0,
+	LZC_SEND_FLAG_LARGE_BLOCK = 1 << 1
+};
 
+int lzc_send(const char *, const char *, int, enum lzc_send_flags);
+int lzc_send_resume(const char *, const char *, int,
+    enum lzc_send_flags, uint64_t, uint64_t);
+int lzc_send_space(const char *, const char *, uint64_t *);
 
+struct dmu_replay_record;
+
+int lzc_receive(const char *, nvlist_t *, const char *, boolean_t, int);
+int lzc_receive_resumable(const char *, nvlist_t *, const char *,
+    boolean_t, int);
+int lzc_receive_with_header(const char *, nvlist_t *, const char *, boolean_t,
+    boolean_t, int, const struct dmu_replay_record *);
+
+boolean_t lzc_exists(const char *);
+
+int lzc_rollback(const char *, char *, int);
+
 #ifdef	__cplusplus
 }
 #endif

Modified: trunk/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core_compat.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core_compat.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core_compat.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core_compat.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core_compat.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core_compat.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *

Modified: trunk/cddl/contrib/opensolaris/lib/libzpool/common/kernel.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libzpool/common/kernel.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libzpool/common/kernel.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -20,6 +21,8 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
  */
 
 #include <assert.h>
@@ -29,6 +32,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <zlib.h>
+#include <libgen.h>
 #include <sys/spa.h>
 #include <sys/stat.h>
 #include <sys/processor.h>
@@ -42,7 +46,9 @@
  * Emulation of kernel services in userland.
  */
 
+#ifndef __FreeBSD__
 int aok;
+#endif
 uint64_t physmem;
 vnode_t *rootdir = (vnode_t *)0xabcd1234;
 char hw_serial[HW_HOSTID_LEN];
@@ -50,6 +56,9 @@
 kmutex_t cpu_lock;
 #endif
 
+/* If set, all blocks read will be copied to the specified directory. */
+char *vn_dumpdir = NULL;
+
 struct utsname utsname = {
 	"userland", "libzpool", "1", "1", "na"
 };
@@ -349,6 +358,49 @@
 	return (1);
 }
 
+/*ARGSUSED*/
+clock_t
+cv_timedwait_hires(kcondvar_t *cv, kmutex_t *mp, hrtime_t tim, hrtime_t res,
+    int flag)
+{
+	int error;
+	timespec_t ts;
+	hrtime_t delta;
+
+	ASSERT(flag == 0 || flag == CALLOUT_FLAG_ABSOLUTE);
+
+top:
+	delta = tim;
+	if (flag & CALLOUT_FLAG_ABSOLUTE)
+		delta -= gethrtime();
+
+	if (delta <= 0)
+		return (-1);
+
+	clock_gettime(CLOCK_REALTIME, &ts);
+	ts.tv_sec += delta / NANOSEC;
+	ts.tv_nsec += delta % NANOSEC;
+	if (ts.tv_nsec >= NANOSEC) {
+		ts.tv_sec++;
+		ts.tv_nsec -= NANOSEC;
+	}
+
+	ASSERT(mutex_owner(mp) == curthread);
+	mp->m_owner = NULL;
+	error = pthread_cond_timedwait(cv, &mp->m_lock, &ts);
+	mp->m_owner = curthread;
+
+	if (error == ETIMEDOUT)
+		return (-1);
+
+	if (error == EINTR)
+		goto top;
+
+	ASSERT(error == 0);
+
+	return (1);
+}
+
 void
 cv_signal(kcondvar_t *cv)
 {
@@ -378,6 +430,7 @@
 vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3)
 {
 	int fd;
+	int dump_fd;
 	vnode_t *vp;
 	int old_umask;
 	char realpath[MAXPATHLEN];
@@ -426,6 +479,17 @@
 	if (flags & FCREAT)
 		(void) umask(old_umask);
 
+	if (vn_dumpdir != NULL) {
+		char dumppath[MAXPATHLEN];
+		(void) snprintf(dumppath, sizeof (dumppath),
+		    "%s/%s", vn_dumpdir, basename(realpath));
+		dump_fd = open64(dumppath, O_CREAT | O_WRONLY, 0666);
+		if (dump_fd == -1)
+			return (errno);
+	} else {
+		dump_fd = -1;
+	}
+
 	if (fd == -1)
 		return (errno);
 
@@ -441,6 +505,7 @@
 	vp->v_fd = fd;
 	vp->v_size = st.st_size;
 	vp->v_path = spa_strdup(path);
+	vp->v_dump_fd = dump_fd;
 
 	return (0);
 }
@@ -467,12 +532,17 @@
 /*ARGSUSED*/
 int
 vn_rdwr(int uio, vnode_t *vp, void *addr, ssize_t len, offset_t offset,
-	int x1, int x2, rlim64_t x3, void *x4, ssize_t *residp)
+    int x1, int x2, rlim64_t x3, void *x4, ssize_t *residp)
 {
 	ssize_t iolen, split;
 
 	if (uio == UIO_READ) {
 		iolen = pread64(vp->v_fd, addr, len, offset);
+		if (vp->v_dump_fd != -1) {
+			int status =
+			    pwrite64(vp->v_dump_fd, addr, iolen, offset);
+			ASSERT(status != -1);
+		}
 	} else {
 		/*
 		 * To simulate partial disk writes, we split writes into two
@@ -499,6 +569,8 @@
 vn_close(vnode_t *vp, int openflag, cred_t *cr, kthread_t *td)
 {
 	close(vp->v_fd);
+	if (vp->v_dump_fd != -1)
+		close(vp->v_dump_fd);
 	spa_strfree(vp->v_path);
 	umem_free(vp, sizeof (vnode_t));
 }
@@ -591,6 +663,12 @@
 		dprintf_print_all = 1;
 }
 
+int
+sysctl_handle_64(SYSCTL_HANDLER_ARGS)
+{
+	return (0);
+}
+
 /*
  * =========================================================================
  * debug printfs
@@ -620,7 +698,7 @@
 		if (dprintf_find_string("pid"))
 			(void) printf("%d ", getpid());
 		if (dprintf_find_string("tid"))
-			(void) printf("%u ", thr_self());
+			(void) printf("%ul ", thr_self());
 #if 0
 		if (dprintf_find_string("cpu"))
 			(void) printf("%u ", getcpuid());
@@ -650,11 +728,9 @@
 void
 vpanic(const char *fmt, va_list adx)
 {
-	(void) fprintf(stderr, "error: ");
-	(void) vfprintf(stderr, fmt, adx);
-	(void) fprintf(stderr, "\n");
-
-	abort();	/* think of it as a "user-level crash dump" */
+	char buf[512];
+	(void) vsnprintf(buf, 512, fmt, adx);
+	assfail(buf, NULL, 0);
 }
 
 void
@@ -759,20 +835,17 @@
 /*
  * Find highest one bit set.
  *	Returns bit number + 1 of highest bit that is set, otherwise returns 0.
- * High order bit is 31 (or 63 in _LP64 kernel).
  */
 int
-highbit(ulong_t i)
+highbit64(uint64_t i)
 {
-	register int h = 1;
+	int h = 1;
 
 	if (i == 0)
 		return (0);
-#ifdef _LP64
-	if (i & 0xffffffff00000000ul) {
+	if (i & 0xffffffff00000000ULL) {
 		h += 32; i >>= 32;
 	}
-#endif
 	if (i & 0xffff0000) {
 		h += 16; i >>= 16;
 	}
@@ -1084,3 +1157,50 @@
 	return (0);
 }
 #endif
+
+#ifdef illumos
+void
+bioinit(buf_t *bp)
+{
+	bzero(bp, sizeof (buf_t));
+}
+
+void
+biodone(buf_t *bp)
+{
+	if (bp->b_iodone != NULL) {
+		(*(bp->b_iodone))(bp);
+		return;
+	}
+	ASSERT((bp->b_flags & B_DONE) == 0);
+	bp->b_flags |= B_DONE;
+}
+
+void
+bioerror(buf_t *bp, int error)
+{
+	ASSERT(bp != NULL);
+	ASSERT(error >= 0);
+
+	if (error != 0) {
+		bp->b_flags |= B_ERROR;
+	} else {
+		bp->b_flags &= ~B_ERROR;
+	}
+	bp->b_error = error;
+}
+
+
+int
+geterror(struct buf *bp)
+{
+	int error = 0;
+
+	if (bp->b_flags & B_ERROR) {
+		error = bp->b_error;
+		if (!error)
+			error = EIO;
+	}
+	return (error);
+}
+#endif

Modified: trunk/cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -20,9 +21,12 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
  */
+/*
+ * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
+ */
 
 #ifndef _SYS_ZFS_CONTEXT_H
 #define	_SYS_ZFS_CONTEXT_H
@@ -62,6 +66,7 @@
 #include <inttypes.h>
 #include <fsshare.h>
 #include <pthread.h>
+#include <sched.h>
 #include <sys/debug.h>
 #include <sys/note.h>
 #include <sys/types.h>
@@ -131,8 +136,18 @@
 
 /*
  * DTrace SDT probes have different signatures in userland than they do in
- * kernel.  If they're being used in kernel code, re-define them out of
+ * the kernel.  If they're being used in kernel code, re-define them out of
  * existence for their counterparts in libzpool.
+ *
+ * Here's an example of how to use the set-error probes in userland:
+ * zfs$target:::set-error /arg0 == EBUSY/ {stack();}
+ *
+ * Here's an example of how to use DTRACE_PROBE probes in userland:
+ * If there is a probe declared as follows:
+ * DTRACE_PROBE2(zfs__probe_name, uint64_t, blkid, dnode_t *, dn);
+ * Then you can use it as follows:
+ * zfs$target:::probe2 /copyinstr(arg0) == "zfs__probe_name"/
+ *     {printf("%u %p\n", arg1, arg2);}
  */
 
 #ifdef DTRACE_PROBE
@@ -201,6 +216,8 @@
  */
 #define	curthread	((void *)(uintptr_t)thr_self())
 
+#define	kpreempt(x)	sched_yield()
+
 typedef struct kthread kthread_t;
 
 #define	thread_create(stk, stksize, func, arg, len, pp, state, pri)	\
@@ -308,11 +325,14 @@
 typedef cond_t kcondvar_t;
 
 #define	CV_DEFAULT	USYNC_THREAD
+#define	CALLOUT_FLAG_ABSOLUTE	0x2
 
 extern void cv_init(kcondvar_t *cv, char *name, int type, void *arg);
 extern void cv_destroy(kcondvar_t *cv);
 extern void cv_wait(kcondvar_t *cv, kmutex_t *mp);
 extern clock_t cv_timedwait(kcondvar_t *cv, kmutex_t *mp, clock_t abstime);
+extern clock_t cv_timedwait_hires(kcondvar_t *cvp, kmutex_t *mp, hrtime_t tim,
+    hrtime_t res, int flag);
 extern void cv_signal(kcondvar_t *cv);
 extern void cv_broadcast(kcondvar_t *cv);
 
@@ -330,9 +350,9 @@
 #define	KM_SLEEP		UMEM_NOFAIL
 #define	KM_PUSHPAGE		KM_SLEEP
 #define	KM_NOSLEEP		UMEM_DEFAULT
-#define	KM_NODEBUG		0
 #define	KMC_NODEBUG		UMC_NODEBUG
 #define	KMC_NOTOUCH		0	/* not needed for userland caches */
+#define	KM_NODEBUG		0
 #define	kmem_alloc(_s, _f)	umem_alloc(_s, _f)
 #define	kmem_zalloc(_s, _f)	umem_zalloc(_s, _f)
 #define	kmem_free(_b, _s)	umem_free(_b, _s)
@@ -365,6 +385,16 @@
 typedef uintptr_t taskqid_t;
 typedef void (task_func_t)(void *);
 
+typedef struct taskq_ent {
+	struct taskq_ent	*tqent_next;
+	struct taskq_ent	*tqent_prev;
+	task_func_t		*tqent_func;
+	void			*tqent_arg;
+	uintptr_t		tqent_flags;
+} taskq_ent_t;
+
+#define	TQENT_FLAG_PREALLOC	0x1	/* taskq_dispatch_ent used */
+
 #define	TASKQ_PREPOPULATE	0x0001
 #define	TASKQ_CPR_SAFE		0x0002	/* Use CPR safe protocol */
 #define	TASKQ_DYNAMIC		0x0004	/* Use dynamic thread scheduling */
@@ -376,6 +406,7 @@
 #define	TQ_NOQUEUE	0x02		/* Do not enqueue if can't dispatch */
 #define	TQ_FRONT	0x08		/* Queue in front */
 
+
 extern taskq_t *system_taskq;
 
 extern taskq_t	*taskq_create(const char *, int, pri_t, int, int, uint_t);
@@ -384,6 +415,8 @@
 #define	taskq_create_sysdc(a, b, d, e, p, dc, f) \
 	    (taskq_create(a, b, maxclsyspri, d, e, f))
 extern taskqid_t taskq_dispatch(taskq_t *, task_func_t, void *, uint_t);
+extern void	taskq_dispatch_ent(taskq_t *, task_func_t, void *, uint_t,
+    taskq_ent_t *);
 extern void	taskq_destroy(taskq_t *);
 extern void	taskq_wait(taskq_t *);
 extern int	taskq_member(taskq_t *, void *);
@@ -403,8 +436,10 @@
 	uint64_t	v_size;
 	int		v_fd;
 	char		*v_path;
+	int		v_dump_fd;
 } vnode_t;
 
+extern char *vn_dumpdir;
 #define	AV_SCANSTAMP_SZ	32		/* length of anti-virus scanstamp */
 
 typedef struct xoptattr {
@@ -484,14 +519,6 @@
 
 #define	vn_lock(vp, type)
 #define	VOP_UNLOCK(vp, type)
-#ifdef VFS_LOCK_GIANT
-#undef VFS_LOCK_GIANT
-#endif
-#define	VFS_LOCK_GIANT(mp)	0
-#ifdef VFS_UNLOCK_GIANT
-#undef VFS_UNLOCK_GIANT
-#endif
-#define	VFS_UNLOCK_GIANT(vfslocked)
 
 extern int vn_open(char *path, int x1, int oflags, int mode, vnode_t **vpp,
     int x2, int x3);
@@ -545,7 +572,7 @@
 
 extern uint64_t physmem;
 
-extern int highbit(ulong_t i);
+extern int highbit64(uint64_t i);
 extern int random_get_bytes(uint8_t *ptr, size_t len);
 extern int random_get_pseudo_bytes(uint8_t *ptr, size_t len);
 
@@ -553,8 +580,9 @@
 extern void kernel_fini(void);
 
 struct spa;
-extern void nicenum(uint64_t num, char *buf);
+extern void nicenum(uint64_t num, char *buf, size_t);
 extern void show_pool_stats(struct spa *);
+extern int set_global_var(char *arg);
 
 typedef struct callb_cpr {
 	kmutex_t	*cc_lockp;
@@ -630,13 +658,6 @@
 extern int zfs_secpolicy_destroy_perms(const char *name, cred_t *cr);
 extern zoneid_t getzoneid(void);
 /* Random compatibility stuff. */
-#define	lbolt	(gethrtime() >> 23)
-#define	lbolt64	(gethrtime() >> 23)
-
-extern uint64_t physmem;
-
-#define	gethrestime_sec()	time(NULL)
-
 #define	pwrite64(d, p, n, o)	pwrite(d, p, n, o)
 #define	readdir64(d)		readdir(d)
 #define	SIGPENDING(td)		(0)
@@ -667,11 +688,55 @@
 
 #define	SX_SYSINIT(name, lock, desc)
 
+#define SYSCTL_HANDLER_ARGS struct sysctl_oid *oidp, void *arg1,	\
+	intptr_t arg2, struct sysctl_req *req
+
+/*
+ * This describes the access space for a sysctl request.  This is needed
+ * so that we can use the interface from the kernel or from user-space.
+ */
+struct sysctl_req {
+	struct thread	*td;		/* used for access checking */
+	int		lock;		/* wiring state */
+	void		*oldptr;
+	size_t		oldlen;
+	size_t		oldidx;
+	int		(*oldfunc)(struct sysctl_req *, const void *, size_t);
+	void		*newptr;
+	size_t		newlen;
+	size_t		newidx;
+	int		(*newfunc)(struct sysctl_req *, void *, size_t);
+	size_t		validlen;
+	int		flags;
+};
+
+SLIST_HEAD(sysctl_oid_list, sysctl_oid);
+
+/*
+ * This describes one "oid" in the MIB tree.  Potentially more nodes can
+ * be hidden behind it, expanded by the handler.
+ */
+struct sysctl_oid {
+	struct sysctl_oid_list *oid_parent;
+	SLIST_ENTRY(sysctl_oid) oid_link;
+	int		oid_number;
+	u_int		oid_kind;
+	void		*oid_arg1;
+	intptr_t	oid_arg2;
+	const char	*oid_name;
+	int 		(*oid_handler)(SYSCTL_HANDLER_ARGS);
+	const char	*oid_fmt;
+	int		oid_refcnt;
+	u_int		oid_running;
+	const char	*oid_descr;
+};
+
 #define	SYSCTL_DECL(...)
 #define	SYSCTL_NODE(...)
 #define	SYSCTL_INT(...)
 #define	SYSCTL_UINT(...)
 #define	SYSCTL_ULONG(...)
+#define	SYSCTL_PROC(...)
 #define	SYSCTL_QUAD(...)
 #define	SYSCTL_UQUAD(...)
 #ifdef TUNABLE_INT
@@ -683,6 +748,8 @@
 #define	TUNABLE_ULONG(...)
 #define	TUNABLE_QUAD(...)
 
+int sysctl_handle_64(SYSCTL_HANDLER_ARGS);
+
 /* Errors */
 
 #ifndef	ERESTART
@@ -719,6 +786,38 @@
 extern int cyclic_reprogram(cyclic_id_t, hrtime_t);
 #endif	/* illumos */
 
+#ifdef illumos
+/*
+ * Buf structure
+ */
+#define	B_BUSY		0x0001
+#define	B_DONE		0x0002
+#define	B_ERROR		0x0004
+#define	B_READ		0x0040	/* read when I/O occurs */
+#define	B_WRITE		0x0100	/* non-read pseudo-flag */
+
+typedef struct buf {
+	int	b_flags;
+	size_t b_bcount;
+	union {
+		caddr_t b_addr;
+	} b_un;
+
+	lldaddr_t	_b_blkno;
+#define	b_lblkno	_b_blkno._f
+	size_t	b_resid;
+	size_t	b_bufsize;
+	int	(*b_iodone)(struct buf *);
+	int	b_error;
+	void	*b_private;
+} buf_t;
+
+extern void bioinit(buf_t *);
+extern void biodone(buf_t *);
+extern void bioerror(buf_t *, int);
+extern int geterror(buf_t *);
+#endif
+
 #ifdef	__cplusplus
 }
 #endif

Modified: trunk/cddl/contrib/opensolaris/lib/libzpool/common/taskq.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libzpool/common/taskq.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libzpool/common/taskq.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -22,6 +23,11 @@
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2012 Garrett D'Amore <garrett at damore.org>.  All rights reserved.
+ * Copyright (c) 2014 by Delphix. All rights reserved.
+ */
 
 #include <sys/zfs_context.h>
 
@@ -28,16 +34,11 @@
 int taskq_now;
 taskq_t *system_taskq;
 
-typedef struct task {
-	struct task	*task_next;
-	struct task	*task_prev;
-	task_func_t	*task_func;
-	void		*task_arg;
-} task_t;
-
 #define	TASKQ_ACTIVE	0x00010000
+#define	TASKQ_NAMELEN	31
 
 struct taskq {
+	char		tq_name[TASKQ_NAMELEN + 1];
 	kmutex_t	tq_lock;
 	krwlock_t	tq_threadlock;
 	kcondvar_t	tq_dispatch_cv;
@@ -51,18 +52,18 @@
 	int		tq_maxalloc;
 	kcondvar_t	tq_maxalloc_cv;
 	int		tq_maxalloc_wait;
-	task_t		*tq_freelist;
-	task_t		tq_task;
+	taskq_ent_t	*tq_freelist;
+	taskq_ent_t	tq_task;
 };
 
-static task_t *
+static taskq_ent_t *
 task_alloc(taskq_t *tq, int tqflags)
 {
-	task_t *t;
+	taskq_ent_t *t;
 	int rv;
 
 again:	if ((t = tq->tq_freelist) != NULL && tq->tq_nalloc >= tq->tq_minalloc) {
-		tq->tq_freelist = t->task_next;
+		tq->tq_freelist = t->tqent_next;
 	} else {
 		if (tq->tq_nalloc >= tq->tq_maxalloc) {
 			if (!(tqflags & KM_SLEEP))
@@ -87,7 +88,7 @@
 		}
 		mutex_exit(&tq->tq_lock);
 
-		t = kmem_alloc(sizeof (task_t), tqflags & KM_SLEEP);
+		t = kmem_alloc(sizeof (taskq_ent_t), tqflags & KM_SLEEP);
 
 		mutex_enter(&tq->tq_lock);
 		if (t != NULL)
@@ -97,15 +98,15 @@
 }
 
 static void
-task_free(taskq_t *tq, task_t *t)
+task_free(taskq_t *tq, taskq_ent_t *t)
 {
 	if (tq->tq_nalloc <= tq->tq_minalloc) {
-		t->task_next = tq->tq_freelist;
+		t->tqent_next = tq->tq_freelist;
 		tq->tq_freelist = t;
 	} else {
 		tq->tq_nalloc--;
 		mutex_exit(&tq->tq_lock);
-		kmem_free(t, sizeof (task_t));
+		kmem_free(t, sizeof (taskq_ent_t));
 		mutex_enter(&tq->tq_lock);
 	}
 
@@ -116,7 +117,7 @@
 taskqid_t
 taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t tqflags)
 {
-	task_t *t;
+	taskq_ent_t *t;
 
 	if (taskq_now) {
 		func(arg);
@@ -130,16 +131,17 @@
 		return (0);
 	}
 	if (tqflags & TQ_FRONT) {
-		t->task_next = tq->tq_task.task_next;
-		t->task_prev = &tq->tq_task;
+		t->tqent_next = tq->tq_task.tqent_next;
+		t->tqent_prev = &tq->tq_task;
 	} else {
-		t->task_next = &tq->tq_task;
-		t->task_prev = tq->tq_task.task_prev;
+		t->tqent_next = &tq->tq_task;
+		t->tqent_prev = tq->tq_task.tqent_prev;
 	}
-	t->task_next->task_prev = t;
-	t->task_prev->task_next = t;
-	t->task_func = func;
-	t->task_arg = arg;
+	t->tqent_next->tqent_prev = t;
+	t->tqent_prev->tqent_next = t;
+	t->tqent_func = func;
+	t->tqent_arg = arg;
+	t->tqent_flags = 0;
 	cv_signal(&tq->tq_dispatch_cv);
 	mutex_exit(&tq->tq_lock);
 	return (1);
@@ -146,10 +148,42 @@
 }
 
 void
+taskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, uint_t flags,
+    taskq_ent_t *t)
+{
+	ASSERT(func != NULL);
+	ASSERT(!(tq->tq_flags & TASKQ_DYNAMIC));
+
+	/*
+	 * Mark it as a prealloc'd task.  This is important
+	 * to ensure that we don't free it later.
+	 */
+	t->tqent_flags |= TQENT_FLAG_PREALLOC;
+	/*
+	 * Enqueue the task to the underlying queue.
+	 */
+	mutex_enter(&tq->tq_lock);
+
+	if (flags & TQ_FRONT) {
+		t->tqent_next = tq->tq_task.tqent_next;
+		t->tqent_prev = &tq->tq_task;
+	} else {
+		t->tqent_next = &tq->tq_task;
+		t->tqent_prev = tq->tq_task.tqent_prev;
+	}
+	t->tqent_next->tqent_prev = t;
+	t->tqent_prev->tqent_next = t;
+	t->tqent_func = func;
+	t->tqent_arg = arg;
+	cv_signal(&tq->tq_dispatch_cv);
+	mutex_exit(&tq->tq_lock);
+}
+
+void
 taskq_wait(taskq_t *tq)
 {
 	mutex_enter(&tq->tq_lock);
-	while (tq->tq_task.task_next != &tq->tq_task || tq->tq_active != 0)
+	while (tq->tq_task.tqent_next != &tq->tq_task || tq->tq_active != 0)
 		cv_wait(&tq->tq_wait_cv, &tq->tq_lock);
 	mutex_exit(&tq->tq_lock);
 }
@@ -158,11 +192,12 @@
 taskq_thread(void *arg)
 {
 	taskq_t *tq = arg;
-	task_t *t;
+	taskq_ent_t *t;
+	boolean_t prealloc;
 
 	mutex_enter(&tq->tq_lock);
 	while (tq->tq_flags & TASKQ_ACTIVE) {
-		if ((t = tq->tq_task.task_next) == &tq->tq_task) {
+		if ((t = tq->tq_task.tqent_next) == &tq->tq_task) {
 			if (--tq->tq_active == 0)
 				cv_broadcast(&tq->tq_wait_cv);
 			cv_wait(&tq->tq_dispatch_cv, &tq->tq_lock);
@@ -169,16 +204,20 @@
 			tq->tq_active++;
 			continue;
 		}
-		t->task_prev->task_next = t->task_next;
-		t->task_next->task_prev = t->task_prev;
+		t->tqent_prev->tqent_next = t->tqent_next;
+		t->tqent_next->tqent_prev = t->tqent_prev;
+		t->tqent_next = NULL;
+		t->tqent_prev = NULL;
+		prealloc = t->tqent_flags & TQENT_FLAG_PREALLOC;
 		mutex_exit(&tq->tq_lock);
 
 		rw_enter(&tq->tq_threadlock, RW_READER);
-		t->task_func(t->task_arg);
+		t->tqent_func(t->tqent_arg);
 		rw_exit(&tq->tq_threadlock);
 
 		mutex_enter(&tq->tq_lock);
-		task_free(tq, t);
+		if (!prealloc)
+			task_free(tq, t);
 	}
 	tq->tq_nthreads--;
 	cv_broadcast(&tq->tq_wait_cv);
@@ -212,13 +251,14 @@
 	cv_init(&tq->tq_dispatch_cv, NULL, CV_DEFAULT, NULL);
 	cv_init(&tq->tq_wait_cv, NULL, CV_DEFAULT, NULL);
 	cv_init(&tq->tq_maxalloc_cv, NULL, CV_DEFAULT, NULL);
+	(void) strncpy(tq->tq_name, name, TASKQ_NAMELEN + 1);
 	tq->tq_flags = flags | TASKQ_ACTIVE;
 	tq->tq_active = nthreads;
 	tq->tq_nthreads = nthreads;
 	tq->tq_minalloc = minalloc;
 	tq->tq_maxalloc = maxalloc;
-	tq->tq_task.task_next = &tq->tq_task;
-	tq->tq_task.task_prev = &tq->tq_task;
+	tq->tq_task.tqent_next = &tq->tq_task;
+	tq->tq_task.tqent_prev = &tq->tq_task;
 	tq->tq_threadlist = kmem_alloc(nthreads * sizeof (thread_t), KM_SLEEP);
 
 	if (flags & TASKQ_PREPOPULATE) {

Modified: trunk/cddl/contrib/opensolaris/lib/libzpool/common/util.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/libzpool/common/util.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/libzpool/common/util.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *
@@ -20,6 +21,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016 by Delphix. All rights reserved.
  */
 
 #include <assert.h>
@@ -31,38 +33,12 @@
 #include <sys/spa.h>
 #include <sys/fs/zfs.h>
 #include <sys/refcount.h>
+#include <dlfcn.h>
 
 /*
  * Routines needed by more than one client of libzpool.
  */
 
-void
-nicenum(uint64_t num, char *buf)
-{
-	uint64_t n = num;
-	int index = 0;
-	char u;
-
-	while (n >= 1024) {
-		n = (n + (1024 / 2)) / 1024; /* Round up or down */
-		index++;
-	}
-
-	u = " KMGTPE"[index];
-
-	if (index == 0) {
-		(void) sprintf(buf, "%llu", (u_longlong_t)n);
-	} else if (n < 10 && (num & (num - 1)) != 0) {
-		(void) sprintf(buf, "%.2f%c",
-		    (double)num / (1ULL << 10 * index), u);
-	} else if (n < 100 && (num & (num - 1)) != 0) {
-		(void) sprintf(buf, "%.1f%c",
-		    (double)num / (1ULL << 10 * index), u);
-	} else {
-		(void) sprintf(buf, "%llu%c", (u_longlong_t)n, u);
-	}
-}
-
 static void
 show_vdev_stats(const char *desc, const char *ctype, nvlist_t *nv, int indent)
 {
@@ -95,20 +71,22 @@
 
 		sec = MAX(1, vs->vs_timestamp / NANOSEC);
 
-		nicenum(vs->vs_alloc, used);
-		nicenum(vs->vs_space - vs->vs_alloc, avail);
-		nicenum(vs->vs_ops[ZIO_TYPE_READ] / sec, rops);
-		nicenum(vs->vs_ops[ZIO_TYPE_WRITE] / sec, wops);
-		nicenum(vs->vs_bytes[ZIO_TYPE_READ] / sec, rbytes);
-		nicenum(vs->vs_bytes[ZIO_TYPE_WRITE] / sec, wbytes);
-		nicenum(vs->vs_read_errors, rerr);
-		nicenum(vs->vs_write_errors, werr);
-		nicenum(vs->vs_checksum_errors, cerr);
+		nicenum(vs->vs_alloc, used, sizeof (used));
+		nicenum(vs->vs_space - vs->vs_alloc, avail, sizeof (avail));
+		nicenum(vs->vs_ops[ZIO_TYPE_READ] / sec, rops, sizeof (rops));
+		nicenum(vs->vs_ops[ZIO_TYPE_WRITE] / sec, wops, sizeof (wops));
+		nicenum(vs->vs_bytes[ZIO_TYPE_READ] / sec, rbytes,
+		    sizeof (rbytes));
+		nicenum(vs->vs_bytes[ZIO_TYPE_WRITE] / sec, wbytes,
+		    sizeof (wbytes));
+		nicenum(vs->vs_read_errors, rerr, sizeof (rerr));
+		nicenum(vs->vs_write_errors, werr, sizeof (werr));
+		nicenum(vs->vs_checksum_errors, cerr, sizeof (cerr));
 
 		(void) printf("%*s%s%*s%*s%*s %5s %5s %5s %5s %5s %5s %5s\n",
 		    indent, "",
 		    prefix,
-		    indent + strlen(prefix) - 25 - (vs->vs_space ? 0 : 12),
+		    (int)(indent + strlen(prefix) - 25 - (vs->vs_space ? 0 : 12)),
 		    desc,
 		    vs->vs_space ? 6 : 0, vs->vs_space ? used : "",
 		    vs->vs_space ? 6 : 0, vs->vs_space ? avail : "",
@@ -153,3 +131,58 @@
 
 	nvlist_free(config);
 }
+
+/*
+ * Sets given global variable in libzpool to given unsigned 32-bit value.
+ * arg: "<variable>=<value>"
+ */
+int
+set_global_var(char *arg)
+{
+	void *zpoolhdl;
+	char *varname = arg, *varval;
+	u_longlong_t val;
+
+#ifndef _LITTLE_ENDIAN
+	/*
+	 * On big endian systems changing a 64-bit variable would set the high
+	 * 32 bits instead of the low 32 bits, which could cause unexpected
+	 * results.
+	 */
+	fprintf(stderr, "Setting global variables is only supported on "
+	    "little-endian systems\n", varname);
+	return (ENOTSUP);
+#endif
+	if ((varval = strchr(arg, '=')) != NULL) {
+		*varval = '\0';
+		varval++;
+		val = strtoull(varval, NULL, 0);
+		if (val > UINT32_MAX) {
+			fprintf(stderr, "Value for global variable '%s' must "
+			    "be a 32-bit unsigned integer\n", varname);
+			return (EOVERFLOW);
+		}
+	} else {
+		return (EINVAL);
+	}
+
+	zpoolhdl = dlopen("libzpool.so", RTLD_LAZY);
+	if (zpoolhdl != NULL) {
+		uint32_t *var;
+		var = dlsym(zpoolhdl, varname);
+		if (var == NULL) {
+			fprintf(stderr, "Global variable '%s' does not exist "
+			    "in libzpool.so\n", varname);
+			return (EINVAL);
+		}
+		*var = (uint32_t)val;
+
+		dlclose(zpoolhdl);
+	} else {
+		fprintf(stderr, "Failed to open libzpool.so to set global "
+		    "variable\n");
+		return (EIO);
+	}
+
+	return (0);
+}

Modified: trunk/cddl/contrib/opensolaris/lib/pyzfs/common/allow.py
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/pyzfs/common/allow.py	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/pyzfs/common/allow.py	2018-06-02 16:07:30 UTC (rev 10229)
@@ -20,6 +20,7 @@
 # CDDL HEADER END
 #
 # Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013 by Delphix. All rights reserved.
 #
 
 """This module implements the "zfs allow" and "zfs unallow" subcommands.
@@ -219,6 +220,7 @@
     hold=_("Allows adding a user hold to a snapshot"),
     release=_("Allows releasing a user hold which\n\t\t\t\tmight destroy the snapshot"),
     diff=_("Allows lookup of paths within a dataset,\n\t\t\t\tgiven an object number. Ordinary users need this\n\t\t\t\tin order to use zfs diff"),
+    bookmark="",
 )
 
 perms_other = dict(


Property changes on: trunk/cddl/contrib/opensolaris/lib/pyzfs/common/allow.py
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/cddl/contrib/opensolaris/lib/pyzfs/common/ioctl.c
===================================================================
--- trunk/cddl/contrib/opensolaris/lib/pyzfs/common/ioctl.c	2018-06-02 16:07:17 UTC (rev 10228)
+++ trunk/cddl/contrib/opensolaris/lib/pyzfs/common/ioctl.c	2018-06-02 16:07:30 UTC (rev 10229)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * CDDL HEADER START
  *



More information about the Midnightbsd-cvs mailing list