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,29 ****
--- 20,30 ----
   */
  
  /*
   * 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,177 ****
--- 169,179 ----
           * 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,507 ****
--- 491,511 ----
  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,533 ****
                   * 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_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);
                  (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:
--- 520,537 ----
                   * 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.
                   */
!                 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 */
!                 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,561 ****
          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_login_success_actions(ic, event_ctx);
                  if (ic->ic_rdma_extensions) {
                          /* T19 */
                          idm_update_state(ic, CS_S12_ENABLE_DM, event_ctx);
                  } else {
--- 555,565 ----
          switch (event_ctx->iec_event) {
          case CE_LOGIN_SUCCESS_RCV:
          case CE_LOGIN_SUCCESS_SND:
                  ASSERT(ic->ic_client_callback == NULL);
  
!                 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,582 ****
                  /*
                   * 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);
                  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;
--- 576,586 ----
                  /*
                   * 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.
                   */
!                 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,606 ****
                  /* FALLTHROUGH */
          case CE_TRANSPORT_FAIL:
          case CE_LOGOUT_OTHER_CONN_SND:
          case CE_LOGOUT_OTHER_CONN_RCV:
                  /* T7 */
!                 (void) untimeout(ic->ic_state_timeout);
                  (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:
                  /*
--- 600,610 ----
                  /* FALLTHROUGH */
          case CE_TRANSPORT_FAIL:
          case CE_LOGOUT_OTHER_CONN_SND:
          case CE_LOGOUT_OTHER_CONN_RCV:
                  /* T7 */
!                 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,618 ****
                   * 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);
                  if (IDM_CONN_ISTGT(ic)) {
                          ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
                  } else {
                          ic->ic_transport_ops->it_ini_conn_disconnect(ic);
                  }
--- 612,622 ----
                   * 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.
                   */
!                 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,833 ****
--- 828,838 ----
  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,857 ****
          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_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_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */
                  idm_update_state(ic, CS_S6_IN_LOGOUT, event_ctx);
                  break;
          case CE_ASYNC_LOGOUT_RCV:
--- 843,862 ----
          case CE_LOGOUT_THIS_CONN_SND:
          case CE_LOGOUT_OTHER_CONN_RCV:
          case CE_LOGOUT_OTHER_CONN_SND:
                  /* T10 */
                  if (IDM_CONN_ISTGT(ic)) {
!                         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)) {
!                         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,883 ****
          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);
                  }
                  /* 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_ffp_disable(ic, FD_SESS_LOGOUT); /* Explicit logout */
  
                  /* Close connection (if it's not already closed) */
                  if (IDM_CONN_ISTGT(ic)) {
--- 868,888 ----
          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)) {
!                         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)) {
!                         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,913 ****
--- 909,919 ----
  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,930 ****
           */
          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);
                  /*FALLTHROUGH*/
          case CE_CLEANUP_TIMEOUT:
                  /* M1 */
                  idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
                  break;
--- 926,936 ----
           */
          switch (event_ctx->iec_event) {
          case CE_LOGOUT_SUCCESS_RCV:
          case CE_LOGOUT_SUCCESS_SND:
          case CE_LOGOUT_SESSION_SUCCESS:
!                 IDM_SM_TIMER_CLEAR(ic);
                  /*FALLTHROUGH*/
          case CE_CLEANUP_TIMEOUT:
                  /* M1 */
                  idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
                  break;
*** 1029,1039 ****
                  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);
                  /*FALLTHROUGH*/
          case CE_CLEANUP_TIMEOUT:
                  idm_update_state(ic, CS_S11_COMPLETE, event_ctx);
                  break;
          case CE_LOGOUT_SUCCESS_SND_DONE:
--- 1035,1045 ----
                  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:
!                 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,1194 ****
--- 1191,1201 ----
  
                  /*
                   * 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,1229 ****
--- 1227,1237 ----
          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,1245 ****
--- 1244,1254 ----
  
                  /* 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;