Linux PCI Non-Transparent Bridge framework and drivers
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Koichiro Den" <den@valinux.co.jp>
Cc: ntb@lists.linux.dev
Subject: Re: [PATCH 07/11] NTB: ntb_transport: Clear link state before QP cleanup
Date: Mon, 07 Sep 2026 14:43:02 +0000	[thread overview]
Message-ID: <20260907144303.3D25A1F00A3A@smtp.kernel.org> (raw)
In-Reply-To: <20260907142429.951930-8-den@valinux.co.jp>

Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:

New issues:
- [Medium] Coding Pattern Violation: Mixing guard() and goto-based cleanup

Pre-existing issues:
- [High] Memory Ordering Race leading to lost wakeups
- [High] Data Race in ntb_qp_link_cleanup allowing concurrent execution
- [High] DMA Memory Corruption due to unterminated transactions
- [High] Missing read memory barrier (dma_rmb) when reading payload after checking DESC_DONE_FLAG
- [High] Stale Data Transmission due to missing flush on link down
--

commit 3aa5fe6a4883f5e1056224f4eb903786b4edfe5a
Author: Koichiro Den <den@valinux.co.jp>

    NTB: ntb_transport: Clear link state before QP cleanup

    Cleanup leaves the transport link marked up after releasing its MWs, allowing
    client link-up requests to start QP link work prematurely. Clear link_is_up
    before cancelling QP work and releasing MWs. Additionally, ensure QP link
    work returns if the transport went down after it was queued.

> diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
> index 411017873a83b..4c0a29693ac23 100644
> --- a/drivers/ntb/ntb_transport.c
> +++ b/drivers/ntb/ntb_transport.c
> @@ -990,6 +990,8 @@ static void ntb_transport_link_cleanup(struct ntb_transport_ctx *nt)
>  
>  	guard(mutex)(&nt->link_event_lock);
>  
> +	WRITE_ONCE(nt->link_is_up, false);
> +
>  	qp_bitmap_alloc = nt->qp_bitmap & ~nt->qp_bitmap_free;
>  
>  	/* Pass along the info to any clients */

[Severity: High]
This is a pre-existing issue, but does this cleanup routine allow concurrent
execution?

Looking at ntb_transport_link_cleanup(), it calls ntb_qp_link_cleanup() on all
active QPs, and then synchronizes cancellation using cancel_work_sync():

drivers/ntb/ntb_transport.c:ntb_transport_link_cleanup() {
    ...
    for (i = 0; i < nt->qp_count; i++)
        if (nt->qp_bitmap_alloc & BIT_ULL(i)) {
            struct ntb_transport_qp *qp = &nt->qp_vec[i];
            ntb_qp_link_cleanup(qp);
            cancel_work_sync(&qp->link_cleanup);
        }
    ...
}

If the ntb_qp_link_cleanup_work() worker is concurrently executing, it will
also invoke ntb_qp_link_cleanup(). Since no lock synchronizes
ntb_qp_link_cleanup(), it can execute concurrently across threads. This could
lead to data races when resetting QP indices and cause duplicate concurrent
calls to the client's event_handler, potentially corrupting the client driver
state.

[Severity: High]
This is a pre-existing issue, but is it possible for active DMA transactions to
corrupt freed memory here?

Later in ntb_transport_link_cleanup(), it frees the backing DMA memory:

drivers/ntb/ntb_transport.c:ntb_transport_link_cleanup() {
    ...
    for (i = 0; i < nt->mw_count; i++)
        ntb_free_mw(nt, i);
    ...
}

ntb_free_mw() calls dma_free_attrs() without ensuring the DMA channel is
stopped. Prior to this, ntb_qp_link_cleanup() kills the RX tasklet with
tasklet_kill(&qp->rxc_db_work), but does not terminate active DMA engine
transactions (e.g., via dmaengine_terminate_all()).

If a DMA transfer was previously submitted, could it continue asynchronously in
hardware, writing into the freed memory pages and leading to IOMMU faults or
memory corruption?

[Severity: High]
This is a pre-existing issue, but does resetting the link context leave stale
data in the transmit queues?

When the link goes down, ntb_qp_link_down_reset() is called:

drivers/ntb/ntb_transport.c:ntb_qp_link_down_reset() {
    ...
    ntb_qp_link_context_reset(qp);
    remote_rx_info = READ_ONCE(qp->remote_rx_info);
    ...
}

The QP context and indices (like qp->tx_index) are reset to 0, but pending
entries in qp->tx_offl_q or other transmit queues are not flushed. These
pending entries already have their entry->tx_index populated with old index
values from before the link dropped.

When the tx_offload_thread processes them, could it write the data to the
old, stale index locations instead of starting correctly at index 0, causing
the remote receiver to hang or receive out-of-sequence packets?

[ ... ]

[Severity: Medium]
Does ntb_transport_link_work() mix scope-based guard macros with legacy
goto-based error cleanup?

The cleanup.md documentation explicitly mandates that usage of "goto" and
cleanup helpers must never be mixed in the same function.

drivers/ntb/ntb_transport.c:ntb_transport_link_work() {
    ...
    guard(mutex)(&nt->link_event_lock);
    ...
        rc = ntb_set_mw(nt, i, val64);
        if (rc)
            goto out1;
    ...
out1:
    for (i = 0; i < nt->mw_count; i++)
        ntb_free_mw(nt, i);
    ...
}

