When stmmac interface releases, kernel might panic with wrong memory access or show SLUB "poison overwritten" errors due to a race condition between NAPI polling and resource freeing. Observed error is one of following: - Poison overwriten [ 1889.547746] eth1: Link is Down [ 1889.549940] ============================================================================= [ 1889.549954] BUG kmalloc-4k (Tainted: G B ): Poison overwritten [ 1889.549959] ----------------------------------------------------------------------------- [ 1889.549963] 0xffffff882dcc4d80-0xffffff882dcc4da7 @offset=19840. First byte 0x0 instead of 0x6b [ 1889.549969] Allocated in __alloc_dma_tx_desc_resources+0x60/0x10c [stmmac] age=169 cpu=7 pid=27759 [ 1889.550020] __kmem_cache_alloc_node+0x100/0x2e8 [ 1889.550032] __kmalloc+0x58/0x1a0 [ 1889.550039] __alloc_dma_tx_desc_resources+0x60/0x10c [stmmac] [ 1889.550052] alloc_dma_desc_resources+0xec/0x164 [stmmac] [ 1889.550064] stmmac_setup_dma_desc+0xec/0x1e4 [stmmac] [ 1889.550076] stmmac_open+0x28/0x94 [stmmac] [...] - Wrong memory address [ 1901.546692] Unable to handle kernel paging request at virtual address dead000000000122 [...] [ 1902.964068] Call trace: [ 1902.967193] free_to_partial_list+0x560/0x600 [ 1902.972227] __slab_free+0x1a8/0x420 [ 1902.976480] __kmem_cache_free+0x204/0x218 [ 1902.981254] kfree+0x6c/0x128 [ 1902.984900] kvfree+0x3c/0x4c [ 1902.988545] page_pool_release+0x234/0x27c [ 1902.993320] page_pool_destroy+0xcc/0x190 [ 1902.998006] __free_dma_rx_desc_resources+0x100/0x360 [stmmac] [ 1903.004516] free_dma_desc_resources+0x8c/0xac [stmmac] [ 1903.010419] stmmac_release+0x1c0/0x2b4 [stmmac] [...] Root cause is stmmac_release() stops DMA and frees TX/RX ring buffers and page pools while NAPI/XDP could still be accessing these resources in the background. Fix is by applying napi_synchronize() instead of synchronize_rcu() to every RX or RXTX queue, instead of only for XDP. Also synchronize_rcu() is not correct nor sufficient function to assure NAPI has finished processing. There might be need for potential clearing again after IRQ disable, but this is very hard to reproduce. If this happens, we need to recheck after IRQ disable. Co-developed-by: Chang-Sub Lee Signed-off-by: Chang-Sub Lee Signed-off-by: Jakub Raczynski --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 3a66f2842527..2c6abd5efd55 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -292,16 +292,18 @@ static void __stmmac_disable_all_queues(struct stmmac_priv *priv) static void stmmac_disable_all_queues(struct stmmac_priv *priv) { u8 rx_queues_cnt = priv->plat->rx_queues_to_use; - struct stmmac_rx_queue *rx_q; u8 queue; - /* synchronize_rcu() needed for pending XDP buffers to drain */ for (queue = 0; queue < rx_queues_cnt; queue++) { - rx_q = &priv->dma_conf.rx_queue[queue]; - if (rx_q->xsk_pool) { - synchronize_rcu(); - break; + struct stmmac_channel *ch = &priv->channel[queue]; + + if (stmmac_xdp_is_enabled(priv) && + test_bit(queue, priv->af_xdp_zc_qps)) { + napi_synchronize(&ch->rxtx_napi); + } else { + napi_synchronize(&ch->rx_napi); } + } __stmmac_disable_all_queues(priv); -- 2.34.1