Re: [PATCH mt76] wifi: mt76: mt792x: drop redundant napi_disable() in unregister path

From: Mikhail Gavrilov

Date: Thu Jul 30 2026 - 03:21:02 EST


On Thu, Jul 30, 2026 at 10:06 AM Eric Biggers <ebiggers@xxxxxxxxxx> wrote:
>
> While this patch fixes the shutdown hang for me too on a system using
> mt7925e, Sashiko found that this patch introduces a use-after-free
> because NAPI is now being disabled too late:
> https://sashiko.dev/#/patchset/20260728002048.19351-1-mikhail.v.gavrilov%40gmail.com
> Should 13b7e6a96a00 be reverted, then fixed in another way such as
> calling napi_disable() in mt7915_unregister_device()?
>

You are right, and so is the report. I went through the path and it is real:

mt792x_poll_rx()
mt7921_queue_rx_skb()
case PKT_TYPE_TXRX_NOTIFY: /* mmio only, so PCIe */
mt7921_mac_tx_free()
mt76_token_release() /* idr_remove() under token_lock */

and with my patch that can now run concurrently with, a few lines up in
mt7921e_unregister_device():

mt76_connac2_tx_token_put()
...
idr_destroy(&dev->token) /* outside token_lock */

The early napi_disable() loops I removed were what kept those two apart.

My justification in the commit message was that RX is harmless once
mac80211 has stopped the hw, because mt76_rx() drops everything with
MT76_STATE_RUNNING clear. That only covers the normal data path -
PKT_TYPE_TXRX_NOTIFY is dispatched in mt7921_queue_rx_skb() before
mt76_rx() is ever reached, and goes straight to the token IDR. So the
window is not benign and the patch is wrong. Please drop it.

I agree with your suggestion. The disable belongs in the drivers that
delete the NAPI instances, where each one can pick a point that is safe
for its own teardown order, rather than in the shared mt76_dma_cleanup()
where it is forced to happen after the driver has already freed state
that the RX poll can still touch. mt7921e/mt7925e already did it, and
early enough; mt7915 and friends simply never did.

Unless Nicolas would rather do it himself, I can send a v2 series:

1) Revert "wifi: mt76: Disable napi when removing device", restoring
reboot, poweroff and module unload on mt7921e/mt7925e
2) wifi: mt76: mt7915: disable napi before deleting it, for the
original __netif_napi_del_locked() and
page_pool_disable_direct_recycling() warnings

I would keep 2) to mt7915 for now, since that is what was reported and
tested. mt7603, mt7615, mt7996 and mt76x0/mt76x2 have the same gap in
their unregister paths and can follow separately.

One more item from the same report, not caused by this patch but worth
someone's attention: mt7921e/mt7925e call tasklet_disable() on
mt76.irq_tasklet without a matching tasklet_kill() before
mt76_free_device(), which can leave a scheduled tasklet pointing at
freed memory.

Thanks for catching this.

--
Thanks,
Mikhail