This function uses guard(mutex)(&nt->link_event_lock) at the beginning, but
continues to use goto out1; and goto out; for error handling and legacy cleanup
paths. Does this violate the established architectural cleanup pattern?

[ ... ]

> @@ -1149,7 +1151,9 @@ static void ntb_qp_link_work(struct work_struct *work)
>  	struct ntb_transport_ctx *nt = qp->transport;
>  	int val;
>  
> -	WARN_ON(!nt->link_is_up);
> +	/* Pair with the link publication in ntb_transport_link_work(). */
> +	if (!smp_load_acquire(&nt->link_is_up))
> +		return;
>  
>  	val = ntb_spad_read(nt->ndev, QP_LINKS);
>  

[Severity: High]
This is a pre-existing issue, but does this Dekker's algorithm pattern lack a
full memory barrier, potentially leading to lost wakeups?

In ntb_transport_link_work(), nt->link_is_up is stored and qp->client_ready is
read:

drivers/ntb/ntb_transport.c:ntb_transport_link_work() {
    ...
    smp_store_release(&nt->link_is_up, true);

    for (i = 0; i < nt->qp_count; i++) {
        struct ntb_transport_qp *qp = &nt->qp_vec[i];

        if (qp->client_ready)
            ntb_transport_schedule_qp_link(qp, 0);
    }
    ...
}

Concurrently, ntb_transport_link_up() stores qp->client_ready and reads
nt->link_is_up:

drivers/ntb/ntb_transport.c:ntb_transport_link_up() {
    ...
    qp->client_ready = true;
    ntb_transport_schedule_qp_link(qp, 0);
    ...
}

Inside ntb_transport_schedule_qp_link(), it checks
smp_load_acquire(&nt->link_is_up). Because smp_store_release() allows
subsequent loads to be reordered before the store, and smp_load_acquire()
allows preceding stores to be reordered after the load, both threads can read
false for the counterpart flag.

Could this result in a lost wakeup where the QP link fails to initialize?

[ ... ]

[Severity: High]
This is a pre-existing issue, but is a read memory barrier required after
checking the DESC_DONE_FLAG?

In ntb_process_rxc(), the descriptor's done flag is read from the DMA-mapped
memory to verify packet completion:

drivers/ntb/ntb_transport.c:ntb_process_rxc() {
    ...
    if (!(hdr->flags & DESC_DONE_FLAG)) {
        dev_dbg(&qp->ndev->pdev->dev, "done flag not set\n");
        qp->rx_ring_empty++;
        return -EAGAIN;
    }
    ...
}

However, there is no dma_rmb() issued after observing the flag. Could this
allow the CPU to speculatively read the subsequent header fields (e.g.,
hdr->ver, hdr->len) and the payload buffer before the done flag read
completes, resulting in stale data being processed?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260907142429.951930-1-den@valinux.co.jp?part=7

  reply	other threads:[~2026-09-07 14:43 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-07 14:24 [PATCH 00/11] NTB: ntb_transport: Miscellaneous fixes Koichiro Den
2026-09-07 14:24 ` [PATCH 01/11] NTB: ntb_transport: Remove the device debugfs directory Koichiro Den
2026-09-07 14:36   ` sashiko-bot
2026-09-07 14:24 ` [PATCH 02/11] NTB: ntb_transport: Start TX offload thread after queue setup Koichiro Den
2026-09-07 14:37   ` sashiko-bot
2026-09-07 14:24 ` [PATCH 03/11] NTB: ntb_transport: Prepare remote RX info accesses for MW teardown Koichiro Den
2026-09-07 14:38   ` sashiko-bot
2026-09-07 14:24 ` [PATCH 04/11] NTB: ntb_transport: Clear QP pointers when freeing an MW Koichiro Den
2026-09-07 14:42   ` sashiko-bot
2026-09-09  4:57     ` Koichiro Den
2026-09-07 14:24 ` [PATCH 05/11] NTB: ntb_transport: Avoid deadlock when cancelling link work Koichiro Den
2026-09-07 14:45   ` sashiko-bot
2026-09-07 14:24 ` [PATCH 06/11] NTB: ntb_transport: Publish link state after QP setup Koichiro Den
2026-09-07 14:47   ` sashiko-bot
2026-09-09  4:42     ` Koichiro Den
2026-09-07 14:24 ` [PATCH 07/11] NTB: ntb_transport: Clear link state before QP cleanup Koichiro Den
2026-09-07 14:43   ` sashiko-bot [this message]
2026-09-09  4:47     ` Koichiro Den
2026-09-07 14:24 ` [PATCH 08/11] NTB: ntb_transport: Abort link setup on QP MW allocation failure Koichiro Den
2026-09-07 14:45   ` sashiko-bot
2026-09-07 14:24 ` [PATCH 09/11] NTB: ntb_transport: Stop QP work before freeing a queue Koichiro Den
2026-09-07 14:50   ` sashiko-bot
2026-09-07 14:24 ` [PATCH 10/11] NTB: ntb_transport: Stop RX tasklet scheduling " Koichiro Den
2026-09-07 14:24 ` [PATCH 11/11] NTB: ntb_transport: Drain RX tasklets during link cleanup Koichiro Den
2026-09-07 14:50   ` sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260907144303.3D25A1F00A3A@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=den@valinux.co.jp \
    --cc=ntb@lists.linux.dev \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox