>
> This is an AI-generated review of your patch. The human sending this email has
> considered the AI review valid, or at least plausible.
> ---
> net: mana: free HWC comp_buf after destroying the EQ
>
> This reorders mana_hwc_destroy_cq() so the EQ is destroyed first, then the
> CQ, and only afterwards hwc_cq->comp_buf is freed. The stated reason is that
> mana_gd_destroy_queue() on the EQ deregisters the IRQ and waits out in-
> flight handlers, fencing EQE dispatch before handler-reachable memory is
> released.
>
> > diff --git a/drivers/net/ethernet/microsoft/mana/hw_channel.c
> > b/drivers/net/ethernet/microsoft/mana/hw_channel.c
> > index 3f011ebbe7b3e..19896bb5ce1a4 100644
> > --- a/drivers/net/ethernet/microsoft/mana/hw_channel.c
> > +++ b/drivers/net/ethernet/microsoft/mana/hw_channel.c
> > @@ -384,14 +384,24 @@ static void mana_hwc_comp_event(void *ctx,
> > struct gdma_queue *q_self)
> >
> > static void mana_hwc_destroy_cq(struct gdma_context *gc, struct
> > hwc_cq *hwc_cq) {
> > - kfree(hwc_cq->comp_buf);
> > + /* Destroy the EQ before the CQ. mana_gd_destroy_queue() on the
> EQ
> > + * deregisters its IRQ and waits out in-flight handlers, fencing all
> > + * EQE dispatch — both the completion path and HWC init/reconfig
> > + * events. Freeing the CQ first would leave the EQ live and able to
> > + * dispatch an event that dereferences hwc->cq->gdma_cq (e.g.
> > + * mana_hwc_init_event_handler()) after it has been freed.
> > + */
> > + if (hwc_cq->gdma_eq)
> > + mana_gd_destroy_queue(gc, hwc_cq->gdma_eq);
>
> [Severity: Medium]
> This isn't a bug introduced by this patch, but the ordering in the only caller
> does not yet match the invariant the new comment states. Does the
> comment's claim that this point fences "all EQE dispatch — both the
> completion path and HWC init/reconfig events" hold for the WQ objects the
> same handlers touch?
>
> At this commit mana_hwc_destroy_channel() frees the WQs before it gets
> here:
>
> if (gc->max_num_cqs > 0)
> mana_smc_teardown_hwc(&gc->shm_channel, false);
>
> if (hwc->txq)
> mana_hwc_destroy_wq(hwc, hwc->txq);
>
> if (hwc->rxq)
> mana_hwc_destroy_wq(hwc, hwc->rxq);
>
> if (hwc->cq)
> mana_hwc_destroy_cq(hwc->gdma_dev->gdma_context, hwc-
> >cq);
>
> mana_hwc_destroy_wq() releases msg_buf (the DMA buffer plus reqs[]), the
> gdma_wq and the hwc_wq itself, and hwc->txq / hwc->rxq are left dangling
> rather than set to NULL. The EQ is still on gic->eq_list and the HWC CQ is
> still
> published in gc->cq_table at that point, since the only dispatch fence
> (mana_gd_deregister_irq() -> list_del_rcu() + synchronize_rcu()) is reached
> from the mana_gd_destroy_queue() call added here.
>
> So can an EQE arriving in that window reach freed memory through
> mana_gd_process_eqe() -> mana_hwc_comp_event() ->
> mana_hwc_rx_event_handler(), which dereferences hwc->rxq and then:
>
> if (WARN_ON_ONCE(hwc_rxq->gdma_wq->id != gdma_rxq_id))
> return;
>
> and later hwc_rxq->msg_buf->mem_info.dma_handle and hwc_rxq->msg_buf-
> >reqs[]? The tx side has only a NULL check:
>
> WARN_ON_ONCE(!hwc_txq || hwc_txq->gdma_wq->id !=
> gdma_txq_id);
>
> which a freed-but-non-NULL pointer passes. mana_hwc_init_event_handler()
> similarly touches hwc->rxq->gdma_wq->id and hwc->txq->gdma_wq.
>
> For what it's worth, a later commit in this series, "net: mana: fix HWC
> teardown
> safety with setup_active flag and destroy ordering", reorders
> mana_hwc_destroy_channel() to call mana_hwc_destroy_cq() before
> mana_hwc_destroy_wq() for txq and rxq, so the final tree state does not have
> this window. Given this patch carries a Fixes: tag and would be a stable
> backport candidate on its own, would it be worth folding the caller reordering
> in here, or noting the dependency in the changelog?
>
> >
> > + /* comp_buf is reached only by mana_hwc_comp_event(), invoked
> from
> > + * the now-fenced EQ handler, so it is safe to free once the EQ and
> > + * CQ are gone.
> > + */
> > if (hwc_cq->gdma_cq)
> > mana_gd_destroy_queue(gc, hwc_cq->gdma_cq);
> >
> > - if (hwc_cq->gdma_eq)
> > - mana_gd_destroy_queue(gc, hwc_cq->gdma_eq);
> > -
> > + kfree(hwc_cq->comp_buf);
> > kfree(hwc_cq);
> > }
>
> [Severity: Medium]
> This is a pre-existing issue, but moving the EQ destroy to the front of this
> function changes which ring is handed back to the DMA allocator first on the
> failure path. Is that safe when the shared-memory teardown was skipped?
>
> mana_hwc_destroy_channel() gates the teardown on max_num_cqs and drops
> the return value:
>
> /* gc->max_num_cqs is set in mana_hwc_init_event_handler(). If it's
> * non-zero, the HWC worked and we should tear down the HWC here.
> */
> if (gc->max_num_cqs > 0)
> mana_smc_teardown_hwc(&gc->shm_channel, false);
>
> If mana_smc_setup_hwc() succeeded (MST entries active, device programmed
> with the HWC ring addresses) but mana_hwc_establish_channel() then timed
> out waiting on hwc_init_eqe_comp, max_num_cqs stays zero, the teardown is
> skipped, and mana_hwc_destroy_cq() still runs. The EQ ring is then the first
> HWC ring released, via mana_gd_destroy_queue() ->
> mana_gd_free_memory() -> dma_free_coherent().
>
> For the HWC EQ, eq.disable_needed is false, so mana_gd_destroy_eq() issues
> no device-side DISABLE_QUEUE, and mana_gd_deregister_irq() fences only the
> driver's handlers. Can the device still post an EQE into those pages after
> they
> are freed? shm_channel.c notes the dependency:
>
> /* Waiting for the hardware to invalidate the MST entries before the
> * driver frees the queue memory */
>
> The same later commit, "net: mana: fix HWC teardown safety with
> setup_active flag and destroy ordering", replaces the max_num_cqs gate with
> hwc->setup_active set before mana_smc_setup_hwc(), and on teardown
> hwc->failure
> returns early and leaks the HWC resources instead of freeing memory the
> device may still write to. Should the ordering change here wait for that
> gate, or
> at least mention the ordering dependency between the two patches?
Thanks. Both windows are pre-existing: patch 3 only reorders the EQ/CQ/comp_buf
destroy inside mana_hwc_destroy_cq() and doesn't touch the caller ordering or
the teardown gate, so it's no worse than the base at this commit. As you note,
"net: mana: fix HWC teardown safety with setup_active flag and destroy
ordering" completes both — it reorders mana_hwc_destroy_channel() to destroy
the CQ (fencing the EQ) before the WQs, and replaces the max_num_cqs gate
with setup_active + leak-on-teardown-failure.
The two patches are part of the same series and are applied together, so the
final tree has no such window. I'd prefer to leave patch 3 as is.
Long