diff options
-rw-r--r-- | include/net/fib_rules.h | 2 | ||||
-rw-r--r-- | net/core/fib_rules.c | 11 |
2 files changed, 7 insertions, 6 deletions
diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h index 106f3097d384..075f1e3a0fed 100644 --- a/include/net/fib_rules.h +++ b/include/net/fib_rules.h | |||
@@ -20,7 +20,7 @@ struct fib_rule { | |||
20 | u32 table; | 20 | u32 table; |
21 | u8 action; | 21 | u8 action; |
22 | u32 target; | 22 | u32 target; |
23 | struct fib_rule * ctarget; | 23 | struct fib_rule __rcu *ctarget; |
24 | char iifname[IFNAMSIZ]; | 24 | char iifname[IFNAMSIZ]; |
25 | char oifname[IFNAMSIZ]; | 25 | char oifname[IFNAMSIZ]; |
26 | struct rcu_head rcu; | 26 | struct rcu_head rcu; |
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 12b43cc2f889..82a4369ae150 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c | |||
@@ -351,12 +351,12 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | |||
351 | 351 | ||
352 | list_for_each_entry(r, &ops->rules_list, list) { | 352 | list_for_each_entry(r, &ops->rules_list, list) { |
353 | if (r->pref == rule->target) { | 353 | if (r->pref == rule->target) { |
354 | rule->ctarget = r; | 354 | RCU_INIT_POINTER(rule->ctarget, r); |
355 | break; | 355 | break; |
356 | } | 356 | } |
357 | } | 357 | } |
358 | 358 | ||
359 | if (rule->ctarget == NULL) | 359 | if (rcu_dereference_protected(rule->ctarget, 1) == NULL) |
360 | unresolved = 1; | 360 | unresolved = 1; |
361 | } else if (rule->action == FR_ACT_GOTO) | 361 | } else if (rule->action == FR_ACT_GOTO) |
362 | goto errout_free; | 362 | goto errout_free; |
@@ -386,7 +386,7 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | |||
386 | list_for_each_entry(r, &ops->rules_list, list) { | 386 | list_for_each_entry(r, &ops->rules_list, list) { |
387 | if (r->action == FR_ACT_GOTO && | 387 | if (r->action == FR_ACT_GOTO && |
388 | r->target == rule->pref) { | 388 | r->target == rule->pref) { |
389 | BUG_ON(r->ctarget != NULL); | 389 | BUG_ON(rtnl_dereference(r->ctarget) != NULL); |
390 | rcu_assign_pointer(r->ctarget, rule); | 390 | rcu_assign_pointer(r->ctarget, rule); |
391 | if (--ops->unresolved_rules == 0) | 391 | if (--ops->unresolved_rules == 0) |
392 | break; | 392 | break; |
@@ -487,7 +487,7 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | |||
487 | */ | 487 | */ |
488 | if (ops->nr_goto_rules > 0) { | 488 | if (ops->nr_goto_rules > 0) { |
489 | list_for_each_entry(tmp, &ops->rules_list, list) { | 489 | list_for_each_entry(tmp, &ops->rules_list, list) { |
490 | if (tmp->ctarget == rule) { | 490 | if (rtnl_dereference(tmp->ctarget) == rule) { |
491 | rcu_assign_pointer(tmp->ctarget, NULL); | 491 | rcu_assign_pointer(tmp->ctarget, NULL); |
492 | ops->unresolved_rules++; | 492 | ops->unresolved_rules++; |
493 | } | 493 | } |
@@ -545,7 +545,8 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule, | |||
545 | frh->action = rule->action; | 545 | frh->action = rule->action; |
546 | frh->flags = rule->flags; | 546 | frh->flags = rule->flags; |
547 | 547 | ||
548 | if (rule->action == FR_ACT_GOTO && rule->ctarget == NULL) | 548 | if (rule->action == FR_ACT_GOTO && |
549 | rcu_dereference_raw(rule->ctarget) == NULL) | ||
549 | frh->flags |= FIB_RULE_UNRESOLVED; | 550 | frh->flags |= FIB_RULE_UNRESOLVED; |
550 | 551 | ||
551 | if (rule->iifname[0]) { | 552 | if (rule->iifname[0]) { |