| From foo@baz Thu Sep 14 23:20:08 PDT 2017 |
| From: Wei Wang <weiwan@google.com> |
| Date: Fri, 25 Aug 2017 15:03:10 -0700 |
| Subject: ipv6: fix sparse warning on rt6i_node |
| |
| From: Wei Wang <weiwan@google.com> |
| |
| |
| [ Upstream commit 4e587ea71bf924f7dac621f1351653bd41e446cb ] |
| |
| Commit c5cff8561d2d adds rcu grace period before freeing fib6_node. This |
| generates a new sparse warning on rt->rt6i_node related code: |
| net/ipv6/route.c:1394:30: error: incompatible types in comparison |
| expression (different address spaces) |
| ./include/net/ip6_fib.h:187:14: error: incompatible types in comparison |
| expression (different address spaces) |
| |
| This commit adds "__rcu" tag for rt6i_node and makes sure corresponding |
| rcu API is used for it. |
| After this fix, sparse no longer generates the above warning. |
| |
| Fixes: c5cff8561d2d ("ipv6: add rcu grace period before freeing fib6_node") |
| Signed-off-by: Wei Wang <weiwan@google.com> |
| Acked-by: Eric Dumazet <edumazet@google.com> |
| Acked-by: Martin KaFai Lau <kafai@fb.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| include/net/ip6_fib.h | 2 +- |
| net/ipv6/addrconf.c | 2 +- |
| net/ipv6/ip6_fib.c | 11 +++++++---- |
| net/ipv6/route.c | 3 ++- |
| 4 files changed, 11 insertions(+), 7 deletions(-) |
| |
| --- a/include/net/ip6_fib.h |
| +++ b/include/net/ip6_fib.h |
| @@ -103,7 +103,7 @@ struct rt6_info { |
| * the same cache line. |
| */ |
| struct fib6_table *rt6i_table; |
| - struct fib6_node *rt6i_node; |
| + struct fib6_node __rcu *rt6i_node; |
| |
| struct in6_addr rt6i_gateway; |
| |
| --- a/net/ipv6/addrconf.c |
| +++ b/net/ipv6/addrconf.c |
| @@ -5443,7 +5443,7 @@ static void __ipv6_ifa_notify(int event, |
| * our DAD process, so we don't need |
| * to do it again |
| */ |
| - if (!(ifp->rt->rt6i_node)) |
| + if (!rcu_access_pointer(ifp->rt->rt6i_node)) |
| ip6_ins_rt(ifp->rt); |
| if (ifp->idev->cnf.forwarding) |
| addrconf_join_anycast(ifp); |
| --- a/net/ipv6/ip6_fib.c |
| +++ b/net/ipv6/ip6_fib.c |
| @@ -874,7 +874,7 @@ add: |
| |
| rt->dst.rt6_next = iter; |
| *ins = rt; |
| - rt->rt6i_node = fn; |
| + rcu_assign_pointer(rt->rt6i_node, fn); |
| atomic_inc(&rt->rt6i_ref); |
| inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags); |
| info->nl_net->ipv6.rt6_stats->fib_rt_entries++; |
| @@ -899,7 +899,7 @@ add: |
| return err; |
| |
| *ins = rt; |
| - rt->rt6i_node = fn; |
| + rcu_assign_pointer(rt->rt6i_node, fn); |
| rt->dst.rt6_next = iter->dst.rt6_next; |
| atomic_inc(&rt->rt6i_ref); |
| inet6_rt_notify(RTM_NEWROUTE, rt, info, NLM_F_REPLACE); |
| @@ -1459,8 +1459,9 @@ static void fib6_del_route(struct fib6_n |
| |
| int fib6_del(struct rt6_info *rt, struct nl_info *info) |
| { |
| + struct fib6_node *fn = rcu_dereference_protected(rt->rt6i_node, |
| + lockdep_is_held(&rt->rt6i_table->tb6_lock)); |
| struct net *net = info->nl_net; |
| - struct fib6_node *fn = rt->rt6i_node; |
| struct rt6_info **rtp; |
| |
| #if RT6_DEBUG >= 2 |
| @@ -1649,7 +1650,9 @@ static int fib6_clean_node(struct fib6_w |
| if (res) { |
| #if RT6_DEBUG >= 2 |
| pr_debug("%s: del failed: rt=%p@%p err=%d\n", |
| - __func__, rt, rt->rt6i_node, res); |
| + __func__, rt, |
| + rcu_access_pointer(rt->rt6i_node), |
| + res); |
| #endif |
| continue; |
| } |
| --- a/net/ipv6/route.c |
| +++ b/net/ipv6/route.c |
| @@ -1361,7 +1361,8 @@ static void rt6_do_update_pmtu(struct rt |
| static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt) |
| { |
| return !(rt->rt6i_flags & RTF_CACHE) && |
| - (rt->rt6i_flags & RTF_PCPU || rt->rt6i_node); |
| + (rt->rt6i_flags & RTF_PCPU || |
| + rcu_access_pointer(rt->rt6i_node)); |
| } |
| |
| static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk, |