]> git.itanic.dy.fi Git - linux-stable/commitdiff
IB/hfi1: Fix abba locking issue with sc_disable()
authorMike Marciniszyn <mike.marciniszyn@cornelisnetworks.com>
Wed, 13 Oct 2021 14:18:52 +0000 (10:18 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 2 Nov 2021 18:46:13 +0000 (19:46 +0100)
commit 13bac861952a78664907a0f927d3e874e9a59034 upstream.

sc_disable() after having disabled the send context wakes up any waiters
by calling hfi1_qp_wakeup() while holding the waitlock for the sc.

This is contrary to the model for all other calls to hfi1_qp_wakeup()
where the waitlock is dropped and a local is used to drive calls to
hfi1_qp_wakeup().

Fix by moving the sc->piowait into a local list and driving the wakeup
calls from the list.

Fixes: 099a884ba4c0 ("IB/hfi1: Handle wakeup of orphaned QPs for pio")
Link: https://lore.kernel.org/r/20211013141852.128104.2682.stgit@awfm-01.cornelisnetworks.com
Signed-off-by: Mike Marciniszyn <mike.marciniszyn@cornelisnetworks.com>
Reported-by: TOTE Robot <oslab@tsinghua.edu.cn>
Signed-off-by: Dennis Dalessandro <dennis.dalessandro@cornelisnetworks.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/infiniband/hw/hfi1/pio.c

index 79126b2b14ab036f6865a5a06fa7db00256202ad..1a82ea73a0fc260c8bd55c6c58d0a6546cd5e079 100644 (file)
@@ -920,6 +920,7 @@ void sc_disable(struct send_context *sc)
 {
        u64 reg;
        struct pio_buf *pbuf;
+       LIST_HEAD(wake_list);
 
        if (!sc)
                return;
@@ -954,19 +955,21 @@ void sc_disable(struct send_context *sc)
        spin_unlock(&sc->release_lock);
 
        write_seqlock(&sc->waitlock);
-       while (!list_empty(&sc->piowait)) {
+       if (!list_empty(&sc->piowait))
+               list_move(&sc->piowait, &wake_list);
+       write_sequnlock(&sc->waitlock);
+       while (!list_empty(&wake_list)) {
                struct iowait *wait;
                struct rvt_qp *qp;
                struct hfi1_qp_priv *priv;
 
-               wait = list_first_entry(&sc->piowait, struct iowait, list);
+               wait = list_first_entry(&wake_list, struct iowait, list);
                qp = iowait_to_qp(wait);
                priv = qp->priv;
                list_del_init(&priv->s_iowait.list);
                priv->s_iowait.lock = NULL;
                hfi1_qp_wakeup(qp, RVT_S_WAIT_PIO | HFI1_S_WAIT_PIO_DRAIN);
        }
-       write_sequnlock(&sc->waitlock);
 
        spin_unlock_irq(&sc->alloc_lock);
 }