Print this page
8901 netstack_find_by_stackid() drops-and-reacquires
Reviewed by: Jason King <jbk@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Ryan Zezeski <rpz@joyent.com>
        
*** 121,130 ****
--- 121,132 ----
  static boolean_t netstack_apply_destroy(kmutex_t *, netstack_t *, int);
  static boolean_t wait_for_zone_creator(netstack_t *, kmutex_t *);
  static boolean_t wait_for_nms_inprogress(netstack_t *, nm_state_t *,
      kmutex_t *);
  
+ static void netstack_hold_locked(netstack_t *);
+ 
  static ksema_t netstack_reap_limiter;
  /*
   * Hard-coded constant, but since this is not tunable in real-time, it seems
   * making it an /etc/system tunable is better than nothing.
   */
*** 925,940 ****
  {
          netstack_t *ns;
  
          ns = curproc->p_zone->zone_netstack;
          ASSERT(ns != NULL);
!         if (ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING))
!                 return (NULL);
! 
!         netstack_hold(ns);
! 
!         return (ns);
  }
  
  /*
   * Find a stack instance given the cred.
   * This is used by the modules to potentially allow for a future when
--- 927,937 ----
  {
          netstack_t *ns;
  
          ns = curproc->p_zone->zone_netstack;
          ASSERT(ns != NULL);
!         return (netstack_hold_if_active(ns));
  }
  
  /*
   * Find a stack instance given the cred.
   * This is used by the modules to potentially allow for a future when
*** 962,972 ****
   * netstack_rele().
   *
   * If there is no exact match then assume the shared stack instance
   * matches.
   *
!  * Skip the unitialized ones.
   */
  netstack_t *
  netstack_find_by_zoneid(zoneid_t zoneid)
  {
          netstack_t *ns;
--- 959,969 ----
   * netstack_rele().
   *
   * If there is no exact match then assume the shared stack instance
   * matches.
   *
!  * Skip the uninitialized and closing ones.
   */
  netstack_t *
  netstack_find_by_zoneid(zoneid_t zoneid)
  {
          netstack_t *ns;
*** 975,990 ****
          zone = zone_find_by_id(zoneid);
  
          if (zone == NULL)
                  return (NULL);
  
!         ns = zone->zone_netstack;
!         ASSERT(ns != NULL);
!         if (ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING))
!                 ns = NULL;
!         else
!                 netstack_hold(ns);
  
          zone_rele(zone);
          return (ns);
  }
  
--- 972,983 ----
          zone = zone_find_by_id(zoneid);
  
          if (zone == NULL)
                  return (NULL);
  
!         ASSERT(zone->zone_netstack != NULL);
!         ns = netstack_hold_if_active(zone->zone_netstack);
  
          zone_rele(zone);
          return (ns);
  }
  
*** 1002,1029 ****
   * Skip the unitialized ones.
   */
  netstack_t *
  netstack_find_by_zoneid_nolock(zoneid_t zoneid)
  {
-         netstack_t *ns;
          zone_t *zone;
  
          zone = zone_find_by_id_nolock(zoneid);
  
          if (zone == NULL)
                  return (NULL);
  
!         ns = zone->zone_netstack;
!         ASSERT(ns != NULL);
! 
!         if (ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING))
!                 ns = NULL;
!         else
!                 netstack_hold(ns);
! 
          /* zone_find_by_id_nolock does not have a hold on the zone */
!         return (ns);
  }
  
  /*
   * Find a stack instance given the stackid with exact match?
   * Increases the reference count if found; caller must do a
--- 995,1014 ----
   * Skip the unitialized ones.
   */
  netstack_t *
  netstack_find_by_zoneid_nolock(zoneid_t zoneid)
  {
          zone_t *zone;
  
          zone = zone_find_by_id_nolock(zoneid);
  
          if (zone == NULL)
                  return (NULL);
  
!         ASSERT(zone->zone_netstack != NULL);
          /* zone_find_by_id_nolock does not have a hold on the zone */
!         return (netstack_hold_if_active(zone->zone_netstack));
  }
  
  /*
   * Find a stack instance given the stackid with exact match?
   * Increases the reference count if found; caller must do a
*** 1036,1050 ****
  {
          netstack_t *ns;
  
          mutex_enter(&netstack_g_lock);
          for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) {
                  mutex_enter(&ns->netstack_lock);
                  if (ns->netstack_stackid == stackid &&
                      !(ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING))) {
                          mutex_exit(&ns->netstack_lock);
-                         netstack_hold(ns);
                          mutex_exit(&netstack_g_lock);
                          return (ns);
                  }
                  mutex_exit(&ns->netstack_lock);
          }
--- 1021,1036 ----
  {
          netstack_t *ns;
  
          mutex_enter(&netstack_g_lock);
          for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) {
+                 /* Can't use hold_if_active because of stackid check. */
                  mutex_enter(&ns->netstack_lock);
                  if (ns->netstack_stackid == stackid &&
                      !(ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING))) {
+                         netstack_hold_locked(ns);
                          mutex_exit(&ns->netstack_lock);
                          mutex_exit(&netstack_g_lock);
                          return (ns);
                  }
                  mutex_exit(&ns->netstack_lock);
          }
