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.
Unified · Split
| @@ -105,7 +105,7 @@ struct rt6_info { · 104 unmodified lines | ||
| 105 | 105 | * the same cache line. |
| 106 | 106 | */ |
| 107 | 107 | struct fib6_table *rt6i_table; |
| 108 | − struct fib6_node *rt6i_node; | |
| 108 | + struct fib6_node __rcu *rt6i_node; | |
| 109 | 109 | |
| 110 | 110 | struct in6_addr rt6i_gateway; |
| 111 | 111 | |
| @@ -5556,7 +5556,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) · 5555 unmodified lines | ||
| 5556 | 5556 | * our DAD process, so we don't need |
| 5557 | 5557 | * to do it again |
| 5558 | 5558 | */ |
| 5559 | − if (!(ifp->rt->rt6i_node)) | |
| 5559 | + if (!rcu_access_pointer(ifp->rt->rt6i_node)) | |
| 5560 | 5560 | ip6_ins_rt(ifp->rt); |
| 5561 | 5561 | if (ifp->idev->cnf.forwarding) |
| 5562 | 5562 | addrconf_join_anycast(ifp); |
| @@ -889,7 +889,7 @@ add: · 888 unmodified lines | ||
| 889 | 889 | |
| 890 | 890 | rt->dst.rt6_next = iter; |
| 891 | 891 | *ins = rt; |
| 892 | − rt->rt6i_node = fn; | |
| 892 | + rcu_assign_pointer(rt->rt6i_node, fn); | |
| 893 | 893 | atomic_inc(&rt->rt6i_ref); |
| 894 | 894 | if (!info->skip_notify) |
| 895 | 895 | inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags); |
| @@ -915,7 +915,7 @@ add: · 19 unmodified lines | ||
| 915 | 915 | return err; |
| 916 | 916 | |
| 917 | 917 | *ins = rt; |
| 918 | − rt->rt6i_node = fn; | |
| 918 | + rcu_assign_pointer(rt->rt6i_node, fn); | |
| 919 | 919 | rt->dst.rt6_next = iter->dst.rt6_next; |
| 920 | 920 | atomic_inc(&rt->rt6i_ref); |
| 921 | 921 | if (!info->skip_notify) |
| @@ -1480,8 +1480,9 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, · 558 unmodified lines | ||
| 1480 | 1480 | |
| 1481 | 1481 | int fib6_del(struct rt6_info *rt, struct nl_info *info) |
| 1482 | 1482 | { |
| 1483 | + struct fib6_node *fn = rcu_dereference_protected(rt->rt6i_node, | |
| 1484 | + lockdep_is_held(&rt->rt6i_table->tb6_lock)); | |
| 1483 | 1485 | struct net *net = info->nl_net; |
| 1484 | − struct fib6_node *fn = rt->rt6i_node; | |
| 1485 | 1486 | struct rt6_info **rtp; |
| 1486 | 1487 | |
| 1487 | 1488 | #if RT6_DEBUG >= 2 |
| @@ -1670,7 +1671,9 @@ static int fib6_clean_node(struct fib6_walker *w) · 182 unmodified lines | ||
| 1670 | 1671 | if (res) { |
| 1671 | 1672 | #if RT6_DEBUG >= 2 |
| 1672 | 1673 | pr_debug("%s: del failed: rt=%p@%p err=%d\n", |
| 1673 | − __func__, rt, rt->rt6i_node, res); | |
| 1674 | + __func__, rt, | |
| 1675 | + rcu_access_pointer(rt->rt6i_node), | |
| 1676 | + res); | |
| 1674 | 1677 | #endif |
| 1675 | 1678 | continue; |
| 1676 | 1679 | } |
| @@ -1383,7 +1383,8 @@ static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu) · 1382 unmodified lines | ||
| 1383 | 1383 | static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt) |
| 1384 | 1384 | { |
| 1385 | 1385 | return !(rt->rt6i_flags & RTF_CACHE) && |
| 1386 | − (rt->rt6i_flags & RTF_PCPU || rt->rt6i_node); | |
| 1386 | + (rt->rt6i_flags & RTF_PCPU || | |
| 1387 | + rcu_access_pointer(rt->rt6i_node)); | |
| 1387 | 1388 | } |
| 1388 | 1389 | |
| 1389 | 1390 | static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk, |