Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 42e90414 authored by Joe Eykholt's avatar Joe Eykholt Committed by James Bottomley
Browse files

[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: default avatarJoe Eykholt <jeykholt@cisco.com>
Signed-off-by: default avatarRobert Love <robert.w.love@intel.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent 519e5135
Loading
Loading
Loading
Loading
+3 −3
Original line number Original line Diff line number Diff line
@@ -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)
+18 −4
Original line number Original line Diff line number Diff line
@@ -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);
			}
			}
+2 −0
Original line number Original line Diff line number Diff line
@@ -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;
};
};


/**
/**