--- old/usr/src/cmd/zoneadm/zoneadm.c	Tue Apr 28 02:57:25 2020
+++ new/usr/src/cmd/zoneadm/zoneadm.c	Tue Apr 28 02:57:25 2020
@@ -23,6 +23,7 @@
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
  * Copyright (c) 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2011, Joyent Inc. All rights reserved.
  */
 
 /*
@@ -101,6 +102,7 @@
 	char		zroot[MAXPATHLEN];
 	char		zuuid[UUID_PRINTABLE_STRING_LENGTH];
 	zone_iptype_t	ziptype;
+	zoneid_t	zdid;
 } zone_entry_t;
 
 #define	CLUSTER_BRAND_NAME	"cluster"
@@ -443,6 +445,7 @@
 	}
 	if (!verbose) {
 		char *cp, *clim;
+		char zdid[80];
 
 		if (!parsable) {
 			(void) printf("%s\n", zent->zname);
@@ -458,8 +461,12 @@
 			(void) printf("%.*s\\:", clim - cp, cp);
 			cp = clim + 1;
 		}
-		(void) printf("%s:%s:%s:%s\n", cp, zent->zuuid, zent->zbrand,
-		    ip_type_str);
+		if (zent->zdid == -1)
+			zdid[0] = '\0';
+		else
+			(void) snprintf(zdid, sizeof (zdid), "%d", zent->zdid);
+		(void) printf("%s:%s:%s:%s:%s\n", cp, zent->zuuid, zent->zbrand,
+		    ip_type_str, zdid);
 		return;
 	}
 	if (zent->zstate_str != NULL) {
@@ -554,6 +561,22 @@
 		return (Z_OK);
 	}
 
+	if ((handle = zonecfg_init_handle()) == NULL) {
+		zperror2(zent->zname, gettext("could not init handle"));
+		return (Z_ERR);
+	}
+	if ((err = zonecfg_get_handle(zent->zname, handle)) != Z_OK) {
+		zperror2(zent->zname, gettext("could not get handle"));
+		zonecfg_fini_handle(handle);
+		return (Z_ERR);
+	}
+
+	if ((err = zonecfg_get_iptype(handle, &zent->ziptype)) != Z_OK) {
+		zperror2(zent->zname, gettext("could not get ip-type"));
+		zonecfg_fini_handle(handle);
+		return (Z_ERR);
+	}
+
 	/*
 	 * There is a race condition where the zone could boot while
 	 * we're walking the index file.  In this case the zone state
@@ -574,25 +597,11 @@
 				zent->ziptype = ZS_EXCLUSIVE;
 			else
 				zent->ziptype = ZS_SHARED;
-			return (Z_OK);
 		}
 	}
 
-	if ((handle = zonecfg_init_handle()) == NULL) {
-		zperror2(zent->zname, gettext("could not init handle"));
-		return (Z_ERR);
-	}
-	if ((err = zonecfg_get_handle(zent->zname, handle)) != Z_OK) {
-		zperror2(zent->zname, gettext("could not get handle"));
-		zonecfg_fini_handle(handle);
-		return (Z_ERR);
-	}
+	zent->zdid = zonecfg_get_did(handle);
 
-	if ((err = zonecfg_get_iptype(handle, &zent->ziptype)) != Z_OK) {
-		zperror2(zent->zname, gettext("could not get ip-type"));
-		zonecfg_fini_handle(handle);
-		return (Z_ERR);
-	}
 	zonecfg_fini_handle(handle);
 
 	return (Z_OK);
@@ -2792,6 +2801,61 @@
 	return (return_code);
 }
 
+/*
+ * Called when readying or booting a zone.  We double check that the zone's
+ * debug ID is set and is unique.  This covers the case of pre-existing zones
+ * with no ID.  Also, its possible that a zone was migrated to this host
+ * and as a result it has a duplicate ID.  In this case we preserve the ID
+ * of the first zone we match on in the index file (since it was there before
+ * the current zone) and we assign a new unique ID to the current zone.
+ * Return true if we assigned a new ID, indicating that the zone configuration
+ * needs to be saved.
+ */
+static boolean_t
+verify_fix_did(zone_dochandle_t handle)
+{
+	zoneid_t mydid;
+	zone_entry_t zent;
+	FILE *cookie;
+	char *name;
+	boolean_t fix = B_FALSE;
+
+	mydid = zonecfg_get_did(handle);
+	if (mydid == -1) {
+		zonecfg_set_did(handle);
+		return (B_TRUE);
+	}
+
+	/* Get the full list of zones from the configuration. */
+	cookie = setzoneent();
+	while ((name = getzoneent(cookie)) != NULL) {
+		if (strcmp(target_zone, name) == 0) {
+			free(name);
+			break;	/* Once we find our entry, stop. */
+		}
+
+		if (strcmp(name, "global") == 0 ||
+		    lookup_zone_info(name, ZONE_ID_UNDEFINED, &zent) != Z_OK) {
+			free(name);
+			continue;
+		}
+
+		free(name);
+		if (zent.zdid == mydid) {
+			fix = B_TRUE;
+			break;
+		}
+	}
+	endzoneent(cookie);
+
+	if (fix) {
+		zonecfg_set_did(handle);
+		return (B_TRUE);
+	}
+
+	return (B_FALSE);
+}
+
 static int
 verify_details(int cmd_num, char *argv[])
 {
@@ -2851,6 +2915,12 @@
 	if (verify_handle(cmd_num, handle, argv) != Z_OK)
 		return_code = Z_ERR;
 
+	if (cmd_num == CMD_READY || cmd_num == CMD_BOOT)
+		if (verify_fix_did(handle))
+			if (zonecfg_save(handle) != Z_OK)
+				(void) fprintf(stderr, gettext("Could not save "
+				    "debug ID.\n"));
+
 	zonecfg_fini_handle(handle);
 	if (return_code == Z_ERR)
 		(void) fprintf(stderr,
--- old/usr/src/cmd/zoneadmd/vplat.c	Tue Apr 28 02:57:26 2020
+++ new/usr/src/cmd/zoneadmd/vplat.c	Tue Apr 28 02:57:26 2020
@@ -4753,8 +4753,14 @@
 	return (res);
 }
 
+/*
+ * The zone_did is a persistent debug ID.  Each zone should have a unique ID
+ * in the kernel.  This is used for things like DTrace which want to monitor
+ * zones across reboots.  They can't use the zoneid since that changes on
+ * each boot.
+ */
 zoneid_t
-vplat_create(zlog_t *zlogp, zone_mnt_t mount_cmd)
+vplat_create(zlog_t *zlogp, zone_mnt_t mount_cmd, zoneid_t zone_did)
 {
 	zoneid_t rval = -1;
 	priv_set_t *privs;
@@ -4895,7 +4901,7 @@
 	xerr = 0;
 	if ((zoneid = zone_create(kzone, rootpath, privs, rctlbuf,
 	    rctlbufsz, zfsbuf, zfsbufsz, &xerr, match, doi, zlabel,
-	    flags)) == -1) {
+	    flags, zone_did)) == -1) {
 		if (xerr == ZE_AREMOUNTS) {
 			if (zonecfg_find_mounts(rootpath, NULL, NULL) < 1) {
 				zerror(zlogp, B_FALSE,
--- old/usr/src/cmd/zoneadmd/zoneadmd.c	Tue Apr 28 02:57:26 2020
+++ new/usr/src/cmd/zoneadmd/zoneadmd.c	Tue Apr 28 02:57:26 2020
@@ -23,6 +23,7 @@
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
  * Copyright (c) 2016 by Delphix. All rights reserved.
+ * Copyright (c) 2011, Joyent Inc. All rights reserved.
  */
 
 /*
@@ -117,6 +118,7 @@
 boolean_t zone_islabeled;
 boolean_t shutdown_in_progress;
 static zoneid_t zone_id;
+static zoneid_t zone_did = 0;
 dladm_handle_t dld_handle = NULL;
 
 static char pre_statechg_hook[2 * MAXPATHLEN];
@@ -547,7 +549,10 @@
 		goto bad;
 	}
 
-	if ((zone_id = vplat_create(zlogp, mount_cmd)) == -1) {
+	if (zone_did == 0)
+		zone_did = zone_get_did(zone_name);
+
+	if ((zone_id = vplat_create(zlogp, mount_cmd, zone_did)) == -1) {
 		if ((err = zonecfg_destroy_snapshot(zone_name)) != Z_OK)
 			zerror(zlogp, B_FALSE, "destroying snapshot: %s",
 			    zonecfg_strerror(err));
@@ -1355,8 +1360,8 @@
 		case Z_BOOT:
 		case Z_FORCEBOOT:
 			eventstream_write(Z_EVT_ZONE_BOOTING);
-			if ((rval = zone_ready(zlogp, Z_MNT_BOOT, zstate))
-			    == 0) {
+			if ((rval = zone_ready(zlogp, Z_MNT_BOOT,
+			    zstate)) == 0) {
 				rval = zone_bootup(zlogp, zargp->bootbuf,
 				    zstate);
 			}
@@ -1544,7 +1549,8 @@
 			if ((rval = zone_halt(zlogp, B_FALSE, B_TRUE, zstate))
 			    != 0)
 				break;
-			if ((rval = zone_ready(zlogp, Z_MNT_BOOT, zstate)) == 0)
+			if ((rval = zone_ready(zlogp, Z_MNT_BOOT, zstate))
+			    == 0)
 				eventstream_write(Z_EVT_ZONE_READIED);
 			else
 				eventstream_write(Z_EVT_ZONE_HALTED);
--- old/usr/src/cmd/zoneadmd/zoneadmd.h	Tue Apr 28 02:57:26 2020
+++ new/usr/src/cmd/zoneadmd/zoneadmd.h	Tue Apr 28 02:57:26 2020
@@ -22,6 +22,7 @@
 /*
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2011, Joyent Inc. All rights reserved.
  */
 
 #ifndef	_ZONEADMD_H
@@ -135,7 +136,7 @@
 /*
  * Virtual platform interfaces.
  */
-extern zoneid_t vplat_create(zlog_t *, zone_mnt_t);
+extern zoneid_t vplat_create(zlog_t *, zone_mnt_t, zoneid_t);
 extern int vplat_bringup(zlog_t *, zone_mnt_t, zoneid_t);
 extern int vplat_teardown(zlog_t *, boolean_t, boolean_t);
 extern int vplat_get_iptype(zlog_t *, zone_iptype_t *);
--- old/usr/src/cmd/zonecfg/zonecfg.c	Tue Apr 28 02:57:26 2020
+++ new/usr/src/cmd/zonecfg/zonecfg.c	Tue Apr 28 02:57:26 2020
@@ -6410,6 +6410,12 @@
 
 	if (save) {
 		if (ret_val == Z_OK) {
+			/*
+			 * If the zone doesn't yet have a debug ID, set one now.
+			 */
+			if (zonecfg_get_did(handle) == -1)
+				zonecfg_set_did(handle);
+
 			if ((ret_val = zonecfg_save(handle)) == Z_OK) {
 				need_to_commit = B_FALSE;
 				(void) strlcpy(revert_zone, zone,
--- old/usr/src/head/libzonecfg.h	Tue Apr 28 02:57:26 2020
+++ new/usr/src/head/libzonecfg.h	Tue Apr 28 02:57:26 2020
@@ -324,6 +324,8 @@
 extern	int	zonecfg_get_sched_class(zone_dochandle_t, char *, size_t);
 extern	int	zonecfg_set_sched(zone_dochandle_t, char *);
 extern	int	zonecfg_get_dflt_sched_class(zone_dochandle_t, char *, int);
+extern	zoneid_t zonecfg_get_did(zone_dochandle_t);
+extern	void	zonecfg_set_did(zone_dochandle_t);
 
 /*
  * Set/retrieve the brand for the zone
@@ -528,6 +530,7 @@
  * Higher-level routines.
  */
 extern  int	zone_get_brand(char *, char *, size_t);
+extern  zoneid_t zone_get_did(char *);
 extern	int	zone_get_rootpath(char *, char *, size_t);
 extern	int	zone_get_devroot(char *, char *, size_t);
 extern	int	zone_get_zonepath(char *, char *, size_t);
--- old/usr/src/head/zone.h	Tue Apr 28 02:57:27 2020
+++ new/usr/src/head/zone.h	Tue Apr 28 02:57:27 2020
@@ -21,6 +21,7 @@
 /*
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright 2011 Joyent Inc.  All rights reserved.
  */
 
 #ifndef _ZONE_H
@@ -56,7 +57,7 @@
 /* System call API */
 extern zoneid_t	zone_create(const char *, const char *,
     const struct priv_set *, const char *, size_t, const char *, size_t, int *,
-    int, int, const bslabel_t *, int);
+    int, int, const bslabel_t *, int, zoneid_t);
 extern int	zone_boot(zoneid_t);
 extern int	zone_destroy(zoneid_t);
 extern ssize_t	zone_getattr(zoneid_t, int, void *, size_t);
--- old/usr/src/lib/Makefile	Tue Apr 28 02:57:27 2020
+++ new/usr/src/lib/Makefile	Tue Apr 28 02:57:27 2020
@@ -615,7 +615,7 @@
 libdll:		libast
 libdlpi:	libinetutil libdladm
 libds:		libsysevent
-libdtrace:	libproc libgen libctf libmapmalloc
+libdtrace:	libproc libgen libctf libmapmalloc libzonecfg
 libdtrace_jni:	libuutil libdtrace
 libdwarf:	../cmd/sgs/libelf
 libefi:		libuuid libsmbios
--- old/usr/src/lib/libc/port/sys/zone.c	Tue Apr 28 02:57:27 2020
+++ new/usr/src/lib/libc/port/sys/zone.c	Tue Apr 28 02:57:27 2020
@@ -22,6 +22,7 @@
 /*
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright 2011 Joyent Inc.  All rights reserved.
  */
 
 #include "lint.h"
@@ -39,7 +40,8 @@
 zoneid_t
 zone_create(const char *name, const char *root, const struct priv_set *privs,
     const char *rctls, size_t rctlsz, const char *zfs, size_t zfssz,
-    int *extended_error, int match, int doi, const bslabel_t *label, int flags)
+    int *extended_error, int match, int doi, const bslabel_t *label, int flags,
+    zoneid_t zone_did)
 {
 	zone_def  zd;
 	priv_data_t *d;
@@ -59,6 +61,7 @@
 	zd.doi = doi;
 	zd.label = label;
 	zd.flags = flags;
+	zd.zone_did = zone_did;
 
 	return ((zoneid_t)syscall(SYS_zone, ZONE_CREATE, &zd));
 }
--- old/usr/src/lib/libdtrace/Makefile.com	Tue Apr 28 02:57:27 2020
+++ new/usr/src/lib/libdtrace/Makefile.com	Tue Apr 28 02:57:27 2020
@@ -138,7 +138,7 @@
 SMATCH=off
 
 YYCFLAGS =
-LDLIBS += -lgen -lproc -lrtld_db -lnsl -lsocket -lctf -lelf -lc
+LDLIBS += -lgen -lproc -lrtld_db -lnsl -lsocket -lctf -lelf -lc -lzonecfg
 DRTILDLIBS = $(LDLIBS.lib) -lc
 LIBDAUDITLIBS = $(LDLIBS.lib) -lmapmalloc -lc -lproc
 
--- old/usr/src/lib/libdtrace/common/dt_impl.h	Tue Apr 28 02:57:27 2020
+++ new/usr/src/lib/libdtrace/common/dt_impl.h	Tue Apr 28 02:57:27 2020
@@ -267,6 +267,7 @@
 	uint_t dt_droptags;	/* boolean:  set via -xdroptags */
 	uint_t dt_active;	/* boolean:  set once tracing is active */
 	uint_t dt_stopped;	/* boolean:  set once tracing is stopped */
+	uint_t dt_optset;	/* boolean:  set once options have been set */
 	processorid_t dt_beganon; /* CPU that executed BEGIN probe (if any) */
 	processorid_t dt_endedon; /* CPU that executed END probe (if any) */
 	uint_t dt_oflags;	/* dtrace open-time options (see dtrace.h) */
--- old/usr/src/lib/libdtrace/common/dt_options.c	Tue Apr 28 02:57:27 2020
+++ new/usr/src/lib/libdtrace/common/dt_options.c	Tue Apr 28 02:57:27 2020
@@ -41,6 +41,8 @@
 #include <alloca.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <zone.h>
+#include <libzonecfg.h>
 
 #include <dt_impl.h>
 #include <dt_string.h>
@@ -854,6 +856,44 @@
 	return (0);
 }
 
+/*ARGSUSED*/
+static int
+dt_opt_zone(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+	zoneid_t z, did;
+
+	if (arg == NULL)
+		return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+	/*
+	 * If the specified zone is currently running, we'll query the kernel
+	 * for its debugger ID.  If it doesn't appear to be running, we'll look
+	 * for it for among all installed zones (thereby allowing a zdefs
+	 * enabling against a halted zone).
+	 */
+	if ((z = getzoneidbyname(arg)) != -1) {
+		if (zone_getattr(z, ZONE_ATTR_DID, &did, sizeof (did)) < 0)
+			return (dt_set_errno(dtp, EDT_BADOPTVAL));
+	} else {
+		zone_dochandle_t handle;
+
+		if ((handle = zonecfg_init_handle()) == NULL)
+			return (dt_set_errno(dtp, errno));
+
+		if (zonecfg_get_handle(arg, handle) != Z_OK) {
+			zonecfg_fini_handle(handle);
+			return (dt_set_errno(dtp, EDT_BADOPTVAL));
+		}
+
+		did = zonecfg_get_did(handle);
+		zonecfg_fini_handle(handle);
+	}
+
+	dtp->dt_options[DTRACEOPT_ZONE] = did;
+
+	return (0);
+}
+
 int
 dt_options_load(dtrace_hdl_t *dtp)
 {
@@ -994,6 +1034,7 @@
 	{ "strsize", dt_opt_strsize, DTRACEOPT_STRSIZE },
 	{ "ustackframes", dt_opt_runtime, DTRACEOPT_USTACKFRAMES },
 	{ "temporal", dt_opt_runtime, DTRACEOPT_TEMPORAL },
+	{ "zone", dt_opt_zone, DTRACEOPT_ZONE },
 	{ NULL }
 };
 
--- old/usr/src/lib/libdtrace/common/dt_program.c	Tue Apr 28 02:57:27 2020
+++ new/usr/src/lib/libdtrace/common/dt_program.c	Tue Apr 28 02:57:27 2020
@@ -22,6 +22,7 @@
 /*
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2011 by Delphix. All rights reserved.
+ * Copyright (c) 2011, Joyent, Inc. All rights reserved.
  */
 
 #include <unistd.h>
@@ -154,6 +155,24 @@
 	void *dof;
 	int n, err;
 
+	if (!dtp->dt_optset) {
+		/*
+		 * If we have not yet ioctl'd down our options DOF, we'll
+		 * do that before enabling any probes (some options will
+		 * affect which probes we match).
+		 */
+		if ((dof = dtrace_getopt_dof(dtp)) == NULL)
+			return (-1); /* dt_errno has been set for us */
+
+		err = dt_ioctl(dtp, DTRACEIOC_ENABLE, dof);
+		dtrace_dof_destroy(dtp, dof);
+
+		if (err == -1)
+			return (-1);
+
+		dtp->dt_optset = B_TRUE;
+	}
+
 	dtrace_program_info(dtp, pgp, pip);
 
 	if ((dof = dtrace_dof_create(dtp, pgp, DTRACE_D_STRIP)) == NULL)
--- old/usr/src/lib/libdtrace/common/dt_work.c	Tue Apr 28 02:57:27 2020
+++ new/usr/src/lib/libdtrace/common/dt_work.c	Tue Apr 28 02:57:27 2020
@@ -25,7 +25,9 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * Copyright (c) 2011, Joyent, Inc. All rights reserved.
+ */
 
 #include <dt_impl.h>
 #include <stddef.h>
@@ -164,9 +166,6 @@
 int
 dtrace_go(dtrace_hdl_t *dtp)
 {
-	void *dof;
-	int err;
-
 	if (dtp->dt_active)
 		return (dt_set_errno(dtp, EINVAL));
 
@@ -182,15 +181,6 @@
 	    dtp->dt_errno != ENOTTY || dtp->dt_vector == NULL))
 		return (-1); /* dt_errno has been set for us */
 
-	if ((dof = dtrace_getopt_dof(dtp)) == NULL)
-		return (-1); /* dt_errno has been set for us */
-
-	err = dt_ioctl(dtp, DTRACEIOC_ENABLE, dof);
-	dtrace_dof_destroy(dtp, dof);
-
-	if (err == -1 && (errno != ENOTTY || dtp->dt_vector == NULL))
-		return (dt_set_errno(dtp, errno));
-
 	if (dt_ioctl(dtp, DTRACEIOC_GO, &dtp->dt_beganon) == -1) {
 		if (errno == EACCES)
 			return (dt_set_errno(dtp, EDT_DESTRUCTIVE));
--- old/usr/src/lib/libzonecfg/common/libzonecfg.c	Tue Apr 28 02:57:28 2020
+++ new/usr/src/lib/libzonecfg/common/libzonecfg.c	Tue Apr 28 02:57:28 2020
@@ -80,6 +80,8 @@
 #define	ZONE_EVENT_PING_SUBCLASS	"ping"
 #define	ZONE_EVENT_PING_PUBLISHER	"solaris"
 
+#define	DEBUGID_FILE	"/etc/zones/did.txt"
+
 /* Hard-code the DTD element/attribute/entity names just once, here. */
 #define	DTD_ELEM_ATTR		(const xmlChar *) "attr"
 #define	DTD_ELEM_COMMENT	(const xmlChar *) "comment"
@@ -132,6 +134,7 @@
 #define	DTD_ATTR_MODE		(const xmlChar *) "mode"
 #define	DTD_ATTR_ACL		(const xmlChar *) "acl"
 #define	DTD_ATTR_BRAND		(const xmlChar *) "brand"
+#define	DTD_ATTR_DID		(const xmlChar *) "debugid"
 #define	DTD_ATTR_HOSTID		(const xmlChar *) "hostid"
 #define	DTD_ATTR_USER		(const xmlChar *) "user"
 #define	DTD_ATTR_AUTHS		(const xmlChar *) "auths"
@@ -5685,6 +5688,171 @@
 	return (err);
 }
 
+/*
+ * Atomically get a new zone_did value.  The currently allocated value
+ * is stored in /etc/zones/did.txt.  Lock the file, read the current value,
+ * increment, save the new value and unlock the file.  Return the new value
+ * or -1 if there was an error.  The ID namespace is large enough that we
+ * don't worry about recycling an ID when a zone is deleted.
+ */
+static zoneid_t
+new_zone_did()
+{
+	int fd;
+	int len;
+	int val;
+	struct flock lck;
+	char pathbuf[PATH_MAX];
+	char buf[80];
+
+	if (snprintf(pathbuf, sizeof (pathbuf), "%s%s", zonecfg_get_root(),
+	    DEBUGID_FILE) >= sizeof (pathbuf)) {
+		printf(gettext("alternate root path is too long"));
+		return (-1);
+	}
+
+	if ((fd = open(pathbuf, O_RDWR | O_CREAT,
+	    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
+		perror("new_zone_did open failed");
+		return (-1);
+	}
+
+        /* Initialize the lock. */
+        lck.l_whence = SEEK_SET;
+        lck.l_start = 0;
+        lck.l_len = 0;
+
+	/* Wait until we acquire an exclusive lock on the file. */
+	lck.l_type = F_WRLCK;
+	if (fcntl(fd, F_SETLKW, &lck) == -1) {
+		perror("new_zone_did lock failed");
+		(void) close(fd);
+		return (-1);
+	}
+
+	/* Get currently allocated value */
+	len = read(fd, buf, sizeof (buf));
+	if (len == -1) {
+		perror("new_zone_did read failed");
+		val = -1;
+	} else {
+		if (lseek(fd, 0L, SEEK_SET) == -1) {
+			perror("new_zone_did seek failed");
+			val = -1;
+		} else {
+			if (len == 0) {
+				/* Just created the file, initialize at 1 */
+				val = 1;
+			} else {
+				val = atoi(buf);
+				val++;
+			}
+
+			(void) snprintf(buf, sizeof (buf), "%d\n", val);
+			len = strlen(buf);
+
+			/* Save newly allocated value */
+			if (write(fd, buf, len) == -1) {
+				perror("new_zone_did write failed");
+				val = -1;
+			}
+		}
+	}
+
+	/* Release the file lock. */
+	lck.l_type = F_UNLCK;
+	if (fcntl(fd, F_SETLK, &lck) == -1) {
+		perror("new_zone_did unlock failed");
+		val = -1;
+	}
+
+	if (close(fd) != 0)
+		perror("new_zone_did close failed");
+
+	return (val);
+}
+
+/*
+ * Called by zoneadmd to get the zone's debug ID.
+ * If the zone doesn't already have an ID, a new one is generated and
+ * persistently saved onto the zone.  Normally either zoneadm or zonecfg
+ * will assign a new ID for the zone, so zoneadmd should never have to
+ * generate one, but we also handle that here just to be paranoid.
+ */
+zoneid_t
+zone_get_did(char *zone_name)
+{
+	int res;
+	zoneid_t new_did;
+	zone_dochandle_t handle;
+	char did_str[80];
+
+	if ((handle = zonecfg_init_handle()) == NULL)
+		return (getpid());
+
+	if (zonecfg_get_handle((char *)zone_name, handle) != Z_OK)
+		return (getpid());
+
+	res = getrootattr(handle, DTD_ATTR_DID, did_str, sizeof (did_str));
+
+	/* If the zone already has an assigned debug ID, return it. */
+	if (res == Z_OK && did_str[0] != '\0') {
+		zonecfg_fini_handle(handle);
+		return (atoi(did_str));
+	}
+
+	/*
+	 * The zone doesn't have an assigned debug ID yet, generate one and
+	 * save it as part of the zone definition.
+	 */
+	if ((new_did = new_zone_did()) == -1) {
+		/*
+		 * We should really never hit this block of code.
+		 * Generating a new ID failed for some reason.  Use the current
+		 * pid as a temporary ID so that the zone can continue to boot
+		 * but we don't persistently save this temporary ID on the zone.
+		 */
+		zonecfg_fini_handle(handle);
+		return (getpid());
+	}
+
+	/* Now persistently save this new ID onto the zone. */
+	(void) snprintf(did_str, sizeof (did_str), "%d", new_did);
+	(void) setrootattr(handle, DTD_ATTR_DID, did_str);
+	(void) zonecfg_save(handle);
+
+	zonecfg_fini_handle(handle);
+	return (new_did);
+}
+
+zoneid_t
+zonecfg_get_did(zone_dochandle_t handle)
+{
+	char did_str[80];
+	int err;
+	zoneid_t did;
+
+	err = getrootattr(handle, DTD_ATTR_DID, did_str, sizeof (did_str));
+	if (err == Z_OK && did_str[0] != '\0')
+		did = atoi(did_str);
+	else
+		did = -1;
+
+	return (did);
+}
+
+void
+zonecfg_set_did(zone_dochandle_t handle)
+{
+	zoneid_t new_did;
+	char did_str[80];
+
+	if ((new_did = new_zone_did()) == -1)
+		return;
+	(void) snprintf(did_str, sizeof (did_str), "%d", new_did);
+	(void) setrootattr(handle, DTD_ATTR_DID, did_str);
+}
+
 /*
  * Return the appropriate root for the active /dev.
  * For normal zone, the path is $ZONEPATH/root;
--- old/usr/src/lib/libzonecfg/common/mapfile-vers	Tue Apr 28 02:57:28 2020
+++ new/usr/src/lib/libzonecfg/common/mapfile-vers	Tue Apr 28 02:57:28 2020
@@ -20,6 +20,7 @@
 #
 #
 # Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, Joyent Inc. All rights reserved.
 #
 
 #
@@ -120,6 +121,7 @@
 	zonecfg_get_bootargs;
 	zonecfg_get_brand;
 	zonecfg_get_dflt_sched_class;
+	zonecfg_get_did;
 	zonecfg_getdevent;
 	zonecfg_getdevperment;
 	zonecfg_getdsent;
@@ -201,6 +203,7 @@
 	zonecfg_set_autoboot;
 	zonecfg_set_bootargs;
 	zonecfg_set_brand;
+	zonecfg_set_did;
 	zonecfg_setdevent;
 	zonecfg_setdevperment;
 	zonecfg_setdsent;
@@ -234,6 +237,7 @@
 	zonecfg_verify_save;
 	zonecfg_warn_poold;
 	zone_get_brand;
+	zone_get_did;
 	zone_get_devroot;
 	zone_get_id;
 	zone_get_rootpath;
--- old/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1	Tue Apr 28 02:57:28 2020
+++ new/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1	Tue Apr 28 02:57:28 2020
@@ -21,6 +21,7 @@
  CDDL HEADER END
 
  Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2011, Joyent Inc. All rights reserved.
 
 -->
 
@@ -162,6 +163,7 @@
 			limitpriv	CDATA ""
 			bootargs	CDATA ""
 			brand		CDATA ""
+			debugid		CDATA ""
 			scheduling-class	CDATA ""
 			fs-allowed	CDATA ""
 			version		NMTOKEN #FIXED '1'>
--- old/usr/src/uts/common/dtrace/dtrace.c	Tue Apr 28 02:57:29 2020
+++ new/usr/src/uts/common/dtrace/dtrace.c	Tue Apr 28 02:57:29 2020
@@ -7793,7 +7793,7 @@
 		priv = DTRACE_PRIV_ALL;
 	} else {
 		*uidp = crgetuid(cr);
-		*zoneidp = crgetzoneid(cr);
+		*zoneidp = crgetzonedid(cr);
 
 		priv = 0;
 		if (PRIV_POLICY_ONLY(cr, PRIV_DTRACE_KERNEL, B_FALSE))
@@ -8289,7 +8289,7 @@
 	provider->dtpv_priv.dtpp_flags = priv;
 	if (cr != NULL) {
 		provider->dtpv_priv.dtpp_uid = crgetuid(cr);
-		provider->dtpv_priv.dtpp_zoneid = crgetzoneid(cr);
+		provider->dtpv_priv.dtpp_zoneid = crgetzonedid(cr);
 	}
 	provider->dtpv_pops = *pops;
 
@@ -8893,6 +8893,7 @@
 	uint32_t priv;
 	uid_t uid;
 	zoneid_t zoneid;
+	dtrace_state_t *state = enab->dten_vstate->dtvs_state;
 
 	ASSERT(MUTEX_HELD(&dtrace_lock));
 	dtrace_ecb_create_cache = NULL;
@@ -8907,9 +8908,23 @@
 	}
 
 	dtrace_probekey(desc, &pkey);
-	dtrace_cred2priv(enab->dten_vstate->dtvs_state->dts_cred.dcr_cred,
-	    &priv, &uid, &zoneid);
+	dtrace_cred2priv(state->dts_cred.dcr_cred, &priv, &uid, &zoneid);
 
+	if ((priv & DTRACE_PRIV_ZONEOWNER) &&
+	    state->dts_options[DTRACEOPT_ZONE] != DTRACEOPT_UNSET) {
+		/*
+		 * If we have the privilege of instrumenting all zones but we
+		 * have been told to instrument but one, we will spoof this up
+		 * depriving ourselves of DTRACE_PRIV_ZONEOWNER for purposes
+		 * of dtrace_match().  (Note that DTRACEOPT_ZONE is not for
+		 * security but rather for performance: it allows the global
+		 * zone to instrument USDT probes in a local zone without
+		 * requiring all zones to be instrumented.)
+		 */
+		priv &= ~DTRACE_PRIV_ZONEOWNER;
+		zoneid = state->dts_options[DTRACEOPT_ZONE];
+	}
+
 	return (dtrace_match(&pkey, priv, uid, zoneid, dtrace_ecb_create_enable,
 	    enab));
 }
@@ -12370,10 +12385,10 @@
 	for (enab = dtrace_retained; enab != NULL; enab = enab->dten_next) {
 		dtrace_cred_t *dcr = &enab->dten_vstate->dtvs_state->dts_cred;
 		cred_t *cr = dcr->dcr_cred;
-		zoneid_t zone = cr != NULL ? crgetzoneid(cr) : 0;
+		zoneid_t zone = cr != NULL ? crgetzonedid(cr) : 0;
 
 		if ((dcr->dcr_visible & DTRACE_CRV_ALLZONE) || (cr != NULL &&
-		    (zone == GLOBAL_ZONEID || getzoneid() == zone)))
+		    (zone == GLOBAL_ZONEID || getzonedid() == zone)))
 			(void) dtrace_enabling_match(enab, NULL);
 	}
 
--- old/usr/src/uts/common/os/cred.c	Tue Apr 28 02:57:29 2020
+++ new/usr/src/uts/common/os/cred.c	Tue Apr 28 02:57:29 2020
@@ -729,6 +729,14 @@
 	    cr->cr_zone->zone_id);
 }
 
