scsi: fcoe: hold disc_mutex when traversing rport lists
authorHannes Reinecke <hare@suse.de>
Wed, 11 Jul 2018 08:09:30 +0000 (10:09 +0200)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 13 Jul 2018 03:01:16 +0000 (23:01 -0400)
When calling either fc_rport_logon() or fc_rport_logoff() during rport list
traversal we cannot use the RCU list traversal, as either of these
functions will be taking a mutex.  So we need to partially revert commit
a407c593398c to take the disc mutex during traversal.  We should, however,
continue to use krefs to ensure that the rport object will not be freed
from under us.

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/fcoe/fcoe_ctlr.c

index ea23c8dffc252af3d0209167e99118c98575d848..b42bfc790e0416bd95212d5ca24f1f20a44ba08b 100644 (file)
@@ -2175,15 +2175,13 @@ static void fcoe_ctlr_disc_stop_locked(struct fc_lport *lport)
 {
        struct fc_rport_priv *rdata;
 
-       rcu_read_lock();
+       mutex_lock(&lport->disc.disc_mutex);
        list_for_each_entry_rcu(rdata, &lport->disc.rports, peers) {
                if (kref_get_unless_zero(&rdata->kref)) {
                        fc_rport_logoff(rdata);
                        kref_put(&rdata->kref, fc_rport_destroy);
                }
        }
-       rcu_read_unlock();
-       mutex_lock(&lport->disc.disc_mutex);
        lport->disc.disc_callback = NULL;
        mutex_unlock(&lport->disc.disc_mutex);
 }
@@ -2712,7 +2710,7 @@ static unsigned long fcoe_ctlr_vn_age(struct fcoe_ctlr *fip)
        unsigned long deadline;
 
        next_time = jiffies + msecs_to_jiffies(FIP_VN_BEACON_INT * 10);
-       rcu_read_lock();
+       mutex_lock(&lport->disc.disc_mutex);
        list_for_each_entry_rcu(rdata, &lport->disc.rports, peers) {
                if (!kref_get_unless_zero(&rdata->kref))
                        continue;
@@ -2733,7 +2731,7 @@ static unsigned long fcoe_ctlr_vn_age(struct fcoe_ctlr *fip)
                        next_time = deadline;
                kref_put(&rdata->kref, fc_rport_destroy);
        }
-       rcu_read_unlock();
+       mutex_unlock(&lport->disc.disc_mutex);
        return next_time;
 }
 
@@ -3080,8 +3078,6 @@ static void fcoe_ctlr_vn_disc(struct fcoe_ctlr *fip)
        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;
@@ -3090,7 +3086,7 @@ static void fcoe_ctlr_vn_disc(struct fcoe_ctlr *fip)
                        fc_rport_login(rdata);
                kref_put(&rdata->kref, fc_rport_destroy);
        }
-       rcu_read_unlock();
+       mutex_unlock(&disc->disc_mutex);
        if (callback)
                callback(lport, DISC_EV_SUCCESS);
 }