Print this page
Running stmfadm remove-hg-member caused a NULL pointer dereference panic in stmf_remove_lu_from_session
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Running stmfadm remove-hg-member caused a NULL pointer dereference panic in stmf_remove_lu_from_session
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
SUP-770 deadlock between thread acquiring iss->iss_lockp in stmf_task_free() and thread holding sl->sl_pgr->pgr_lock from sbd_pgr_remove_it_handle()
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
        
*** 45,56 ****
  void stmf_update_sessions_per_ve(stmf_view_entry_t *ve,
                  stmf_lu_t *lu, int action);
  void stmf_add_lus_to_session_per_vemap(stmf_i_local_port_t *ilport,
                  stmf_i_scsi_session_t *iss, stmf_lun_map_t *vemap);
  stmf_id_data_t *stmf_lookup_group_for_host(uint8_t *ident, uint16_t ident_size);
! stmf_status_t stmf_add_ent_to_map(stmf_lun_map_t *sm, void *ent, uint8_t *lun);
! stmf_status_t stmf_remove_ent_from_map(stmf_lun_map_t *sm, uint8_t *lun);
  uint16_t stmf_get_next_free_lun(stmf_lun_map_t *sm, uint8_t *lun);
  stmf_status_t stmf_add_tg(uint8_t *tg_name, uint16_t tg_name_size,
                  int allow_special, uint32_t *err_detail);
  stmf_status_t stmf_add_hg(uint8_t *hg_name, uint16_t hg_name_size,
                  int allow_special, uint32_t *err_detail);
--- 45,57 ----
  void stmf_update_sessions_per_ve(stmf_view_entry_t *ve,
                  stmf_lu_t *lu, int action);
  void stmf_add_lus_to_session_per_vemap(stmf_i_local_port_t *ilport,
                  stmf_i_scsi_session_t *iss, stmf_lun_map_t *vemap);
  stmf_id_data_t *stmf_lookup_group_for_host(uint8_t *ident, uint16_t ident_size);
! static stmf_status_t stmf_add_ent_to_map(stmf_lun_map_t *sm, void *ent,
!     uint8_t *lun);
! static stmf_status_t stmf_remove_ent_from_map(stmf_lun_map_t *sm, uint8_t *lun);
  uint16_t stmf_get_next_free_lun(stmf_lun_map_t *sm, uint8_t *lun);
  stmf_status_t stmf_add_tg(uint8_t *tg_name, uint16_t tg_name_size,
                  int allow_special, uint32_t *err_detail);
  stmf_status_t stmf_add_hg(uint8_t *hg_name, uint16_t hg_name_size,
                  int allow_special, uint32_t *err_detail);
*** 177,186 ****
--- 178,188 ----
          }
  }
  
  /*
   * Create luns map for session based on the view
+  * iss_lockp is held
   */
  stmf_status_t
  stmf_session_create_lun_map(stmf_i_local_port_t *ilport,
                  stmf_i_scsi_session_t *iss)
  {
*** 234,289 ****
  
          return (STMF_SUCCESS);
  }
  
  /*
-  * destroy lun map for session
-  */
- /* ARGSUSED */
- stmf_status_t
- stmf_session_destroy_lun_map(stmf_i_local_port_t *ilport,
-                 stmf_i_scsi_session_t *iss)
- {
-         stmf_lun_map_t *sm;
-         stmf_i_lu_t *ilu;
-         uint16_t n;
-         stmf_lun_map_ent_t *ent;
- 
-         ASSERT(mutex_owned(&stmf_state.stmf_lock));
-         /*
-          * to avoid conflict with updating session's map,
-          * which only grab stmf_lock
-          */
-         sm = iss->iss_sm;
-         iss->iss_sm = NULL;
-         iss->iss_hg = NULL;
-         if (sm->lm_nentries) {
-                 for (n = 0; n < sm->lm_nentries; n++) {
-                         if ((ent = (stmf_lun_map_ent_t *)sm->lm_plus[n])
-                             != NULL) {
-                                 if (ent->ent_itl_datap) {
-                                         stmf_do_itl_dereg(ent->ent_lu,
-                                             ent->ent_itl_datap,
-                                             STMF_ITL_REASON_IT_NEXUS_LOSS);
-                                 }
-                                 ilu = (stmf_i_lu_t *)
-                                     ent->ent_lu->lu_stmf_private;
-                                 atomic_dec_32(&ilu->ilu_ref_cnt);
-                                 kmem_free(sm->lm_plus[n],
-                                     sizeof (stmf_lun_map_ent_t));
-                         }
-                 }
-                 kmem_free(sm->lm_plus,
-                     sizeof (stmf_lun_map_ent_t *) * sm->lm_nentries);
-         }
- 
-         kmem_free(sm, sizeof (*sm));
-         return (STMF_SUCCESS);
- }
- 
- /*
   * Expects the session lock to be held.
   */
  stmf_xfer_data_t *
  stmf_session_prepare_report_lun_data(stmf_lun_map_t *sm)
  {
          stmf_xfer_data_t *xd;
--- 236,247 ----
  
          return (STMF_SUCCESS);
  }
  
  /*
   * Expects the session lock to be held.
+  * iss_lockp is held
   */
  stmf_xfer_data_t *
  stmf_session_prepare_report_lun_data(stmf_lun_map_t *sm)
  {
          stmf_xfer_data_t *xd;
*** 388,399 ****
                          break;
          }
  }
  /*
   * add lu to a session, stmf_lock is already held
   */
