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;