Print this page
6470 mac_unregister() needs to mod_hash_remove() BEFORE holding the perimeter.
Reviewed by: Ryan Zezeski <ryan@zinascii.com>

@@ -19,10 +19,11 @@
  * CDDL HEADER END
  */
 
 /*
  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 OmniTI Computer Consulting, Inc. All rights reserved.
  */
 
 #include <sys/types.h>
 #include <sys/conf.h>
 #include <sys/id_space.h>

@@ -512,10 +513,22 @@
         /*
          * Clean up notification thread and wait for it to exit.
          */
         i_mac_notify_exit(mip);
 
+        /*
+         * Prior to acquiring the MAC perimeter, remove the MAC instance from
+         * the internal hash table. Such removal means table-walkers that
+         * acquire the perimeter will not do so on behalf of what we are
+         * unregistering, which prevents a deadlock.
+         */
+        rw_enter(&i_mac_impl_lock, RW_WRITER);
+        (void) mod_hash_remove(i_mac_impl_hash,
+            (mod_hash_key_t)mip->mi_name, &val);
+        rw_exit(&i_mac_impl_lock);
+        ASSERT(mip == (mac_impl_t *)val);
+
         i_mac_perim_enter(mip);
 
         /*
          * There is still resource properties configured over this mac.
          */

@@ -531,14 +544,10 @@
         ASSERT(mip->mi_nactiveclients == 0 && !(mip->mi_state_flags &
             MIS_EXCLUSIVE));
 
         mac_driver_stat_delete(mip);
 
-        (void) mod_hash_remove(i_mac_impl_hash,
-            (mod_hash_key_t)mip->mi_name, &val);
-        ASSERT(mip == (mac_impl_t *)val);
-
         ASSERT(i_mac_impl_count > 0);
         atomic_dec_32(&i_mac_impl_count);
 
         if (mip->mi_pdata != NULL)
                 kmem_free(mip->mi_pdata, mip->mi_pdata_size);