! stmf_status_t
  stmf_add_lu_to_session(stmf_i_local_port_t *ilport,
                  stmf_i_scsi_session_t   *iss,
                  stmf_lu_t *lu,
                  uint8_t *lu_nbr)
  {
--- 346,358 ----
                          break;
          }
  }
  /*
   * add lu to a session, stmf_lock is already held
+  * iss_lockp/ilport_lock already held
   */
! static stmf_status_t
  stmf_add_lu_to_session(stmf_i_local_port_t *ilport,
                  stmf_i_scsi_session_t   *iss,
                  stmf_lu_t *lu,
                  uint8_t *lu_nbr)
  {
*** 432,448 ****
          return (STMF_SUCCESS);
  }
  
  /*
   * remvoe lu from a session, stmf_lock is already held
   */
! /* ARGSUSED */
! stmf_status_t
! stmf_remove_lu_from_session(stmf_i_local_port_t *ilport,
!                 stmf_i_scsi_session_t *iss,
!                 stmf_lu_t *lu,
!                 uint8_t *lu_nbr)
  {
          stmf_status_t ret;
          stmf_i_lu_t *ilu;
          stmf_lun_map_t *sm = iss->iss_sm;
          stmf_lun_map_ent_t *lun_map_ent;
--- 391,405 ----
          return (STMF_SUCCESS);
  }
  
  /*
   * remvoe lu from a session, stmf_lock is already held
+  * iss_lockp held
   */
! static void
! stmf_remove_lu_from_session(stmf_i_scsi_session_t *iss,
!     stmf_lu_t *lu, uint8_t *lu_nbr)
  {
          stmf_status_t ret;
          stmf_i_lu_t *ilu;
          stmf_lun_map_t *sm = iss->iss_sm;
          stmf_lun_map_ent_t *lun_map_ent;
*** 449,459 ****
          uint16_t luNbr =
              ((uint16_t)lu_nbr[1] | (((uint16_t)(lu_nbr[0] & 0x3F)) << 8));
  
          ASSERT(mutex_owned(&stmf_state.stmf_lock));
          lun_map_ent = stmf_get_ent_from_map(sm, luNbr);
!         ASSERT(lun_map_ent && lun_map_ent->ent_lu == lu);
  
          ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
  
          ret = stmf_remove_ent_from_map(sm, lu_nbr);
          ASSERT(ret == STMF_SUCCESS);
--- 406,419 ----
          uint16_t luNbr =
              ((uint16_t)lu_nbr[1] | (((uint16_t)(lu_nbr[0] & 0x3F)) << 8));
  
          ASSERT(mutex_owned(&stmf_state.stmf_lock));
          lun_map_ent = stmf_get_ent_from_map(sm, luNbr);
!         ASSERT(lun_map_ent->ent_lu == lu);
!         if (lun_map_ent == NULL) {
!                 return;
!         }
  
          ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
  
          ret = stmf_remove_ent_from_map(sm, lu_nbr);
          ASSERT(ret == STMF_SUCCESS);
*** 462,472 ****
          if (lun_map_ent->ent_itl_datap) {
                  stmf_do_itl_dereg(lu, lun_map_ent->ent_itl_datap,
                      STMF_ITL_REASON_USER_REQUEST);
          }
          kmem_free((void *)lun_map_ent, sizeof (stmf_lun_map_ent_t));
-         return (STMF_SUCCESS);
  }
  
  /*
   * add or remove lu from all related sessions based on view entry,
   * action is 0 for delete, 1 for add
--- 422,431 ----
*** 517,528 ****
                      iss = iss->iss_next) {
                          if (!all_hg && iss->iss_hg != ve->ve_hg)
                                  continue;
                          /* This host belongs to the host group */
                          if (action == 0) { /* to remove */
!                                 (void) stmf_remove_lu_from_session(ilport, iss,
!                                     lu_to_add, ve->ve_lun);
                                  if (ilu_tmp->ilu_ref_cnt == 0) {
                                          rw_exit(&ilport->ilport_lock);
                                          return;
                                  }
                          } else {
--- 476,487 ----
                      iss = iss->iss_next) {
                          if (!all_hg && iss->iss_hg != ve->ve_hg)
                                  continue;
                          /* This host belongs to the host group */
                          if (action == 0) { /* to remove */
!                                 stmf_remove_lu_from_session(iss, lu_to_add,
!                                     ve->ve_lun);
                                  if (ilu_tmp->ilu_ref_cnt == 0) {
                                          rw_exit(&ilport->ilport_lock);
                                          return;
                                  }
                          } else {
*** 547,557 ****
          stmf_i_lu_t *ilu;
          stmf_view_entry_t *ve;
          uint32_t        i;
  
          ASSERT(mutex_owned(&stmf_state.stmf_lock));
- 
          for (i = 0; i < vemap->lm_nentries; i++) {
                  ve = (stmf_view_entry_t *)vemap->lm_plus[i];
                  if (!ve)
                          continue;
                  ilu = (stmf_i_lu_t *)ve->ve_luid->id_pt_to_object;
--- 506,515 ----
*** 560,573 ****
                          (void) stmf_add_lu_to_session(ilport, iss, lu,
                              ve->ve_lun);
                  }
          }
  }
! /* remove luns in view entry map from a session */
  void
! stmf_remove_lus_from_session_per_vemap(stmf_i_local_port_t *ilport,
!                 stmf_i_scsi_session_t *iss,
                  stmf_lun_map_t *vemap)
  {
          stmf_lu_t *lu;
          stmf_i_lu_t *ilu;
          stmf_view_entry_t *ve;
--- 518,533 ----
                          (void) stmf_add_lu_to_session(ilport, iss, lu,
                              ve->ve_lun);
                  }
          }
  }
! /*
!  * remove luns in view entry map from a session
!  * iss_lockp held
!  */
  void
! stmf_remove_lus_from_session_per_vemap(stmf_i_scsi_session_t *iss,
      stmf_lun_map_t *vemap)
  {
          stmf_lu_t *lu;
          stmf_i_lu_t *ilu;
          stmf_view_entry_t *ve;
*** 580,591 ****
                  if (!ve)
                          continue;
                  ilu = (stmf_i_lu_t *)ve->ve_luid->id_pt_to_object;
                  if (ilu && ilu->ilu_state == STMF_STATE_ONLINE) {
                          lu = ilu->ilu_lu;
!                         (void) stmf_remove_lu_from_session(ilport, iss, lu,
!                             ve->ve_lun);
                  }
          }
  }
  
  stmf_id_data_t *
--- 540,550 ----
                  if (!ve)
                          continue;
                  ilu = (stmf_i_lu_t *)ve->ve_luid->id_pt_to_object;
                  if (ilu && ilu->ilu_state == STMF_STATE_ONLINE) {
                          lu = ilu->ilu_lu;
!                         stmf_remove_lu_from_session(iss, lu, ve->ve_lun);
                  }
          }
  }
  
  stmf_id_data_t *
*** 708,717 ****
--- 667,677 ----
  /*
   * The refcnts of objects in a view entry are updated when then entry
   * is successfully added. ve_map is just another representation of the
   * view enrtries in a LU. Duplicating or merging a ve map does not
   * affect any refcnts.
+  * stmf_state.stmf_lock held
   */
  stmf_lun_map_t *
  stmf_duplicate_ve_map(stmf_lun_map_t *src)
  {
          stmf_lun_map_t *dst;
*** 740,749 ****
--- 700,713 ----
                  kmem_free(dst->lm_plus, dst->lm_nentries * sizeof (void *));
          }
          kmem_free(dst, sizeof (*dst));
  }
  
+ /*
+  * stmf_state.stmf_lock held. Operations are stmf global in nature and
+  * not session level.
+  */
  int
  stmf_merge_ve_map(stmf_lun_map_t *src, stmf_lun_map_t *dst,
                  stmf_lun_map_t **pp_ret_map, stmf_merge_flags_t mf)
  {
          int i;
*** 1064,1074 ****
                  stmf_free_id(luid);
          }
          return (ret);
  }
  
! stmf_status_t
  stmf_add_ent_to_map(stmf_lun_map_t *lm, void *ent, uint8_t *lun)
  {
          uint16_t n;
          if (((lun[0] & 0xc0) >> 6) != 0)
                  return (STMF_FAILURE);
--- 1028,1042 ----
                  stmf_free_id(luid);
          }
          return (ret);
  }
  
! /*
!  * protected by stmf_state.stmf_lock when working on global lun map.
!  * iss_lockp when working at the session level.
!  */
! static stmf_status_t
  stmf_add_ent_to_map(stmf_lun_map_t *lm, void *ent, uint8_t *lun)
  {
          uint16_t n;
          if (((lun[0] & 0xc0) >> 6) != 0)
                  return (STMF_FAILURE);
*** 1096,1106 ****
                  goto try_again_to_add;
          }
  }
  
  
! stmf_status_t
  stmf_remove_ent_from_map(stmf_lun_map_t *lm, uint8_t *lun)
  {
          uint16_t n, i;
          uint8_t lutype = (lun[0] & 0xc0) >> 6;
          if (lutype != 0)
--- 1064,1078 ----
                  goto try_again_to_add;
          }
  }
  
  
! /*
!  * iss_lockp held when working on a session.
!  * stmf_state.stmf_lock is held when working on the global views.
!  */
! static stmf_status_t
  stmf_remove_ent_from_map(stmf_lun_map_t *lm, uint8_t *lun)
  {
          uint16_t n, i;
          uint8_t lutype = (lun[0] & 0xc0) >> 6;
          if (lutype != 0)
*** 1133,1142 ****
--- 1105,1117 ----
          }
  
          return (STMF_SUCCESS);
  }
  
+ /*
+  * stmf_state.stmf_lock held
+  */
  uint16_t
  stmf_get_next_free_lun(stmf_lun_map_t *sm, uint8_t *lun)
  {
          uint16_t luNbr;
  
*** 1156,1165 ****
--- 1131,1144 ----
          }
  
          return (luNbr);
  }
  
+ /*
+  * stmf_state.stmf_lock is held when working on global view map
+  * iss_lockp (RW_WRITER) is held when working on session map.
+  */
  void *
  stmf_get_ent_from_map(stmf_lun_map_t *sm, uint16_t lun_num)
  {
          if ((lun_num & 0xC000) == 0) {
                  if (sm->lm_nentries > lun_num)
*** 1490,1508 ****
--- 1469,1489 ----
                      entry_ident, entry_size);
                  if (iss) {
                          stmf_id_data_t *tgid;
                          iss->iss_hg = (void *)id_grp;
                          tgid = ilport->ilport_tg;
+                         rw_enter(iss->iss_lockp, RW_WRITER);
                          if (tgid) {
                                  vemap = stmf_get_ve_map_per_ids(tgid, id_grp);
                                  if (vemap)
                                          stmf_add_lus_to_session_per_vemap(
                                              ilport, iss, vemap);
                          }
                          if (vemap_alltgt)
                                  stmf_add_lus_to_session_per_vemap(ilport,
                                      iss, vemap_alltgt);
+                         rw_exit(iss->iss_lockp);
                  }
          }
  
          return (0);
  }
*** 1575,1595 ****
                          continue;
                  iss = stmf_lookup_session_for_hostident(ilport,
                      entry_ident, entry_size);
                  if (iss) {
                          stmf_id_data_t *tgid;
                          iss->iss_hg = NULL;
                          tgid = ilport->ilport_tg;
                          if (tgid) {
                                  vemap = stmf_get_ve_map_per_ids(tgid, id_grp);
                                  if (vemap)
                                          stmf_remove_lus_from_session_per_vemap(
!                                             ilport, iss, vemap);
                          }
                          if (vemap_alltgt)
!                                 stmf_remove_lus_from_session_per_vemap(ilport,
!                                     iss, vemap_alltgt);
                  }
          }
  
          return (0);
  }
--- 1556,1578 ----
                          continue;
                  iss = stmf_lookup_session_for_hostident(ilport,
                      entry_ident, entry_size);
                  if (iss) {
                          stmf_id_data_t *tgid;
+                         rw_enter(iss->iss_lockp, RW_WRITER);
                          iss->iss_hg = NULL;
                          tgid = ilport->ilport_tg;
                          if (tgid) {
                                  vemap = stmf_get_ve_map_per_ids(tgid, id_grp);
                                  if (vemap)
                                          stmf_remove_lus_from_session_per_vemap(
!                                             iss, vemap);
                          }
                          if (vemap_alltgt)
!                                 stmf_remove_lus_from_session_per_vemap(iss,
!                                     vemap_alltgt);
!                         rw_exit(iss->iss_lockp);
                  }
          }
  
          return (0);
  }