Thread (21 messages) flat view 21 messages, 2 authors, 6d ago
COOLING6d

[PATCH 04/16] NTB: ntb_transport: Stop QP work before freeing a queue

From: Koichiro Den <hidden>
Date: 2026-08-10 16:51:55
Also in: lkml
Subsystem: ntb driver core, the rest · Maintainers: Jon Mason, Dave Jiang, Allen Hubbe, Linus Torvalds

ntb_transport_link_down() clears client_ready, but asynchronous QP work
can outlive that transition. This leaves three teardown races:

  1. Queued link_work can mark the QP active again and schedule RX
     processing.
  2. A per-QP MSI can schedule RX processing after client link-down.
  3. link_cleanup can run while ntb_transport_free_queue() releases queue
     state and can rearm link_work. RX processing can also queue another
     cleanup while it is being drained.

Gate link_work and the MSI handler with client_ready. Before releasing
queue resources, drain link_cleanup and link_work. After stopping RX
processing, drain link_cleanup once more, then link_work because cleanup
can rearm it.

Fixes: fce8a7bb5b4b ("PCI-Express Non-Transparent Bridge Support")
Signed-off-by: Koichiro Den <redacted>
---
 drivers/ntb/ntb_transport.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index 044d8b5747fc..4afad4489772 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -653,7 +653,8 @@ static irqreturn_t ntb_transport_isr(int irq, void *dev)
 {
 	struct ntb_transport_qp *qp = dev;
 
-	tasklet_schedule(&qp->rxc_db_work);
+	if (qp->client_ready)
+		tasklet_schedule(&qp->rxc_db_work);
 
 	return IRQ_HANDLED;
 }
@@ -1133,6 +1134,9 @@ static void ntb_qp_link_work(struct work_struct *work)
 	struct ntb_transport_ctx *nt = qp->transport;
 	int val;
 
+	if (!qp->client_ready)
+		return;
+
 	WARN_ON(!nt->link_is_up);
 
 	val = ntb_spad_read(nt->ndev, QP_LINKS);
@@ -2182,6 +2186,8 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp)
 
 	pdev = qp->ndev->pdev;
 
+	cancel_work_sync(&qp->link_cleanup);
+	cancel_delayed_work_sync(&qp->link_work);
 	qp->active = false;
 
 	if (qp->tx_offload_thread) {
@@ -2229,6 +2235,8 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp)
 	ntb_db_set_mask(qp->ndev, qp_bit);
 	tasklet_kill(&qp->rxc_db_work);
 
+	/* Catch cleanup queued while draining RX processing. */
+	cancel_work_sync(&qp->link_cleanup);
 	cancel_delayed_work_sync(&qp->link_work);
 
 	qp->cb_data = NULL;
-- 
2.51.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help