[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