summaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorHannes Reinecke <hare@suse.de>2018-07-11 10:09:28 +0200
committerMartin K. Petersen <martin.petersen@oracle.com>2018-07-12 23:01:16 -0400
commitbc3d12b75491c0e844a8a7ce05e84de8f7d94822 (patch)
treef9c4a04f23c7f53692304362cb56aa38dc275785 /drivers/scsi
parent9a26653b9525c08bc3d0a2c5c65721e4de3a5f6d (diff)
downloadlinux-bc3d12b75491c0e844a8a7ce05e84de8f7d94822.tar.gz
linux-bc3d12b75491c0e844a8a7ce05e84de8f7d94822.tar.bz2
linux-bc3d12b75491c0e844a8a7ce05e84de8f7d94822.zip
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: a407c593398c ("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>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/libfc/fc_disc.c10
1 files changed, 4 insertions, 6 deletions
diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c
index c1756b9b3ea5..f969a71348ef 100644
--- a/drivers/scsi/libfc/fc_disc.c
+++ b/drivers/scsi/libfc/fc_disc.c
@@ -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);
}
/**