diff options
author | Martin KaFai Lau <kafai@fb.com> | 2015-08-14 14:05:53 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-08-17 17:28:03 -0400 |
commit | a73e4195636c17f310b8530643a576f42b82385f (patch) | |
tree | 084823d7d514bc015523526b8317ae05db15e629 | |
parent | ad706862890171e02df1d7391b05599fb676ec18 (diff) |
ipv6: Add rt6_make_pcpu_route()
It is a prep work for fixing a potential deadlock when creating
a pcpu rt.
The current rt6_get_pcpu_route() will also create a pcpu rt if one does not
exist. This patch moves the pcpu rt creation logic into another function,
rt6_make_pcpu_route().
Signed-off-by: Martin KaFai Lau <kafai@fb.com>
CC: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/ipv6/route.c | 20 |
1 files changed, 16 insertions, 4 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index c95c3197c186..0a82653efc88 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -993,13 +993,21 @@ static struct rt6_info *ip6_rt_pcpu_alloc(struct rt6_info *rt) | |||
993 | /* It should be called with read_lock_bh(&tb6_lock) acquired */ | 993 | /* It should be called with read_lock_bh(&tb6_lock) acquired */ |
994 | static struct rt6_info *rt6_get_pcpu_route(struct rt6_info *rt) | 994 | static struct rt6_info *rt6_get_pcpu_route(struct rt6_info *rt) |
995 | { | 995 | { |
996 | struct rt6_info *pcpu_rt, *prev, **p; | 996 | struct rt6_info *pcpu_rt, **p; |
997 | 997 | ||
998 | p = this_cpu_ptr(rt->rt6i_pcpu); | 998 | p = this_cpu_ptr(rt->rt6i_pcpu); |
999 | pcpu_rt = *p; | 999 | pcpu_rt = *p; |
1000 | 1000 | ||
1001 | if (pcpu_rt) | 1001 | if (pcpu_rt) { |
1002 | goto done; | 1002 | dst_hold(&pcpu_rt->dst); |
1003 | rt6_dst_from_metrics_check(pcpu_rt); | ||
1004 | } | ||
1005 | return pcpu_rt; | ||
1006 | } | ||
1007 | |||
1008 | static struct rt6_info *rt6_make_pcpu_route(struct rt6_info *rt) | ||
1009 | { | ||
1010 | struct rt6_info *pcpu_rt, *prev, **p; | ||
1003 | 1011 | ||
1004 | pcpu_rt = ip6_rt_pcpu_alloc(rt); | 1012 | pcpu_rt = ip6_rt_pcpu_alloc(rt); |
1005 | if (!pcpu_rt) { | 1013 | if (!pcpu_rt) { |
@@ -1009,6 +1017,7 @@ static struct rt6_info *rt6_get_pcpu_route(struct rt6_info *rt) | |||
1009 | goto done; | 1017 | goto done; |
1010 | } | 1018 | } |
1011 | 1019 | ||
1020 | p = this_cpu_ptr(rt->rt6i_pcpu); | ||
1012 | prev = cmpxchg(p, NULL, pcpu_rt); | 1021 | prev = cmpxchg(p, NULL, pcpu_rt); |
1013 | if (prev) { | 1022 | if (prev) { |
1014 | /* If someone did it before us, return prev instead */ | 1023 | /* If someone did it before us, return prev instead */ |
@@ -1093,8 +1102,11 @@ redo_rt6_select: | |||
1093 | rt->dst.lastuse = jiffies; | 1102 | rt->dst.lastuse = jiffies; |
1094 | rt->dst.__use++; | 1103 | rt->dst.__use++; |
1095 | pcpu_rt = rt6_get_pcpu_route(rt); | 1104 | pcpu_rt = rt6_get_pcpu_route(rt); |
1096 | read_unlock_bh(&table->tb6_lock); | ||
1097 | 1105 | ||
1106 | if (!pcpu_rt) | ||
1107 | pcpu_rt = rt6_make_pcpu_route(rt); | ||
1108 | |||
1109 | read_unlock_bh(&table->tb6_lock); | ||
1098 | return pcpu_rt; | 1110 | return pcpu_rt; |
1099 | } | 1111 | } |
1100 | } | 1112 | } |