Print this page
        
@@ -19,12 +19,12 @@
  * CDDL HEADER END
  */
 
 /*
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2016, Joyent Inc.
  * Copyright (c) 2015 by Delphix. All rights reserved.
+ * Copyright 2016, Joyent Inc.
  */
 
 /*
  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  */
@@ -134,13 +134,10 @@
         MNTOPT_RO "," MNTOPT_LOFS_NOSUB "," MNTOPT_NODEVICES
 
 #define DFSTYPES        "/etc/dfs/fstypes"
 #define MAXTNZLEN       2048
 
-/* Number of times to retry unmounting if it fails */
-#define UMOUNT_RETRIES  30
-
 /* a reasonable estimate for the number of lwps per process */
 #define LWPS_PER_PROCESS        10
 
 /* for routing socket */
 static int rts_seqno = 0;
@@ -178,11 +175,10 @@
 /* from libsocket, not in any header file */
 extern int getnetmaskbyaddr(struct in_addr, struct in_addr *);
 
 /* from zoneadmd */
 extern char query_hook[];
-extern char post_statechg_hook[];
 
 /*
  * For each "net" resource configured in zonecfg, we track a zone_addr_list_t
  * node in a linked list that is sorted by linkid.  The list is constructed as
  * the xml configuration file is parsed, and the information
@@ -215,11 +211,11 @@
 autofs_cleanup(zoneid_t zoneid)
 {
         /*
          * Ask autofs to unmount all trigger nodes in the given zone.
          */
-        return (_autofssys(AUTOFS_UNMOUNTALL, (void *)((uintptr_t)zoneid)));
+        return (_autofssys(AUTOFS_UNMOUNTALL, (void *)zoneid));
 }
 
 static void
 free_mnttable(struct mnttab *mnt_array, uint_t nelem)
 {
@@ -606,28 +602,10 @@
                 resolve_lofs(zlogp, zroot, zrootlen);
         (void) strcpy(strrchr(zroot, '/') + 1, "lu");
 }
 
 /*
- * Perform brand-specific cleanup if we are unable to unmount a FS.
- */
-static void
-brand_umount_cleanup(zlog_t *zlogp, char *path)
-{
-        char cmdbuf[2 * MAXPATHLEN];
-
-        if (post_statechg_hook[0] == '\0')
-                return;
-
-        if (snprintf(cmdbuf, sizeof (cmdbuf), "%s %d %d %s", post_statechg_hook,
-            ZONE_STATE_DOWN, Z_UNMOUNT, path) > sizeof (cmdbuf))
-                return;
-
-        (void) do_subproc(zlogp, cmdbuf, NULL, B_FALSE);
-}
-
-/*
  * The general strategy for unmounting filesystems is as follows:
  *
  * - Remote filesystems may be dead, and attempting to contact them as
  * part of a regular unmount may hang forever; we want to always try to
  * forcibly unmount such filesystems and only fall back to regular
@@ -656,11 +634,10 @@
  */
 static int
 unmount_filesystems(zlog_t *zlogp, zoneid_t zoneid, boolean_t unmount_cmd)
 {
         int error = 0;
-        int fail = 0;
         FILE *mnttab;
         struct mnttab *mnts;
         uint_t nmnt;
         char zroot[MAXPATHLEN + 1];
         size_t zrootlen;
@@ -744,45 +721,24 @@
                          */
                         if (stuck) {
                                 if (umount2(path, MS_FORCE) == 0) {
                                         unmounted = B_TRUE;
                                         stuck = B_FALSE;
-                                        fail = 0;
                                 } else {
                                         /*
-                                         * We may hit a failure here if there
-                                         * is an app in the GZ with an open
-                                         * pipe into the zone (commonly into
-                                         * the zone's /var/run).  This type
-                                         * of app will notice the closed
-                                         * connection and cleanup, but it may
-                                         * take a while and we have no easy
-                                         * way to notice that.  To deal with
-                                         * this case, we will wait and retry
-                                         * a few times before we give up.
+                                         * The first failure indicates a
+                                         * mount we won't be able to get
+                                         * rid of automatically, so we
+                                         * bail.
                                          */
-                                        fail++;
-                                        if (fail < (UMOUNT_RETRIES - 1)) {
-                                                zerror(zlogp, B_FALSE,
-                                                    "unable to unmount '%s', "
-                                                    "retrying in 2 seconds",
-                                                    path);
-                                                (void) sleep(2);
-                                        } else if (fail > UMOUNT_RETRIES) {
                                                 error++;
                                                 zerror(zlogp, B_FALSE,
-                                                    "unmount of '%s' failed",
-                                                    path);
+                                            "unable to unmount '%s'", path);
                                                 free_mnttable(mnts, nmnt);
                                                 goto out;
-                                        } else {
-                                                /* Try the hook 2 times */
-                                                brand_umount_cleanup(zlogp,
-                                                    path);
                                         }
                                 }
-                        }
                         /*
                          * Try regular unmounts for everything else.
                          */
                         if (!unmounted && umount2(path, 0) != 0)
                                 newcount++;
