Skip to content

Commit 3df75ff

Browse files
igsilyagregkh
authored andcommitted
openvswitch: vport: fix self-deadlock on release of tunnel ports
commit aa69918 upstream. vports are used concurrently and protected by RCU, so netdev_put() must happen after the RCU grace period. So, either in an RCU call or after the synchronize_net(). The rtnl_delete_link() must happen under RTNL and so can't be executed in RCU context. Calling synchronize_net() while holding RTNL is not a good idea for performance and system stability under load in general, so calling netdev_put() in RCU call is the right solution here. However, when the device is deleted, rtnl_unlock() will call netdev_run_todo() and block until all the references are gone. In the current code this means that we never reach the call_rcu() and the vport is never freed and the reference is never released, causing a self-deadlock on device removal. Fix that by moving the rcu_call() before the rtnl_unlock(), so the scheduled RCU callback will be executed when synchronize_net() is called from the rtnl_unlock()->netdev_run_todo() while the RTNL itself is already released. Fixes: 6931d21 ("openvswitch: defer tunnel netdev_put to RCU release") Cc: stable@vger.kernel.org Acked-by: Eelco Chaudron <echaudro@redhat.com> Signed-off-by: Ilya Maximets <i.maximets@ovn.org> Acked-by: Aaron Conole <aconole@redhat.com> Link: https://patch.msgid.link/20260430233848.440994-2-i.maximets@ovn.org Signed-off-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 781f47d commit 3df75ff

1 file changed

Lines changed: 5 additions & 1 deletion

File tree

net/openvswitch/vport-netdev.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,9 +196,13 @@ void ovs_netdev_tunnel_destroy(struct vport *vport)
196196
*/
197197
if (vport->dev->reg_state == NETREG_REGISTERED)
198198
rtnl_delete_link(vport->dev, 0, NULL);
199-
rtnl_unlock();
200199

200+
/* We can't put the device reference yet, since it can still be in
201+
* use, but rtnl_unlock()->netdev_run_todo() will block until all
202+
* the references are released, so the RCU call must be before it.
203+
*/
201204
call_rcu(&vport->rcu, vport_netdev_free);
205+
rtnl_unlock();
202206
}
203207
EXPORT_SYMBOL_GPL(ovs_netdev_tunnel_destroy);
204208

0 commit comments

Comments
 (0)