diff options
author | Joe Eykholt <jeykholt@cisco.com> | 2010-07-20 18:19:37 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-07-28 10:05:48 -0400 |
commit | 42e9041467cf5fd33501b91b27e26807c259c896 (patch) | |
tree | 41a335a931e151f3fa00f384b5d1fb024421b7d2 /drivers/scsi/libfc | |
parent | 519e5135e2537c9dbc1cbcc0891b0a936ff5dcd2 (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.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 *); | |||
63 | void fc_disc_stop_rports(struct fc_disc *disc) | 63 | void 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 | */ |
99 | static struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport, | 101 | static 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 | */ | ||
159 | static 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 | } |