diff options
author | Jozsef Kadlecsik <kadlec@netfilter.org> | 2024-05-21 12:57:28 +0200 |
---|---|---|
committer | Jozsef Kadlecsik <kadlec@netfilter.org> | 2024-05-21 12:57:28 +0200 |
commit | 66019ce63c9be21e9c72c99e1233d867160ca219 (patch) | |
tree | 3aa85a256191b409ad0f5bd89e3a3a77af07e10c /kernel/net | |
parent | dffbdff22523c31601307ed0c39e9f6362cf7bf9 (diff) |
Revert "netfilter: ipset: remove set destroy at ip_set module removal"
In case of namespace exit the modules are not unloaded but the sets belonging
to the namespace must be destroyed.
This reverts commit 099916e8f2c0a9c84f79469a8db49f775d4af16e.
Signed-off-by: Jozsef Kadlecsik <kadlec@netfilter.org>
Diffstat (limited to 'kernel/net')
-rw-r--r-- | kernel/net/netfilter/ipset/ip_set_core.c | 27 |
1 files changed, 24 insertions, 3 deletions
diff --git a/kernel/net/netfilter/ipset/ip_set_core.c b/kernel/net/netfilter/ipset/ip_set_core.c index c31dbc3..a99c1bd 100644 --- a/kernel/net/netfilter/ipset/ip_set_core.c +++ b/kernel/net/netfilter/ipset/ip_set_core.c @@ -30,6 +30,7 @@ static DEFINE_RWLOCK(ip_set_ref_lock); /* protects the set refs */ struct ip_set_net { struct ip_set * __rcu *ip_set_list; /* all individual sets */ ip_set_id_t ip_set_max; /* max number of sets */ + bool is_deleted; /* deleted by ip_set_net_exit */ bool is_destroyed; /* all sets are destroyed */ }; @@ -925,9 +926,11 @@ ip_set_nfnl_put(struct net *net, ip_set_id_t index) struct ip_set_net *inst = ip_set_pernet(net); nfnl_lock(NFNL_SUBSYS_IPSET); - set = ip_set(inst, index); - if (set) - __ip_set_put(set); + if (!inst->is_deleted) { /* already deleted from ip_set_net_exit() */ + set = ip_set(inst, index); + if (set) + __ip_set_put(set); + } nfnl_unlock(NFNL_SUBSYS_IPSET); } EXPORT_SYMBOL_GPL(ip_set_nfnl_put); @@ -2481,6 +2484,7 @@ ip_set_net_init(struct net *net) #else goto err_alloc; #endif + inst->is_deleted = false; inst->is_destroyed = false; rcu_assign_pointer(inst->ip_set_list, list); return 0; @@ -2497,6 +2501,20 @@ ip_set_net_exit(struct net *net) { struct ip_set_net *inst = ip_set_pernet(net); + struct ip_set *set = NULL; + ip_set_id_t i; + + inst->is_deleted = true; /* flag for ip_set_nfnl_put */ + + nfnl_lock(NFNL_SUBSYS_IPSET); + for (i = 0; i < inst->ip_set_max; i++) { + set = ip_set(inst, i); + if (set) { + ip_set(inst, i) = NULL; + ip_set_destroy_set(set); + } + } + nfnl_unlock(NFNL_SUBSYS_IPSET); kvfree(rcu_dereference_protected(inst->ip_set_list, 1)); #ifndef HAVE_NET_OPS_ID kvfree(inst); @@ -2563,6 +2581,9 @@ ip_set_fini(void) nfnetlink_subsys_unregister(&ip_set_netlink_subsys); UNREGISTER_PERNET_SUBSYS(&ip_set_net_ops); + /* Wait for call_rcu() in destroy */ + rcu_barrier(); + pr_debug("these are the famous last words\n"); } |