diff options
Diffstat (limited to 'net/core/fib_rules.c')
-rw-r--r-- | net/core/fib_rules.c | 14 |
1 files changed, 9 insertions, 5 deletions
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index e7ab0c0285b5..c02e63c908da 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
14 | #include <linux/list.h> | 14 | #include <linux/list.h> |
15 | #include <linux/module.h> | ||
15 | #include <net/net_namespace.h> | 16 | #include <net/net_namespace.h> |
16 | #include <net/sock.h> | 17 | #include <net/sock.h> |
17 | #include <net/fib_rules.h> | 18 | #include <net/fib_rules.h> |
@@ -384,8 +385,8 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | |||
384 | */ | 385 | */ |
385 | list_for_each_entry(r, &ops->rules_list, list) { | 386 | list_for_each_entry(r, &ops->rules_list, list) { |
386 | if (r->action == FR_ACT_GOTO && | 387 | if (r->action == FR_ACT_GOTO && |
387 | r->target == rule->pref) { | 388 | r->target == rule->pref && |
388 | BUG_ON(rtnl_dereference(r->ctarget) != NULL); | 389 | rtnl_dereference(r->ctarget) == NULL) { |
389 | rcu_assign_pointer(r->ctarget, rule); | 390 | rcu_assign_pointer(r->ctarget, rule); |
390 | if (--ops->unresolved_rules == 0) | 391 | if (--ops->unresolved_rules == 0) |
391 | break; | 392 | break; |
@@ -475,8 +476,11 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | |||
475 | 476 | ||
476 | list_del_rcu(&rule->list); | 477 | list_del_rcu(&rule->list); |
477 | 478 | ||
478 | if (rule->action == FR_ACT_GOTO) | 479 | if (rule->action == FR_ACT_GOTO) { |
479 | ops->nr_goto_rules--; | 480 | ops->nr_goto_rules--; |
481 | if (rtnl_dereference(rule->ctarget) == NULL) | ||
482 | ops->unresolved_rules--; | ||
483 | } | ||
480 | 484 | ||
481 | /* | 485 | /* |
482 | * Check if this rule is a target to any of them. If so, | 486 | * Check if this rule is a target to any of them. If so, |
@@ -487,7 +491,7 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | |||
487 | if (ops->nr_goto_rules > 0) { | 491 | if (ops->nr_goto_rules > 0) { |
488 | list_for_each_entry(tmp, &ops->rules_list, list) { | 492 | list_for_each_entry(tmp, &ops->rules_list, list) { |
489 | if (rtnl_dereference(tmp->ctarget) == rule) { | 493 | if (rtnl_dereference(tmp->ctarget) == rule) { |
490 | rcu_assign_pointer(tmp->ctarget, NULL); | 494 | RCU_INIT_POINTER(tmp->ctarget, NULL); |
491 | ops->unresolved_rules++; | 495 | ops->unresolved_rules++; |
492 | } | 496 | } |
493 | } | 497 | } |
@@ -545,7 +549,7 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule, | |||
545 | frh->flags = rule->flags; | 549 | frh->flags = rule->flags; |
546 | 550 | ||
547 | if (rule->action == FR_ACT_GOTO && | 551 | if (rule->action == FR_ACT_GOTO && |
548 | rcu_dereference_raw(rule->ctarget) == NULL) | 552 | rcu_access_pointer(rule->ctarget) == NULL) |
549 | frh->flags |= FIB_RULE_UNRESOLVED; | 553 | frh->flags |= FIB_RULE_UNRESOLVED; |
550 | 554 | ||
551 | if (rule->iifname[0]) { | 555 | if (rule->iifname[0]) { |