Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d997d4e4 authored by Mike Marciniszyn's avatar Mike Marciniszyn Committed by Greg Kroah-Hartman
Browse files

IB/hfi1: Fix abba locking issue with sc_disable()

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: 099a884b ("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: default avatarMike Marciniszyn <mike.marciniszyn@cornelisnetworks.com>
Reported-by: default avatarTOTE Robot <oslab@tsinghua.edu.cn>
Signed-off-by: default avatarDennis Dalessandro <dennis.dalessandro@cornelisnetworks.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 0f8cdfff
Loading
Loading
Loading
Loading
+6 −3
Original line number Original line Diff line number Diff line
@@ -920,6 +920,7 @@ void sc_disable(struct send_context *sc)
{
{
	u64 reg;
	u64 reg;
	struct pio_buf *pbuf;
	struct pio_buf *pbuf;
	LIST_HEAD(wake_list);


	if (!sc)
	if (!sc)
		return;
		return;
@@ -954,19 +955,21 @@ void sc_disable(struct send_context *sc)
	spin_unlock(&sc->release_lock);
	spin_unlock(&sc->release_lock);


	write_seqlock(&sc->waitlock);
	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 iowait *wait;
		struct rvt_qp *qp;
		struct rvt_qp *qp;
		struct hfi1_qp_priv *priv;
		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);
		qp = iowait_to_qp(wait);
		priv = qp->priv;
		priv = qp->priv;
		list_del_init(&priv->s_iowait.list);
		list_del_init(&priv->s_iowait.list);
		priv->s_iowait.lock = NULL;
		priv->s_iowait.lock = NULL;
		hfi1_qp_wakeup(qp, RVT_S_WAIT_PIO | HFI1_S_WAIT_PIO_DRAIN);
		hfi1_qp_wakeup(qp, RVT_S_WAIT_PIO | HFI1_S_WAIT_PIO_DRAIN);
	}
	}
	write_sequnlock(&sc->waitlock);


	spin_unlock_irq(&sc->alloc_lock);
	spin_unlock_irq(&sc->alloc_lock);
}
}