From 95bba60a0a20217c4c662dbe30c0fbf76b6bed9a Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sat, 24 Jul 2010 16:47:29 +0000 Subject: [PATCH] Fixed a bug in the command abortion logic that could result rmmod ib_srpt to hang. git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1873 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- srpt/src/ib_srpt.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/srpt/src/ib_srpt.c b/srpt/src/ib_srpt.c index d24bf0a89..79e961a38 100644 --- a/srpt/src/ib_srpt.c +++ b/srpt/src/ib_srpt.c @@ -1182,13 +1182,11 @@ static void srpt_abort_scst_cmd(struct srpt_ioctx *ioctx, */ WARN_ON(!scst_cmd_aborted(scmnd)); break; - case SRPT_STATE_NEED_DATA: - /* RDMA read error or RDMA read timeout. */ case SRPT_STATE_DATA_IN: - /* - * SCST command abort flag has been set after the RDMA read - * started and before srpt_xmit_response() has been invoked. - */ + WARN_ON("ERROR: unexpected command state"); + break; + case SRPT_STATE_NEED_DATA: + /* SCST_DATA_WRITE - RDMA read error or RDMA read timeout. */ case SRPT_STATE_CMD_RSP_SENT: /* * SRP_RSP sending failed or the SRP_RSP send completion has @@ -1592,7 +1590,7 @@ static void srpt_handle_new_iu(struct srpt_rdma_ch *ch, ioctx->ch = ch; atomic_set(&ioctx->state, SRPT_STATE_NEW); - if (ch_state == RDMA_CHANNEL_DISCONNECTING) { + if (unlikely(ch_state == RDMA_CHANNEL_DISCONNECTING)) { srpt_set_cmd_state(ioctx, SRPT_STATE_DONE); srpt_reset_ioctx(ch, ioctx); return; @@ -2973,7 +2971,7 @@ out: } /** - * srpt_xfer_data() - Start data transfer between initiator and target. + * srpt_xfer_data() - Start data transfer from initiator to target. * * Note: Must not block. */ @@ -3052,10 +3050,10 @@ static void srpt_pending_cmd_timeout(struct scst_cmd *scmnd) } /** - * srpt_rdy_to_xfer() - SCST rdy_to_xfer callback. + * srpt_rdy_to_xfer() - SCST callback that fetches data from the initiator. * * Called by the SCST core to inform ib_srpt that data reception from the - * initiator should start (SCST_DATA_WRITE). Must not block. + * initiator to the target should start (SCST_DATA_WRITE). Must not block. */ static int srpt_rdy_to_xfer(struct scst_cmd *scmnd) { @@ -3189,7 +3187,8 @@ static int srpt_wait_for_cred(struct srpt_rdma_ch *ch, int req_lim_min) * srpt_xmit_response() - SCST callback function that transmits the response * to a SCSI command. * - * Must not block. + * Must not block. Must ensure that scst_tgt_cmd_done() will get invoked when + * returning SCST_TGT_RES_SUCCESS. */ static int srpt_xmit_response(struct scst_cmd *scmnd) { @@ -3207,6 +3206,11 @@ static int srpt_xmit_response(struct scst_cmd *scmnd) ch = scst_sess_get_tgt_priv(scst_cmd_get_session(scmnd)); BUG_ON(!ch); + EXTRACHECKS_WARN_ON(srpt_get_cmd_state(ioctx) != SRPT_STATE_NEW + && srpt_get_cmd_state(ioctx) != SRPT_STATE_DATA_IN); + + new_state = srpt_set_cmd_state(ioctx, SRPT_STATE_CMD_RSP_SENT); + if (unlikely(scst_cmd_aborted(scmnd))) { srpt_abort_scst_cmd(ioctx, srpt_context); ret = SCST_TGT_RES_SUCCESS; @@ -3215,9 +3219,6 @@ static int srpt_xmit_response(struct scst_cmd *scmnd) EXTRACHECKS_BUG_ON(scst_cmd_atomic(scmnd)); - new_state = srpt_set_cmd_state(ioctx, SRPT_STATE_CMD_RSP_SENT); - WARN_ON(new_state == SRPT_STATE_DONE); - dir = scst_cmd_get_data_direction(scmnd); ret = SCST_TGT_RES_SUCCESS;