@@ -377,6 +377,7 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
377377{
378378 struct rt6_info * rt = (struct rt6_info * )dst ;
379379 struct inet6_dev * idev = rt -> rt6i_idev ;
380+ struct fib6_info * from ;
380381
381382 if (idev && idev -> dev != blackhole_netdev ) {
382383 struct inet6_dev * blackhole_idev = in6_dev_get (blackhole_netdev );
@@ -386,6 +387,8 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
386387 in6_dev_put (idev );
387388 }
388389 }
390+ from = unrcu_pointer (xchg (& rt -> from , NULL ));
391+ fib6_info_release (from );
389392}
390393
391394static bool __rt6_check_expired (const struct rt6_info * rt )
@@ -416,8 +419,8 @@ void fib6_select_path(const struct net *net, struct fib6_result *res,
416419 struct flowi6 * fl6 , int oif , bool have_oif_match ,
417420 const struct sk_buff * skb , int strict )
418421{
419- struct fib6_info * sibling , * next_sibling ;
420422 struct fib6_info * match = res -> f6i ;
423+ struct fib6_info * sibling ;
421424
422425 if (!match -> nh && (!match -> fib6_nsiblings || have_oif_match ))
423426 goto out ;
@@ -443,8 +446,8 @@ void fib6_select_path(const struct net *net, struct fib6_result *res,
443446 if (fl6 -> mp_hash <= atomic_read (& match -> fib6_nh -> fib_nh_upper_bound ))
444447 goto out ;
445448
446- list_for_each_entry_safe (sibling , next_sibling , & match -> fib6_siblings ,
447- fib6_siblings ) {
449+ list_for_each_entry_rcu (sibling , & match -> fib6_siblings ,
450+ fib6_siblings ) {
448451 const struct fib6_nh * nh = sibling -> fib6_nh ;
449452 int nh_upper_bound ;
450453
@@ -1449,7 +1452,6 @@ static DEFINE_SPINLOCK(rt6_exception_lock);
14491452static void rt6_remove_exception (struct rt6_exception_bucket * bucket ,
14501453 struct rt6_exception * rt6_ex )
14511454{
1452- struct fib6_info * from ;
14531455 struct net * net ;
14541456
14551457 if (!bucket || !rt6_ex )
@@ -1461,8 +1463,6 @@ static void rt6_remove_exception(struct rt6_exception_bucket *bucket,
14611463 /* purge completely the exception to allow releasing the held resources:
14621464 * some [sk] cache may keep the dst around for unlimited time
14631465 */
1464- from = xchg ((__force struct fib6_info * * )& rt6_ex -> rt6i -> from , NULL );
1465- fib6_info_release (from );
14661466 dst_dev_put (& rt6_ex -> rt6i -> dst );
14671467
14681468 hlist_del_rcu (& rt6_ex -> hlist );
@@ -5216,14 +5216,18 @@ static void ip6_route_mpath_notify(struct fib6_info *rt,
52165216 * nexthop. Since sibling routes are always added at the end of
52175217 * the list, find the first sibling of the last route appended
52185218 */
5219+ rcu_read_lock ();
5220+
52195221 if ((nlflags & NLM_F_APPEND ) && rt_last && rt_last -> fib6_nsiblings ) {
5220- rt = list_first_entry (& rt_last -> fib6_siblings ,
5221- struct fib6_info ,
5222- fib6_siblings );
5222+ rt = list_first_or_null_rcu (& rt_last -> fib6_siblings ,
5223+ struct fib6_info ,
5224+ fib6_siblings );
52235225 }
52245226
52255227 if (rt )
52265228 inet6_rt_notify (RTM_NEWROUTE , rt , info , nlflags );
5229+
5230+ rcu_read_unlock ();
52275231}
52285232
52295233static bool ip6_route_mpath_should_notify (const struct fib6_info * rt )
@@ -5568,17 +5572,21 @@ static size_t rt6_nlmsg_size(struct fib6_info *f6i)
55685572 nexthop_for_each_fib6_nh (f6i -> nh , rt6_nh_nlmsg_size ,
55695573 & nexthop_len );
55705574 } else {
5571- struct fib6_info * sibling , * next_sibling ;
55725575 struct fib6_nh * nh = f6i -> fib6_nh ;
5576+ struct fib6_info * sibling ;
55735577
55745578 nexthop_len = 0 ;
55755579 if (f6i -> fib6_nsiblings ) {
55765580 rt6_nh_nlmsg_size (nh , & nexthop_len );
55775581
5578- list_for_each_entry_safe (sibling , next_sibling ,
5579- & f6i -> fib6_siblings , fib6_siblings ) {
5582+ rcu_read_lock ();
5583+
5584+ list_for_each_entry_rcu (sibling , & f6i -> fib6_siblings ,
5585+ fib6_siblings ) {
55805586 rt6_nh_nlmsg_size (sibling -> fib6_nh , & nexthop_len );
55815587 }
5588+
5589+ rcu_read_unlock ();
55825590 }
55835591 nexthop_len += lwtunnel_get_encap_size (nh -> fib_nh_lws );
55845592 }
@@ -5708,7 +5716,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
57085716 goto nla_put_failure ;
57095717 } else if (dest ) {
57105718 struct in6_addr saddr_buf ;
5711- if (ip6_route_get_saddr (net , rt , dest , 0 , & saddr_buf ) == 0 &&
5719+ if (ip6_route_get_saddr (net , rt , dest , 0 , 0 , & saddr_buf ) == 0 &&
57125720 nla_put_in6_addr (skb , RTA_PREFSRC , & saddr_buf ))
57135721 goto nla_put_failure ;
57145722 }
@@ -5742,7 +5750,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
57425750 lwtunnel_fill_encap (skb , dst -> lwtstate , RTA_ENCAP , RTA_ENCAP_TYPE ) < 0 )
57435751 goto nla_put_failure ;
57445752 } else if (rt -> fib6_nsiblings ) {
5745- struct fib6_info * sibling , * next_sibling ;
5753+ struct fib6_info * sibling ;
57465754 struct nlattr * mp ;
57475755
57485756 mp = nla_nest_start_noflag (skb , RTA_MULTIPATH );
@@ -5754,14 +5762,21 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
57545762 0 ) < 0 )
57555763 goto nla_put_failure ;
57565764
5757- list_for_each_entry_safe (sibling , next_sibling ,
5758- & rt -> fib6_siblings , fib6_siblings ) {
5765+ rcu_read_lock ();
5766+
5767+ list_for_each_entry_rcu (sibling , & rt -> fib6_siblings ,
5768+ fib6_siblings ) {
57595769 if (fib_add_nexthop (skb , & sibling -> fib6_nh -> nh_common ,
57605770 sibling -> fib6_nh -> fib_nh_weight ,
5761- AF_INET6 , 0 ) < 0 )
5771+ AF_INET6 , 0 ) < 0 ) {
5772+ rcu_read_unlock ();
5773+
57625774 goto nla_put_failure ;
5775+ }
57635776 }
57645777
5778+ rcu_read_unlock ();
5779+
57655780 nla_nest_end (skb , mp );
57665781 } else if (rt -> nh ) {
57675782 if (nla_put_u32 (skb , RTA_NH_ID , rt -> nh -> id ))
@@ -6198,7 +6213,7 @@ void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info,
61986213 err = - ENOBUFS ;
61996214 seq = info -> nlh ? info -> nlh -> nlmsg_seq : 0 ;
62006215
6201- skb = nlmsg_new (rt6_nlmsg_size (rt ), gfp_any () );
6216+ skb = nlmsg_new (rt6_nlmsg_size (rt ), GFP_ATOMIC );
62026217 if (!skb )
62036218 goto errout ;
62046219
@@ -6211,7 +6226,7 @@ void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info,
62116226 goto errout ;
62126227 }
62136228 rtnl_notify (skb , net , info -> portid , RTNLGRP_IPV6_ROUTE ,
6214- info -> nlh , gfp_any () );
6229+ info -> nlh , GFP_ATOMIC );
62156230 return ;
62166231errout :
62176232 if (err < 0 )
0 commit comments