@@ -1114,14 +1070,27 @@
 }
 
 int
 vplat_get_iptype(zlog_t *zlogp, zone_iptype_t *iptypep)
 {
-        if (zonecfg_get_iptype(snap_hndl, iptypep) != Z_OK) {
+        zone_dochandle_t handle;
+
+        if ((handle = zonecfg_init_handle()) == NULL) {
+                zerror(zlogp, B_TRUE, "getting zone configuration handle");
+                return (-1);
+        }
+        if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) {
+                zerror(zlogp, B_FALSE, "invalid configuration");
+                zonecfg_fini_handle(handle);
+                return (-1);
+        }
+        if (zonecfg_get_iptype(handle, iptypep) != Z_OK) {
                 zerror(zlogp, B_FALSE, "invalid ip-type configuration");
+                zonecfg_fini_handle(handle);
                 return (-1);
         }
+        zonecfg_fini_handle(handle);
         return (0);
 }
 
 /*
  * Apply the standard lists of devices/symlinks/mappings and the user-specified
@@ -1130,17 +1099,18 @@
  */
 static int
 mount_one_dev(zlog_t *zlogp, char *devpath, zone_mnt_t mount_cmd)
 {
         char                    brand[MAXNAMELEN];
+        zone_dochandle_t        handle = NULL;
         brand_handle_t          bh = NULL;
         struct zone_devtab      ztab;
         di_prof_t               prof = NULL;
         int                     err;
         int                     retval = -1;
         zone_iptype_t           iptype;
-        const char              *curr_iptype = NULL;
+        const char              *curr_iptype;
 
         if (di_prof_init(devpath, &prof)) {
                 zerror(zlogp, B_TRUE, "failed to initialize profile");
                 goto cleanup;
         }
@@ -1171,12 +1141,10 @@
                 break;
         case ZS_EXCLUSIVE:
                 curr_iptype = "exclusive";
                 break;
         }
-        if (curr_iptype == NULL)
-                abort();
 
         if (brand_platform_iter_devices(bh, zone_name,
             mount_one_dev_device_cb, prof, curr_iptype) != 0) {
                 zerror(zlogp, B_TRUE, "failed to add standard device");
                 goto cleanup;
@@ -1187,23 +1155,32 @@
                 zerror(zlogp, B_TRUE, "failed to add standard symlink");
                 goto cleanup;
         }
 
         /* Add user-specified devices and directories */
