Print this page
6742 Freed and reused idm_conn_t buffer leads to system panic.
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Steve Ping <steve.ping@nexenta.com>
Reviewed by: Dan McDonald <danmcd@omniti.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>

@@ -20,10 +20,11 @@
  */
 
 /*
  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  */
 
 #include <sys/cpuvar.h>
 #include <sys/ddi.h>
 #include <sys/sunddi.h>

@@ -168,10 +169,11 @@
          * The thread that generated the event that got us here may still
          * hold the ic_state_mutex. Once it is released we can safely
          * destroy it since there is no way to locate the object now.
          */
         mutex_enter(&ic->ic_state_mutex);
+        IDM_SM_TIMER_CLEAR(ic);
         mutex_destroy(&ic->ic_state_mutex);
 }
 
 void
 idm_conn_event(idm_conn_t *ic, idm_conn_event_t event, uintptr_t event_info)

@@ -489,19 +491,21 @@
 static void
 idm_login_timeout(void *arg)
 {
         idm_conn_t *ic = arg;
 
+        ic->ic_state_timeout = 0;
         idm_conn_event(ic, CE_LOGIN_TIMEOUT, NULL);
 }
 
 static void
 idm_state_s3_xpt_up(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
 {
         switch (event_ctx->iec_event) {
         case CE_LOGIN_RCV:
                 /* T4 */
+                /* Keep login timeout active through S3 and into S4 */
                 idm_initial_login_actions(ic, event_ctx);
                 idm_update_state(ic, CS_S4_IN_LOGIN, event_ctx);
                 break;
         case CE_LOGIN_TIMEOUT:
                 /*

@@ -516,18 +520,18 @@
                  * Iscsit doesn't want to hear from us again in this case.
                  * Since it rejected the connection it doesn't have a
                  * connection context to handle additional notifications.
                  * IDM needs to just clean things up on its own.
                  */
-                (void) untimeout(ic->ic_state_timeout);
+                IDM_SM_TIMER_CLEAR(ic);
                 idm_update_state(ic, CS_S9A_REJECTED, event_ctx);
                 break;
         case CE_CONNECT_FAIL:
         case CE_TRANSPORT_FAIL:
         case CE_LOGOUT_OTHER_CONN_SND:
                 /* T6 */
-                (void) untimeout(ic->ic_state_timeout);
+                IDM_SM_TIMER_CLEAR(ic);
                 (void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL);
                 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
                 break;
         case CE_TX_PROTOCOL_ERROR:
         case CE_RX_PROTOCOL_ERROR:

@@ -551,11 +555,11 @@
         switch (event_ctx->iec_event) {
         case CE_LOGIN_SUCCESS_RCV:
         case CE_LOGIN_SUCCESS_SND:
                 ASSERT(ic->ic_client_callback == NULL);
 
-                (void) untimeout(ic->ic_state_timeout);
+                IDM_SM_TIMER_CLEAR(ic);
                 idm_login_success_actions(ic, event_ctx);
                 if (ic->ic_rdma_extensions) {
                         /* T19 */
                         idm_update_state(ic, CS_S12_ENABLE_DM, event_ctx);
                 } else {

@@ -572,11 +576,11 @@
                 /*
                  * Allow the logout response pdu to be sent and defer
                  * the state machine cleanup until the completion callback.
                  * Only 1 level or callback interposition is allowed.
                  */
-                (void) untimeout(ic->ic_state_timeout);
+                IDM_SM_TIMER_CLEAR(ic);
                 pdu = (idm_pdu_t *)event_ctx->iec_info;
                 ASSERT(ic->ic_client_callback == NULL);
                 ic->ic_client_callback = pdu->isp_callback;
                 pdu->isp_callback =
                     idm_state_s9b_wait_snd_done_cb;

@@ -596,11 +600,11 @@
                 /* FALLTHROUGH */
         case CE_TRANSPORT_FAIL:
         case CE_LOGOUT_OTHER_CONN_SND:
         case CE_LOGOUT_OTHER_CONN_RCV:
                 /* T7 */
-                (void) untimeout(ic->ic_state_timeout);
+                IDM_SM_TIMER_CLEAR(ic);
                 (void) idm_notify_client(ic, CN_LOGIN_FAIL, NULL);
                 idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
                 break;
         case CE_LOGOUT_SESSION_SUCCESS:
                 /*

@@ -608,11 +612,11 @@
                  * A session reinstatement request can be received while a
                  * session is active and a login is in process. The iSCSI
                  * connections are shut down by a CE_LOGOUT_SESSION_SUCCESS
                  * event sent from the session to the IDM layer.
                  */
-                (void) untimeout(ic->ic_state_timeout);
+                IDM_SM_TIMER_CLEAR(ic);
                 if (IDM_CONN_ISTGT(ic)) {
                         ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
                 } else {
                         ic->ic_transport_ops->it_ini_conn_disconnect(ic);
                 }

@@ -824,10 +828,11 @@
 static void
 idm_logout_req_timeout(void *arg)
 {
         idm_conn_t *ic = arg;
 
+        ic->ic_state_timeout = 0;
         idm_conn_event(ic, CE_LOGOUT_TIMEOUT, NULL);
 }
 
 static void
 idm_state_s7_logout_req(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)

@@ -838,20 +843,20 @@
         case CE_LOGOUT_THIS_CONN_SND:
         case CE_LOGOUT_OTHER_CONN_RCV:
         case CE_LOGOUT_OTHER_CONN_SND:
                 /* T10 */
                 if (IDM_CONN_ISTGT(ic)) {
-                        (void) untimeout(ic->ic_state_timeout);
+                        IDM_SM_TIMER_CLEAR(ic);
                 }
                 idm_ffp_disable(ic, FD_CONN_LOGOUT); /* Explicit logout */
                 idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx);
                 break;
         case CE_LOGOUT_SESSION_RCV:
         case CE_LOGOUT_SESSION_SND:
                 /* T10 */
                 if (IDM_CONN_ISTGT(ic)) {
-                        (void) untimeout(ic->ic_state_timeout);
+                        IDM_SM_TIMER_CLEAR(ic);
                 }
                 idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */
                 idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx);
                 break;
         case CE_ASYNC_LOGOUT_RCV:

@@ -863,21 +868,21 @@
         case CE_ASYNC_DROP_CONN_SND:
         case CE_ASYNC_DROP_ALL_CONN_RCV:
         case CE_ASYNC_DROP_ALL_CONN_SND:
                 /* T16 */
                 if (IDM_CONN_ISTGT(ic)) {
-                        (void) untimeout(ic->ic_state_timeout);
+                        IDM_SM_TIMER_CLEAR(ic);
                 }
                 /* FALLTHROUGH */
         case CE_LOGOUT_TIMEOUT:
                 idm_ffp_disable(ic, FD_CONN_FAIL); /* Implicit logout */
                 idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
                 break;
         case CE_LOGOUT_SESSION_SUCCESS:
                 /* T18 */
                 if (IDM_CONN_ISTGT(ic)) {
-                        (void) untimeout(ic->ic_state_timeout);
+                        IDM_SM_TIMER_CLEAR(ic);
                 }
                 idm_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */
 
                 /* Close connection (if it's not already closed) */
                 if (IDM_CONN_ISTGT(ic)) {

@@ -904,10 +909,11 @@
 static void
 idm_cleanup_timeout(void *arg)
 {
         idm_conn_t *ic = arg;
 
+        ic->ic_state_timeout = 0;
         idm_conn_event(ic, CE_CLEANUP_TIMEOUT, NULL);
 }
 
 static void
 idm_state_s8_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)

@@ -920,11 +926,11 @@
          */
         switch (event_ctx->iec_event) {
         case CE_LOGOUT_SUCCESS_RCV:
         case CE_LOGOUT_SUCCESS_SND:
         case CE_LOGOUT_SESSION_SUCCESS:
-                (void) untimeout(ic->ic_state_timeout);
+                IDM_SM_TIMER_CLEAR(ic);
                 /*FALLTHROUGH*/
         case CE_CLEANUP_TIMEOUT:
                 /* M1 */
                 idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
                 break;

@@ -1029,11 +1035,11 @@
                 idm_update_state(ic, CS_S8_CLEANUP, event_ctx);
                 break;
         case CE_LOGOUT_SUCCESS_SND:
         case CE_LOGOUT_SUCCESS_RCV:
         case CE_LOGOUT_SESSION_SUCCESS:
-                (void) untimeout(ic->ic_state_timeout);
+                IDM_SM_TIMER_CLEAR(ic);
                 /*FALLTHROUGH*/
         case CE_CLEANUP_TIMEOUT:
                 idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
                 break;
         case CE_LOGOUT_SUCCESS_SND_DONE:

@@ -1185,10 +1191,11 @@
 
                 /*
                  * First login received will cause a transition to
                  * CS_S4_IN_LOGIN.  Start login timer.
                  */
+                IDM_SM_TIMER_CHECK(ic);
                 ic->ic_state_timeout = timeout(idm_login_timeout, ic,
                     drv_usectohz(IDM_LOGIN_SECONDS*1000000));
                 break;
         case CS_S4_IN_LOGIN:
                 if (ic->ic_conn_type == CONN_TYPE_INI) {

@@ -1220,10 +1227,11 @@
         case CS_S6_IN_LOGOUT:
                 break;
         case CS_S7_LOGOUT_REQ:
                 /* Start logout timer for target connections */
                 if (IDM_CONN_ISTGT(ic)) {
+                        IDM_SM_TIMER_CHECK(ic);
                         ic->ic_state_timeout = timeout(idm_logout_req_timeout,
                             ic, drv_usectohz(IDM_LOGOUT_SECONDS*1000000));
                 }
                 break;
         case CS_S8_CLEANUP:

@@ -1236,10 +1244,11 @@
 
                 /* Stop executing active tasks */
                 idm_task_abort(ic, NULL, AT_INTERNAL_SUSPEND);
 
                 /* Start logout timer */
+                IDM_SM_TIMER_CHECK(ic);
                 ic->ic_state_timeout = timeout(idm_cleanup_timeout, ic,
                     drv_usectohz(IDM_CLEANUP_SECONDS*1000000));
                 break;
         case CS_S10_IN_CLEANUP:
                 break;