mana_hwc_destroy_cq() freed hwc_cq->comp_buf and destroyed the CQ before the EQ. That was unsafe while the EQ was still registered: the EQ interrupt handler reaches comp_buf via mana_hwc_comp_event() and the CQ object (hwc->cq->gdma_cq) via mana_hwc_init_event_handler(), so a late EQE dispatched after the free could touch freed memory. Destroy the EQ first. mana_gd_destroy_queue() on the EQ deregisters its IRQ and waits out in-flight handlers, fencing all EQE dispatch; only then free the CQ and comp_buf. Fixes: ca9c54d2d6a5 ("net: mana: Add a driver for Microsoft Azure Network Adapter (MANA)") Signed-off-by: Long Li --- Changes in v6: - None. Changes in v5: - No code changes since v4 (resend as a standalone thread). Changes in v4: - No functional change since v3; the teardown-ordering guarantees this patch relies on are made explicit in patch 5. .../net/ethernet/microsoft/mana/hw_channel.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/microsoft/mana/hw_channel.c b/drivers/net/ethernet/microsoft/mana/hw_channel.c index 3f011ebbe7b3e3de2665bfa164c678c89b9b3005..19896bb5ce1a4e365a3a8363b78b005242f84e8b 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); + /* 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); } -- 2.43.0