-        if ((err = zonecfg_setdevent(snap_hndl)) != 0) {
+        if ((handle = zonecfg_init_handle()) == NULL) {
+                zerror(zlogp, B_FALSE, "can't initialize zone handle");
+                goto cleanup;
+        }
+        if ((err = zonecfg_get_handle(zone_name, handle)) != 0) {
+                zerror(zlogp, B_FALSE, "can't get handle for zone "
+                    "%s: %s", zone_name, zonecfg_strerror(err));
+                goto cleanup;
+        }
+        if ((err = zonecfg_setdevent(handle)) != 0) {
                 zerror(zlogp, B_FALSE, "%s: %s", zone_name,
                     zonecfg_strerror(err));
                 goto cleanup;
         }
-        while (zonecfg_getdevent(snap_hndl, &ztab) == Z_OK) {
+        while (zonecfg_getdevent(handle, &ztab) == Z_OK) {
                 if (di_prof_add_dev(prof, ztab.zone_dev_match)) {
                         zerror(zlogp, B_TRUE, "failed to add "
                             "user-specified device");
                         goto cleanup;
                 }
         }
-        (void) zonecfg_enddevent(snap_hndl);
+        (void) zonecfg_enddevent(handle);
 
         /* Send profile to kernel */
         if (di_prof_commit(prof)) {
                 zerror(zlogp, B_TRUE, "failed to commit profile");
                 goto cleanup;
@@ -1212,10 +1189,12 @@
         retval = 0;
 
 cleanup:
         if (bh != NULL)
                 brand_close(bh);
+        if (handle != NULL)
+                zonecfg_fini_handle(handle);
         if (prof)
                 di_prof_fini(prof);
         return (retval);
 }
 
@@ -1705,10 +1684,11 @@
         char rootpath[MAXPATHLEN];
         char brand[MAXNAMELEN];
         char luroot[MAXPATHLEN];
         int i, num_fs = 0;
         struct zone_fstab *fs_ptr = NULL;
+        zone_dochandle_t handle = NULL;
         zone_state_t zstate;
         brand_handle_t bh;
         plat_gmount_cb_data_t cb;
 
         if (zone_get_state(zone_name, &zstate) != Z_OK ||
@@ -1723,11 +1703,16 @@
         if (zone_get_rootpath(zone_name, rootpath, sizeof (rootpath)) != Z_OK) {
                 zerror(zlogp, B_TRUE, "unable to determine zone root");
                 goto bad;
         }
 
-        if (zonecfg_setfsent(snap_hndl) != Z_OK) {
+        if ((handle = zonecfg_init_handle()) == NULL) {
+                zerror(zlogp, B_TRUE, "getting zone configuration handle");
+                goto bad;
+        }
+        if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK ||
+            zonecfg_setfsent(handle) != Z_OK) {
                 zerror(zlogp, B_FALSE, "invalid configuration");
                 goto bad;
         }
 
         /*
@@ -1741,10 +1726,11 @@
         }
 
         /* Get a handle to the brand info for this zone */
         if ((bh = brand_open(brand)) == NULL) {
                 zerror(zlogp, B_FALSE, "unable to determine zone brand");
+                zonecfg_fini_handle(handle);
                 return (-1);
         }
 
         /*
          * Get the list of global filesystems to mount from the brand
@@ -1755,10 +1741,11 @@
         cb.pgcd_num_fs = &num_fs;
         if (brand_platform_iter_gmounts(bh, zone_name, zonepath,
             plat_gmount_cb, &cb) != 0) {
                 zerror(zlogp, B_FALSE, "unable to mount filesystems");
                 brand_close(bh);
+                zonecfg_fini_handle(handle);
                 return (-1);
         }
         brand_close(bh);
 
         /*
@@ -1765,14 +1752,17 @@
          * Iterate through the rest of the filesystems. Sort them all,
          * then mount them in sorted order. This is to make sure the
          * higher level directories (e.g., /usr) get mounted before
          * any beneath them (e.g., /usr/local).
          */
-        if (mount_filesystems_fsent(snap_hndl, zlogp, &fs_ptr, &num_fs,
+        if (mount_filesystems_fsent(handle, zlogp, &fs_ptr, &num_fs,
             mount_cmd) != 0)
                 goto bad;
 
+        zonecfg_fini_handle(handle);
+        handle = NULL;
+
         /*
          * Normally when we mount a zone all the zone filesystems
          * get mounted relative to rootpath, which is usually
          * <zonepath>/root.  But when mounting a zone for administration
          * purposes via the zone "mount" state, build_mounted_pre_var()
@@ -1864,10 +1854,12 @@
          * Everything looks fine.
          */
         return (0);
 
 bad:
+        if (handle != NULL)
+                zonecfg_fini_handle(handle);
         free_fs_data(fs_ptr, num_fs);
         return (-1);
 }
 
 /* caller makes sure neither parameter is NULL */
@@ -2219,11 +2211,17 @@
         (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr));
 
         if (ioctl(s, SIOCLIFADDIF, (caddr_t)&lifr) < 0) {
                 /*
                  * Here, we know that the interface can't be brought up.
+                 * A similar warning message was already printed out to
+                 * the console by zoneadm(1M) so instead we log the
+                 * message to syslog and continue.
                  */
+                zerror(&logsys, B_TRUE, "WARNING: skipping network interface "
+                    "'%s' which may not be present/plumbed in the "
+                    "global zone.", lifr.lifr_name);
                 (void) close(s);
                 return (Z_OK);
         }
 
         /* Preserve literal IPv4 address for later potential printing. */
@@ -2432,31 +2430,42 @@
  * whatever we set up, and return an error.
  */
 static int
 configure_shared_network_interfaces(zlog_t *zlogp)
 {
+        zone_dochandle_t handle;
         struct zone_nwiftab nwiftab, loopback_iftab;
         zoneid_t zoneid;
 
         if ((zoneid = getzoneidbyname(zone_name)) == ZONE_ID_UNDEFINED) {
                 zerror(zlogp, B_TRUE, "unable to get zoneid");
                 return (-1);
         }
 
-        if (zonecfg_setnwifent(snap_hndl) == Z_OK) {
+        if ((handle = zonecfg_init_handle()) == NULL) {
+                zerror(zlogp, B_TRUE, "getting zone configuration handle");
+                return (-1);
+        }
+        if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) {
+                zerror(zlogp, B_FALSE, "invalid configuration");
+                zonecfg_fini_handle(handle);
+                return (-1);
+        }
+        if (zonecfg_setnwifent(handle) == Z_OK) {
                 for (;;) {
-                        if (zonecfg_getnwifent(snap_hndl, &nwiftab) != Z_OK)
+                        if (zonecfg_getnwifent(handle, &nwiftab) != Z_OK)
                                 break;
-                        nwifent_free_attrs(&nwiftab);
                         if (configure_one_interface(zlogp, zoneid, &nwiftab) !=
                             Z_OK) {
-                                (void) zonecfg_endnwifent(snap_hndl);
+                                (void) zonecfg_endnwifent(handle);
+                                zonecfg_fini_handle(handle);
                                 return (-1);
                         }
                 }
-                (void) zonecfg_endnwifent(snap_hndl);
+                (void) zonecfg_endnwifent(handle);
         }
+        zonecfg_fini_handle(handle);
         if (is_system_labeled()) {
                 /*
                  * Labeled zones share the loopback interface
                  * so it is not plumbed for shared stack instances.
                  */
@@ -2899,45 +2908,78 @@
                 free(new);
         }
 }
 
 /*
+ * For IP networking, we need to use the illumos-native device tree.  For most
+ * zones, this is $ZONEROOT/dev.  For LX ones, it's $ZONEROOT/native/dev.
+ * Return the appropriate post-$ZONEROOT path.
+ */
+static char *
+get_brand_dev(void)
+{
+        static char *lxpath = "/native/dev";
+        /* Cheesy hard-coding of strlen("/native") */
+        char *default_path = lxpath + 7;
+
+        /* LX zones are the exception... */
+        if (strcmp(brand_name, "lx") == 0)
+                return (lxpath);
+
+        return (default_path);
+}
+
+/*
  * Add the kernel access control information for the interface names.
  * If anything goes wrong, we log a general error message, attempt to tear down
  * whatever we set up, and return an error.
  */
 static int
 configure_exclusive_network_interfaces(zlog_t *zlogp, zoneid_t zoneid)
 {
+        zone_dochandle_t handle;
         struct zone_nwiftab nwiftab;
         char rootpath[MAXPATHLEN];
         char path[MAXPATHLEN];
         datalink_id_t linkid;
         di_prof_t prof = NULL;
         boolean_t added = B_FALSE;
         zone_addr_list_t *zalist = NULL, *new;
 
-        if (zonecfg_setnwifent(snap_hndl) != Z_OK)
+        if ((handle = zonecfg_init_handle()) == NULL) {
+                zerror(zlogp, B_TRUE, "getting zone configuration handle");
+                return (-1);
+        }
+        if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) {
+                zerror(zlogp, B_FALSE, "invalid configuration");
+                zonecfg_fini_handle(handle);
+                return (-1);
+        }
+
+        if (zonecfg_setnwifent(handle) != Z_OK) {
+                zonecfg_fini_handle(handle);
                 return (0);
+        }
 
         for (;;) {
-                if (zonecfg_getnwifent(snap_hndl, &nwiftab) != Z_OK)
+                if (zonecfg_getnwifent(handle, &nwiftab) != Z_OK)
                         break;
 
-                nwifent_free_attrs(&nwiftab);
                 if (prof == NULL) {
                         if (zone_get_devroot(zone_name, rootpath,
                             sizeof (rootpath)) != Z_OK) {
-                                (void) zonecfg_endnwifent(snap_hndl);
+                                (void) zonecfg_endnwifent(handle);
+                                zonecfg_fini_handle(handle);
                                 zerror(zlogp, B_TRUE,
                                     "unable to determine dev root");
                                 return (-1);
                         }
                         (void) snprintf(path, sizeof (path), "%s%s", rootpath,
-                            "/dev");
+                            get_brand_dev());
                         if (di_prof_init(path, &prof) != 0) {
-                                (void) zonecfg_endnwifent(snap_hndl);
+                                (void) zonecfg_endnwifent(handle);
+                                zonecfg_fini_handle(handle);
                                 zerror(zlogp, B_TRUE,
                                     "failed to initialize profile");
                                 return (-1);
                         }
                 }
@@ -2957,38 +2999,40 @@
                     &linkid, NULL, NULL, NULL) == DLADM_STATUS_OK &&
                     add_datalink(zlogp, zone_name, linkid,
                     nwiftab.zone_nwif_physical) == 0) {
                         added = B_TRUE;
                 } else {
-                        /*
-                         * Failed to add network device, but the brand hook
-                         * might be doing this for us, so keep silent.
-                         */
-                        continue;
+                        (void) zonecfg_endnwifent(handle);
+                        zonecfg_fini_handle(handle);
+                        zerror(zlogp, B_TRUE, "failed to add network device");
+                        return (-1);
                 }
                 /* set up the new IP interface, and add them all later */
                 new = malloc(sizeof (*new));
                 if (new == NULL) {
                         zerror(zlogp, B_TRUE, "no memory for %s",
                             nwiftab.zone_nwif_physical);
+                        zonecfg_fini_handle(handle);
                         free_ip_interface(zalist);
                 }
                 bzero(new, sizeof (*new));
                 new->za_nwiftab = nwiftab;
                 new->za_linkid = linkid;
                 zalist = add_ip_interface(zalist, new);
         }
         if (zalist != NULL) {
                 if ((errno = add_net(zlogp, zoneid, zalist)) != 0) {
-                        (void) zonecfg_endnwifent(snap_hndl);
+                        (void) zonecfg_endnwifent(handle);
+                        zonecfg_fini_handle(handle);
                         zerror(zlogp, B_TRUE, "failed to add address");
                         free_ip_interface(zalist);
                         return (-1);
                 }
                 free_ip_interface(zalist);
         }
