ntb_netdev_open() can call ntb_transport_link_up() while the transport worker is completing setup on another CPU. Concurrent transport setup and a client link-up request can both read the other's flag as false and leave QP link work unqueued. The QP then stays down until another link event or client link-up request. This is the store-buffering pattern described in tools/memory-model/Documentation/recipes.txt ("Store buffering"). Add a full barrier between the store and load on each side. Fixes: fce8a7bb5b4b ("PCI-Express Non-Transparent Bridge Support") Cc: stable@vger.kernel.org Reported-by: Sashiko Link: https://lore.kernel.org/r/20260907144701.702E41F00A3A@smtp.kernel.org/ Signed-off-by: Koichiro Den --- Changes in v3: - Drop the *_ONCE changes. client_ready is now atomic_t. v2: https://lore.kernel.org/r/20260910040836.3792333-6-den@valinux.co.jp/ drivers/ntb/ntb_transport.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index 51d9e9969065..d290e5869c21 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -1101,6 +1101,12 @@ static void ntb_transport_link_work(struct work_struct *work) /* Publish the link only after every QP has been set up. */ atomic_set_release(&nt->link_is_up, true); + /* + * Prevent both sides from missing each other's flag. Pairs with + * the barrier in ntb_transport_link_up(). + */ + smp_mb(); + for (i = 0; i < nt->qp_count; i++) { struct ntb_transport_qp *qp = &nt->qp_vec[i]; @@ -2400,6 +2406,9 @@ void ntb_transport_link_up(struct ntb_transport_qp *qp) atomic_set(&qp->client_ready, true); + /* Pairs with the barrier in ntb_transport_link_work(). */ + smp_mb(); + ntb_transport_schedule_qp_link(qp, 0); } EXPORT_SYMBOL_GPL(ntb_transport_link_up); -- 2.51.0