mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-24 04:34:08 +08:00
[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>
This commit is contained in:
parent
519e5135e2
commit
42e9041467
@ -63,12 +63,12 @@ static void fc_disc_restart(struct fc_disc *);
|
|||||||
void fc_disc_stop_rports(struct fc_disc *disc)
|
void fc_disc_stop_rports(struct fc_disc *disc)
|
||||||
{
|
{
|
||||||
struct fc_lport *lport;
|
struct fc_lport *lport;
|
||||||
struct fc_rport_priv *rdata, *next;
|
struct fc_rport_priv *rdata;
|
||||||
|
|
||||||
lport = disc->lport;
|
lport = disc->lport;
|
||||||
|
|
||||||
mutex_lock(&disc->disc_mutex);
|
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);
|
lport->tt.rport_logoff(rdata);
|
||||||
mutex_unlock(&disc->disc_mutex);
|
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
|
* Skip ports which were never discovered. These are the dNS port
|
||||||
* and ports which were created by PLOGI.
|
* 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)
|
if (!rdata->disc_id)
|
||||||
continue;
|
continue;
|
||||||
if (rdata->disc_id == disc->disc_id)
|
if (rdata->disc_id == disc->disc_id)
|
||||||
|
@ -95,13 +95,15 @@ static const char *fc_rport_state_names[] = {
|
|||||||
* fc_rport_lookup() - Lookup a remote port by port_id
|
* fc_rport_lookup() - Lookup a remote port by port_id
|
||||||
* @lport: The local port to lookup the remote port on
|
* @lport: The local port to lookup the remote port on
|
||||||
* @port_id: The remote port ID to look up
|
* @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,
|
static struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport,
|
||||||
u32 port_id)
|
u32 port_id)
|
||||||
{
|
{
|
||||||
struct fc_rport_priv *rdata;
|
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)
|
if (rdata->ids.port_id == port_id)
|
||||||
return rdata;
|
return rdata;
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -146,10 +148,22 @@ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport,
|
|||||||
INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout);
|
INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout);
|
||||||
INIT_WORK(&rdata->event_work, fc_rport_work);
|
INIT_WORK(&rdata->event_work, fc_rport_work);
|
||||||
if (port_id != FC_FID_DIR_SERV)
|
if (port_id != FC_FID_DIR_SERV)
|
||||||
list_add(&rdata->peers, &lport->disc.rports);
|
list_add_rcu(&rdata->peers, &lport->disc.rports);
|
||||||
return rdata;
|
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
|
* fc_rport_destroy() - Free a remote port after last reference is released
|
||||||
* @kref: The remote port's kref
|
* @kref: The remote port's kref
|
||||||
@ -159,7 +173,7 @@ static void fc_rport_destroy(struct kref *kref)
|
|||||||
struct fc_rport_priv *rdata;
|
struct fc_rport_priv *rdata;
|
||||||
|
|
||||||
rdata = container_of(kref, struct fc_rport_priv, kref);
|
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);
|
mutex_unlock(&rdata->rp_mutex);
|
||||||
} else {
|
} else {
|
||||||
FC_RPORT_DBG(rdata, "work delete\n");
|
FC_RPORT_DBG(rdata, "work delete\n");
|
||||||
list_del(&rdata->peers);
|
list_del_rcu(&rdata->peers);
|
||||||
mutex_unlock(&rdata->rp_mutex);
|
mutex_unlock(&rdata->rp_mutex);
|
||||||
kref_put(&rdata->kref, lport->tt.rport_destroy);
|
kref_put(&rdata->kref, lport->tt.rport_destroy);
|
||||||
}
|
}
|
||||||
|
@ -195,6 +195,7 @@ struct fc_rport_libfc_priv {
|
|||||||
* @rp_mutex: The mutex that protects the remote port
|
* @rp_mutex: The mutex that protects the remote port
|
||||||
* @retry_work: Handle for retries
|
* @retry_work: Handle for retries
|
||||||
* @event_callback: Callback when READY, FAILED or LOGO states complete
|
* @event_callback: Callback when READY, FAILED or LOGO states complete
|
||||||
|
* @rcu: Structure used for freeing in an RCU-safe manner
|
||||||
*/
|
*/
|
||||||
struct fc_rport_priv {
|
struct fc_rport_priv {
|
||||||
struct fc_lport *local_port;
|
struct fc_lport *local_port;
|
||||||
@ -217,6 +218,7 @@ struct fc_rport_priv {
|
|||||||
struct list_head peers;
|
struct list_head peers;
|
||||||
struct work_struct event_work;
|
struct work_struct event_work;
|
||||||
u32 supported_classes;
|
u32 supported_classes;
|
||||||
|
struct rcu_head rcu;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user