-        (void) zonecfg_endnwifent(snap_hndl);
+        (void) zonecfg_endnwifent(handle);
+        zonecfg_fini_handle(handle);
 
         if (prof != NULL && added) {
                 if (di_prof_commit(prof) != 0) {
                         zerror(zlogp, B_TRUE, "failed to commit profile");
                         return (-1);
@@ -3120,27 +3164,52 @@
                     "protection", NULL, 0, DLADM_OPT_ACTIVE);
                 if (dlstatus == DLADM_STATUS_NOTFOUND) {
                         /* datalink does not belong to the GZ */
                         continue;
                 }
-                if (dlstatus != DLADM_STATUS_OK)
+                if (dlstatus != DLADM_STATUS_OK) {
                         zerror(zlogp, B_FALSE,
-                            "clear 'protection' link property: %s",
                             dladm_status2str(dlstatus, dlerr));
-
+                        free(dllinks);
+                        return (-1);
+                }
                 dlstatus = dladm_set_linkprop(dld_handle, *dllink,
                     "allowed-ips", NULL, 0, DLADM_OPT_ACTIVE);
-                if (dlstatus != DLADM_STATUS_OK)
+                if (dlstatus != DLADM_STATUS_OK) {
                         zerror(zlogp, B_FALSE,
-                            "clear 'allowed-ips' link property: %s",
                             dladm_status2str(dlstatus, dlerr));
+                        free(dllinks);
+                        return (-1);
         }
+        }
         free(dllinks);
         return (0);
 }
 
 static int
