]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
IB/hfi1: Avoid hardlockup with flushlist_lock
authorMike Marciniszyn <mike.marciniszyn@intel.com>
Fri, 14 Jun 2019 16:32:26 +0000 (12:32 -0400)
committerKhalid Elmously <khalid.elmously@canonical.com>
Thu, 26 Sep 2019 04:34:52 +0000 (00:34 -0400)
BugLink: https://bugs.launchpad.net/bugs/1844558
[ Upstream commit cf131a81967583ae737df6383a0893b9fee75b4e ]

Heavy contention of the sde flushlist_lock can cause hard lockups at
extreme scale when the flushing logic is under stress.

Mitigate by replacing the item at a time copy to the local list with
an O(1) list_splice_init() and using the high priority work queue to
do the flushes.

Fixes: 7724105686e7 ("IB/hfi1: add driver files")
Cc: <stable@vger.kernel.org>
Reviewed-by: Dennis Dalessandro <dennis.dalessandro@intel.com>
Signed-off-by: Mike Marciniszyn <mike.marciniszyn@intel.com>
Signed-off-by: Dennis Dalessandro <dennis.dalessandro@intel.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Khalid Elmously <khalid.elmously@canonical.com>
drivers/infiniband/hw/hfi1/sdma.c

index 31c8f89b5fc8532f27f38ef5f7d119423edede9d..b9086144891aecb86ad03b532e0d57be8b685519 100644 (file)
@@ -410,10 +410,7 @@ static void sdma_flush(struct sdma_engine *sde)
        sdma_flush_descq(sde);
        spin_lock_irqsave(&sde->flushlist_lock, flags);
        /* copy flush list */
-       list_for_each_entry_safe(txp, txp_next, &sde->flushlist, list) {
-               list_del_init(&txp->list);
-               list_add_tail(&txp->list, &flushlist);
-       }
+       list_splice_init(&sde->flushlist, &flushlist);
        spin_unlock_irqrestore(&sde->flushlist_lock, flags);
        /* flush from flush list */
        list_for_each_entry_safe(txp, txp_next, &flushlist, list)
@@ -2430,7 +2427,7 @@ unlock_noconn:
                wait->tx_count++;
                wait->count += tx->num_desc;
        }
-       schedule_work(&sde->flush_worker);
+       queue_work_on(sde->cpu, system_highpri_wq, &sde->flush_worker);
        ret = -ECOMM;
        goto unlock;
 nodesc:
@@ -2530,7 +2527,7 @@ unlock_noconn:
                }
        }
        spin_unlock(&sde->flushlist_lock);
-       schedule_work(&sde->flush_worker);
+       queue_work_on(sde->cpu, system_highpri_wq, &sde->flush_worker);
        ret = -ECOMM;
        goto update_tail;
 nodesc: