[PATCH v2 03/14] NTB: ntb_transport: Avoid deadlock when cancelling link work

From: Koichiro Den

Date: Thu Sep 10 2026 - 00:16:33 EST


During initial link setup, ntb_transport_link_work() can retry with
nt->link_is_up still false. A retry can block on link_event_lock
while cleanup holds it and waits in cancel_delayed_work_sync(),
leading to deadlock.

Move the conditional cancellation outside link_event_lock, before
QP cleanup. Keep QP cleanup and MW release under the lock so link
work cannot restart QPs between them. Put the locking in
ntb_transport_link_cleanup() to cover both worker and remove paths.

Fixes: 3db835dd8f9a ("ntb: Add mutex to make link_event_callback executed linearly.")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Koichiro Den <den@xxxxxxxxxxxxx>
---
Changes in v2:
- No changes.

drivers/ntb/ntb_transport.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index 55a20ae9a85e..c77b173dca01 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -960,6 +960,15 @@ static void ntb_transport_link_cleanup(struct ntb_transport_ctx *nt)
struct ntb_transport_qp *qp;
u64 qp_bitmap_alloc;
unsigned int i, count;
+ bool cancel_link_work;
+
+ scoped_guard(mutex, &nt->link_event_lock)
+ cancel_link_work = !nt->link_is_up;
+
+ if (cancel_link_work)
+ cancel_delayed_work_sync(&nt->link_work);
+
+ guard(mutex)(&nt->link_event_lock);

qp_bitmap_alloc = nt->qp_bitmap & ~nt->qp_bitmap_free;

@@ -972,9 +981,6 @@ static void ntb_transport_link_cleanup(struct ntb_transport_ctx *nt)
cancel_delayed_work_sync(&qp->link_work);
}

- if (!nt->link_is_up)
- cancel_delayed_work_sync(&nt->link_work);
-
for (i = 0; i < nt->mw_count; i++)
ntb_free_mw(nt, i);

@@ -992,7 +998,6 @@ static void ntb_transport_link_cleanup_work(struct work_struct *work)
struct ntb_transport_ctx *nt =
container_of(work, struct ntb_transport_ctx, link_cleanup);

- guard(mutex)(&nt->link_event_lock);
ntb_transport_link_cleanup(nt);
}

--
2.51.0