mirror of
https://github.com/torvalds/linux.git
synced 2024-11-27 22:51:35 +00:00
netfilter: cttimeout: decouple unlink and free on netns destruction
Make it so netns pre_exit unlinks the objects from the pernet list, so they cannot be found anymore. netns core issues a synchronize_rcu() before calling the exit hooks so any the time the exit hooks run unconfirmed nf_conn entries have been free'd or they have been committed to the hashtable. The exit hook still tags unconfirmed entries as dying, this can now be removed in a followup change. Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
parent
1397af5bfd
commit
78222bacfc
@ -17,14 +17,6 @@ struct nf_ct_timeout {
|
||||
char data[];
|
||||
};
|
||||
|
||||
struct ctnl_timeout {
|
||||
struct list_head head;
|
||||
struct rcu_head rcu_head;
|
||||
refcount_t refcnt;
|
||||
char name[CTNL_TIMEOUT_NAME_MAX];
|
||||
struct nf_ct_timeout timeout;
|
||||
};
|
||||
|
||||
struct nf_conn_timeout {
|
||||
struct nf_ct_timeout __rcu *timeout;
|
||||
};
|
||||
|
@ -33,8 +33,19 @@
|
||||
|
||||
static unsigned int nfct_timeout_id __read_mostly;
|
||||
|
||||
struct ctnl_timeout {
|
||||
struct list_head head;
|
||||
struct rcu_head rcu_head;
|
||||
refcount_t refcnt;
|
||||
char name[CTNL_TIMEOUT_NAME_MAX];
|
||||
struct nf_ct_timeout timeout;
|
||||
|
||||
struct list_head free_head;
|
||||
};
|
||||
|
||||
struct nfct_timeout_pernet {
|
||||
struct list_head nfct_timeout_list;
|
||||
struct list_head nfct_timeout_freelist;
|
||||
};
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
@ -574,10 +585,24 @@ static int __net_init cttimeout_net_init(struct net *net)
|
||||
struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(net);
|
||||
|
||||
INIT_LIST_HEAD(&pernet->nfct_timeout_list);
|
||||
INIT_LIST_HEAD(&pernet->nfct_timeout_freelist);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __net_exit cttimeout_net_pre_exit(struct net *net)
|
||||
{
|
||||
struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(net);
|
||||
struct ctnl_timeout *cur, *tmp;
|
||||
|
||||
list_for_each_entry_safe(cur, tmp, &pernet->nfct_timeout_list, head) {
|
||||
list_del_rcu(&cur->head);
|
||||
list_add(&cur->free_head, &pernet->nfct_timeout_freelist);
|
||||
}
|
||||
|
||||
/* core calls synchronize_rcu() after this */
|
||||
}
|
||||
|
||||
static void __net_exit cttimeout_net_exit(struct net *net)
|
||||
{
|
||||
struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(net);
|
||||
@ -586,8 +611,8 @@ static void __net_exit cttimeout_net_exit(struct net *net)
|
||||
nf_ct_unconfirmed_destroy(net);
|
||||
nf_ct_untimeout(net, NULL);
|
||||
|
||||
list_for_each_entry_safe(cur, tmp, &pernet->nfct_timeout_list, head) {
|
||||
list_del_rcu(&cur->head);
|
||||
list_for_each_entry_safe(cur, tmp, &pernet->nfct_timeout_freelist, head) {
|
||||
list_del(&cur->free_head);
|
||||
|
||||
if (refcount_dec_and_test(&cur->refcnt))
|
||||
kfree_rcu(cur, rcu_head);
|
||||
@ -596,6 +621,7 @@ static void __net_exit cttimeout_net_exit(struct net *net)
|
||||
|
||||
static struct pernet_operations cttimeout_ops = {
|
||||
.init = cttimeout_net_init,
|
||||
.pre_exit = cttimeout_net_pre_exit,
|
||||
.exit = cttimeout_net_exit,
|
||||
.id = &nfct_timeout_id,
|
||||
.size = sizeof(struct nfct_timeout_pernet),
|
||||
|
Loading…
Reference in New Issue
Block a user