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); }