*** 1170,1187 ****
                  (void) taskq_dispatch(system_taskq, netstack_reap, ns,
                      TQ_SLEEP);
          }
  }
  
  void
  netstack_hold(netstack_t *ns)
  {
          mutex_enter(&ns->netstack_lock);
!         ns->netstack_refcnt++;
!         ASSERT(ns->netstack_refcnt > 0);
          mutex_exit(&ns->netstack_lock);
-         DTRACE_PROBE1(netstack__inc__ref, netstack_t *, ns);
  }
  
  /*
   * To support kstat_create_netstack() using kstat_zone_add we need
   * to track both
--- 1156,1202 ----
                  (void) taskq_dispatch(system_taskq, netstack_reap, ns,
                      TQ_SLEEP);
          }
  }
  
+ static void
+ netstack_hold_locked(netstack_t *ns)
+ {
+         ASSERT(MUTEX_HELD(&ns->netstack_lock));
+         ns->netstack_refcnt++;
+         ASSERT(ns->netstack_refcnt > 0);
+         DTRACE_PROBE1(netstack__inc__ref, netstack_t *, ns);
+ }
+ 
+ /*
+  * If the passed-in netstack isn't active (i.e. it's uninitialized or closing),
+  * return NULL, otherwise return it with its reference held.  Common code
+  * for many netstack_find*() functions.
+  */
+ netstack_t *
+ netstack_hold_if_active(netstack_t *ns)
+ {
+         netstack_t *retval;
+ 
+         mutex_enter(&ns->netstack_lock);
+         if (ns->netstack_flags & (NSF_UNINIT | NSF_CLOSING)) {
+                 retval = NULL;
+         } else {
+                 netstack_hold_locked(ns);
+                 retval = ns;
+         }
+         mutex_exit(&ns->netstack_lock);
+ 
+         return (retval);
+ }
+ 
  void
  netstack_hold(netstack_t *ns)
  {
          mutex_enter(&ns->netstack_lock);
!         netstack_hold_locked(ns);
          mutex_exit(&ns->netstack_lock);
  }
  
  /*
   * To support kstat_create_netstack() using kstat_zone_add we need
   * to track both
*** 1418,1440 ****
          for (i = 0; i < end; i++) {
                  if (ns == NULL)
                          break;
                  ns = ns->netstack_next;
          }
!         /* skip those with that aren't really here */
          while (ns != NULL) {
                  mutex_enter(&ns->netstack_lock);
                  if ((ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING)) == 0) {
                          mutex_exit(&ns->netstack_lock);
                          break;
                  }
                  mutex_exit(&ns->netstack_lock);
                  end++;
                  ns = ns->netstack_next;
          }
-         if (ns != NULL) {
-                 *handle = end + 1;
-                 netstack_hold(ns);
-         }
          mutex_exit(&netstack_g_lock);
          return (ns);
  }
--- 1433,1456 ----
          for (i = 0; i < end; i++) {
                  if (ns == NULL)
                          break;
                  ns = ns->netstack_next;
          }
!         /*
!          * Skip those that aren't really here (uninitialized or closing).
!          * Can't use hold_if_active because of "end" tracking.
!          */
          while (ns != NULL) {
                  mutex_enter(&ns->netstack_lock);
                  if ((ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING)) == 0) {
+                         *handle = end + 1;
+                         netstack_hold_locked(ns);
                          mutex_exit(&ns->netstack_lock);
                          break;
                  }
                  mutex_exit(&ns->netstack_lock);
                  end++;
                  ns = ns->netstack_next;
          }
          mutex_exit(&netstack_g_lock);
          return (ns);
  }