Print this page
OS-3342+co
OS-722
OS-478 -- lint
OS-375-1
OS-328 dlmgmtd/mac_link_flow_add() deadlock
OS-249

@@ -19,10 +19,11 @@
  * CDDL HEADER END
  */
 
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, Joyent Inc. All rights reserved.
  */
 
 /*
  * Main door handler functions used by dlmgmtd to process the different door
  * call requests. Door call requests can come from the user-land applications,

@@ -56,10 +57,14 @@
 #include <sys/sysevent/eventdefs.h>
 #include <zone.h>
 #include <libsysevent.h>
 #include <libdlmgmt.h>
 #include <librcm.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
 #include "dlmgmt_impl.h"
 
 typedef void dlmgmt_door_handler_t(void *, void *, size_t *, zoneid_t,
     ucred_t *);
 

@@ -377,10 +382,15 @@
         }
 
         if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
                 goto done;
 
+        if (linkp->ll_tomb == B_TRUE) {
+                err = EINPROGRESS;
+                goto done;
+        }
+
         if (((linkp->ll_flags & flags) & DLMGMT_ACTIVE) != 0) {
                 if ((err = dlmgmt_delete_db_entry(linkp, DLMGMT_ACTIVE)) != 0)
                         goto done;
                 dflags |= DLMGMT_ACTIVE;
         }

@@ -437,10 +447,14 @@
         dlmgmt_door_getlinkid_t *getlinkid = argp;
         dlmgmt_getlinkid_retval_t *retvalp = retp;
         dlmgmt_link_t           *linkp;
         int                     err = 0;
 
+        /* Enable the global zone to lookup links it has given away. */
+        if (zoneid == GLOBAL_ZONEID && getlinkid->ld_zoneid != -1)
+                zoneid = getlinkid->ld_zoneid;
+
         /*
          * Hold the reader lock to access the link
          */
         dlmgmt_table_lock(B_FALSE);
 

@@ -646,10 +660,16 @@
         }
 
         if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
                 goto done;
 
+        if (linkp->ll_tomb == B_TRUE) {
+                err = EBUSY;
+                goto done;
+        }
+
+
         if (link_by_name(remapid->ld_link, linkp->ll_zoneid) != NULL) {
                 err = EEXIST;
                 goto done;
         }
 

@@ -707,10 +727,15 @@
         }
 
         if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
                 goto done;
 
+        if (linkp->ll_tomb == B_TRUE) {
+                err = EBUSY;
+                goto done;
+        }
+
         if (linkp->ll_flags & DLMGMT_ACTIVE) {
                 err = EINVAL;
                 goto done;
         }
 

@@ -1214,10 +1239,15 @@
         }
 
         if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
                 goto done;
 
+        if (linkp->ll_tomb == B_TRUE) {
+                err = EBUSY;
+                goto done;
+        }
+
         /* We can only assign an active link to a zone. */
         if (!(linkp->ll_flags & DLMGMT_ACTIVE)) {
                 err = EINVAL;
                 goto done;
         }

@@ -1243,11 +1273,23 @@
                         err = errno;
                         dlmgmt_log(LOG_WARNING, "unable to remove link %d from "
                             "zone %d: %s", linkid, oldzoneid, strerror(err));
                         goto done;
                 }
-                avl_remove(&dlmgmt_loan_avl, linkp);
+
+                if (newzoneid == GLOBAL_ZONEID && linkp->ll_onloan) {
+                        /*
+                         * We can only reassign a loaned VNIC back to the
+                         * global zone when the zone is shutting down, since
+                         * otherwise the VNIC is in use by the zone and will be
+                         * busy.  Leave the VNIC assigned to the zone so we can
+                         * still see it and delete it when dlmgmt_zonehalt()
+                         * runs.
+                         */
+                        goto done;
+                }
+
                 linkp->ll_onloan = B_FALSE;
         }
         if (newzoneid != GLOBAL_ZONEID) {
                 if (zone_add_datalink(newzoneid, linkid) != 0) {
                         err = errno;

@@ -1254,11 +1296,10 @@
                         dlmgmt_log(LOG_WARNING, "unable to add link %d to zone "
                             "%d: %s", linkid, newzoneid, strerror(err));
                         (void) zone_add_datalink(oldzoneid, linkid);
                         goto done;
                 }
-                avl_add(&dlmgmt_loan_avl, linkp);
                 linkp->ll_onloan = B_TRUE;
         }
 
         avl_remove(&dlmgmt_name_avl, linkp);
         linkp->ll_zoneid = newzoneid;

@@ -1307,20 +1348,41 @@
     ucred_t *cred)
 {
         int                     err = 0;
         dlmgmt_door_zonehalt_t  *zonehalt = argp;
         dlmgmt_zonehalt_retval_t *retvalp = retp;
+        static char my_pid[10];
 
+        if (my_pid[0] == NULL)
+                (void) snprintf(my_pid, sizeof (my_pid), "%d\n", getpid());
+
         if ((err = dlmgmt_checkprivs(0, cred)) == 0) {
                 if (zoneid != GLOBAL_ZONEID) {
                         err = EACCES;
                 } else if (zonehalt->ld_zoneid == GLOBAL_ZONEID) {
                         err = EINVAL;
                 } else {
+                        /*
+                         * dls and mac don't honor the locking rules defined in
+                         * mac. In order to try and make that case less likely
+                         * to happen, we try to serialize some of the zone
+                         * activity here between dlmgmtd and the brands on
+                         * /etc/dladm/zone.lck
+                         */
+                        int fd;
+
+                        while ((fd = open(ZONE_LOCK, O_WRONLY |
+                            O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) < 0)
+                        (void) sleep(1);
+                        (void) write(fd, my_pid, sizeof (my_pid));
+                        (void) close(fd);
+
                         dlmgmt_table_lock(B_TRUE);
                         dlmgmt_db_fini(zonehalt->ld_zoneid);
                         dlmgmt_table_unlock();
+
+                        (void) unlink(ZONE_LOCK);
                 }
         }
         retvalp->lr_err = err;
 }