diff options
author | Joe Eykholt <jeykholt@cisco.com> | 2010-07-21 02:19:37 +0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-07-28 18:05:48 +0400 |
commit | 42e9041467cf5fd33501b91b27e26807c259c896 (patch) | |
tree | 41a335a931e151f3fa00f384b5d1fb024421b7d2 /drivers/scsi/libfc | |
parent | 519e5135e2537c9dbc1cbcc0891b0a936ff5dcd2 (diff) | |
download | linux-42e9041467cf5fd33501b91b27e26807c259c896.tar.xz |
[SCSI] libfc: convert rport lookup to be RCU safe
To allow LLD to do lookups on rports without grabbing a mutex,
make them RCU-safe. The caller of lport->tt.rport_lookup will
have the choice of holding disc_mutex or the rcu_read_lock().
Signed-off-by: Joe Eykholt <jeykholt@cisco.com>
Signed-off-by: Robert Love <robert.w.love@intel.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/libfc')
-rw-r--r-- | drivers/scsi/libfc/fc_disc.c | 6 | ||||
-rw-r--r-- | drivers/scsi/libfc/fc_rport.c | 22 |
2 files changed, 21 insertions, 7 deletions
diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index c7985da88099..d0fa9a0ddc8d 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -63,12 +63,12 @@ static void fc_disc_restart(struct fc_disc *); void fc_disc_stop_rports(struct fc_disc *disc) { struct fc_lport *lport; - struct fc_rport_priv *rdata, *next; + struct fc_rport_priv *rdata; lport = disc->lport; mutex_lock(&disc->disc_mutex); - list_for_each_entry_safe(rdata, next, &disc->rports, peers) + list_for_each_entry_rcu(rdata, &disc->rports, peers) lport->tt.rport_logoff(rdata); mutex_unlock(&disc->disc_mutex); } @@ -292,7 +292,7 @@ static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event) * Skip ports which were never discovered. These are the dNS port * and ports which were created by PLOGI. */ - list_for_each_entry(rdata, &disc->rports, peers) { + list_for_each_entry_rcu(rdata, &disc->rports, peers) { if (!rdata->disc_id) continue; if (rdata->disc_id == disc->disc_id) diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 363cde30c940..6b569732f892 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -95,13 +95,15 @@ static const char *fc_rport_state_names[] = { * fc_rport_lookup() - Lookup a remote port by port_id * @lport: The local port to lookup the remote port on * @port_id: The remote port ID to look up + * + * The caller must hold either disc_mutex or rcu_read_lock(). */ static struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport, u32 port_id) { struct fc_rport_priv *rdata; - list_for_each_entry(rdata, &lport->disc.rports, peers) + list_for_each_entry_rcu(rdata, &lport->disc.rports, peers) if (rdata->ids.port_id == port_id) return rdata; return NULL; @@ -146,11 +148,23 @@ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout); INIT_WORK(&rdata->event_work, fc_rport_work); if (port_id != FC_FID_DIR_SERV) - list_add(&rdata->peers, &lport->disc.rports); + list_add_rcu(&rdata->peers, &lport->disc.rports); return rdata; } /** + * fc_rport_free_rcu() - Free a remote port + * @rcu: The rcu_head structure inside the remote port + */ +static void fc_rport_free_rcu(struct rcu_head *rcu) +{ + struct fc_rport_priv *rdata; + + rdata = container_of(rcu, struct fc_rport_priv, rcu); + kfree(rdata); +} + +/** * fc_rport_destroy() - Free a remote port after last reference is released * @kref: The remote port's kref */ @@ -159,7 +173,7 @@ static void fc_rport_destroy(struct kref *kref) struct fc_rport_priv *rdata; rdata = container_of(kref, struct fc_rport_priv, kref); - kfree(rdata); + call_rcu(&rdata->rcu, fc_rport_free_rcu); } /** @@ -334,7 +348,7 @@ static void fc_rport_work(struct work_struct *work) mutex_unlock(&rdata->rp_mutex); } else { FC_RPORT_DBG(rdata, "work delete\n"); - list_del(&rdata->peers); + list_del_rcu(&rdata->peers); mutex_unlock(&rdata->rp_mutex); kref_put(&rdata->kref, lport->tt.rport_destroy); } |