@@ -359,7 +359,7 @@ EXPORT_SYMBOL(ip6_dst_alloc);
359
359
static void ip6_dst_destroy (struct dst_entry * dst )
360
360
{
361
361
struct rt6_info * rt = (struct rt6_info * )dst ;
362
- struct fib6_info * from = rt -> from ;
362
+ struct fib6_info * from ;
363
363
struct inet6_dev * idev ;
364
364
365
365
dst_destroy_metrics_generic (dst );
@@ -371,8 +371,11 @@ static void ip6_dst_destroy(struct dst_entry *dst)
371
371
in6_dev_put (idev );
372
372
}
373
373
374
- rt -> from = NULL ;
374
+ rcu_read_lock ();
375
+ from = rcu_dereference (rt -> from );
376
+ rcu_assign_pointer (rt -> from , NULL );
375
377
fib6_info_release (from );
378
+ rcu_read_unlock ();
376
379
}
377
380
378
381
static void ip6_dst_ifdown (struct dst_entry * dst , struct net_device * dev ,
@@ -402,12 +405,16 @@ static bool __rt6_check_expired(const struct rt6_info *rt)
402
405
403
406
static bool rt6_check_expired (const struct rt6_info * rt )
404
407
{
408
+ struct fib6_info * from ;
409
+
410
+ from = rcu_dereference (rt -> from );
411
+
405
412
if (rt -> rt6i_flags & RTF_EXPIRES ) {
406
413
if (time_after (jiffies , rt -> dst .expires ))
407
414
return true;
408
- } else if (rt -> from ) {
415
+ } else if (from ) {
409
416
return rt -> dst .obsolete != DST_OBSOLETE_FORCE_CHK ||
410
- fib6_check_expired (rt -> from );
417
+ fib6_check_expired (from );
411
418
}
412
419
return false;
413
420
}
@@ -963,7 +970,7 @@ static void rt6_set_from(struct rt6_info *rt, struct fib6_info *from)
963
970
{
964
971
rt -> rt6i_flags &= ~RTF_EXPIRES ;
965
972
fib6_info_hold (from );
966
- rt -> from = from ;
973
+ rcu_assign_pointer ( rt -> from , from ) ;
967
974
dst_init_metrics (& rt -> dst , from -> fib6_metrics -> metrics , true);
968
975
if (from -> fib6_metrics != & dst_default_metrics ) {
969
976
rt -> dst ._metrics |= DST_METRICS_REFCOUNTED ;
@@ -2133,11 +2140,13 @@ static bool fib6_check(struct fib6_info *f6i, u32 cookie)
2133
2140
return true;
2134
2141
}
2135
2142
2136
- static struct dst_entry * rt6_check (struct rt6_info * rt , u32 cookie )
2143
+ static struct dst_entry * rt6_check (struct rt6_info * rt ,
2144
+ struct fib6_info * from ,
2145
+ u32 cookie )
2137
2146
{
2138
2147
u32 rt_cookie = 0 ;
2139
2148
2140
- if ((rt -> from && !fib6_get_cookie_safe (rt -> from , & rt_cookie )) ||
2149
+ if ((from && !fib6_get_cookie_safe (from , & rt_cookie )) ||
2141
2150
rt_cookie != cookie )
2142
2151
return NULL ;
2143
2152
@@ -2147,11 +2156,13 @@ static struct dst_entry *rt6_check(struct rt6_info *rt, u32 cookie)
2147
2156
return & rt -> dst ;
2148
2157
}
2149
2158
2150
- static struct dst_entry * rt6_dst_from_check (struct rt6_info * rt , u32 cookie )
2159
+ static struct dst_entry * rt6_dst_from_check (struct rt6_info * rt ,
2160
+ struct fib6_info * from ,
2161
+ u32 cookie )
2151
2162
{
2152
2163
if (!__rt6_check_expired (rt ) &&
2153
2164
rt -> dst .obsolete == DST_OBSOLETE_FORCE_CHK &&
2154
- fib6_check (rt -> from , cookie ))
2165
+ fib6_check (from , cookie ))
2155
2166
return & rt -> dst ;
2156
2167
else
2157
2168
return NULL ;
@@ -2160,6 +2171,7 @@ static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt, u32 cookie)
2160
2171
static struct dst_entry * ip6_dst_check (struct dst_entry * dst , u32 cookie )
2161
2172
{
2162
2173
struct dst_entry * dst_ret ;
2174
+ struct fib6_info * from ;
2163
2175
struct rt6_info * rt ;
2164
2176
2165
2177
rt = container_of (dst , struct rt6_info , dst );
@@ -2171,11 +2183,13 @@ static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
2171
2183
* into this function always.
2172
2184
*/
2173
2185
2174
- if (rt -> rt6i_flags & RTF_PCPU ||
2175
- (unlikely (!list_empty (& rt -> rt6i_uncached )) && rt -> from ))
2176
- dst_ret = rt6_dst_from_check (rt , cookie );
2186
+ from = rcu_dereference (rt -> from );
2187
+
2188
+ if (from && (rt -> rt6i_flags & RTF_PCPU ||
2189
+ unlikely (!list_empty (& rt -> rt6i_uncached ))))
2190
+ dst_ret = rt6_dst_from_check (rt , from , cookie );
2177
2191
else
2178
- dst_ret = rt6_check (rt , cookie );
2192
+ dst_ret = rt6_check (rt , from , cookie );
2179
2193
2180
2194
rcu_read_unlock ();
2181
2195
@@ -2211,22 +2225,33 @@ static void ip6_link_failure(struct sk_buff *skb)
2211
2225
if (rt -> rt6i_flags & RTF_CACHE ) {
2212
2226
if (dst_hold_safe (& rt -> dst ))
2213
2227
rt6_remove_exception_rt (rt );
2214
- } else if (rt -> from ) {
2228
+ } else {
2229
+ struct fib6_info * from ;
2215
2230
struct fib6_node * fn ;
2216
2231
2217
2232
rcu_read_lock ();
2218
- fn = rcu_dereference (rt -> from -> fib6_node );
2219
- if (fn && (rt -> rt6i_flags & RTF_DEFAULT ))
2220
- fn -> fn_sernum = -1 ;
2233
+ from = rcu_dereference (rt -> from );
2234
+ if (from ) {
2235
+ fn = rcu_dereference (from -> fib6_node );
2236
+ if (fn && (rt -> rt6i_flags & RTF_DEFAULT ))
2237
+ fn -> fn_sernum = -1 ;
2238
+ }
2221
2239
rcu_read_unlock ();
2222
2240
}
2223
2241
}
2224
2242
}
2225
2243
2226
2244
static void rt6_update_expires (struct rt6_info * rt0 , int timeout )
2227
2245
{
2228
- if (!(rt0 -> rt6i_flags & RTF_EXPIRES ) && rt0 -> from )
2229
- rt0 -> dst .expires = rt0 -> from -> expires ;
2246
+ if (!(rt0 -> rt6i_flags & RTF_EXPIRES )) {
2247
+ struct fib6_info * from ;
2248
+
2249
+ rcu_read_lock ();
2250
+ from = rcu_dereference (rt0 -> from );
2251
+ if (from )
2252
+ rt0 -> dst .expires = from -> expires ;
2253
+ rcu_read_unlock ();
2254
+ }
2230
2255
2231
2256
dst_set_expires (& rt0 -> dst , timeout );
2232
2257
rt0 -> rt6i_flags |= RTF_EXPIRES ;
@@ -2243,8 +2268,14 @@ static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)
2243
2268
2244
2269
static bool rt6_cache_allowed_for_pmtu (const struct rt6_info * rt )
2245
2270
{
2271
+ bool from_set ;
2272
+
2273
+ rcu_read_lock ();
2274
+ from_set = !!rcu_dereference (rt -> from );
2275
+ rcu_read_unlock ();
2276
+
2246
2277
return !(rt -> rt6i_flags & RTF_CACHE ) &&
2247
- (rt -> rt6i_flags & RTF_PCPU || rt -> from );
2278
+ (rt -> rt6i_flags & RTF_PCPU || from_set );
2248
2279
}
2249
2280
2250
2281
static void __ip6_rt_update_pmtu (struct dst_entry * dst , const struct sock * sk ,
@@ -2280,16 +2311,18 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
2280
2311
if (rt6 -> rt6i_flags & RTF_CACHE )
2281
2312
rt6_update_exception_stamp_rt (rt6 );
2282
2313
} else if (daddr ) {
2314
+ struct fib6_info * from ;
2283
2315
struct rt6_info * nrt6 ;
2284
2316
2285
2317
rcu_read_lock ();
2286
- nrt6 = ip6_rt_cache_alloc (rt6 -> from , daddr , saddr );
2287
- rcu_read_unlock ( );
2318
+ from = rcu_dereference (rt6 -> from );
2319
+ nrt6 = ip6_rt_cache_alloc ( from , daddr , saddr );
2288
2320
if (nrt6 ) {
2289
2321
rt6_do_update_pmtu (nrt6 , mtu );
2290
- if (rt6_insert_exception (nrt6 , rt6 -> from ))
2322
+ if (rt6_insert_exception (nrt6 , from ))
2291
2323
dst_release_immediate (& nrt6 -> dst );
2292
2324
}
2325
+ rcu_read_unlock ();
2293
2326
}
2294
2327
}
2295
2328
@@ -3222,6 +3255,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
3222
3255
struct ndisc_options ndopts ;
3223
3256
struct inet6_dev * in6_dev ;
3224
3257
struct neighbour * neigh ;
3258
+ struct fib6_info * from ;
3225
3259
struct rd_msg * msg ;
3226
3260
int optlen , on_link ;
3227
3261
u8 * lladdr ;
@@ -3304,7 +3338,8 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
3304
3338
NDISC_REDIRECT , & ndopts );
3305
3339
3306
3340
rcu_read_lock ();
3307
- nrt = ip6_rt_cache_alloc (rt -> from , & msg -> dest , NULL );
3341
+ from = rcu_dereference (rt -> from );
3342
+ nrt = ip6_rt_cache_alloc (from , & msg -> dest , NULL );
3308
3343
rcu_read_unlock ();
3309
3344
if (!nrt )
3310
3345
goto out ;
@@ -4687,6 +4722,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
4687
4722
struct net * net = sock_net (in_skb -> sk );
4688
4723
struct nlattr * tb [RTA_MAX + 1 ];
4689
4724
int err , iif = 0 , oif = 0 ;
4725
+ struct fib6_info * from ;
4690
4726
struct dst_entry * dst ;
4691
4727
struct rt6_info * rt ;
4692
4728
struct sk_buff * skb ;
@@ -4783,15 +4819,21 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
4783
4819
}
4784
4820
4785
4821
skb_dst_set (skb , & rt -> dst );
4822
+
4823
+ rcu_read_lock ();
4824
+ from = rcu_dereference (rt -> from );
4825
+
4786
4826
if (fibmatch )
4787
- err = rt6_fill_node (net , skb , rt -> from , NULL , NULL , NULL , iif ,
4827
+ err = rt6_fill_node (net , skb , from , NULL , NULL , NULL , iif ,
4788
4828
RTM_NEWROUTE , NETLINK_CB (in_skb ).portid ,
4789
4829
nlh -> nlmsg_seq , 0 );
4790
4830
else
4791
- err = rt6_fill_node (net , skb , rt -> from , dst ,
4792
- & fl6 .daddr , & fl6 . saddr , iif , RTM_NEWROUTE ,
4831
+ err = rt6_fill_node (net , skb , from , dst , & fl6 . daddr ,
4832
+ & fl6 .saddr , iif , RTM_NEWROUTE ,
4793
4833
NETLINK_CB (in_skb ).portid , nlh -> nlmsg_seq ,
4794
4834
0 );
4835
+ rcu_read_unlock ();
4836
+
4795
4837
if (err < 0 ) {
4796
4838
kfree_skb (skb );
4797
4839
goto errout ;
0 commit comments