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