From e2a66d91789c43a2b9df0e9aa0bf5fe11b7928d9 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Tue, 12 Aug 2008 20:47:23 -0500 Subject: [PATCH 03/23] libfc: remove exrta hold/release sequences For most functions where we do a hold, lock, release the caller has hold on the ep already, so there is no point in doing this. The exception was fc_exch_reset. I changed this so we hold the em_lock when looping over the ex_list and take a hold like is done in the the find function. It also looked like fc_exch_reset could run while fc_exch_recv was running. If fc_exch_recv had passed the port state checks then it could release eps next to the one fc_exch_reset was working on and list_for_each_entry cannot handle that. I just restart the loop for this case, so we do not return from the function until we have completed one loop over the list. Signed-off-by: Mike Christie --- drivers/scsi/libfc/fc_exch.c | 24 +++++++++++++++++------- 1 files changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 6b4236e..377d165 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -408,13 +408,11 @@ static void fc_exch_timeout(unsigned long ep_arg) ep->esb_stat |= ESB_ST_COMPLETE; spin_unlock_bh(&ep->ex_lock); } else { - fc_exch_hold(ep); resp = ep->resp; ep->resp = NULL; arg = ep->resp_arg; spin_unlock_bh(&ep->ex_lock); fc_seq_exch_abort(sp); - fc_exch_release(ep); if (resp) resp(sp, ERR_PTR(-FC_EX_TIMEOUT), arg); @@ -1262,7 +1260,6 @@ static void fc_exch_abts_resp(struct fc_exch *ep, struct fc_frame *fp) if (fc_exch_debug) FC_DBG("exch: BLS rctl %x - %s\n", fh->fh_r_ctl, fc_exch_rctl_name(fh->fh_r_ctl)); - fc_exch_hold(ep); spin_lock_bh(&ep->ex_lock); switch (fh->fh_r_ctl) { case FC_RCTL_BA_ACC: @@ -1293,7 +1290,6 @@ static void fc_exch_abts_resp(struct fc_exch *ep, struct fc_frame *fp) if (ntoh24(fh->fh_f_ctl) & FC_FC_LAST_SEQ) fc_exch_complete_locked(ep); spin_unlock_bh(&ep->ex_lock); - fc_exch_release(ep); fc_frame_free(fp); } @@ -1408,7 +1404,6 @@ static void fc_exch_reset(struct fc_exch *ep) void (*resp)(struct fc_seq *, struct fc_frame *, void *); void *arg; - fc_exch_hold(ep); spin_lock_bh(&ep->ex_lock); resp = ep->resp; ep->resp = NULL; @@ -1426,7 +1421,6 @@ static void fc_exch_reset(struct fc_exch *ep) spin_unlock_bh(&ep->ex_lock); if (resp) resp(sp, ERR_PTR(-FC_EX_CLOSED), arg); - fc_exch_release(ep); } /* @@ -1439,11 +1433,27 @@ void fc_exch_mgr_reset(struct fc_exch_mgr *mp, u32 sid, u32 did) struct fc_exch *ep; struct fc_exch *next; + spin_lock_bh(&mp->em_lock); +restart: list_for_each_entry_safe(ep, next, &mp->ex_list, ex_list) { if ((sid == 0 || sid == ep->sid) && - (did == 0 || did == ep->did)) + (did == 0 || did == ep->did)) { + fc_exch_hold(ep); + spin_unlock_bh(&mp->em_lock); + fc_exch_reset(ep); + + fc_exch_release(ep); + spin_lock_bh(&mp->em_lock); + + /* + * must restart loop incase while lock was down + * multiple eps were released. + */ + goto restart; + } } + spin_unlock_bh(&mp->em_lock); } EXPORT_SYMBOL(fc_exch_mgr_reset); -- 1.5.5.1