aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libfc
diff options
context:
space:
mode:
authorJoe Eykholt <jeykholt@cisco.com>2010-07-20 18:19:37 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-07-28 10:05:48 -0400
commit42e9041467cf5fd33501b91b27e26807c259c896 (patch)
tree41a335a931e151f3fa00f384b5d1fb024421b7d2 /drivers/scsi/libfc
parent519e5135e2537c9dbc1cbcc0891b0a936ff5dcd2 (diff)
[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.c6
-rw-r--r--drivers/scsi/libfc/fc_rport.c22
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 *);
63void fc_disc_stop_rports(struct fc_disc *disc) 63void fc_disc_stop_rports(struct fc_disc *disc)
64{ 64{
65 struct fc_lport *lport; 65 struct fc_lport *lport;
66 struct fc_rport_priv *rdata, *next; 66 struct fc_rport_priv *rdata;
67 67
68 lport = disc->lport; 68 lport = disc->lport;
69 69
70 mutex_lock(&disc->disc_mutex); 70 mutex_lock(&disc->disc_mutex);
71 list_for_each_entry_safe(rdata, next, &disc->rports, peers) 71 list_for_each_entry_rcu(rdata, &disc->rports, peers)
72 lport->tt.rport_logoff(rdata); 72 lport->tt.rport_logoff(rdata);
73 mutex_unlock(&disc->disc_mutex); 73 mutex_unlock(&disc->disc_mutex);
74} 74}
@@ -292,7 +292,7 @@ static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event)
292 * Skip ports which were never discovered. These are the dNS port 292 * Skip ports which were never discovered. These are the dNS port
293 * and ports which were created by PLOGI. 293 * and ports which were created by PLOGI.
294 */ 294 */
295 list_for_each_entry(rdata, &disc->rports, peers) { 295 list_for_each_entry_rcu(rdata, &disc->rports, peers) {
296 if (!rdata->disc_id) 296 if (!rdata->disc_id)
297 continue; 297 continue;
298 if (rdata->disc_id == disc->disc_id) 298 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[] = {
95 * fc_rport_lookup() - Lookup a remote port by port_id 95 * fc_rport_lookup() - Lookup a remote port by port_id
96 * @lport: The local port to lookup the remote port on 96 * @lport: The local port to lookup the remote port on
97 * @port_id: The remote port ID to look up 97 * @port_id: The remote port ID to look up
98 *
99 * The caller must hold either disc_mutex or rcu_read_lock().
98 */ 100 */
99static struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport, 101static struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport,
100 u32 port_id) 102 u32 port_id)
101{ 103{
102 struct fc_rport_priv *rdata; 104 struct fc_rport_priv *rdata;
103 105
104 list_for_each_entry(rdata, &lport->disc.rports, peers) 106 list_for_each_entry_rcu(rdata, &lport->disc.rports, peers)
105 if (rdata->ids.port_id == port_id) 107 if (rdata->ids.port_id == port_id)
106 return rdata; 108 return rdata;
107 return NULL; 109 return NULL;
@@ -146,11 +148,23 @@ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport,
146 INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout); 148 INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout);
147 INIT_WORK(&rdata->event_work, fc_rport_work); 149 INIT_WORK(&rdata->event_work, fc_rport_work);
148 if (port_id != FC_FID_DIR_SERV) 150 if (port_id != FC_FID_DIR_SERV)
149 list_add(&rdata->peers, &lport->disc.rports); 151 list_add_rcu(&rdata->peers, &lport->disc.rports);
150 return rdata; 152 return rdata;
151} 153}
152 154
153/** 155/**
156 * fc_rport_free_rcu() - Free a remote port
157 * @rcu: The rcu_head structure inside the remote port
158 */
159static void fc_rport_free_rcu(struct rcu_head *rcu)
160{
161 struct fc_rport_priv *rdata;
162
163 rdata = container_of(rcu, struct fc_rport_priv, rcu);
164 kfree(rdata);
165}
166
167/**
154 * fc_rport_destroy() - Free a remote port after last reference is released 168 * fc_rport_destroy() - Free a remote port after last reference is released
155 * @kref: The remote port's kref 169 * @kref: The remote port's kref
156 */ 170 */
@@ -159,7 +173,7 @@ static void fc_rport_destroy(struct kref *kref)
159 struct fc_rport_priv *rdata; 173 struct fc_rport_priv *rdata;
160 174
161 rdata = container_of(kref, struct fc_rport_priv, kref); 175 rdata = container_of(kref, struct fc_rport_priv, kref);
162 kfree(rdata); 176 call_rcu(&rdata->rcu, fc_rport_free_rcu);
163} 177}
164 178
165/** 179/**
@@ -334,7 +348,7 @@ static void fc_rport_work(struct work_struct *work)
334 mutex_unlock(&rdata->rp_mutex); 348 mutex_unlock(&rdata->rp_mutex);
335 } else { 349 } else {
336 FC_RPORT_DBG(rdata, "work delete\n"); 350 FC_RPORT_DBG(rdata, "work delete\n");
337 list_del(&rdata->peers); 351 list_del_rcu(&rdata->peers);
338 mutex_unlock(&rdata->rp_mutex); 352 mutex_unlock(&rdata->rp_mutex);
339 kref_put(&rdata->kref, lport->tt.rport_destroy); 353 kref_put(&rdata->kref, lport->tt.rport_destroy);
340 } 354 }