[PATCH net-next 2/7] ibmveth: do not close twice after a failed reopen
flat view
WARM3d
From: Mingming Cao <hidden>
Date: 2026-10-03 01:58:06
Also in:
netdev
Subsystem:
ibm power virtual ethernet device driver, linux for powerpc (32-bit and 64-bit), networking drivers, the rest · Maintainers:
Nick Child, Madhavan Srinivasan, Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
ibmveth_change_mtu(), veth_pool_store(), ibmveth_set_csum_offload()
and ibmveth_set_tso() call close() and open() directly. If open() fails,
NAPI is left disabled while IFF_UP stays set, so the next close()
(ifdown, unregister or another reconfiguration) calls napi_disable()
again and waits forever with RTNL held. Networking and shutdown
hang; only a reboot recovers. ethtool -L in that state also wakes
queues that have no TX buffer and dereferences NULL in
ibmveth_start_xmit().
Any open() failure on those paths triggers it, for example an
allocation failure on an MTU change to jumbo frames.
Track a successful open in adapter->opened. close() returns early
when it is clear, and set_channels() checks it instead of IFF_UP.
The open() error-path leaks are fixed separately in net by
commit af0524bf4ce1 ("ibmveth: h_free logical LAN on open-fail after
register") and commit 84bec0bf0352 ("ibmveth: fix TX LTB and filter
unwind on open-fail"); this patch does not depend on them.
Tested on a POWER10 LPAR with ibmveth_open() forced to fail:
'ip link set dev eth1 mtu 9000' fails, then 'ip link set dev eth1 down'
returns at once and 'ip link set dev eth1 up' recovers the interface.
Fixes: 860f242eb534 ("[PATCH] ibmveth change buffer pools dynamically")
Signed-off-by: Mingming Cao <redacted>
---
drivers/net/ethernet/ibm/ibmveth.c | 24 +++++++++++++++++-------
drivers/net/ethernet/ibm/ibmveth.h | 2 ++
2 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index aa2300e97081..00cee2916920 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c@@ -738,6 +738,7 @@ static int ibmveth_open(struct net_device *netdev) netif_tx_start_all_queues(netdev); + adapter->opened = true; netdev_dbg(netdev, "open complete\n"); return 0;
@@ -779,6 +780,14 @@ static int ibmveth_close(struct net_device *netdev) long lpar_rc; int i; + /* change_mtu, pool sysfs, set_csum and set_tso call close() and + * open() directly. If that open() fails, IFF_UP stays set and + * NAPI is disabled; a second close() would hang in napi_disable(). + */ + if (!adapter->opened) + return 0; + adapter->opened = false; + netdev_dbg(netdev, "close starting\n"); napi_disable(&adapter->napi);
@@ -830,10 +839,10 @@ static int ibmveth_close(struct net_device *netdev) * * @w: pointer to work_struct embedded in adapter structure * - * Context: This routine acquires rtnl_mutex and disables its NAPI through - * ibmveth_close. It can't be called directly in a context that has - * already acquired rtnl_mutex or disabled its NAPI, or directly from - * a poll routine. + * Context: This routine acquires rtnl_mutex and, if the device is open, + * disables its NAPI through ibmveth_close. It can't be called + * directly in a context that has already acquired rtnl_mutex or + * disabled its NAPI, or directly from a poll routine. * * Return: void */
@@ -1127,10 +1136,11 @@ static int ibmveth_set_channels(struct net_device *netdev, goal = channels->tx_count; int rc, i; - /* If ndo_open has not been called yet then don't allocate, just set - * desired netdev_queue's and return + /* If the device is not open (including a failed close/open with + * IFF_UP still set) then don't allocate, just set desired + * netdev_queue's and return */ - if (!(netdev->flags & IFF_UP)) + if (!adapter->opened) return netif_set_real_num_tx_queues(netdev, goal); /* We have IBMVETH_MAX_QUEUES netdev_queue's allocated
diff --git a/drivers/net/ethernet/ibm/ibmveth.h b/drivers/net/ethernet/ibm/ibmveth.h
index d87713668ed3..3f2240823f6a 100644
--- a/drivers/net/ethernet/ibm/ibmveth.h
+++ b/drivers/net/ethernet/ibm/ibmveth.h@@ -172,6 +172,8 @@ struct ibmveth_adapter { int rx_csum; int large_send; bool is_active_trunk; + /* Set by a successful ibmveth_open(), cleared by ibmveth_close(). */ + bool opened; unsigned int rx_buffers_per_hcall; u64 fw_ipv6_csum_support;
--
2.39.3 (Apple Git-146)