From 8599ec445244736218cd56602f5e27ca463f2d41 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Wed, 26 Mar 2014 23:51:36 +0000 Subject: [PATCH] Reimplement dropping of TM requests in a more reliable manner git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@5395 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- iscsi-scst/kernel/iscsi.c | 34 +++++++++++++++++++++++++++------- scst/README | 15 +++++++++------ scst/README_in-tree | 15 +++++++++------ scst/include/scst.h | 19 +++++++++++++------ scst/src/scst_targ.c | 4 +--- 5 files changed, 59 insertions(+), 28 deletions(-) diff --git a/iscsi-scst/kernel/iscsi.c b/iscsi-scst/kernel/iscsi.c index c4b903c6e..0bddc6dcf 100644 --- a/iscsi-scst/kernel/iscsi.c +++ b/iscsi-scst/kernel/iscsi.c @@ -61,7 +61,8 @@ static struct page *dummy_page; static struct scatterlist dummy_sg; static void cmnd_remove_data_wait_hash(struct iscsi_cmnd *cmnd); -static void iscsi_send_task_mgmt_resp(struct iscsi_cmnd *req, int status); +static void iscsi_send_task_mgmt_resp(struct iscsi_cmnd *req, int status, + bool dropped); static void iscsi_check_send_delayed_tm_resp(struct iscsi_session *sess); static void req_cmnd_release(struct iscsi_cmnd *req); static int cmnd_insert_data_wait_hash(struct iscsi_cmnd *cmnd); @@ -2660,7 +2661,7 @@ static void execute_task_management(struct iscsi_cmnd *req) reject: if (rc != 0) - iscsi_send_task_mgmt_resp(req, status); + iscsi_send_task_mgmt_resp(req, status, false); return; } @@ -3488,7 +3489,8 @@ out: return; } -static void iscsi_send_task_mgmt_resp(struct iscsi_cmnd *req, int status) +static void iscsi_send_task_mgmt_resp(struct iscsi_cmnd *req, int status, + bool drop) { struct iscsi_cmnd *rsp; struct iscsi_task_mgt_hdr *req_hdr = @@ -3500,7 +3502,26 @@ static void iscsi_send_task_mgmt_resp(struct iscsi_cmnd *req, int status) TRACE_ENTRY(); TRACE_MGMT_DBG("TM req %p finished", req); - TRACE(TRACE_MGMT, "iSCSI TM fn %d finished, status %d", fn, status); + TRACE(TRACE_MGMT, "iSCSI TM fn %d finished, status %d, dropped %d", + fn, status, drop); + + if (drop) { + spin_lock(&sess->sn_lock); + sess->tm_active--; + spin_unlock(&sess->sn_lock); + if (fn == ISCSI_FUNCTION_TARGET_COLD_RESET) { + struct iscsi_target *target = req->conn->session->target; + + PRINT_INFO("Closing all connections for target %x at " + "COLD RESET from initiator %s", target->tid, + req->conn->session->initiator_name); + + mutex_lock(&target->target_mutex); + target_del_all_sess(target, 0); + mutex_unlock(&target->target_mutex); + } + goto out_release; + } rsp = iscsi_alloc_rsp(req); rsp_hdr = (struct iscsi_task_rsp_hdr *)&rsp->pdu.bhs; @@ -3569,8 +3590,7 @@ static void iscsi_task_mgmt_fn_done(struct scst_mgmt_cmd *scst_mcmd) int fn = scst_mgmt_cmd_get_fn(scst_mcmd); struct iscsi_cmnd *req = (struct iscsi_cmnd *) scst_mgmt_cmd_get_tgt_priv(scst_mcmd); - int status = - iscsi_get_mgmt_response(scst_mgmt_cmd_get_status(scst_mcmd)); + int status = iscsi_get_mgmt_response(scst_mgmt_cmd_get_status(scst_mcmd)); if ((status == ISCSI_RESPONSE_UNKNOWN_TASK) && (fn == SCST_ABORT_TASK)) { @@ -3592,7 +3612,7 @@ static void iscsi_task_mgmt_fn_done(struct scst_mgmt_cmd *scst_mcmd) sBUG_ON(1); break; default: - iscsi_send_task_mgmt_resp(req, status); + iscsi_send_task_mgmt_resp(req, status, scst_mgmt_cmd_dropped(scst_mcmd)); scst_mgmt_cmd_set_tgt_priv(scst_mcmd, NULL); break; } diff --git a/scst/README b/scst/README index 640cc016e..3e45a2cf6 100644 --- a/scst/README +++ b/scst/README @@ -603,16 +603,19 @@ Every target should have at least the following entries: * 2 - immediately abort all coming commands and drop all coming TM commands - * 3 - immediately abort all coming data transfer commands. This is - the most evil mode, because it is not too well handled by many - initiator OS'es, including Linux, so they may never recover from - it. + * 3 - immediately abort all coming data transfer commands. * 4 - immediately abort all coming data transfer commands and drop all coming TM commands - CAUTION! With some target drivers modes 2 and 4 can cause internal - resources leaks, so don't abuse those options! + Modes 3 and 4 are the most evil ones, because they are not too well + handled by many initiator OS'es, including Linux, so they may never + recover from it. + + Note, dropping TM commands, i.e. not sending response on them, + implemented not for all target drivers. If it's implemented for your + particular target driver or not, you can find out by checking traces + or the target driver's source code. - cpu_mask - defines CPU affinity mask for threads serving this target. For threads serving LUNs it is used only for devices with diff --git a/scst/README_in-tree b/scst/README_in-tree index ba1824acb..1e19ed397 100644 --- a/scst/README_in-tree +++ b/scst/README_in-tree @@ -465,16 +465,19 @@ Every target should have at least the following entries: * 2 - immediately abort all coming commands and drop all coming TM commands - * 3 - immediately abort all coming data transfer commands. This is - the most evil mode, because it is not too well handled by many - initiator OS'es, including Linux, so they may never recover from - it. + * 3 - immediately abort all coming data transfer commands. * 4 - immediately abort all coming data transfer commands and drop all coming TM commands - CAUTION! With some target drivers modes 2 and 4 can cause internal - resources leaks, so don't abuse those options! + Modes 3 and 4 are the most evil ones, because they are not too well + handled by many initiator OS'es, including Linux, so they may never + recover from it. + + Note, dropping TM commands, i.e. not sending response on them, + implemented not for all target drivers. If it's implemented for your + particular target driver or not, you can find out by checking traces + or the target driver's source code. - cpu_mask - defines CPU affinity mask for threads serving this target. For threads serving LUNs it is used only for devices with diff --git a/scst/include/scst.h b/scst/include/scst.h index c8357a53d..378dc589c 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -2289,6 +2289,7 @@ struct scst_mgmt_cmd { unsigned int cmd_sn_set:1; /* set, if cmd_sn field is valid */ /* Set if dev handler's task_mgmt_fn_received was called */ unsigned int task_mgmt_fn_received_called:1; + unsigned int mcmd_dropped:1; /* set if mcmd was dropped */ /* * Number of commands to finish before sending response, @@ -3717,12 +3718,6 @@ static inline int scst_mgmt_cmd_get_status(struct scst_mgmt_cmd *mcmd) return mcmd->status; } -/* Returns mgmt cmd's TM fn */ -static inline int scst_mgmt_cmd_get_fn(struct scst_mgmt_cmd *mcmd) -{ - return mcmd->fn; -} - static inline void scst_mgmt_cmd_set_status(struct scst_mgmt_cmd *mcmd, int status) { @@ -3732,6 +3727,18 @@ static inline void scst_mgmt_cmd_set_status(struct scst_mgmt_cmd *mcmd, mcmd->status = status; } +/* Returns mgmt cmd's TM fn */ +static inline int scst_mgmt_cmd_get_fn(struct scst_mgmt_cmd *mcmd) +{ + return mcmd->fn; +} + +/* Returns true if mgmt cmd should be dropped, i.e. response not sent */ +static inline bool scst_mgmt_cmd_dropped(struct scst_mgmt_cmd *mcmd) +{ + return mcmd->mcmd_dropped; +} + /* * Called by dev handler's task_mgmt_fn_*() to notify SCST core that mcmd * is going to complete asynchronously. diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index f84a9fe64..a75190726 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -5497,13 +5497,11 @@ static int scst_mgmt_cmd_init(struct scst_mgmt_cmd *mcmd) TRACE_ENTRY(); t = mcmd->sess->acg->acg_black_hole_type; - if (unlikely((t == SCST_ACG_BLACK_HOLE_ALL) || (t == SCST_ACG_BLACK_HOLE_DATA_MCMD))) { TRACE_MGMT_DBG("Dropping mcmd %p (fn %d, initiator %s)", mcmd, mcmd->fn, mcmd->sess->initiator_name); - mcmd->state = SCST_MCMD_STATE_FINISHED; - goto out; + mcmd->mcmd_dropped = 1; } switch (mcmd->fn) {