Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

net: openvswitch: Avoid needlessly taking the RTNL on vport destroy

The openvswitch teardown code will immediately call
ovs_netdev_detach_dev() in response to a NETDEV_UNREGISTER notification.
It will then start the dp_notify_work workqueue, which will later end up
calling the vport destroy() callback. This callback takes the RTNL to do
another ovs_netdev_detach_port(), which in this case is unnecessary.
This causes extra pressure on the RTNL, in some cases leading to
"unregister_netdevice: waiting for XX to become free" warnings on
teardown.

We can straight-forwardly avoid the extra RTNL lock acquisition by
checking the device flags before taking the lock, and skip the locking
altogether if the IFF_OVS_DATAPATH flag has already been unset.

Fixes: b07c26511e94 ("openvswitch: fix vport-netdev unregister")
Tested-by: Adrian Moreno <amorenoz@redhat.com>
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
Acked-by: Eelco Chaudron <echaudro@redhat.com>
Acked-by: Aaron Conole <aconole@redhat.com>
Link: https://patch.msgid.link/20251211115006.228876-1-toke@redhat.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Toke Høiland-Jørgensen and committed by
Paolo Abeni
54982276 1e5a5414

+13 -4
+13 -4
net/openvswitch/vport-netdev.c
··· 160 160 161 161 static void netdev_destroy(struct vport *vport) 162 162 { 163 - rtnl_lock(); 164 - if (netif_is_ovs_port(vport->dev)) 165 - ovs_netdev_detach_dev(vport); 166 - rtnl_unlock(); 163 + /* When called from ovs_db_notify_wq() after a dp_device_event(), the 164 + * port has already been detached, so we can avoid taking the RTNL by 165 + * checking this first. 166 + */ 167 + if (netif_is_ovs_port(vport->dev)) { 168 + rtnl_lock(); 169 + /* Check again while holding the lock to ensure we don't race 170 + * with the netdev notifier and detach twice. 171 + */ 172 + if (netif_is_ovs_port(vport->dev)) 173 + ovs_netdev_detach_dev(vport); 174 + rtnl_unlock(); 175 + } 167 176 168 177 call_rcu(&vport->rcu, vport_netdev_free); 169 178 }