--- old/usr/src/cmd/zoneadmd/zoneadmd.c	Mon Oct 25 15:54:19 2021
+++ new/usr/src/cmd/zoneadmd/zoneadmd.c	Mon Oct 25 15:54:19 2021
@@ -1292,8 +1292,8 @@
 	dladm_status_t status;
 	char errmsg[DLADM_STRSIZE];
 	int err;
-	boolean_t restart_init;
 	boolean_t app_svc_dep;
+	boolean_t restart_init, restart_init0, restart_initreboot;
 
 	if (brand_prestatechg(zlogp, zstate, Z_BOOT, debug) != 0)
 		return (-1);
@@ -1345,8 +1345,10 @@
 		goto bad;
 	}
 
-	/* See if we should restart init if it dies. */
+	/* See if this zone's brand should restart init if it dies. */
 	restart_init = restartinit(bh);
+	restart_init0 = brand_restartinit0(bh);
+	restart_initreboot = brand_restartinitreboot(bh);
 
 	/*
 	 * See if we need to setup contract dependencies between the zone's
@@ -1427,6 +1429,17 @@
 		zerror(zlogp, B_TRUE, "could not set zone init-no-restart");
 		goto bad;
 	}
+	if (restart_init0 && zone_setattr(zoneid, ZONE_ATTR_INITRESTART0,
+	    NULL, 0) == -1) {
+		zerror(zlogp, B_TRUE,
+		    "could not set zone init-restart-on-exit-0");
+		goto bad;
+	}
+	if (restart_initreboot && zone_setattr(zoneid, ZONE_ATTR_INITREBOOT,
+	    NULL, 0) == -1) {
+		zerror(zlogp, B_TRUE, "could not set zone reboot-on-init-exit");
+		goto bad;
+	}
 
 	if (app_svc_dep && zone_setattr(zoneid, ZONE_ATTR_APP_SVC_CT,
 	    (void *)B_TRUE, sizeof (boolean_t)) == -1) {
--- old/usr/src/lib/libbrand/common/libbrand.c	Mon Oct 25 15:54:19 2021
+++ new/usr/src/lib/libbrand/common/libbrand.c	Mon Oct 25 15:54:19 2021
@@ -63,6 +63,8 @@
 #define	DTD_ELEM_MODNAME	((const xmlChar *) "modname")
 #define	DTD_ELEM_MOUNT		((const xmlChar *) "mount")
 #define	DTD_ELEM_RESTARTINIT	((const xmlChar *) "restartinit")
+#define	DTD_ELEM_RESTARTINIT0	((const xmlChar *) "restartinit0")
+#define	DTD_ELEM_RESTARTINITREBOOT	((const xmlChar *) "restartinitreboot")
 #define	DTD_ELEM_POSTATTACH	((const xmlChar *) "postattach")
 #define	DTD_ELEM_POSTCLONE	((const xmlChar *) "postclone")
 #define	DTD_ELEM_POSTINSTALL	((const xmlChar *) "postinstall")
@@ -530,15 +532,16 @@
 	    buf, len, DTD_ELEM_INITNAME, B_FALSE, B_FALSE));
 }
 
-boolean_t
-brand_restartinit(brand_handle_t bh)
+static boolean_t
+i_brand_restartinit(brand_handle_t bh, const xmlChar *tagname, boolean_t deflt)
 {
 	struct brand_handle *bhp = (struct brand_handle *)bh;
 	char val[80];
 
 	if (brand_get_value(bhp, NULL, NULL, NULL, NULL,
-	    val, sizeof (val), DTD_ELEM_RESTARTINIT, B_FALSE, B_FALSE) != 0)
-		return (B_TRUE);
+	    val, sizeof (val), tagname, B_FALSE, B_FALSE) != 0) {
+		return (deflt);
+	}
 
 	if (strcmp(val, "false") == 0)
 		return (B_FALSE);
@@ -545,6 +548,24 @@
 	return (B_TRUE);
 }
 
+boolean_t
+brand_restartinit(brand_handle_t bh)
+{
+	return (i_brand_restartinit(bh, DTD_ELEM_RESTARTINIT, B_TRUE));
+}
+
+boolean_t
+brand_restartinit0(brand_handle_t bh)
+{
+	return (i_brand_restartinit(bh, DTD_ELEM_RESTARTINIT0, B_FALSE));
+}
+
+boolean_t
+brand_restartinitreboot(brand_handle_t bh)
+{
+	return (i_brand_restartinit(bh, DTD_ELEM_RESTARTINITREBOOT, B_FALSE));
+}
+
 int
 brand_get_login_cmd(brand_handle_t bh, const char *username,
     char *buf, size_t len)
--- old/usr/src/lib/libbrand/common/libbrand.h	Mon Oct 25 15:54:20 2021
+++ new/usr/src/lib/libbrand/common/libbrand.h	Mon Oct 25 15:54:20 2021
@@ -62,6 +62,8 @@
     char *, size_t);
 extern int brand_get_initname(brand_handle_t, char *, size_t);
 extern boolean_t brand_restartinit(brand_handle_t);
+extern boolean_t brand_restartinit0(brand_handle_t);
+extern boolean_t brand_restartinitreboot(brand_handle_t);
 extern int brand_get_install(brand_handle_t, const char *, const char *,
     char *, size_t);
 extern int brand_get_installopts(brand_handle_t, char *, size_t);
--- old/usr/src/lib/libbrand/common/mapfile-vers	Mon Oct 25 15:54:20 2021
+++ new/usr/src/lib/libbrand/common/mapfile-vers	Mon Oct 25 15:54:20 2021
@@ -80,6 +80,8 @@
 	brand_platform_iter_link;
 	brand_platform_iter_mounts;
 	brand_restartinit;
+	brand_restartinit0;
+	brand_restartinitreboot;
     local:
 	*;
 };
--- old/usr/src/lib/libbrand/dtd/brand.dtd.1	Mon Oct 25 15:54:20 2021
+++ new/usr/src/lib/libbrand/dtd/brand.dtd.1	Mon Oct 25 15:54:20 2021
@@ -212,17 +212,36 @@
 <!ATTLIST initname>
 
 <!--
-  restartinit
+  restartinit, restartinit0 and restartinitreboot
 
-    Boolean indicating that the program specified by the initname attr
-    should be restarted, or not, if it exits.  By default, the init program
-    will be restarted if this attribute is not provided.  Specifying false
-    for this attr will prevent that.
+    These three boolean elements control what action is taken when the
+    program specified by the 'initname' element exits.
 
-    It has no attributes.
+    The default values are:
+
+        restartinit:       true
+        restartinit0:      false
+        restartinitreboot: false
+
+    If 'restartinit' is set to false then the init process will never be
+    restarted and the zone will shut down once init exits. In this case, the
+    other restartinit elements are ignored.
+
+    When 'restartinit0' is set, init will only be restarted if it exited with
+    an exit status of 0, otherwise the zone will shut down.
+
+    If 'restartinitreboot' is set to true then whenever init should be
+    restarted, based on the other restartinit elements, the zone will instead
+    be rebooted.
+
+    These have no attributes.
 -->
 <!ELEMENT restartinit	(#PCDATA) >
 <!ATTLIST restartinit>
+<!ELEMENT restartinit0	(#PCDATA) >
+<!ATTLIST restartinit0>
+<!ELEMENT restartinitreboot	(#PCDATA) >
+<!ATTLIST restartinitreboot>
 
 <!--
   login_cmd
@@ -627,7 +646,7 @@
 
 -->
 <!ELEMENT privilege	(#PCDATA) >
-<!ATTLIST privilege	set	( default | prohibited | required ) #REQUIRED 
+<!ATTLIST privilege	set	( default | prohibited | required ) #REQUIRED
 			name	CDATA #REQUIRED
 			ip-type ( shared | exclusive ) "all" >
 
@@ -642,7 +661,9 @@
 		directory in which the configuration file is stored.
 -->
 
-<!ELEMENT brand		(modname?, initname, restartinit?, login_cmd,
+<!ELEMENT brand		(modname?, initname, restartinit?,
+			restartinit0?, restartinitreboot?,
+			login_cmd,
 			forcedlogin_cmd, user_cmd, install,
 			installopts?, boot?, sysboot?, halt?, shutdown?,
 			verify_cfg?, verify_adm?, postattach?, postclone?,
--- old/usr/src/test/zfs-tests/tests/functional/removal/remove_raidz.ksh	Mon Oct 25 15:54:21 2021
+++ new/usr/src/test/zfs-tests/tests/functional/removal/remove_raidz.ksh	Mon Oct 25 15:54:21 2021
@@ -25,7 +25,9 @@
 log_must mkfile $MINVDEVSIZE $TMPDIR/dsk1
 log_must mkfile $MINVDEVSIZE $TMPDIR/dsk2
 log_must mkfile $MINVDEVSIZE $TMPDIR/dsk3
-DISKS="$TMPDIR/dsk1 raidz $TMPDIR/dsk2 $TMPDIR/dsk3"
+DISKS1="$TMPDIR/dsk1"
+DISKS2="$TMPDIR/dsk2 $TMPDIR/dsk3"
+DISKS="$DISKS1 $DISKS2"
 
 function cleanup
 {
@@ -33,7 +35,7 @@
 	log_must rm -f $DISKS
 }
 
-log_must default_setup_noexit "$DISKS"
+log_must default_setup_noexit "$DISKS1 raidz $DISKS2"
 log_onexit cleanup
 
 # Attempt to remove the non raidz disk.
--- old/usr/src/uts/common/os/exit.c	Mon Oct 25 15:54:21 2021
+++ new/usr/src/uts/common/os/exit.c	Mon Oct 25 15:54:21 2021
@@ -166,7 +166,7 @@
  * it failed.  As long as the given zone is still in the "running"
  * state, we will re-exec() init, but first we need to reset things
  * which are usually inherited across exec() but will break init's
- * assumption that it is being exec()'d from a virgin process.  Most
+ * assumption that it is being exec()'d from a virgin process.	Most
  * importantly this includes closing all file descriptors (exec only
  * closes those marked close-on-exec) and resetting signals (exec only
  * resets handled signals, and we need to clear any signals which
@@ -343,7 +343,7 @@
 	/*
 	 * If proc_exit() fails, then some other lwp in the process
 	 * got there first.  We just have to call lwp_exit() to allow
-	 * the other lwp to finish exiting the process.  Otherwise we're
+	 * the other lwp to finish exiting the process.	 Otherwise we're
 	 * restarting init, and should return.
 	 */
 	if (proc_exit(why, what) != 0) {
@@ -356,7 +356,7 @@
 
 /*
  * Set the SEXITING flag on the process, after making sure /proc does
- * not have it locked.  This is done in more places than proc_exit(),
+ * not have it locked.	This is done in more places than proc_exit(),
  * so it is a separate function.
  */
 void
@@ -471,9 +471,9 @@
 		}
 	}
 
