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;