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;