-
 	/*
-	 * The restart failed, the zone will shut down.
+	 * The restart failed, or the criteria for a restart are not met;
+	 * the zone will shut down.
 	 */
 	z->zone_init_status = wstat(why, what);
 	(void) zone_kadmin(A_SHUTDOWN, AD_HALT, NULL, zone_kcred());
@@ -510,7 +510,7 @@
 
 	/*
 	 * Stop and discard the process's lwps except for the current one,
-	 * unless some other lwp beat us to it.  If exitlwps() fails then
+	 * unless some other lwp beat us to it.	 If exitlwps() fails then
 	 * return and the calling lwp will call (or continue in) lwp_exit().
 	 */
 	proc_is_exiting(p);
@@ -528,6 +528,13 @@
 	}
 	mutex_exit(&p->p_lock);
 
+	/*
+	 * Don't let init exit unless zone_start_init() failed its exec, or
+	 * we are shutting down the zone or the machine.
+	 *
+	 * Since we are single threaded, we don't need to lock the
+	 * following accesses to zone_proc_initpid.
+	 */
 	if (p->p_pid == z->zone_proc_initpid) {
 		/* If zone's init restarts, we're done here. */
 		if (zone_init_exit(z, why, what))
@@ -1005,7 +1012,7 @@
 	 * curthread's proc pointer is changed to point to the 'sched'
 	 * process for the corresponding zone, except in the case when
 	 * the exiting process is in fact a zsched instance, in which
-	 * case the proc pointer is set to p0.  We do so, so that the
+	 * case the proc pointer is set to p0.	We do so, so that the
 	 * process still points at the right zone when we call the VN_RELE()
 	 * below.
 	 *
@@ -1089,7 +1096,7 @@
 	/*
 	 * task_rele() may ultimately cause the zone to go away (or
 	 * may cause the last user process in a zone to go away, which
-	 * signals zsched to go away).  So prior to this call, we must
+	 * signals zsched to go away).	So prior to this call, we must
 	 * no longer point at zsched.
 	 */
 	t->t_procp = &p0;
