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>
sn->n_tunnels--;
if (sn->n_tunnels)
goto out;
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)
out:
n_tunnels--;
if (n_tunnels)
struct net *net = stt_dev->net;
list_del_rcu(&stt_dev->up_next);
struct net *net = stt_dev->net;
list_del_rcu(&stt_dev->up_next);
tcp_sock_release(stt_dev->sock);
stt_dev->sock = NULL;
stt_cleanup(net);
tcp_sock_release(stt_dev->sock);
stt_dev->sock = NULL;
stt_cleanup(net);
struct net_device *dev, *aux;
LIST_HEAD(list);
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 */
rtnl_lock();
/* gather any stt devices that were moved into this ns */
+ INIT_LIST_HEAD(&nf_hook_ops.list);
pr_info("STT tunneling driver\n");
return 0;
out2:
pr_info("STT tunneling driver\n");
return 0;
out2:
void stt_cleanup_module(void)
{
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);
}
rtnl_link_unregister(&stt_link_ops);
unregister_pernet_subsys(&stt_net_ops);
}