We leak an active timer, the hotcpu notifier and all allocated
resources when we exit a namespace. Fix this by introducing a
flow_cache_fini() function where we release the resources before
we exit.
Fixes: ca925cf1534e ("flowcache: Make flow cache name space aware")
Reported-by: Jakub Kicinski <moorray3@wp.pl>
Tested-by: Jakub Kicinski <moorray3@wp.pl>
Cc: Eric Dumazet <eric.dumazet@gmail.com>
Cc: Fan Du <fan.du@windriver.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Acked-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
                                            u8 dir, flow_resolve_t resolver,
                                            void *ctx);
 int flow_cache_init(struct net *net);
+void flow_cache_fini(struct net *net);
 
 void flow_cache_flush(struct net *net);
 void flow_cache_flush_deferred(struct net *net);
 
        return -ENOMEM;
 }
 EXPORT_SYMBOL(flow_cache_init);
+
+void flow_cache_fini(struct net *net)
+{
+       int i;
+       struct flow_cache *fc = &net->xfrm.flow_cache_global;
+
+       del_timer_sync(&fc->rnd_timer);
+       unregister_hotcpu_notifier(&fc->hotcpu_notifier);
+
+       for_each_possible_cpu(i) {
+               struct flow_cache_percpu *fcp = per_cpu_ptr(fc->percpu, i);
+               kfree(fcp->hash_table);
+               fcp->hash_table = NULL;
+       }
+
+       free_percpu(fc->percpu);
+       fc->percpu = NULL;
+}
+EXPORT_SYMBOL(flow_cache_fini);
 
        rv = xfrm_sysctl_init(net);
        if (rv < 0)
                goto out_sysctl;
+       rv = flow_cache_init(net);
+       if (rv < 0)
+               goto out;
 
        /* Initialize the per-net locks here */
        spin_lock_init(&net->xfrm.xfrm_state_lock);
        rwlock_init(&net->xfrm.xfrm_policy_lock);
        mutex_init(&net->xfrm.xfrm_cfg_mutex);
 
-       flow_cache_init(net);
        return 0;
 
+out:
+       xfrm_sysctl_fini(net);
 out_sysctl:
        xfrm_policy_fini(net);
 out_policy:
 
 static void __net_exit xfrm_net_exit(struct net *net)
 {
+       flow_cache_fini(net);
        xfrm_sysctl_fini(net);
        xfrm_policy_fini(net);
        xfrm_state_fini(net);