+zoneid_t
+crgetzonedid(const cred_t *cr)
+{
+	return (cr->cr_zone == NULL ?
+	    (cr->cr_uid == -1 ? (zoneid_t)-1 : GLOBAL_ZONEID) :
+	    cr->cr_zone->zone_did);
+}
+
 projid_t
 crgetprojid(const cred_t *cr)
 {
--- old/usr/src/uts/common/os/zone.c	Tue Apr 28 02:57:29 2020
+++ new/usr/src/uts/common/os/zone.c	Tue Apr 28 02:57:29 2020
@@ -419,8 +419,9 @@
  * Version 5 alters the zone_boot system call, and converts its old
  *     bootargs parameter to be set by the zone_setattr API instead.
  * Version 6 adds the flag argument to zone_create.
+ * Version 7 adds the requested zone_did to zone_create.
  */
-static const int ZONE_SYSCALL_API_VERSION = 6;
+static const int ZONE_SYSCALL_API_VERSION = 7;
 
 /*
  * Certain filesystems (such as NFS and autofs) need to know which zone
@@ -3020,6 +3021,12 @@
 	return (curproc->p_zone->zone_id);
 }
 
+zoneid_t
+getzonedid(void)
+{
+	return (curproc->p_zone->zone_did);
+}
+
 /*
  * Internal versions of zone_find_by_*().  These don't zone_hold() or
  * check the validity of a zone's state.
@@ -4402,7 +4409,7 @@
     caddr_t rctlbuf, size_t rctlbufsz,
     caddr_t zfsbuf, size_t zfsbufsz, int *extended_error,
     int match, uint32_t doi, const bslabel_t *label,
-    int flags)
+    int flags, zoneid_t zone_did)
 {
 	struct zsched_arg zarg;
 	nvlist_t *rctls = NULL;
@@ -4422,6 +4429,7 @@
 	if (PTOU(pp)->u_rdir != NULL && PTOU(pp)->u_rdir != rootdir)
 		return (zone_create_error(ENOTSUP, ZE_CHROOTED,
 		    extended_error));
+
 	/*
 	 * As the first step of zone creation, we want to allocate a zoneid.
 	 * This allocation is complicated by the fact that netstacks use the
@@ -4473,7 +4481,9 @@
 	}
 
 	zone = kmem_zalloc(sizeof (zone_t), KM_SLEEP);
+
 	zone->zone_id = zoneid;
+	zone->zone_did = zone_did;
 	zone->zone_status = ZONE_IS_UNINITIALIZED;
 	zone->zone_pool = pool_default;
 	zone->zone_pool_mod = gethrtime();
@@ -5677,6 +5687,14 @@
 		}
 		kmem_free(zbuf, bufsize);
 		break;
+	case ZONE_ATTR_DID:
+		size = sizeof (zoneid_t);
+		if (bufsize > size)
+			bufsize = size;
+
+		if (buf != NULL && copyout(&zone->zone_did, buf, bufsize) != 0)
+			error = EFAULT;
+		break;
 	default:
 		if ((attr >= ZONE_ATTR_BRAND_ATTRS) && ZONE_IS_BRANDED(zone)) {
 			size = bufsize;
@@ -6481,6 +6499,7 @@
 			zs.doi = zs32.doi;
 			zs.label = (const bslabel_t *)(uintptr_t)zs32.label;
 			zs.flags = zs32.flags;
+			zs.zone_did = zs32.zone_did;
 #else
 			panic("get_udatamodel() returned bogus result\n");
 #endif
@@ -6491,7 +6510,7 @@
 		    (caddr_t)zs.rctlbuf, zs.rctlbufsz,
 		    (caddr_t)zs.zfsbuf, zs.zfsbufsz,
 		    zs.extended_error, zs.match, zs.doi,
-		    zs.label, zs.flags));
+		    zs.label, zs.flags, zs.zone_did));
 	case ZONE_BOOT:
 		return (zone_boot((zoneid_t)(uintptr_t)arg1));
 	case ZONE_DESTROY:
--- old/usr/src/uts/common/sys/cred.h	Tue Apr 28 02:57:30 2020
+++ new/usr/src/uts/common/sys/cred.h	Tue Apr 28 02:57:30 2020
@@ -93,6 +93,7 @@
 extern gid_t crgetrgid(const cred_t *);
 extern gid_t crgetsgid(const cred_t *);
 extern zoneid_t crgetzoneid(const cred_t *);
+extern zoneid_t crgetzonedid(const cred_t *);
 extern projid_t crgetprojid(const cred_t *);
 
 extern cred_t *crgetmapped(const cred_t *);
--- old/usr/src/uts/common/sys/zone.h	Tue Apr 28 02:57:30 2020
+++ new/usr/src/uts/common/sys/zone.h	Tue Apr 28 02:57:30 2020
@@ -117,6 +117,7 @@
 #define	ZONE_ATTR_NETWORK	17
 #define	ZONE_ATTR_INITNORESTART	20
 #define	ZONE_ATTR_SECFLAGS	21
+#define	ZONE_ATTR_DID		22
 
 /* Start of the brand-specific attribute namespace */
 #define	ZONE_ATTR_BRAND_ATTRS	32768
@@ -197,6 +198,7 @@
 	uint32_t doi;			/* DOI for label */
 	caddr32_t label;		/* label associated with zone */
 	int flags;
+	zoneid_t zone_did;		/* zone debug ID */
 } zone_def32;
 #endif
 typedef struct {
@@ -213,6 +215,7 @@
 	uint32_t doi;			/* DOI for label */
 	const bslabel_t *label;		/* label associated with zone */
 	int flags;
+	zoneid_t zone_did;		/* zone debug ID */
 } zone_def;
 
 /* extended error information */
@@ -462,6 +465,7 @@
 	 */
 	list_node_t	zone_linkage;
 	zoneid_t	zone_id;	/* ID of zone */
+	zoneid_t	zone_did;	/* persistent debug ID of zone */
 	uint_t		zone_ref;	/* count of zone_hold()s on zone */
 	uint_t		zone_cred_ref;	/* count of zone_hold_cred()s on zone */
 	/*
@@ -664,6 +668,7 @@
 extern zone_t *zone_find_by_any_path(const char *, boolean_t);
 extern zone_t *zone_find_by_path(const char *);
 extern zoneid_t getzoneid(void);
+extern zoneid_t getzonedid(void);
 extern zone_t *zone_find_by_id_nolock(zoneid_t);
 extern int zone_datalink_walk(zoneid_t, int (*)(datalink_id_t, void *), void *);
 extern int zone_check_datalink(zoneid_t *, datalink_id_t);
