From c27ebc66b4ff3151b76dc3d1fb9b555df9ac2dd9 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 14 Aug 2008 23:19:12 -0500 Subject: [PATCH 14/23] libfc: check ESB_ST_COMPLETE before completing ep (take 2) I guess the list is not allowing attachments, so here is a resend inline. If an abort thread and a normal thread decided to call exch_done then we end up doing a dec on the refcount too many times. This patch checks for ESB_ST_COMPLETE before completing it. Signed-off-by: Mike Christie --- drivers/scsi/libfc/fc_exch.c | 13 +++++++++++-- 1 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 7d7a3ef..a4d3901 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -390,7 +390,7 @@ static void fc_exch_timeout(unsigned long ep_arg) spin_lock_bh(&ep->ex_lock); e_stat = ep->esb_stat; if (e_stat & ESB_ST_COMPLETE) { - ep->esb_stat = e_stat & ~ESB_ST_REC_QUAL; + ep->esb_stat = e_stat & ~(ESB_ST_REC_QUAL | ESB_ST_COMPLETE); spin_unlock_bh(&ep->ex_lock); if (e_stat & ESB_ST_REC_QUAL) fc_exch_rrq(ep); @@ -559,8 +559,17 @@ static int fc_exch_done_locked(struct fc_exch *ep) { int rc = 1; - ep->esb_stat |= ESB_ST_COMPLETE; + /* + * We must check for completion in case there are two threads + * tyring to complete this. But the rrq code will reuse the + * ep, and in that case we only clear the resp and set it as + * complete, so it can be reused by the timer to send the rrq. + */ ep->resp = NULL; + if (ep->esb_stat & ESB_ST_COMPLETE) + return rc; + ep->esb_stat |= ESB_ST_COMPLETE; + if (!(ep->esb_stat & ESB_ST_REC_QUAL)) { if (del_timer(&ep->ex_timer)) atomic_dec(&ep->ex_refcnt); /* drop hold for timer */ -- 1.5.4.1