diff options
author | Pravin B Shelar <pshelar@nicira.com> | 2016-01-12 11:45:18 -0800 |
---|---|---|
committer | Pravin B Shelar <pshelar@nicira.com> | 2016-01-12 11:45:18 -0800 |
commit | fee43fa277f62d1ed7e08b21ece96f4e15df2569 (patch) | |
tree | 920f704fe226c136a87b658c084a265cae462044 /datapath | |
parent | 32d37ce8518f23309acb2e60dba891672f5de84f (diff) | |
download | openvswitch-fee43fa277f62d1ed7e08b21ece96f4e15df2569.tar.gz |
datapath: Fix deadlock on STT device destroy.
STT unregisters nf-hook when there are no other STT devices
left in the namespace. On some kernel versions the nf-unreg API
take RTNL lock, but it is already taken in the tunnel device
destroy code path which results in deadlock. To fix the issue
I moved the unreg call into net-exit.
VMware-BZ: #1582410
Reported-by: Joe Stringer <joe@ovn.org>
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Acked-by: Joe Stringer <joe@ovn.org>
Diffstat (limited to 'datapath')
-rw-r--r-- | datapath/linux/compat/stt.c | 20 |
1 files changed, 14 insertions, 6 deletions
diff --git a/datapath/linux/compat/stt.c b/datapath/linux/compat/stt.c index 85ddbe7ca..98d6d5b3c 100644 --- a/datapath/linux/compat/stt.c +++ b/datapath/linux/compat/stt.c @@ -1586,12 +1586,6 @@ static void stt_cleanup(struct net *net) sn->n_tunnels--; if (sn->n_tunnels) goto out; -#ifdef HAVE_NF_REGISTER_NET_HOOK - nf_unregister_net_hook(net, &nf_hook_ops); -#else - nf_unregister_hook(&nf_hook_ops); -#endif - out: n_tunnels--; if (n_tunnels) @@ -1668,6 +1662,7 @@ static int stt_stop(struct net_device *dev) struct net *net = stt_dev->net; list_del_rcu(&stt_dev->up_next); + synchronize_net(); tcp_sock_release(stt_dev->sock); stt_dev->sock = NULL; stt_cleanup(net); @@ -1869,6 +1864,14 @@ static void stt_exit_net(struct net *net) struct net_device *dev, *aux; LIST_HEAD(list); +#ifdef HAVE_NF_REGISTER_NET_HOOK + /* Ideally this should be done from stt_stop(), But on some kernels + * nf-unreg operation needs RTNL-lock, which can cause deallock. + * So it is done from here. */ + if (!list_empty(&nf_hook_ops.list)) + nf_unregister_net_hook(net, &nf_hook_ops); +#endif + rtnl_lock(); /* gather any stt devices that were moved into this ns */ @@ -1908,6 +1911,7 @@ int stt_init_module(void) if (rc) goto out2; + INIT_LIST_HEAD(&nf_hook_ops.list); pr_info("STT tunneling driver\n"); return 0; out2: @@ -1918,6 +1922,10 @@ out1: void stt_cleanup_module(void) { +#ifndef HAVE_NF_REGISTER_NET_HOOK + if (!list_empty(&nf_hook_ops.list)) + nf_unregister_hook(&nf_hook_ops); +#endif rtnl_link_unregister(&stt_link_ops); unregister_pernet_subsys(&stt_net_ops); } |