net/smc: lock smc_lgr_list in port_terminate()
authorHans Wippel <hwippel@linux.ibm.com>
Wed, 23 May 2018 14:38:10 +0000 (16:38 +0200)
committerDavid S. Miller <davem@davemloft.net>
Wed, 23 May 2018 20:02:35 +0000 (16:02 -0400)
Currently, smc_port_terminate() is not holding the lock of the lgr list
while it is traversing the list. This patch adds locking to this
function and changes smc_lgr_terminate() accordingly.

Signed-off-by: Hans Wippel <hwippel@linux.ibm.com>
Signed-off-by: Ursula Braun <ubraun@linux.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/smc/smc_core.c

index 1e5c0e9..21c244f 100644 (file)
@@ -346,7 +346,7 @@ void smc_lgr_forget(struct smc_link_group *lgr)
 }
 
 /* terminate linkgroup abnormally */
-void smc_lgr_terminate(struct smc_link_group *lgr)
+static void __smc_lgr_terminate(struct smc_link_group *lgr)
 {
        struct smc_connection *conn;
        struct smc_sock *smc;
@@ -355,7 +355,8 @@ void smc_lgr_terminate(struct smc_link_group *lgr)
        if (lgr->terminating)
                return; /* lgr already terminating */
        lgr->terminating = 1;
-       smc_lgr_forget(lgr);
+       if (!list_empty(&lgr->list)) /* forget lgr */
+               list_del_init(&lgr->list);
        smc_llc_link_inactive(&lgr->lnk[SMC_SINGLE_LINK]);
 
        write_lock_bh(&lgr->conns_lock);
@@ -377,16 +378,25 @@ void smc_lgr_terminate(struct smc_link_group *lgr)
        smc_lgr_schedule_free_work(lgr);
 }
 
+void smc_lgr_terminate(struct smc_link_group *lgr)
+{
+       spin_lock_bh(&smc_lgr_list.lock);
+       __smc_lgr_terminate(lgr);
+       spin_unlock_bh(&smc_lgr_list.lock);
+}
+
 /* Called when IB port is terminated */
 void smc_port_terminate(struct smc_ib_device *smcibdev, u8 ibport)
 {
        struct smc_link_group *lgr, *l;
 
+       spin_lock_bh(&smc_lgr_list.lock);
        list_for_each_entry_safe(lgr, l, &smc_lgr_list.list, list) {
                if (lgr->lnk[SMC_SINGLE_LINK].smcibdev == smcibdev &&
                    lgr->lnk[SMC_SINGLE_LINK].ibport == ibport)
-                       smc_lgr_terminate(lgr);
+                       __smc_lgr_terminate(lgr);
        }
+       spin_unlock_bh(&smc_lgr_list.lock);
 }
 
 /* Determine vlan of internal TCP socket.