scsi: libfc: hold disc_mutex in fc_disc_stop_rports()
authorHannes Reinecke <hare@suse.de>
Wed, 11 Jul 2018 08:09:28 +0000 (10:09 +0200)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 13 Jul 2018 03:01:16 +0000 (23:01 -0400)
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>
drivers/scsi/libfc/fc_disc.c

index c1756b9b3ea55f5791102b27c52a7d82b7d126cd..f969a71348ef1e94c3a725c863f3f49ca9bbc8ea 100644 (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);
 }
 
 /**