[net-next,v4,2/6] net: stmmac: close the interface after a failed MTU reopen
Commit Message
An MTU change stops the data path and then reopens it using a newly
allocated DMA configuration. If reopening fails, the new allocation is
freed while the netdev remains up and priv->dma_conf retains copies of
the freed pointers. A subsequent close repeats NAPI disable and IRQ and
DMA-resource teardown. It can hang in napi_disable() or access resources
which have already been freed.
Track successful opens of the data path separately from the netdev's
administrative state. Clear that state when releasing the data path and
skip a second release after a failed reopen. Close the netdev through the
network core on the MTU error path, so the PHY attachment and runtime-PM
reference are released and the interface is marked down. A subsequent
open can then allocate fresh resources and retry normally.
Keep successful MTU changes on the existing path, retaining the PHY
attachment and runtime-PM reference. Allocation failures before stopping
the original data path still leave the running interface unchanged.
Fixes: 3470079687448 ("net: ethernet: stmicro: stmmac: permit MTU change with interface up")
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
---
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 2 ++
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 10 ++++++++++
2 files changed, 12 insertions(+)
@@ -281,6 +281,8 @@ struct stmmac_priv {
struct mutex lock;
struct stmmac_dma_conf dma_conf;
+ /* Paired __stmmac_open()/__stmmac_release(), serialized by RTNL. */
+ bool opened;
/* Generic channel for NAPI */
struct stmmac_channel channel[STMMAC_CH_MAX];
@@ -4212,6 +4212,7 @@ static int __stmmac_open(struct net_device *dev,
stmmac_enable_all_queues(priv);
netif_tx_start_all_queues(priv->dev);
stmmac_enable_all_dma_irq(priv);
+ priv->opened = true;
return 0;
@@ -4287,6 +4288,11 @@ static void __stmmac_release(struct net_device *dev)
struct stmmac_priv *priv = netdev_priv(dev);
u8 chan;
+ /* A failed MTU reopen has already released the data path. */
+ if (!priv->opened)
+ return;
+ priv->opened = false;
+
/* Stop and disconnect the PHY */
phylink_stop(priv->phylink);
@@ -6212,6 +6218,10 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu)
if (ret) {
free_dma_desc_resources(priv, dma_conf);
kfree(dma_conf);
+ /* Finish closing the PHY and PM state, but do not repeat
+ * the data-path teardown after the failed reopen.
+ */
+ netif_close(dev);
netdev_err(priv->dev, "failed reopening the interface after MTU change\n");
return ret;
}