Print this page
NEX-19489 BDD tests causes node panic during stage-vm1
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-17944 HBA drivers don't need the redundant devfs_clean step
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
NEX-3414 CLONE - Port 3339 iscsi/fs:5 causes panic on initiator
NEX-3419 CLONE - Run multi initiator sessions to a single target test can panic the initiator
Reviewed by: Steve Peng <steve.peng@nexenta.com>

*** 16,34 **** * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. ! * * iSCSI logical unit interfaces */ #include "iscsi.h" - #include <sys/fs/dv_node.h> /* devfs_clean */ #include <sys/bootprops.h> #include <sys/sysevent/eventdefs.h> #include <sys/sysevent/dev.h> /* tpgt bytes in string form */ --- 16,40 ---- * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ + /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. ! */ ! ! /* ! * Copyright 2019 Nexenta Systems, Inc. ! */ ! ! /* * iSCSI logical unit interfaces */ #include "iscsi.h" #include <sys/bootprops.h> #include <sys/sysevent/eventdefs.h> #include <sys/sysevent/dev.h> /* tpgt bytes in string form */
*** 121,130 **** --- 127,141 ---- ilp->lun_addr_type = lun_addr_type; ilp->lun_sess = isp; ilp->lun_addr = addr; ilp->lun_type = inq->inq_dtype & DTYPE_MASK; ilp->lun_oid = oid_tmp; + /* + * Setting refcnt to 1 is the first hold for the LUN structure. + */ + ilp->lun_refcnt = 1; + mutex_init(&ilp->lun_mutex, NULL, MUTEX_DRIVER, NULL); bcopy(inq->inq_vid, ilp->lun_vid, sizeof (inq->inq_vid)); bcopy(inq->inq_pid, ilp->lun_pid, sizeof (inq->inq_pid)); /* store GUID if valid one exists */
*** 187,196 **** --- 198,208 ---- if (ilp->lun_guid != NULL) { kmem_free(ilp->lun_guid, ilp->lun_guid_size); ilp->lun_guid = NULL; } + mutex_destroy(&ilp->lun_mutex); kmem_free(ilp, sizeof (iscsi_lun_t)); } else { ilp->lun_state &= ISCSI_LUN_STATE_CLEAR; ilp->lun_state |= ISCSI_LUN_STATE_ONLINE; ilp->lun_time_online = ddi_get_time();
*** 213,223 **** --- 225,310 ---- rw_exit(&isp->sess_lun_list_rwlock); return (rtn); } + void + iscsi_lun_hold(iscsi_lun_t *ilp) + { + mutex_enter(&ilp->lun_mutex); + /* + * By design lun_refcnt should never be zero when this routine + * is called. When the LUN is created the refcnt is set to 1. + * If iscsi_lun_rele is called and the refcnt goes to zero the + * structure will be freed so this method shouldn't be called + * afterwards. + */ + ASSERT(ilp->lun_refcnt > 0); + ilp->lun_refcnt++; + mutex_exit(&ilp->lun_mutex); + } + + void + iscsi_lun_rele(iscsi_lun_t *ilp) + { + ASSERT(ilp != NULL); + + mutex_enter(&ilp->lun_mutex); + ASSERT(ilp->lun_refcnt > 0); + if (--ilp->lun_refcnt == 0) { + iscsi_sess_t *isp; + + isp = ilp->lun_sess; + ASSERT(isp != NULL); + + /* ---- release its memory ---- */ + kmem_free(ilp->lun_addr, (strlen((char *)isp->sess_name) + + ADDR_EXT_SIZE + 1)); + + if (ilp->lun_guid != NULL) { + kmem_free(ilp->lun_guid, ilp->lun_guid_size); + } + mutex_destroy(&ilp->lun_mutex); + kmem_free(ilp, sizeof (iscsi_lun_t)); + } else { + mutex_exit(&ilp->lun_mutex); + } + } + /* + * iscsi_lun_cmd_cancel -- as the name implies, cancel all commands for the lun + * + * This code is similar to the timeout function with a lot less checking of + * state before sending the ABORT event for commands on the pending queue. + * + * This function is only used by iscsi_lun_destroy(). + */ + static void + iscsi_lun_cmd_cancel(iscsi_lun_t *ilp) + { + iscsi_sess_t *isp; + iscsi_cmd_t *icmdp, *nicmdp; + + isp = ilp->lun_sess; + rw_enter(&isp->sess_state_rwlock, RW_READER); + mutex_enter(&isp->sess_queue_pending.mutex); + for (icmdp = isp->sess_queue_pending.head; + icmdp; icmdp = nicmdp) { + nicmdp = icmdp->cmd_next; + + /* + * For commands on the pending queue we can go straight + * to and abort request which will free the command + * and call back to the complete function. + */ + iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E4, isp); + } + mutex_exit(&isp->sess_queue_pending.mutex); + rw_exit(&isp->sess_state_rwlock); + } + + /* * iscsi_lun_destroy - offline and remove lun * * This interface is called when a name service change has * occured and the storage is no longer available to this * initiator. This function will offline and free the
*** 238,247 **** --- 325,337 ---- ASSERT(ilp != NULL); isp = ilp->lun_sess; ASSERT(isp != NULL); + /* flush all outstanding commands first */ + iscsi_lun_cmd_cancel(ilp); + /* attempt to offline and free solaris node */ status = iscsi_lun_offline(ihp, ilp, B_TRUE); /* If we successfully unplumbed the lun remove it from our lists */ if (ISCSI_SUCCESS(status)) {
*** 267,287 **** /* couldn't find session */ ASSERT(FALSE); } } ! /* release its memory */ ! kmem_free(ilp->lun_addr, (strlen((char *)isp->sess_name) + ! ADDR_EXT_SIZE + 1)); ! ilp->lun_addr = NULL; ! if (ilp->lun_guid != NULL) { ! kmem_free(ilp->lun_guid, ilp->lun_guid_size); ! ilp->lun_guid = NULL; } - kmem_free(ilp, sizeof (iscsi_lun_t)); - ilp = NULL; - } return (status); } /* --- 357,368 ---- /* couldn't find session */ ASSERT(FALSE); } } ! iscsi_lun_rele(ilp); } return (status); } /*
*** 639,718 **** iscsi_status_t iscsi_lun_offline(iscsi_hba_t *ihp, iscsi_lun_t *ilp, boolean_t lun_free) { iscsi_status_t status = ISCSI_STATUS_SUCCESS; int circ = 0; ! dev_info_t *cdip, *pdip; ! char *devname = NULL; char *pathname = NULL; - int rval; boolean_t offline = B_FALSE; nvlist_t *attr_list = NULL; ASSERT(ilp != NULL); ASSERT((ilp->lun_pip != NULL) || (ilp->lun_dip != NULL)); ! /* ! * Since we carry the logical units parent ! * lock across the offline call it will not ! * issue devfs_clean() and may fail with a ! * devi_ref count > 0. ! */ ! if (ilp->lun_pip == NULL) { cdip = ilp->lun_dip; ! } else { cdip = mdi_pi_get_client(ilp->lun_pip); - } - if ((cdip != NULL) && - (lun_free == B_TRUE) && - (ilp->lun_state & ISCSI_LUN_STATE_ONLINE)) { - /* - * Make sure node is attached otherwise - * it won't have related cache nodes to - * clean up. i_ddi_devi_attached is - * similiar to i_ddi_node_state(cdip) >= - * DS_ATTACHED. We should clean up only - * when lun_free is set. - */ - if (i_ddi_devi_attached(cdip)) { - - /* Get parent dip */ - pdip = ddi_get_parent(cdip); - - /* Get full devname */ - devname = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP); - ndi_devi_enter(pdip, &circ); - (void) ddi_deviname(cdip, devname); - /* Release lock before devfs_clean() */ - ndi_devi_exit(pdip, circ); - - /* Clean cache */ - (void) devfs_clean(pdip, devname + 1, DV_CLEAN_FORCE); - kmem_free(devname, MAXNAMELEN + 1); - } - } - if (cdip != NULL && ilp->lun_type == DTYPE_DIRECT) { pathname = kmem_zalloc(MAXNAMELEN + 1, KM_SLEEP); (void) ddi_pathname(cdip, pathname); } /* Attempt to offline the logical units */ if (ilp->lun_pip != NULL) { - /* virt/mdi */ ndi_devi_enter(scsi_vhci_dip, &circ); ! if ((lun_free == B_TRUE) && ! (ilp->lun_state & ISCSI_LUN_STATE_ONLINE)) { ! rval = mdi_pi_offline(ilp->lun_pip, ! NDI_DEVI_REMOVE); ! } else { ! rval = mdi_pi_offline(ilp->lun_pip, 0); ! } ! ! if (rval == MDI_SUCCESS) { ilp->lun_state &= ISCSI_LUN_STATE_CLEAR; ilp->lun_state |= ISCSI_LUN_STATE_OFFLINE; if (lun_free == B_TRUE) { (void) mdi_prop_remove(ilp->lun_pip, NULL); (void) mdi_pi_free(ilp->lun_pip, 0); --- 720,752 ---- iscsi_status_t iscsi_lun_offline(iscsi_hba_t *ihp, iscsi_lun_t *ilp, boolean_t lun_free) { iscsi_status_t status = ISCSI_STATUS_SUCCESS; int circ = 0; ! dev_info_t *cdip; char *pathname = NULL; boolean_t offline = B_FALSE; nvlist_t *attr_list = NULL; ASSERT(ilp != NULL); ASSERT((ilp->lun_pip != NULL) || (ilp->lun_dip != NULL)); ! if (ilp->lun_pip == NULL) cdip = ilp->lun_dip; ! else cdip = mdi_pi_get_client(ilp->lun_pip); if (cdip != NULL && ilp->lun_type == DTYPE_DIRECT) { pathname = kmem_zalloc(MAXNAMELEN + 1, KM_SLEEP); (void) ddi_pathname(cdip, pathname); } /* Attempt to offline the logical units */ if (ilp->lun_pip != NULL) { /* virt/mdi */ ndi_devi_enter(scsi_vhci_dip, &circ); ! if (mdi_pi_offline(ilp->lun_pip, 0) == MDI_SUCCESS) { ilp->lun_state &= ISCSI_LUN_STATE_CLEAR; ilp->lun_state |= ISCSI_LUN_STATE_OFFLINE; if (lun_free == B_TRUE) { (void) mdi_prop_remove(ilp->lun_pip, NULL); (void) mdi_pi_free(ilp->lun_pip, 0);
*** 726,747 **** } } ndi_devi_exit(scsi_vhci_dip, circ); } else { - /* phys/ndi */ ndi_devi_enter(ihp->hba_dip, &circ); ! if ((lun_free == B_TRUE) && ! (ilp->lun_state & ISCSI_LUN_STATE_ONLINE)) { ! rval = ndi_devi_offline( ! ilp->lun_dip, NDI_DEVI_REMOVE); ! } else { ! rval = ndi_devi_offline( ! ilp->lun_dip, 0); ! } ! if (rval != NDI_SUCCESS) { status = ISCSI_STATUS_BUSY; if (lun_free == B_FALSE) { ilp->lun_state |= ISCSI_LUN_STATE_INVALID; offline = B_TRUE; } --- 760,777 ---- } } ndi_devi_exit(scsi_vhci_dip, circ); } else { /* phys/ndi */ + int flags = NDI_DEVFS_CLEAN; + ndi_devi_enter(ihp->hba_dip, &circ); ! if (lun_free == B_TRUE && ! (ilp->lun_state & ISCSI_LUN_STATE_ONLINE)) ! flags |= NDI_DEVI_REMOVE; ! if (ndi_devi_offline(ilp->lun_dip, flags) != NDI_SUCCESS) { status = ISCSI_STATUS_BUSY; if (lun_free == B_FALSE) { ilp->lun_state |= ISCSI_LUN_STATE_INVALID; offline = B_TRUE; }