Re: [PATCH v3 04/15] NTB: ntb_transport: Avoid deadlock when cancelling link work
From: Dave Jiang
Date: Fri Oct 09 2026 - 19:09:17 EST
On 9/28/26 8:25 AM, Koichiro Den wrote:
> 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
> Reviewed-by: Logan Gunthorpe <logang@xxxxxxxxxxxx>
> Signed-off-by: Koichiro Den <den@xxxxxxxxxxxxx>
Reviewed-by: Dave Jiang <dave.jiang@xxxxxxxxx>
> ---
> Changes in v3:
> - Use atomic_read() for the cancellation check instead of taking
> link_event_lock.
> - Carry over Reviewed-by.
>
> v2: https://lore.kernel.org/r/20260910040836.3792333-4-den@xxxxxxxxxxxxx/
>
> @Logan, with link_is_up now atomic_t, I dropped the mutex acquisition
> around the cancellation check. Would appreciate another look, thanks.
>
> drivers/ntb/ntb_transport.c | 9 +++++----
> 1 file changed, 5 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
> index 5d2ec484c3df..8941da0b3d61 100644
> --- a/drivers/ntb/ntb_transport.c
> +++ b/drivers/ntb/ntb_transport.c
> @@ -962,6 +962,11 @@ static void ntb_transport_link_cleanup(struct ntb_transport_ctx *nt)
> u64 qp_bitmap_alloc;
> unsigned int i, count;
>
> + if (!atomic_read(&nt->link_is_up))
> + cancel_delayed_work_sync(&nt->link_work);
> +
> + guard(mutex)(&nt->link_event_lock);
> +
> qp_bitmap_alloc = nt->qp_bitmap & ~nt->qp_bitmap_free;
>
> /* Pass along the info to any clients */
> @@ -973,9 +978,6 @@ static void ntb_transport_link_cleanup(struct ntb_transport_ctx *nt)
> cancel_delayed_work_sync(&qp->link_work);
> }
>
> - if (!atomic_read(&nt->link_is_up))
> - cancel_delayed_work_sync(&nt->link_work);
> -
> for (i = 0; i < nt->mw_count; i++)
> ntb_free_mw(nt, i);
>
> @@ -993,7 +995,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);
> }
>