When ovpn_dellink() is called, it invokes cancel_delayed_work_sync() to stop keepalive_work before freeing the device. However, ovpn_nl_peer_new_doit() runs without any lock shared with the RTNL path, so keepalive_work can be scheduled after cancel_delayed_work_sync() returns. The following is a simple race scenario: cpu0 cpu1 ovpn_dellink(dev) cancel_delayed_work_sync(keepalive_work) ovpn_nl_peer_new_doit() ovpn_nl_peer_modify() ovpn_peer_keepalive_set() mod_delayed_work(keepalive_work) To prevent this race condition, cancel_delayed_work_sync() is replaced with disable_delayed_work_sync(). Fixes: 3ecfd9349f40 ("ovpn: implement keepalive mechanism") Signed-off-by: Hyunwoo Kim --- drivers/net/ovpn/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c index 2e0420febda0..ada73dd35ba4 100644 --- a/drivers/net/ovpn/main.c +++ b/drivers/net/ovpn/main.c @@ -212,7 +212,7 @@ static void ovpn_dellink(struct net_device *dev, struct list_head *head) { struct ovpn_priv *ovpn = netdev_priv(dev); - cancel_delayed_work_sync(&ovpn->keepalive_work); + disable_delayed_work_sync(&ovpn->keepalive_work); ovpn_peers_free(ovpn, NULL, OVPN_DEL_PEER_REASON_TEARDOWN); unregister_netdevice_queue(dev, head); } -- 2.43.0