From e5e54f312b379997252ee8f3a1ddfd4576b0deb8 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Fri, 31 Jul 2015 01:09:58 +0000 Subject: [PATCH] iscsi-scst: Move old TM response dropping to preparing new response stage The second TM request can come while the old one, response for which is going to be delayed, is still being processed, hence no response prepared yet, so the delayed response should be dropped on the stage of the new response preparing. Otherwise in this place the old delayed response will trigger BUG_ON(). git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@6456 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- iscsi-scst/kernel/iscsi.c | 61 +++++++++++++++++++++++++------------ iscsi-scst/kernel/iscsi.h | 1 + iscsi-scst/kernel/nthread.c | 5 +-- 3 files changed, 44 insertions(+), 23 deletions(-) diff --git a/iscsi-scst/kernel/iscsi.c b/iscsi-scst/kernel/iscsi.c index b1442504b..e21a68403 100644 --- a/iscsi-scst/kernel/iscsi.c +++ b/iscsi-scst/kernel/iscsi.c @@ -2610,6 +2610,26 @@ again: return; } +/* + * Drops, but not releases(!) delayed TM response. + * sn_lock supposed to be held on entry. + */ +void iscsi_drop_delayed_tm_rsp(struct iscsi_cmnd *tm_rsp) +{ + struct iscsi_conn *conn = tm_rsp->conn; + struct iscsi_session *sess = conn->session; + + TRACE_ENTRY(); + + TRACE_MGMT_DBG("Dropping delayed TM rsp %p", tm_rsp); + sess->tm_rsp = NULL; + sess->tm_active--; + sBUG_ON(sess->tm_active < 0); + + TRACE_EXIT(); + return; +} + static void execute_task_management(struct iscsi_cmnd *req) { struct iscsi_conn *conn = req->conn; @@ -2630,21 +2650,7 @@ static void execute_task_management(struct iscsi_cmnd *req) spin_lock(&sess->sn_lock); sess->tm_active++; sess->tm_sn = req_hdr->cmd_sn; - if (sess->tm_rsp != NULL) { - struct iscsi_cmnd *tm_rsp = sess->tm_rsp; - - TRACE_MGMT_DBG("Dropping delayed TM rsp %p", tm_rsp); - - sess->tm_rsp = NULL; - sess->tm_active--; - - spin_unlock(&sess->sn_lock); - - sBUG_ON(sess->tm_active < 0); - - rsp_cmnd_release(tm_rsp); - } else - spin_unlock(&sess->sn_lock); + spin_unlock(&sess->sn_lock); scst_rx_mgmt_params_init(¶ms); @@ -3593,6 +3599,11 @@ static bool iscsi_is_delay_tm_resp(struct iscsi_cmnd *rsp) /* This should be checked for immediate TM commands as well */ +#if 0 + if (((scst_random() % 10) == 2)) + res = 1; +#endif + switch (function) { default: if (before(sess->exp_cmd_sn, req_hdr->cmd_sn)) @@ -3684,9 +3695,22 @@ static void iscsi_send_task_mgmt_resp(struct iscsi_cmnd *req, int status, rsp->should_close_all_conn = 1; } - sBUG_ON(sess->tm_rsp != NULL); - +again: spin_lock(&sess->sn_lock); + if (sess->tm_rsp != NULL) { + struct iscsi_cmnd *old_tm_rsp = sess->tm_rsp; + /* + * It is assumed that if we have another TM request, the + * original command the delayed TM response is waiting for + * is not going to come, hence we can drop it. + */ + iscsi_drop_delayed_tm_rsp(old_tm_rsp); + + spin_unlock(&sess->sn_lock); + rsp_cmnd_release(old_tm_rsp); + goto again; + } + if (iscsi_is_delay_tm_resp(rsp)) { TRACE_MGMT_DBG("Delaying TM fn %d response %p " "(req %p), because not all affected commands " @@ -3698,9 +3722,8 @@ static void iscsi_send_task_mgmt_resp(struct iscsi_cmnd *req, int status, goto out_release; } sess->tm_active--; - spin_unlock(&sess->sn_lock); - sBUG_ON(sess->tm_active < 0); + spin_unlock(&sess->sn_lock); iscsi_cmnd_init_write(rsp, ISCSI_INIT_WRITE_WAKE); diff --git a/iscsi-scst/kernel/iscsi.h b/iscsi-scst/kernel/iscsi.h index 908068bd0..7a4ca36ab 100644 --- a/iscsi-scst/kernel/iscsi.h +++ b/iscsi-scst/kernel/iscsi.h @@ -548,6 +548,7 @@ extern void cmnd_tx_start(struct iscsi_cmnd *); extern void cmnd_tx_end(struct iscsi_cmnd *); extern void req_cmnd_release_force(struct iscsi_cmnd *req); extern void rsp_cmnd_release(struct iscsi_cmnd *); +extern void iscsi_drop_delayed_tm_rsp(struct iscsi_cmnd *tm_rsp); extern void cmnd_done(struct iscsi_cmnd *cmnd); extern void conn_abort(struct iscsi_conn *conn); extern void iscsi_restart_cmnd(struct iscsi_cmnd *cmnd); diff --git a/iscsi-scst/kernel/nthread.c b/iscsi-scst/kernel/nthread.c index 1a0405a41..8329290e4 100644 --- a/iscsi-scst/kernel/nthread.c +++ b/iscsi-scst/kernel/nthread.c @@ -459,10 +459,7 @@ static void close_conn(struct iscsi_conn *conn) spin_lock(&session->sn_lock); if (session->tm_rsp && session->tm_rsp->conn == conn) { struct iscsi_cmnd *tm_rsp = session->tm_rsp; - TRACE_MGMT_DBG("Dropping delayed TM rsp %p", tm_rsp); - session->tm_rsp = NULL; - session->tm_active--; - WARN_ON(session->tm_active < 0); + iscsi_drop_delayed_tm_rsp(tm_rsp); spin_unlock(&session->sn_lock); mutex_unlock(&target->target_mutex);