[PATCH 09/11] NTB: ntb_transport: Stop QP work before freeing a queue
From: Koichiro Den
Date: Mon Sep 07 2026 - 10:36:06 EST
ntb_transport_free_queue() cancels qp->link_work but not qp->link_cleanup.
A peer link-down message can queue cleanup while ntb_netdev is freeing
the QP. Cleanup can then requeue link work after the queue resources
have been freed.
Disable and wait for cleanup, then link work, before freeing resources.
Unlike cancel, disable also prevents the RX tasklet and transport link
setup from queuing more work. Enable the works only after queue creation
succeeds.
Clear client_ready first so RX completions and transport link setup see
that the client is no longer ready. Clear link_is_up and active after
the workers stop, since link work can set both back to true.
Fixes: 7b4f2d3c3b82 ("NTB: No sleeping in interrupt context")
Signed-off-by: Koichiro Den <den@xxxxxxxxxxxxx>
---
Reworked from the corresponding patch in the direct TX/RX series v1:
https://lore.kernel.org/r/20260810165136.2292436-5-den@xxxxxxxxxxxxx/
drivers/ntb/ntb_transport.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index a902fce4ba60..d009bb5bb54b 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -1251,6 +1251,8 @@ static int ntb_transport_init_queue(struct ntb_transport_ctx *nt,
INIT_DELAYED_WORK(&qp->link_work, ntb_qp_link_work);
INIT_WORK(&qp->link_cleanup, ntb_qp_link_cleanup_work);
+ disable_delayed_work(&qp->link_work);
+ disable_work(&qp->link_cleanup);
spin_lock_init(&qp->ntb_rx_q_lock);
spin_lock_init(&qp->ntb_tx_free_q_lock);
@@ -2164,6 +2166,9 @@ ntb_transport_create_queue(void *data, struct device *client_dev,
}
}
+ enable_work(&qp->link_cleanup);
+ enable_delayed_work(&qp->link_work);
+
ntb_db_clear(qp->ndev, qp_bit);
ntb_db_clear_mask(qp->ndev, qp_bit);
@@ -2209,6 +2214,10 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp)
pdev = qp->ndev->pdev;
+ qp->client_ready = false;
+ disable_work_sync(&qp->link_cleanup);
+ disable_delayed_work_sync(&qp->link_work);
+ qp->link_is_up = false;
qp->active = false;
if (qp->tx_offload_thread) {
@@ -2256,8 +2265,6 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp)
ntb_db_set_mask(qp->ndev, qp_bit);
tasklet_kill(&qp->rxc_db_work);
- cancel_delayed_work_sync(&qp->link_work);
-
qp->cb_data = NULL;
qp->rx_handler = NULL;
qp->tx_handler = NULL;
--
2.51.0