aboutsummaryrefslogtreecommitdiffstats
path: root/include/net/ip6_fib.h
diff options
context:
space:
mode:
authorDavid Ahern <dsahern@gmail.com>2018-04-20 15:38:02 -0700
committerDavid S. Miller <davem@davemloft.net>2018-04-21 16:06:14 -0400
commita68886a691804d3f6d479ebf6825480fbafb6a00 (patch)
tree2240cab921badf927268bcd687b8b2743179e86c /include/net/ip6_fib.h
parentnet/ipv6: Move release of fib6_info from pcpu routes to helper (diff)
downloadlinux-dev-a68886a691804d3f6d479ebf6825480fbafb6a00.tar.xz
linux-dev-a68886a691804d3f6d479ebf6825480fbafb6a00.zip
net/ipv6: Make from in rt6_info rcu protected
When a dst entry is created from a fib entry, the 'from' in rt6_info is set to the fib entry. The 'from' reference is used most notably for cookie checking - making sure stale dst entries are updated if the fib entry is changed. When a fib entry is deleted, the pcpu routes on it are walked releasing the fib6_info reference. This is needed for the fib6_info cleanup to happen and to make sure all device references are released in a timely manner. There is a race window when a FIB entry is deleted and the 'from' on the pcpu route is dropped and the pcpu route hits a cookie check. Handle this race using rcu on from. Signed-off-by: David Ahern <dsahern@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include/net/ip6_fib.h')
-rw-r--r--include/net/ip6_fib.h10
1 files changed, 6 insertions, 4 deletions
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index dc3505fb62b3..1af450d4e923 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -174,7 +174,7 @@ struct fib6_info {
struct rt6_info {
struct dst_entry dst;
- struct fib6_info *from;
+ struct fib6_info __rcu *from;
struct rt6key rt6i_dst;
struct rt6key rt6i_src;
@@ -248,13 +248,15 @@ static inline bool fib6_get_cookie_safe(const struct fib6_info *f6i,
static inline u32 rt6_get_cookie(const struct rt6_info *rt)
{
+ struct fib6_info *from;
u32 cookie = 0;
rcu_read_lock();
- if (rt->rt6i_flags & RTF_PCPU ||
- (unlikely(!list_empty(&rt->rt6i_uncached)) && rt->from))
- fib6_get_cookie_safe(rt->from, &cookie);
+ from = rcu_dereference(rt->from);
+ if (from && (rt->rt6i_flags & RTF_PCPU ||
+ unlikely(!list_empty(&rt->rt6i_uncached))))
+ fib6_get_cookie_safe(from, &cookie);
rcu_read_unlock();