Skip to content

Commit c0b5dc7

Browse files
haokexinkuba-moo
authored andcommitted
net: cpsw_new: Execute ndo_set_rx_mode callback in a work queue
Commit 1767bb2 ("ipv6: mcast: Don't hold RTNL for IPV6_ADD_MEMBERSHIP and MCAST_JOIN_GROUP.") removed the RTNL lock for IPV6_ADD_MEMBERSHIP and MCAST_JOIN_GROUP operations. However, this change triggered the following call trace on my BeagleBone Black board: WARNING: net/8021q/vlan_core.c:236 at vlan_for_each+0x120/0x124, CPU#0: rpcbind/496 RTNL: assertion failed at net/8021q/vlan_core.c (236) Modules linked in: CPU: 0 UID: 997 PID: 496 Comm: rpcbind Not tainted 6.19.0-rc6-next-20260122-yocto-standard+ #8 PREEMPT Hardware name: Generic AM33XX (Flattened Device Tree) Call trace: unwind_backtrace from show_stack+0x28/0x2c show_stack from dump_stack_lvl+0x30/0x38 dump_stack_lvl from __warn+0xb8/0x11c __warn from warn_slowpath_fmt+0x130/0x194 warn_slowpath_fmt from vlan_for_each+0x120/0x124 vlan_for_each from cpsw_add_mc_addr+0x54/0xd8 cpsw_add_mc_addr from __hw_addr_ref_sync_dev+0xc4/0xec __hw_addr_ref_sync_dev from __dev_mc_add+0x78/0x88 __dev_mc_add from igmp6_group_added+0x84/0xec igmp6_group_added from __ipv6_dev_mc_inc+0x1fc/0x2f0 __ipv6_dev_mc_inc from __ipv6_sock_mc_join+0x124/0x1b4 __ipv6_sock_mc_join from do_ipv6_setsockopt+0x84c/0x1168 do_ipv6_setsockopt from ipv6_setsockopt+0x88/0xc8 ipv6_setsockopt from do_sock_setsockopt+0xe8/0x19c do_sock_setsockopt from __sys_setsockopt+0x84/0xac __sys_setsockopt from ret_fast_syscall+0x0/0x5 This trace occurs because vlan_for_each() is called within cpsw_ndo_set_rx_mode(), which expects the RTNL lock to be held. Since modifying vlan_for_each() to operate without the RTNL lock is not straightforward, and because ndo_set_rx_mode() is invoked both with and without the RTNL lock across different code paths, simply adding rtnl_lock() in cpsw_ndo_set_rx_mode() is not a viable solution. To resolve this issue, we opt to execute the actual processing within a work queue, following the approach used by the icssg-prueth driver. Fixes: 1767bb2 ("ipv6: mcast: Don't hold RTNL for IPV6_ADD_MEMBERSHIP and MCAST_JOIN_GROUP.") Signed-off-by: Kevin Hao <haokexin@gmail.com> Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260203-bbb-v5-1-ea0ea217a85c@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent 279fe48 commit c0b5dc7

File tree

2 files changed

+30
-5
lines changed

2 files changed

+30
-5
lines changed

drivers/net/ethernet/ti/cpsw_new.c

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -248,16 +248,22 @@ static int cpsw_purge_all_mc(struct net_device *ndev, const u8 *addr, int num)
248248
return 0;
249249
}
250250

251-
static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
251+
static void cpsw_ndo_set_rx_mode_work(struct work_struct *work)
252252
{
253-
struct cpsw_priv *priv = netdev_priv(ndev);
253+
struct cpsw_priv *priv = container_of(work, struct cpsw_priv, rx_mode_work);
254254
struct cpsw_common *cpsw = priv->cpsw;
255+
struct net_device *ndev = priv->ndev;
255256

257+
rtnl_lock();
258+
if (!netif_running(ndev))
259+
goto unlock_rtnl;
260+
261+
netif_addr_lock_bh(ndev);
256262
if (ndev->flags & IFF_PROMISC) {
257263
/* Enable promiscuous mode */
258264
cpsw_set_promiscious(ndev, true);
259265
cpsw_ale_set_allmulti(cpsw->ale, IFF_ALLMULTI, priv->emac_port);
260-
return;
266+
goto unlock_addr;
261267
}
262268

263269
/* Disable promiscuous mode */
@@ -270,6 +276,18 @@ static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
270276
/* add/remove mcast address either for real netdev or for vlan */
271277
__hw_addr_ref_sync_dev(&ndev->mc, ndev, cpsw_add_mc_addr,
272278
cpsw_del_mc_addr);
279+
280+
unlock_addr:
281+
netif_addr_unlock_bh(ndev);
282+
unlock_rtnl:
283+
rtnl_unlock();
284+
}
285+
286+
static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
287+
{
288+
struct cpsw_priv *priv = netdev_priv(ndev);
289+
290+
schedule_work(&priv->rx_mode_work);
273291
}
274292

275293
static unsigned int cpsw_rxbuf_total_len(unsigned int len)
@@ -1398,6 +1416,7 @@ static int cpsw_create_ports(struct cpsw_common *cpsw)
13981416
priv->msg_enable = netif_msg_init(debug_level, CPSW_DEBUG);
13991417
priv->emac_port = i + 1;
14001418
priv->tx_packet_min = CPSW_MIN_PACKET_SIZE;
1419+
INIT_WORK(&priv->rx_mode_work, cpsw_ndo_set_rx_mode_work);
14011420

14021421
if (is_valid_ether_addr(slave_data->mac_addr)) {
14031422
ether_addr_copy(priv->mac_addr, slave_data->mac_addr);
@@ -1447,13 +1466,18 @@ static int cpsw_create_ports(struct cpsw_common *cpsw)
14471466

14481467
static void cpsw_unregister_ports(struct cpsw_common *cpsw)
14491468
{
1469+
struct net_device *ndev;
1470+
struct cpsw_priv *priv;
14501471
int i = 0;
14511472

14521473
for (i = 0; i < cpsw->data.slaves; i++) {
1453-
if (!cpsw->slaves[i].ndev)
1474+
ndev = cpsw->slaves[i].ndev;
1475+
if (!ndev)
14541476
continue;
14551477

1456-
unregister_netdev(cpsw->slaves[i].ndev);
1478+
priv = netdev_priv(ndev);
1479+
unregister_netdev(ndev);
1480+
disable_work_sync(&priv->rx_mode_work);
14571481
}
14581482
}
14591483

drivers/net/ethernet/ti/cpsw_priv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,7 @@ struct cpsw_priv {
391391
u32 tx_packet_min;
392392
struct cpsw_ale_ratelimit ale_bc_ratelimit;
393393
struct cpsw_ale_ratelimit ale_mc_ratelimit;
394+
struct work_struct rx_mode_work;
394395
};
395396

396397
#define ndev_to_cpsw(ndev) (((struct cpsw_priv *)netdev_priv(ndev))->cpsw)

0 commit comments

Comments
 (0)