@ -354,7 +354,7 @@ static struct rt6_info *__ip6_dst_alloc(struct net *net,
int flags )
{
struct rt6_info * rt = dst_alloc ( & net - > ipv6 . ip6_dst_ops , dev ,
0 , DST_OBSOLETE_FORCE_CHK , flags ) ;
1 , DST_OBSOLETE_FORCE_CHK , flags ) ;
if ( rt )
rt6_info_init ( rt ) ;
@ -381,7 +381,9 @@ struct rt6_info *ip6_dst_alloc(struct net *net,
* p = NULL ;
}
} else {
dst_destroy ( ( struct dst_entry * ) rt ) ;
dst_release ( & rt - > dst ) ;
if ( ! ( flags & DST_NOCACHE ) )
dst_destroy ( ( struct dst_entry * ) rt ) ;
return NULL ;
}
}
@ -932,9 +934,9 @@ struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
EXPORT_SYMBOL ( rt6_lookup ) ;
/* ip6_ins_rt is called with FREE table->tb6_lock.
It takes new route entry , the addition fails by any reason the
route is freed . In any case , if caller does not hold it , it may
be destroyed .
* It takes new route entry , the addition fails by any reason the
* route is released .
* Caller must hold dst before calling it .
*/
static int __ip6_ins_rt ( struct rt6_info * rt , struct nl_info * info ,
@ -957,6 +959,8 @@ int ip6_ins_rt(struct rt6_info *rt)
struct nl_info info = { . nl_net = dev_net ( rt - > dst . dev ) , } ;
struct mx6_config mxc = { . mx = NULL , } ;
/* Hold dst to account for the reference from the fib6 tree */
dst_hold ( & rt - > dst ) ;
return __ip6_ins_rt ( rt , & info , & mxc , NULL ) ;
}
@ -1049,6 +1053,7 @@ static struct rt6_info *rt6_make_pcpu_route(struct rt6_info *rt)
prev = cmpxchg ( p , NULL , pcpu_rt ) ;
if ( prev ) {
/* If someone did it before us, return prev instead */
dst_release ( & pcpu_rt - > dst ) ;
dst_destroy ( & pcpu_rt - > dst ) ;
pcpu_rt = prev ;
}
@ -1059,6 +1064,7 @@ static struct rt6_info *rt6_make_pcpu_route(struct rt6_info *rt)
* since rt is going away anyway . The next
* dst_check ( ) will trigger a re - lookup .
*/
dst_release ( & pcpu_rt - > dst ) ;
dst_destroy ( & pcpu_rt - > dst ) ;
pcpu_rt = rt ;
}
@ -1129,12 +1135,15 @@ redo_rt6_select:
uncached_rt = ip6_rt_cache_alloc ( rt , & fl6 - > daddr , NULL ) ;
dst_release ( & rt - > dst ) ;
if ( uncached_rt )
if ( uncached_rt ) {
/* Uncached_rt's refcnt is taken during ip6_rt_cache_alloc()
* No need for another dst_hold ( )
*/
rt6_uncached_list_add ( uncached_rt ) ;
else
} else {
uncached_rt = net - > ipv6 . ip6_null_entry ;
dst_hold ( & uncached_rt - > dst ) ;
dst_hold ( & uncached_rt - > dst ) ;
}
trace_fib6_table_lookup ( net , uncached_rt , table - > tb6_id , fl6 ) ;
return uncached_rt ;
@ -1422,6 +1431,10 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
* invalidate the sk - > sk_dst_cache .
*/
ip6_ins_rt ( nrt6 ) ;
/* Release the reference taken in
* ip6_rt_cache_alloc ( )
*/
dst_release ( & nrt6 - > dst ) ;
}
}
}
@ -1673,7 +1686,6 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
rt - > dst . flags | = DST_HOST ;
rt - > dst . output = ip6_output ;
atomic_set ( & rt - > dst . __refcnt , 1 ) ;
rt - > rt6i_gateway = fl6 - > daddr ;
rt - > rt6i_dst . addr = fl6 - > daddr ;
rt - > rt6i_dst . plen = 128 ;
@ -2130,8 +2142,10 @@ out:
dev_put ( dev ) ;
if ( idev )
in6_dev_put ( idev ) ;
if ( rt )
if ( rt ) {
dst_release ( & rt - > dst ) ;
dst_free ( & rt - > dst ) ;
}
return ERR_PTR ( err ) ;
}
@ -2160,8 +2174,10 @@ int ip6_route_add(struct fib6_config *cfg,
return err ;
out :
if ( rt )
if ( rt ) {
dst_release ( & rt - > dst ) ;
dst_free ( & rt - > dst ) ;
}
return err ;
}
@ -2398,7 +2414,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
nrt - > rt6i_gateway = * ( struct in6_addr * ) neigh - > primary_key ;
if ( ip6_ins_rt ( nrt ) )
goto out ;
goto out_release ;
netevent . old = & rt - > dst ;
netevent . new = & nrt - > dst ;
@ -2411,6 +2427,12 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
ip6_del_rt ( rt ) ;
}
out_release :
/* Release the reference taken in
* ip6_rt_cache_alloc ( )
*/
dst_release ( & nrt - > dst ) ;
out :
neigh_release ( neigh ) ;
}
@ -2760,8 +2782,6 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
rt - > rt6i_table = fib6_get_table ( net , tb_id ) ;
rt - > dst . flags | = DST_NOCACHE ;
atomic_set ( & rt - > dst . __refcnt , 1 ) ;
return rt ;
}
@ -3186,6 +3206,7 @@ static int ip6_route_multipath_add(struct fib6_config *cfg,
err = ip6_route_info_append ( & rt6_nh_list , rt , & r_cfg ) ;
if ( err ) {
dst_release ( & rt - > dst ) ;
dst_free ( & rt - > dst ) ;
goto cleanup ;
}
@ -3249,8 +3270,10 @@ add_errout:
cleanup :
list_for_each_entry_safe ( nh , nh_safe , & rt6_nh_list , next ) {
if ( nh - > rt6_info )
if ( nh - > rt6_info ) {
dst_release ( & nh - > rt6_info - > dst ) ;
dst_free ( & nh - > rt6_info - > dst ) ;
}
kfree ( nh - > mxc . mx ) ;
list_del ( & nh - > next ) ;
kfree ( nh ) ;