scsi: libfc: hold disc_mutex in fc_disc_stop_rports()

fc_disc_stop_rports() is calling fc_rport_logoff(), which in turn is
acquiring the rport mutex. So we cannot use RCU list traversal here, but
rather need to hold the disc mutex to avoid list corruption while
traversing.

Fixes: a407c59339 ("scsi: libfc: Fixup disc_mutex handling")
Signed-off-by: Hannes Reinecke <hare@suse.com>
Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Hannes Reinecke 2018-07-11 10:09:28 +02:00 committed by Martin K. Petersen
parent 9a26653b95
commit bc3d12b754
1 changed files with 4 additions and 6 deletions

View File

@ -62,20 +62,16 @@ static void fc_disc_restart(struct fc_disc *);
*/
static void fc_disc_stop_rports(struct fc_disc *disc)
{
struct fc_lport *lport;
struct fc_rport_priv *rdata;
lport = fc_disc_lport(disc);
lockdep_assert_held(&lport->lp_mutex);
lockdep_assert_held(&disc->disc_mutex);
rcu_read_lock();
list_for_each_entry_rcu(rdata, &disc->rports, peers) {
list_for_each_entry(rdata, &disc->rports, peers) {
if (kref_get_unless_zero(&rdata->kref)) {
fc_rport_logoff(rdata);
kref_put(&rdata->kref, fc_rport_destroy);
}
}
rcu_read_unlock();
}
/**
@ -699,7 +695,9 @@ static void fc_disc_stop(struct fc_lport *lport)
if (disc->pending)
cancel_delayed_work_sync(&disc->disc_work);
mutex_lock(&disc->disc_mutex);
fc_disc_stop_rports(disc);
mutex_unlock(&disc->disc_mutex);
}
/**