Hi Hannes,

On Thu, Apr 07, 2016 at 04:57:40PM +0200, Hannes Frederic Sowa wrote:
> Due to the fact that the udp socket is destructed asynchronously in a
> work queue, we have some nondeterministic behavior during shutdown of
> vxlan tunnels and creating new ones. Fix this by keeping the destruction
> process synchronous in regards to the user space process so IFF_UP can
> be reliably set.
> 
> udp_tunnel_sock_release destroys vs->sock->sk if reference counter
> indicates so. We expect to have the same lifetime of vxlan_sock and
> vxlan_sock->sock->sk even in fast paths with only rcu locks held. So
> only destruct the whole socket after we can be sure it cannot be found
> by searching vxlan_net->sock_list.
> 
> Cc: Jiri Benc <jb...@redhat.com>
> Signed-off-by: Hannes Frederic Sowa <han...@stressinduktion.org>
> ---
>  drivers/net/vxlan.c | 20 +++-----------------
>  include/net/vxlan.h |  2 --
>  2 files changed, 3 insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
> index 1c0fa364323e28..487e48b7a53090 100644
> --- a/drivers/net/vxlan.c
> +++ b/drivers/net/vxlan.c
> @@ -98,7 +98,6 @@ struct vxlan_fdb {
>  
>  /* salt for hash table */
>  static u32 vxlan_salt __read_mostly;
> -static struct workqueue_struct *vxlan_wq;
>  
>  static inline bool vxlan_collect_metadata(struct vxlan_sock *vs)
>  {
> @@ -1065,7 +1064,9 @@ static void __vxlan_sock_release(struct vxlan_sock *vs)
>       vxlan_notify_del_rx_port(vs);
>       spin_unlock(&vn->sock_lock);
>  
> -     queue_work(vxlan_wq, &vs->del_work);
> +     synchronize_rcu();

__vxlan_sock_release is called by vxlan_sock_release which is called by
vxlan_open/stop. Do we really want to have synchronize_rcu() while
holding rtnl?

> +     udp_tunnel_sock_release(vs->sock);
> +     kfree(vs);
>  }
>  
>  static void vxlan_sock_release(struct vxlan_dev *vxlan)
> @@ -2574,13 +2575,6 @@ static const struct ethtool_ops vxlan_ethtool_ops = {
>       .get_link       = ethtool_op_get_link,
>  };
>  
> -static void vxlan_del_work(struct work_struct *work)
> -{
> -     struct vxlan_sock *vs = container_of(work, struct vxlan_sock, del_work);
> -     udp_tunnel_sock_release(vs->sock);
> -     kfree_rcu(vs, rcu);
> -}
> -
>  static struct socket *vxlan_create_sock(struct net *net, bool ipv6,
>                                       __be16 port, u32 flags)
>  {
> @@ -2626,8 +2620,6 @@ static struct vxlan_sock *vxlan_socket_create(struct 
> net *net, bool ipv6,
>       for (h = 0; h < VNI_HASH_SIZE; ++h)
>               INIT_HLIST_HEAD(&vs->vni_list[h]);
>  
> -     INIT_WORK(&vs->del_work, vxlan_del_work);
> -
>       sock = vxlan_create_sock(net, ipv6, port, flags);
>       if (IS_ERR(sock)) {
>               pr_info("Cannot bind port %d, err=%ld\n", ntohs(port),
> @@ -3218,10 +3210,6 @@ static int __init vxlan_init_module(void)
>  {
>       int rc;
>  
> -     vxlan_wq = alloc_workqueue("vxlan", 0, 0);
> -     if (!vxlan_wq)
> -             return -ENOMEM;
> -
>       get_random_bytes(&vxlan_salt, sizeof(vxlan_salt));
>  
>       rc = register_pernet_subsys(&vxlan_net_ops);
> @@ -3242,7 +3230,6 @@ out3:
>  out2:
>       unregister_pernet_subsys(&vxlan_net_ops);
>  out1:
> -     destroy_workqueue(vxlan_wq);
>       return rc;
>  }
>  late_initcall(vxlan_init_module);
> @@ -3251,7 +3238,6 @@ static void __exit vxlan_cleanup_module(void)
>  {
>       rtnl_link_unregister(&vxlan_link_ops);
>       unregister_netdevice_notifier(&vxlan_notifier_block);
> -     destroy_workqueue(vxlan_wq);
>       unregister_pernet_subsys(&vxlan_net_ops);
>       /* rcu_barrier() is called by netns */
>  }
> diff --git a/include/net/vxlan.h b/include/net/vxlan.h
> index 73ed2e951c020d..2113f808e905a4 100644
> --- a/include/net/vxlan.h
> +++ b/include/net/vxlan.h
> @@ -126,9 +126,7 @@ struct vxlan_metadata {
>  /* per UDP socket information */
>  struct vxlan_sock {
>       struct hlist_node hlist;
> -     struct work_struct del_work;
>       struct socket    *sock;
> -     struct rcu_head   rcu;
>       struct hlist_head vni_list[VNI_HASH_SIZE];
>       atomic_t          refcnt;
>       struct udp_offload udp_offloads;
> -- 
> 2.5.5
> 

Reply via email to