From 421dbafa7caad416f715451d630b8c0a24ceaace Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sun, 17 Jan 2010 13:07:46 +0000 Subject: [PATCH] Changes: - The entire receive queue can be used again instead of only SRPT_RQ_SIZE - 1 elements (as in r1470). - Added initiator-lockup-avoidance code to SRP_TSK_MGMT processing code too. git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1473 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- srpt/src/ib_srpt.c | 46 +++++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/srpt/src/ib_srpt.c b/srpt/src/ib_srpt.c index 7655f5e75..1de961e18 100644 --- a/srpt/src/ib_srpt.c +++ b/srpt/src/ib_srpt.c @@ -2596,15 +2596,29 @@ out: /** * srpt_must_wait_for_cred() - Whether or not the target must wait with * sending a response towards the initiator in order to avoid that the - * initiator locks up. Since an initiator must not send an SRP_CMD request - * when its req_lim variable is less than 2, and since sending a response to - * the initiator will make its req_lim variable equal to ch->req_lim, do not - * send a response to the initiator that would make its req_lim variable less - * than 2. + * initiator locks up. The Linux SRP initiator locks up when: + * initiator.req_lim < req_lim_min (2 for SRP_CMD; 1 for SRP_TSK_MGMT). + * no new SRP_RSP is received, or new SRP_RSP do not increase initiator.req_lim. + * In order to avoid an initiator lock up, the target must not send an SRP_RSP + * that keeps initiator.req_lim < req_lim_min when initiator.req_lim + * < req_lim_min. when target.req_lim == req_lim_min - 1, initiator.req_lim must + * also equal req_lim_min - 1 because of the credit mechanism defined in the + * SRP standard. Hence wait with sending a response if that response would not + * increase initiator.req_lim. */ -static inline bool srpt_must_wait_for_cred(struct srpt_rdma_ch *ch) +static bool srpt_must_wait_for_cred(struct srpt_rdma_ch *ch, int req_lim_min) { - return atomic_read(&ch->req_lim) < 2; + int req_lim; + req_lim = atomic_read(&ch->req_lim); + + return req_lim < req_lim_min + && req_lim - atomic_read(&ch->last_response_req_lim) + 1 <= 0; +} + +static void srpt_wait_for_cred(struct srpt_rdma_ch *ch, int req_lim_min) +{ + while (unlikely(srpt_must_wait_for_cred(ch, req_lim_min))) + schedule(); } /** @@ -2636,16 +2650,13 @@ static int srpt_xmit_response(struct scst_cmd *scmnd) goto out; } - if (srpt_must_wait_for_cred(ch)) { - if (scst_cmd_atomic(scmnd)) { - TRACE_DBG("%s", "Switching to thread context."); - ret = SCST_TGT_RES_NEED_THREAD_CTX; - goto out; - } - while (srpt_must_wait_for_cred(ch)) - schedule(); + if (unlikely(scst_cmd_atomic(scmnd))) { + TRACE_DBG("%s", "Switching to thread context."); + ret = SCST_TGT_RES_NEED_THREAD_CTX; + goto out; } + srpt_wait_for_cred(ch, 2); if (srpt_set_cmd_state(ioctx, SRPT_STATE_PROCESSED) == SRPT_STATE_ABORTED) { @@ -2715,8 +2726,9 @@ static void srpt_tsk_mgmt_done(struct scst_mgmt_cmd *mcmnd) __func__, (unsigned long long)mgmt_ioctx->tag, scst_mgmt_cmd_get_status(mcmnd)); - if (atomic_read(&ch->req_lim) < 1) - PRINT_ERROR("%s", "Initiator may lock up !!"); + WARN_ON(in_irq()); + + srpt_wait_for_cred(ch, 1); if (srpt_set_cmd_state(ioctx, SRPT_STATE_PROCESSED) == SRPT_STATE_ABORTED)