+unconfigure_exclusive_network_interfaces(zlog_t *zlogp, zoneid_t zoneid)
+{
+        int dlnum = 0;
+
+        /*
+         * The kernel shutdown callback for the dls module should have removed
+         * all datalinks from this zone.  If any remain, then there's a
+         * problem.
+         */
+        if (zone_list_datalink(zoneid, &dlnum, NULL) != 0) {
+                zerror(zlogp, B_TRUE, "unable to list network interfaces");
+                return (-1);
+        }
+        if (dlnum != 0) {
+                zerror(zlogp, B_FALSE,
+                    "datalinks remain in zone after shutdown");
+                return (-1);
+        }
+        return (0);
+}
+
+static int
 tcp_abort_conn(zlog_t *zlogp, zoneid_t zoneid,
     const struct sockaddr_storage *local, const struct sockaddr_storage *remote)
 {
         int fd;
         struct strioctl ioc;
@@ -3218,18 +3287,30 @@
 
 static int
 get_privset(zlog_t *zlogp, priv_set_t *privs, zone_mnt_t mount_cmd)
 {
         int error = -1;
+        zone_dochandle_t handle;
         char *privname = NULL;
 
+        if ((handle = zonecfg_init_handle()) == NULL) {
+                zerror(zlogp, B_TRUE, "getting zone configuration handle");
+                return (-1);
+        }
+        if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) {
+                zerror(zlogp, B_FALSE, "invalid configuration");
+                zonecfg_fini_handle(handle);
+                return (-1);
+        }
+
         if (ALT_MOUNT(mount_cmd)) {
                 zone_iptype_t   iptype;
-                const char      *curr_iptype = NULL;
+                const char      *curr_iptype;
 
-                if (zonecfg_get_iptype(snap_hndl, &iptype) != Z_OK) {
+                if (zonecfg_get_iptype(handle, &iptype) != Z_OK) {
                         zerror(zlogp, B_TRUE, "unable to determine ip-type");
+                        zonecfg_fini_handle(handle);
                         return (-1);
                 }
 
                 switch (iptype) {
                 case ZS_SHARED:
@@ -3238,19 +3319,21 @@
                 case ZS_EXCLUSIVE:
                         curr_iptype = "exclusive";
                         break;
                 }
 
-                if (zonecfg_default_privset(privs, curr_iptype) == Z_OK)
+                if (zonecfg_default_privset(privs, curr_iptype) == Z_OK) {
+                        zonecfg_fini_handle(handle);
                         return (0);
-
+                }
                 zerror(zlogp, B_FALSE,
                     "failed to determine the zone's default privilege set");
+                zonecfg_fini_handle(handle);
                 return (-1);
         }
 
-        switch (zonecfg_get_privset(snap_hndl, privs, &privname)) {
+        switch (zonecfg_get_privset(handle, privs, &privname)) {
         case Z_OK:
                 error = 0;
                 break;
         case Z_PRIV_PROHIBITED:
                 zerror(zlogp, B_FALSE, "privilege \"%s\" is not permitted "
@@ -3269,10 +3352,11 @@
                     "privilege set");
                 break;
         }
 
         free(privname);
+        zonecfg_fini_handle(handle);
         return (error);
 }
 
 static char *
 zone_proj_rctl(const char *name)
@@ -3294,19 +3378,30 @@
         char *nvl_packed = NULL;
         size_t nvl_size = 0;
         nvlist_t **nvlv = NULL;
         int rctlcount = 0;
         int error = -1;
+        zone_dochandle_t handle;
         struct zone_rctltab rctltab;
         rctlblk_t *rctlblk = NULL;
         uint64_t maxlwps;
         uint64_t maxprocs;
         int rproc, rlwp;
 
         *bufp = NULL;
         *bufsizep = 0;
 
+        if ((handle = zonecfg_init_handle()) == NULL) {
+                zerror(zlogp, B_TRUE, "getting zone configuration handle");
+                return (-1);
+        }
+        if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) {
+                zerror(zlogp, B_FALSE, "invalid configuration");
+                zonecfg_fini_handle(handle);
+                return (-1);
+        }
+
         rctltab.zone_rctl_valptr = NULL;
         if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
                 zerror(zlogp, B_TRUE, "%s failed", "nvlist_alloc");
                 goto out;
         }
@@ -3335,20 +3430,20 @@
                             "unable to set max-processes alias");
                         goto out;
                 }
         }
 
-        if (zonecfg_setrctlent(snap_hndl) != Z_OK) {
+        if (zonecfg_setrctlent(handle) != Z_OK) {
                 zerror(zlogp, B_FALSE, "%s failed", "zonecfg_setrctlent");
                 goto out;
         }
 
         if ((rctlblk = malloc(rctlblk_size())) == NULL) {
                 zerror(zlogp, B_TRUE, "memory allocation failed");
                 goto out;
         }
-        while (zonecfg_getrctlent(snap_hndl, &rctltab) == Z_OK) {
+        while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) {
                 struct zone_rctlvaltab *rctlval;
                 uint_t i, count;
                 const char *name = rctltab.zone_rctl_name;
                 char *proj_nm;
 
@@ -3447,11 +3542,11 @@
                         nvlist_free(nvlv[i]);
                 free(nvlv);
                 nvlv = NULL;
                 rctlcount++;
         }
-        (void) zonecfg_endrctlent(snap_hndl);
+        (void) zonecfg_endrctlent(handle);
 
         if (rctlcount == 0) {
                 error = 0;
                 goto out;
         }
@@ -3471,10 +3566,12 @@
         if (error && nvl_packed != NULL)
                 free(nvl_packed);
         nvlist_free(nvl);
         if (nvlv != NULL)
                 free(nvlv);
+        if (handle != NULL)
+                zonecfg_fini_handle(handle);
         return (error);
 }
 
 static int
 get_implicit_datasets(zlog_t *zlogp, char **retstr)
@@ -3486,19 +3583,20 @@
 
         if (snprintf(cmdbuf, sizeof (cmdbuf), "%s datasets", query_hook)
             > sizeof (cmdbuf))
                 return (-1);
 
-        if (do_subproc(zlogp, cmdbuf, retstr, B_FALSE) != 0)
+        if (do_subproc(zlogp, cmdbuf, retstr) != 0)
                 return (-1);
 
         return (0);
 }
 
 static int
 get_datasets(zlog_t *zlogp, char **bufp, size_t *bufsizep)
 {
+        zone_dochandle_t handle;
         struct zone_dstab dstab;
         size_t total, offset, len;
         int error = -1;
         char *str = NULL;
         char *implicit_datasets = NULL;
@@ -3505,24 +3603,34 @@
         int implicit_len = 0;
 
         *bufp = NULL;
         *bufsizep = 0;
 
+        if ((handle = zonecfg_init_handle()) == NULL) {
+                zerror(zlogp, B_TRUE, "getting zone configuration handle");
+                return (-1);
+        }
+        if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) {
+                zerror(zlogp, B_FALSE, "invalid configuration");
+                zonecfg_fini_handle(handle);
+                return (-1);
+        }
+
         if (get_implicit_datasets(zlogp, &implicit_datasets) != 0) {
                 zerror(zlogp, B_FALSE, "getting implicit datasets failed");
                 goto out;
         }
 
