Print this page
NEX-9981 Deadman timer panic from idm_refcnt_wait_ref thread while offlining iSCSI targets
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
NEX-6018 Return of the walking dead idm_refcnt_wait_ref comstar threads
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-3746 Panic seen if iSCSI Initiator sends a SCSI Response packet to target
NEX-3777 COMSTAR iscsi/io test can panic the target running 5.0
NEX-3785 This is on 5.0 release and iSCSI target can panic while running iSCSI mpxio disable test
Reviewed by: Steve Peng <steve.peng@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
NEX-2359 iSCSI target connection handling is missing refcount audit information
re #10417 rb2398 incorrect handling in iscsit of duplicate PDUs with cmdsn > expsn
re #9966: sysretq doesn't properly handle non-canonical addresses
re #9966: sysretq doesn't properly handle non-canonical addresses
--HG--
branch : stable-4.0
re #9822 - libiscsi test panics COMSTAR
--HG--
branch : stable-4.0
re #9822 - libiscsi test panics COMSTAR
@@ -18,12 +18,11 @@
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- *
- * Copyright 2014, 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc.
* Copyright (c) 2017, Joyent, Inc. All rights reserved.
*/
#include <sys/cpuvar.h>
#include <sys/types.h>
@@ -562,10 +561,11 @@
cleanup:
if (cfg)
it_config_free_cmn(cfg);
if (cfg_pnvlist)
kmem_free(cfg_pnvlist, setcfg.set_cfg_pnvlist_len);
+ if (cfg_nvlist)
nvlist_free(cfg_nvlist);
/*
* Now that the reconfig is complete set our state back to
* enabled.
@@ -990,11 +990,11 @@
*
* STMF specification is wrong... says to return
* STMF_ABORTED, the code actually looks for
* STMF_ABORT_SUCCESS.
*/
- stmf_task_lport_aborted(itask->it_stmf_task,
+ stmf_task_lport_aborted_unlocked(itask->it_stmf_task,
STMF_ABORT_SUCCESS, STMF_IOF_LPORT_DONE);
return;
} else {
mutex_exit(&itask->it_mutex);
/*
@@ -1222,10 +1222,11 @@
ict->ict_keepalive_ttt = IDM_TASKIDS_MAX; /* Avoid IDM TT range */
ic->ic_handle = ict;
mutex_init(&ict->ict_mutex, NULL, MUTEX_DRIVER, NULL);
mutex_init(&ict->ict_statsn_mutex, NULL, MUTEX_DRIVER, NULL);
idm_refcnt_init(&ict->ict_refcnt, ict);
+ idm_refcnt_init(&ict->ict_dispatch_refcnt, ict);
/*
* Initialize login state machine
*/
if (iscsit_login_sm_init(ict) != IDM_STATUS_SUCCESS) {
@@ -1367,10 +1368,13 @@
}
/*
* Make sure there aren't any PDU's transitioning from the receive
* handler to the dispatch taskq.
*/
+ if (idm_refcnt_is_held(&ict->ict_dispatch_refcnt) < 0) {
+ cmn_err(CE_WARN, "Possible hang in iscsit_conn_lost");
+ }
idm_refcnt_wait_ref(&ict->ict_dispatch_refcnt);
return (IDM_STATUS_SUCCESS);
}
@@ -1383,17 +1387,14 @@
ict->ict_destroyed = B_TRUE;
mutex_exit(&ict->ict_mutex);
/* Generate session state machine event */
if (ict->ict_sess != NULL) {
- /*
- * Session state machine will call iscsit_conn_destroy_done()
- * when it has removed references to this connection.
- */
iscsit_sess_sm_event(ict->ict_sess, SE_CONN_FAIL, ict);
}
+ idm_refcnt_wait_ref(&ict->ict_dispatch_refcnt);
idm_refcnt_wait_ref(&ict->ict_refcnt);
/*
* The session state machine does not need to post
* events to IDM any longer, so it is safe to set
* the idm connection reference to NULL
@@ -1405,10 +1406,11 @@
/* Clean up any text command remnants */
iscsit_text_cmd_fini(ict);
mutex_destroy(&ict->ict_mutex);
+ idm_refcnt_destroy(&ict->ict_dispatch_refcnt);
idm_refcnt_destroy(&ict->ict_refcnt);
kmem_free(ict, sizeof (*ict));
iscsit_global_rele();
@@ -1886,25 +1888,13 @@
mutex_exit(&iscsit_task->it_mutex);
/*
* Call IDM to abort the task. Due to a variety of
* circumstances the task may already be in the process of
* aborting.
- * We'll let IDM worry about rationalizing all that except
- * for one particular instance. If the state of the task
- * is TASK_COMPLETE, we need to indicate to the framework
- * that we are in fact done. This typically happens with
- * framework-initiated task management type requests
- * (e.g. abort task).
*/
- if (idt->idt_state == TASK_COMPLETE) {
- idm_refcnt_wait_ref(&idt->idt_refcnt);
- return (STMF_ABORT_SUCCESS);
- } else {
- idm_task_abort(idt->idt_ic, idt, AT_TASK_MGMT_ABORT);
- return (STMF_SUCCESS);
+ return (idm_task_abort(idt->idt_ic, idt, AT_TASK_MGMT_ABORT));
}
- }
/*NOTREACHED*/
}
/*ARGSUSED*/
@@ -1960,10 +1950,25 @@
iscsit_post_scsi_cmd(ic, rx_pdu);
}
iscsit_process_pdu_in_queue(ict->ict_sess);
}
+static int
+iscsit_validate_idm_pdu(idm_pdu_t *rx_pdu)
+{
+ iscsi_scsi_cmd_hdr_t *iscsi_scsi =
+ (iscsi_scsi_cmd_hdr_t *)rx_pdu->isp_hdr;
+
+ if ((iscsi_scsi->scb[0] == SCMD_READ) ||
+ (iscsi_scsi->scb[0] == SCMD_READ_G1) ||
+ (iscsi_scsi->scb[0] == SCMD_READ_G4)) {
+ if (iscsi_scsi->flags & ISCSI_FLAG_CMD_WRITE)
+ return (IDM_STATUS_FAIL);
+ }
+ return (IDM_STATUS_SUCCESS);
+}
+
/*
* ISCSI protocol
*/
void
@@ -1977,11 +1982,20 @@
(iscsi_scsi_cmd_hdr_t *)rx_pdu->isp_hdr;
iscsi_addl_hdr_t *ahs_hdr;
uint16_t addl_cdb_len = 0;
ict = ic->ic_handle;
+ if (iscsit_validate_idm_pdu(rx_pdu) != IDM_STATUS_SUCCESS) {
+ /* Finish processing request */
+ iscsit_set_cmdsn(ict, rx_pdu);
+ iscsit_send_direct_scsi_resp(ict, rx_pdu,
+ ISCSI_STATUS_CMD_COMPLETED, STATUS_CHECK);
+ idm_pdu_complete(rx_pdu, IDM_STATUS_PROTOCOL_ERROR);
+ return;
+ }
+
itask = iscsit_task_alloc(ict);
if (itask == NULL) {
/* Finish processing request */
iscsit_set_cmdsn(ict, rx_pdu);