|
@@ -1008,10 +1008,8 @@ notify:
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static void nf_tables_rcu_chain_destroy(struct rcu_head *head)
|
|
|
+static void nf_tables_chain_destroy(struct nft_chain *chain)
|
|
|
{
|
|
|
- struct nft_chain *chain = container_of(head, struct nft_chain, rcu_head);
|
|
|
-
|
|
|
BUG_ON(chain->use > 0);
|
|
|
|
|
|
if (chain->flags & NFT_BASE_CHAIN) {
|
|
@@ -1059,7 +1057,9 @@ static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb,
|
|
|
family);
|
|
|
|
|
|
/* Make sure all rule references are gone before this is released */
|
|
|
- call_rcu(&chain->rcu_head, nf_tables_rcu_chain_destroy);
|
|
|
+ synchronize_rcu();
|
|
|
+
|
|
|
+ nf_tables_chain_destroy(chain);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -1531,9 +1531,8 @@ err:
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
-static void nf_tables_rcu_rule_destroy(struct rcu_head *head)
|
|
|
+static void nf_tables_rule_destroy(struct nft_rule *rule)
|
|
|
{
|
|
|
- struct nft_rule *rule = container_of(head, struct nft_rule, rcu_head);
|
|
|
struct nft_expr *expr;
|
|
|
|
|
|
/*
|
|
@@ -1548,11 +1547,6 @@ static void nf_tables_rcu_rule_destroy(struct rcu_head *head)
|
|
|
kfree(rule);
|
|
|
}
|
|
|
|
|
|
-static void nf_tables_rule_destroy(struct nft_rule *rule)
|
|
|
-{
|
|
|
- call_rcu(&rule->rcu_head, nf_tables_rcu_rule_destroy);
|
|
|
-}
|
|
|
-
|
|
|
#define NFT_RULE_MAXEXPRS 128
|
|
|
|
|
|
static struct nft_expr_info *info;
|
|
@@ -1819,9 +1813,6 @@ static int nf_tables_commit(struct sk_buff *skb)
|
|
|
synchronize_rcu();
|
|
|
|
|
|
list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) {
|
|
|
- /* Delete this rule from the dirty list */
|
|
|
- list_del(&rupd->list);
|
|
|
-
|
|
|
/* This rule was inactive in the past and just became active.
|
|
|
* Clear the next bit of the genmask since its meaning has
|
|
|
* changed, now it is the future.
|
|
@@ -1832,6 +1823,7 @@ static int nf_tables_commit(struct sk_buff *skb)
|
|
|
rupd->chain, rupd->rule,
|
|
|
NFT_MSG_NEWRULE, 0,
|
|
|
rupd->family);
|
|
|
+ list_del(&rupd->list);
|
|
|
kfree(rupd);
|
|
|
continue;
|
|
|
}
|
|
@@ -1841,7 +1833,15 @@ static int nf_tables_commit(struct sk_buff *skb)
|
|
|
nf_tables_rule_notify(skb, rupd->nlh, rupd->table, rupd->chain,
|
|
|
rupd->rule, NFT_MSG_DELRULE, 0,
|
|
|
rupd->family);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Make sure we don't see any packet traversing old rules */
|
|
|
+ synchronize_rcu();
|
|
|
+
|
|
|
+ /* Now we can safely release unused old rules */
|
|
|
+ list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) {
|
|
|
nf_tables_rule_destroy(rupd->rule);
|
|
|
+ list_del(&rupd->list);
|
|
|
kfree(rupd);
|
|
|
}
|
|
|
|
|
@@ -1854,20 +1854,26 @@ static int nf_tables_abort(struct sk_buff *skb)
|
|
|
struct nft_rule_trans *rupd, *tmp;
|
|
|
|
|
|
list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) {
|
|
|
- /* Delete all rules from the dirty list */
|
|
|
- list_del(&rupd->list);
|
|
|
-
|
|
|
if (!nft_rule_is_active_next(net, rupd->rule)) {
|
|
|
nft_rule_clear(net, rupd->rule);
|
|
|
+ list_del(&rupd->list);
|
|
|
kfree(rupd);
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
/* This rule is inactive, get rid of it */
|
|
|
list_del_rcu(&rupd->rule->list);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Make sure we don't see any packet accessing aborted rules */
|
|
|
+ synchronize_rcu();
|
|
|
+
|
|
|
+ list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) {
|
|
|
nf_tables_rule_destroy(rupd->rule);
|
|
|
+ list_del(&rupd->list);
|
|
|
kfree(rupd);
|
|
|
}
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|