-        if (zonecfg_setdsent(snap_hndl) != Z_OK) {
+        if (zonecfg_setdsent(handle) != Z_OK) {
                 zerror(zlogp, B_FALSE, "%s failed", "zonecfg_setdsent");
                 goto out;
         }
 
         total = 0;
-        while (zonecfg_getdsent(snap_hndl, &dstab) == Z_OK)
+        while (zonecfg_getdsent(handle, &dstab) == Z_OK)
                 total += strlen(dstab.zone_dataset_name) + 1;
-        (void) zonecfg_enddsent(snap_hndl);
+        (void) zonecfg_enddsent(handle);
 
         if (implicit_datasets != NULL)
                 implicit_len = strlen(implicit_datasets);
         if (implicit_len > 0)
                 total += implicit_len + 1;
@@ -3535,24 +3643,24 @@
         if ((str = malloc(total)) == NULL) {
                 zerror(zlogp, B_TRUE, "memory allocation failed");
                 goto out;
         }
 
-        if (zonecfg_setdsent(snap_hndl) != Z_OK) {
+        if (zonecfg_setdsent(handle) != Z_OK) {
                 zerror(zlogp, B_FALSE, "%s failed", "zonecfg_setdsent");
                 goto out;
         }
         offset = 0;
-        while (zonecfg_getdsent(snap_hndl, &dstab) == Z_OK) {
+        while (zonecfg_getdsent(handle, &dstab) == Z_OK) {
                 len = strlen(dstab.zone_dataset_name);
                 (void) strlcpy(str + offset, dstab.zone_dataset_name,
                     total - offset);
                 offset += len;
                 if (offset < total - 1)
                         str[offset++] = ',';
         }
-        (void) zonecfg_enddsent(snap_hndl);
+        (void) zonecfg_enddsent(handle);
 
         if (implicit_len > 0)
                 (void) strlcpy(str + offset, implicit_datasets, total - offset);
 
         error = 0;
@@ -3560,39 +3668,55 @@
         *bufsizep = total;
 
 out:
         if (error != 0 && str != NULL)
                 free(str);
+        if (handle != NULL)
+                zonecfg_fini_handle(handle);
         if (implicit_datasets != NULL)
                 free(implicit_datasets);
 
         return (error);
 }
 
 static int
 validate_datasets(zlog_t *zlogp)
 {
+        zone_dochandle_t handle;
         struct zone_dstab dstab;
         zfs_handle_t *zhp;
         libzfs_handle_t *hdl;
 
-        if (zonecfg_setdsent(snap_hndl) != Z_OK) {
+        if ((handle = zonecfg_init_handle()) == NULL) {
+                zerror(zlogp, B_TRUE, "getting zone configuration handle");
+                return (-1);
+        }
+        if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) {
                 zerror(zlogp, B_FALSE, "invalid configuration");
+                zonecfg_fini_handle(handle);
                 return (-1);
         }
 
+        if (zonecfg_setdsent(handle) != Z_OK) {
+                zerror(zlogp, B_FALSE, "invalid configuration");
+                zonecfg_fini_handle(handle);
+                return (-1);
+        }
+
         if ((hdl = libzfs_init()) == NULL) {
                 zerror(zlogp, B_FALSE, "opening ZFS library");
+                zonecfg_fini_handle(handle);
                 return (-1);
         }
 
-        while (zonecfg_getdsent(snap_hndl, &dstab) == Z_OK) {
+        while (zonecfg_getdsent(handle, &dstab) == Z_OK) {
 
                 if ((zhp = zfs_open(hdl, dstab.zone_dataset_name,
                     ZFS_TYPE_FILESYSTEM)) == NULL) {
                         zerror(zlogp, B_FALSE, "cannot open ZFS dataset '%s'",
                             dstab.zone_dataset_name);
+                        zonecfg_fini_handle(handle);
                         libzfs_fini(hdl);
                         return (-1);
                 }
 
                 /*
@@ -3603,19 +3727,21 @@
                     zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_ZONED),
                     "on") != 0) {
                         zerror(zlogp, B_FALSE, "cannot set 'zoned' "
                             "property for ZFS dataset '%s'\n",
                             dstab.zone_dataset_name);
+                        zonecfg_fini_handle(handle);
                         zfs_close(zhp);
                         libzfs_fini(hdl);
                         return (-1);
                 }
 
                 zfs_close(zhp);
         }
-        (void) zonecfg_enddsent(snap_hndl);
+        (void) zonecfg_enddsent(handle);
 
+        zonecfg_fini_handle(handle);
         libzfs_fini(hdl);
 
         return (0);
 }
 
@@ -4348,14 +4474,26 @@
 setup_zone_rm(zlog_t *zlogp, char *zone_name, zoneid_t zoneid)
 {
         int res;
         uint64_t tmp;
         char sched[MAXNAMELEN];
+        zone_dochandle_t handle = NULL;
         char pool_err[128];
 
+        if ((handle = zonecfg_init_handle()) == NULL) {
+                zerror(zlogp, B_TRUE, "getting zone configuration handle");
+                return (Z_BAD_HANDLE);
+        }
+
+        if ((res = zonecfg_get_snapshot_handle(zone_name, handle)) != Z_OK) {
+                zerror(zlogp, B_FALSE, "invalid configuration");
+                zonecfg_fini_handle(handle);
+                return (res);
+        }
+
         /* Get the scheduling class set in the zone configuration. */
-        if (zonecfg_get_sched_class(snap_hndl, sched, sizeof (sched)) == Z_OK &&
+        if (zonecfg_get_sched_class(handle, sched, sizeof (sched)) == Z_OK &&
             strlen(sched) > 0) {
                 if (zone_setattr(zoneid, ZONE_ATTR_SCHED_CLASS, sched,
                     strlen(sched)) == -1)
                         zerror(zlogp, B_TRUE, "WARNING: unable to set the "
                             "default scheduling class");
@@ -4396,11 +4534,11 @@
                  * in by default so we can print a warning and modify the class
                  * if we wouldn't be using FSS.
                  */
                 char class_name[PC_CLNMSZ];
 
-                if (zonecfg_get_dflt_sched_class(snap_hndl, class_name,
+                if (zonecfg_get_dflt_sched_class(handle, class_name,
                     sizeof (class_name)) != Z_OK) {
                         zerror(zlogp, B_FALSE, "WARNING: unable to determine "
                             "the zone's scheduling class");
 
                 } else if (strcmp("FSS", class_name) != 0) {
@@ -4429,36 +4567,37 @@
          * If we are rebooting we want to attempt to reuse any temporary pool
          * that was previously set up.  zonecfg_bind_tmp_pool() will do the
          * right thing in all cases (reuse or create) based on the current
          * zonecfg.
          */
-        if ((res = zonecfg_bind_tmp_pool(snap_hndl, zoneid, pool_err,
+        if ((res = zonecfg_bind_tmp_pool(handle, zoneid, pool_err,
             sizeof (pool_err))) != Z_OK) {
                 if (res == Z_POOL || res == Z_POOL_CREATE || res == Z_POOL_BIND)
                         zerror(zlogp, B_FALSE, "%s: %s\ndedicated-cpu setting "
                             "cannot be instantiated", zonecfg_strerror(res),
                             pool_err);
                 else
                         zerror(zlogp, B_FALSE, "could not bind zone to "
                             "temporary pool: %s", zonecfg_strerror(res));
+                zonecfg_fini_handle(handle);
                 return (Z_POOL_BIND);
         }
 
         /*
          * Check if we need to warn about poold not being enabled.
          */
-        if (zonecfg_warn_poold(snap_hndl)) {
+        if (zonecfg_warn_poold(handle)) {
                 zerror(zlogp, B_FALSE, "WARNING: A range of dedicated-cpus has "
                     "been specified\nbut the dynamic pool service is not "
                     "enabled.\nThe system will not dynamically adjust the\n"
                     "processor allocation within the specified range\n"
                     "until svc:/system/pools/dynamic is enabled.\n"
                     "See poold(1M).");
         }
 
         /* The following is a warning, not an error. */
-        if ((res = zonecfg_bind_pool(snap_hndl, zoneid, pool_err,
+        if ((res = zonecfg_bind_pool(handle, zoneid, pool_err,
             sizeof (pool_err))) != Z_OK) {
                 if (res == Z_POOL_BIND)
                         zerror(zlogp, B_FALSE, "WARNING: unable to bind to "
                             "pool '%s'; using default pool.", pool_err);
                 else if (res == Z_POOL)
@@ -4468,13 +4607,14 @@
                         zerror(zlogp, B_FALSE, "WARNING: %s",
                             zonecfg_strerror(res));
         }
 
         /* Update saved pool name in case it has changed */
-        (void) zonecfg_get_poolname(snap_hndl, zone_name, pool_name,
+        (void) zonecfg_get_poolname(handle, zone_name, pool_name,
             sizeof (pool_name));
 
+        zonecfg_fini_handle(handle);
         return (Z_OK);
 }
 
 static void
 report_prop_err(zlog_t *zlogp, const char *name, const char *value, int res)
@@ -4571,32 +4711,37 @@
 
         return (Z_OK);
 }
 
 static int
-setup_zone_attrs(zlog_t *zlogp, zoneid_t zoneid)
+setup_zone_attrs(zlog_t *zlogp, char *zone_namep, zoneid_t zoneid)
 {
+        zone_dochandle_t handle;
         int res = Z_OK;
 
-        if ((res = setup_zone_hostid(snap_hndl, zlogp, zoneid)) != Z_OK)
+        if ((handle = zonecfg_init_handle()) == NULL) {
+                zerror(zlogp, B_TRUE, "getting zone configuration handle");
+                return (Z_BAD_HANDLE);
+        }
+        if ((res = zonecfg_get_snapshot_handle(zone_namep, handle)) != Z_OK) {
+                zerror(zlogp, B_FALSE, "invalid configuration");
                 goto out;
+        }
 
-        if ((res = setup_zone_fs_allowed(snap_hndl, zlogp, zoneid)) != Z_OK)
+        if ((res = setup_zone_hostid(handle, zlogp, zoneid)) != Z_OK)
                 goto out;
 
+        if ((res = setup_zone_fs_allowed(handle, zlogp, zoneid)) != Z_OK)
+                goto out;
+
 out:
+        zonecfg_fini_handle(handle);
         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, zoneid_t zone_did)
+vplat_create(zlog_t *zlogp, zone_mnt_t mount_cmd)
 {
         zoneid_t rval = -1;
         priv_set_t *privs;
         char rootpath[MAXPATHLEN];
         char *rctlbuf = NULL;
@@ -4608,11 +4753,11 @@
         char *kzone;
         FILE *fp = NULL;
         tsol_zcent_t *zcent = NULL;
         int match = 0;
         int doi = 0;
-        int flags = -1;
+        int flags;
         zone_iptype_t iptype;
 
         if (zone_get_rootpath(zone_name, rootpath, sizeof (rootpath)) != Z_OK) {
                 zerror(zlogp, B_TRUE, "unable to determine zone root");
                 return (-1);
@@ -4630,12 +4775,10 @@
                 break;
         case ZS_EXCLUSIVE:
                 flags = ZCF_NET_EXCL;
                 break;
         }
-        if (flags == -1)
-                abort();
 
         if ((privs = priv_allocset()) == NULL) {
                 zerror(zlogp, B_TRUE, "%s failed", "priv_allocset");
                 return (-1);
         }
@@ -4735,11 +4878,11 @@
         }
 
         xerr = 0;
         if ((zoneid = zone_create(kzone, rootpath, privs, rctlbuf,
             rctlbufsz, zfsbuf, zfsbufsz, &xerr, match, doi, zlabel,
-            flags, zone_did)) == -1) {
+            flags)) == -1) {
                 if (xerr == ZE_AREMOUNTS) {
                         if (zonecfg_find_mounts(rootpath, NULL, NULL) < 1) {
                                 zerror(zlogp, B_FALSE,
                                     "An unknown file-system is mounted on "
                                     "a subdirectory of %s", rootpath);
@@ -4781,11 +4924,11 @@
         if (mount_cmd == Z_MNT_BOOT) {
                 brand_handle_t bh;
                 struct brand_attr attr;
                 char modname[MAXPATHLEN];
 
-                if (setup_zone_attrs(zlogp, zoneid) != Z_OK)
+                if (setup_zone_attrs(zlogp, zone_name, zoneid) != Z_OK)
                         goto error;
 
                 if ((bh = brand_open(brand_name)) == NULL) {
                         zerror(zlogp, B_FALSE,
                             "unable to determine brand name");
@@ -4839,12 +4982,10 @@
                 (void) zone_shutdown(zoneid);
                 (void) zone_destroy(zoneid);
         }
         if (rctlbuf != NULL)
                 free(rctlbuf);
-        if (zfsbuf != NULL)
-                free(zfsbuf);
         priv_freeset(privs);
         if (fp != NULL)
                 zonecfg_close_scratch(fp);
         lofs_discard_mnttab();
         if (zcent != NULL)
@@ -4979,12 +5120,10 @@
                             0) {
                                 lofs_discard_mnttab();
                                 return (-1);
                         }
                         break;
-                default:
-                        abort();
                 }
         }
 
         write_index_file(zoneid);
 
@@ -5056,12 +5195,11 @@
                 return (0);
         }
 }
 
 int
-vplat_teardown(zlog_t *zlogp, boolean_t unmount_cmd, boolean_t rebooting,
-    boolean_t debug)
+vplat_teardown(zlog_t *zlogp, boolean_t unmount_cmd, boolean_t rebooting)
 {
         char *kzone;
         zoneid_t zoneid;
         int res;
         char pool_err[128];
@@ -5095,16 +5233,20 @@
                 if (unmount_cmd)
                         (void) lu_root_teardown(zlogp);
                 goto error;
         }
 
-        if (remove_datalink_pool(zlogp, zoneid) != 0)
+        if (remove_datalink_pool(zlogp, zoneid) != 0) {
                 zerror(zlogp, B_FALSE, "unable clear datalink pool property");
+                goto error;
+        }
 
-        if (remove_datalink_protect(zlogp, zoneid) != 0)
+        if (remove_datalink_protect(zlogp, zoneid) != 0) {
                 zerror(zlogp, B_FALSE,
                     "unable clear datalink protect property");
+                goto error;
+        }
 
         /*
          * The datalinks assigned to the zone will be removed from the NGZ as
          * part of zone_shutdown() so that we need to remove protect/pool etc.
          * before zone_shutdown(). Even if the shutdown itself fails, the zone
@@ -5134,11 +5276,11 @@
                 goto error;
         }
         brand_close(bh);
 
         if ((strlen(cmdbuf) > EXEC_LEN) &&
-            (do_subproc(zlogp, cmdbuf, NULL, debug) != Z_OK)) {
+            (do_subproc(zlogp, cmdbuf, NULL) != Z_OK)) {
                 zerror(zlogp, B_FALSE, "%s failed", cmdbuf);
                 goto error;
         }
 
         if (!unmount_cmd) {
@@ -5166,10 +5308,16 @@
                                     "network interfaces in zone");
                                 goto error;
                         }
                         break;
                 case ZS_EXCLUSIVE:
+                        if (unconfigure_exclusive_network_interfaces(zlogp,
+                            zoneid) != 0) {
+                                zerror(zlogp, B_FALSE, "unable to unconfigure "
+                                    "network interfaces in zone");
+                                goto error;
+                        }
                         status = dladm_zone_halt(dld_handle, zoneid);
                         if (status != DLADM_STATUS_OK) {
                                 zerror(zlogp, B_FALSE, "unable to notify "
                                     "dlmgmtd of zone halt: %s",
                                     dladm_status2str(status, errmsg));
@@ -5202,13 +5350,18 @@
         if (!unmount_cmd) {
                 boolean_t destroy_tmp_pool = B_TRUE;
 
                 if (rebooting) {
                         struct zone_psettab pset_tab;
+                        zone_dochandle_t handle;
 
-                        if (zonecfg_lookup_pset(snap_hndl, &pset_tab) == Z_OK)
+                        if ((handle = zonecfg_init_handle()) != NULL &&
+                            zonecfg_get_handle(zone_name, handle) == Z_OK &&
+                            zonecfg_lookup_pset(handle, &pset_tab) == Z_OK)
                                 destroy_tmp_pool = B_FALSE;
+
+                        zonecfg_fini_handle(handle);
                 }
 
                 if (destroy_tmp_pool) {
                         if ((res = zonecfg_destroy_tmp_pool(zone_name, pool_err,
                             sizeof (pool_err))) != Z_OK) {