{
struct fc_rport_priv *rdata;
+ rcu_read_lock();
+ list_for_each_entry_rcu(rdata, &lport->disc.rports, peers) {
+ if (kref_get_unless_zero(&rdata->kref)) {
+ lport->tt.rport_logoff(rdata);
+ kref_put(&rdata->kref, lport->tt.rport_destroy);
+ }
+ }
+ rcu_read_unlock();
mutex_lock(&lport->disc.disc_mutex);
- list_for_each_entry_rcu(rdata, &lport->disc.rports, peers)
- lport->tt.rport_logoff(rdata);
lport->disc.disc_callback = NULL;
mutex_unlock(&lport->disc.disc_mutex);
}
mutex_unlock(&lport->disc.disc_mutex);
return;
}
+ mutex_lock(&rdata->rp_mutex);
+ mutex_unlock(&lport->disc.disc_mutex);
rdata->ops = &fcoe_ctlr_vn_rport_ops;
rdata->disc_id = lport->disc.disc_id;
ids = &rdata->ids;
if ((ids->port_name != -1 && ids->port_name != new->ids.port_name) ||
- (ids->node_name != -1 && ids->node_name != new->ids.node_name))
+ (ids->node_name != -1 && ids->node_name != new->ids.node_name)) {
+ mutex_unlock(&rdata->rp_mutex);
lport->tt.rport_logoff(rdata);
+ mutex_lock(&rdata->rp_mutex);
+ }
ids->port_name = new->ids.port_name;
ids->node_name = new->ids.node_name;
- mutex_unlock(&lport->disc.disc_mutex);
+ mutex_unlock(&rdata->rp_mutex);
frport = fcoe_ctlr_rport(rdata);
LIBFCOE_FIP_DBG(fip, "vn_add rport %6.6x %s\n",
unsigned long deadline;
next_time = jiffies + msecs_to_jiffies(FIP_VN_BEACON_INT * 10);
- mutex_lock(&lport->disc.disc_mutex);
+ rcu_read_lock();
list_for_each_entry_rcu(rdata, &lport->disc.rports, peers) {
+ if (!kref_get_unless_zero(&rdata->kref))
+ continue;
frport = fcoe_ctlr_rport(rdata);
- if (!frport->time)
+ if (!frport->time) {
+ kref_put(&rdata->kref, lport->tt.rport_destroy);
continue;
+ }
deadline = frport->time +
msecs_to_jiffies(FIP_VN_BEACON_INT * 25 / 10);
if (time_after_eq(jiffies, deadline)) {
lport->tt.rport_logoff(rdata);
} else if (time_before(deadline, next_time))
next_time = deadline;
+ kref_put(&rdata->kref, lport->tt.rport_destroy);
}
- mutex_unlock(&lport->disc.disc_mutex);
+ rcu_read_unlock();
return next_time;
}
mutex_lock(&disc->disc_mutex);
callback = disc->pending ? disc->disc_callback : NULL;
disc->pending = 0;
+ mutex_unlock(&disc->disc_mutex);
+ rcu_read_lock();
list_for_each_entry_rcu(rdata, &disc->rports, peers) {
+ if (!kref_get_unless_zero(&rdata->kref))
+ continue;
frport = fcoe_ctlr_rport(rdata);
if (frport->time)
lport->tt.rport_login(rdata);
+ kref_put(&rdata->kref, lport->tt.rport_destroy);
}
- mutex_unlock(&disc->disc_mutex);
+ rcu_read_unlock();
if (callback)
callback(lport, DISC_EV_SUCCESS);
}
lport = fc_disc_lport(disc);
- mutex_lock(&disc->disc_mutex);
- list_for_each_entry_rcu(rdata, &disc->rports, peers)
- lport->tt.rport_logoff(rdata);
- mutex_unlock(&disc->disc_mutex);
+ rcu_read_lock();
+ list_for_each_entry_rcu(rdata, &disc->rports, peers) {
+ if (kref_get_unless_zero(&rdata->kref)) {
+ lport->tt.rport_logoff(rdata);
+ kref_put(&rdata->kref, lport->tt.rport_destroy);
+ }
+ }
+ rcu_read_unlock();
}
/**
* Skip ports which were never discovered. These are the dNS port
* and ports which were created by PLOGI.
*/
+ rcu_read_lock();
list_for_each_entry_rcu(rdata, &disc->rports, peers) {
- if (!rdata->disc_id)
+ if (!kref_get_unless_zero(&rdata->kref))
continue;
- if (rdata->disc_id == disc->disc_id)
- lport->tt.rport_login(rdata);
- else
- lport->tt.rport_logoff(rdata);
+ if (rdata->disc_id) {
+ if (rdata->disc_id == disc->disc_id)
+ lport->tt.rport_login(rdata);
+ else
+ lport->tt.rport_logoff(rdata);
+ }
+ kref_put(&rdata->kref, lport->tt.rport_destroy);
}
-
+ rcu_read_unlock();
mutex_unlock(&disc->disc_mutex);
disc->disc_callback(lport, event);
mutex_lock(&disc->disc_mutex);
lport = rdata->local_port;
disc = &lport->disc;
- mutex_lock(&disc->disc_mutex);
if (PTR_ERR(fp) == -FC_EX_CLOSED)
goto out;
if (IS_ERR(fp))
goto redisc;
pn = (struct fc_ns_gid_pn *)(cp + 1);
port_name = get_unaligned_be64(&pn->fn_wwpn);
+ mutex_lock(&rdata->rp_mutex);
if (rdata->ids.port_name == -1)
rdata->ids.port_name = port_name;
else if (rdata->ids.port_name != port_name) {
FC_DISC_DBG(disc, "GPN_ID accepted. WWPN changed. "
"Port-id %6.6x wwpn %16.16llx\n",
rdata->ids.port_id, port_name);
+ mutex_unlock(&rdata->rp_mutex);
lport->tt.rport_logoff(rdata);
-
+ mutex_lock(&lport->disc.disc_mutex);
new_rdata = lport->tt.rport_create(lport,
rdata->ids.port_id);
+ mutex_unlock(&lport->disc.disc_mutex);
if (new_rdata) {
new_rdata->disc_id = disc->disc_id;
lport->tt.rport_login(new_rdata);
goto out;
}
rdata->disc_id = disc->disc_id;
+ mutex_unlock(&rdata->rp_mutex);
lport->tt.rport_login(rdata);
} else if (ntohs(cp->ct_cmd) == FC_FS_RJT) {
FC_DISC_DBG(disc, "GPN_ID rejected reason %x exp %x\n",
FC_DISC_DBG(disc, "GPN_ID unexpected response code %x\n",
ntohs(cp->ct_cmd));
redisc:
+ mutex_lock(&disc->disc_mutex);
fc_disc_restart(disc);
+ mutex_unlock(&disc->disc_mutex);
}
out:
- mutex_unlock(&disc->disc_mutex);
kref_put(&rdata->kref, lport->tt.rport_destroy);
}
* @remote_fid: The FID of the ptp rport
* @remote_wwpn: The WWPN of the ptp rport
* @remote_wwnn: The WWNN of the ptp rport
+ *
+ * Locking Note: The lport lock is expected to be held before calling
+ * this routine.
*/
static void fc_lport_ptp_setup(struct fc_lport *lport,
u32 remote_fid, u64 remote_wwpn,
u64 remote_wwnn)
{
- mutex_lock(&lport->disc.disc_mutex);
if (lport->ptp_rdata) {
lport->tt.rport_logoff(lport->ptp_rdata);
kref_put(&lport->ptp_rdata->kref, lport->tt.rport_destroy);
}
+ mutex_lock(&lport->disc.disc_mutex);
lport->ptp_rdata = lport->tt.rport_create(lport, remote_fid);
kref_get(&lport->ptp_rdata->kref);
lport->ptp_rdata->ids.port_name = remote_wwpn;
*/
static void fc_lport_reset_locked(struct fc_lport *lport)
{
- if (lport->dns_rdata)
+ if (lport->dns_rdata) {
lport->tt.rport_logoff(lport->dns_rdata);
+ lport->dns_rdata = NULL;
+ }
if (lport->ptp_rdata) {
lport->tt.rport_logoff(lport->ptp_rdata);
mutex_unlock(&rdata->rp_mutex);
} else {
FC_RPORT_DBG(rdata, "work delete\n");
+ mutex_lock(&lport->disc.disc_mutex);
list_del_rcu(&rdata->peers);
+ mutex_unlock(&lport->disc.disc_mutex);
mutex_unlock(&rdata->rp_mutex);
kref_put(&rdata->kref, lport->tt.rport_destroy);
}