Print this page
        
@@ -19,11 +19,10 @@
  * CDDL HEADER END
  */
 
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, Joyent Inc. All rights reserved.
  */
 
 /*
  * Utility functions used by the dlmgmtd daemon.
  */
@@ -44,14 +43,17 @@
 #include "dlmgmt_impl.h"
 
 /*
  * There are three datalink AVL tables.  The dlmgmt_name_avl tree contains all
  * datalinks and is keyed by zoneid and link name.  The dlmgmt_id_avl also
- * contains all datalinks, and it is keyed by link ID.
+ * contains all datalinks, and it is keyed by link ID.  The dlmgmt_loan_avl is
+ * keyed by link name, and contains the set of global-zone links that are
+ * currently on loan to non-global zones.
  */
 avl_tree_t      dlmgmt_name_avl;
 avl_tree_t      dlmgmt_id_avl;
+avl_tree_t      dlmgmt_loan_avl;
 
 avl_tree_t      dlmgmt_dlconf_avl;
 
 static pthread_rwlock_t dlmgmt_avl_lock = PTHREAD_RWLOCK_INITIALIZER;
 static pthread_mutex_t  dlmgmt_avl_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -158,10 +160,12 @@
 
         avl_create(&dlmgmt_name_avl, cmp_link_by_zname, sizeof (dlmgmt_link_t),
             offsetof(dlmgmt_link_t, ll_name_node));
         avl_create(&dlmgmt_id_avl, cmp_link_by_id, sizeof (dlmgmt_link_t),
             offsetof(dlmgmt_link_t, ll_id_node));
+        avl_create(&dlmgmt_loan_avl, cmp_link_by_name, sizeof (dlmgmt_link_t),
+            offsetof(dlmgmt_link_t, ll_loan_node));
         avl_create(&dlmgmt_dlconf_avl, cmp_dlconf_by_id,
             sizeof (dlmgmt_dlconf_t), offsetof(dlmgmt_dlconf_t, ld_node));
         dlmgmt_nextlinkid = 1;
 }
 
@@ -175,10 +179,11 @@
                 free(lpp);
         }
 
         avl_destroy(&dlmgmt_dlconf_avl);
         avl_destroy(&dlmgmt_name_avl);
+        avl_destroy(&dlmgmt_loan_avl);
         avl_destroy(&dlmgmt_id_avl);
 }
 
 static void
 linkattr_add(dlmgmt_linkattr_t **headp, dlmgmt_linkattr_t *attrp)
@@ -378,10 +383,11 @@
                         if (avl_find(&dlmgmt_name_avl, linkp, NULL) != NULL)
                                 avl_remove(&dlmgmt_name_avl, linkp);
 
                         linkp->ll_zoneid = zoneid;
                         avl_add(&dlmgmt_name_avl, linkp);
+                        avl_add(&dlmgmt_loan_avl, linkp);
                         linkp->ll_onloan = B_TRUE;
                 }
         } else if (linkp->ll_zoneid != GLOBAL_ZONEID) {
                 err = zone_add_datalink(linkp->ll_zoneid, linkp->ll_linkid);
         }
@@ -422,10 +428,14 @@
         dlmgmt_link_t   link, *linkp;
 
         (void) strlcpy(link.ll_link, name, MAXLINKNAMELEN);
         link.ll_zoneid = zoneid;
         linkp = avl_find(&dlmgmt_name_avl, &link, NULL);
+        if (linkp == NULL && zoneid == GLOBAL_ZONEID) {
+                /* The link could be on loan to a non-global zone? */
+                linkp = avl_find(&dlmgmt_loan_avl, &link, NULL);
+        }
         return (linkp);
 }
 
 int
 dlmgmt_create_common(const char *name, datalink_class_t class, uint32_t media,
@@ -500,10 +510,12 @@
                 linkp->ll_head = NULL;
         }
 
         if ((flags & DLMGMT_ACTIVE) && linkp->ll_zoneid != GLOBAL_ZONEID) {
                 (void) zone_remove_datalink(linkp->ll_zoneid, linkp->ll_linkid);
+                if (linkp->ll_onloan)
+                        avl_remove(&dlmgmt_loan_avl, linkp);
         }
 
         if (linkp->ll_flags == 0) {
                 avl_remove(&dlmgmt_id_avl, linkp);
                 avl_remove(&dlmgmt_name_avl, linkp);