@@ -170,6 +170,7 @@ struct rt6_info *fib6_info_alloc(gfp_t gfp_flags)
170170void fib6_info_destroy (struct rt6_info * f6i )
171171{
172172 struct rt6_exception_bucket * bucket ;
173+ struct dst_metrics * m ;
173174
174175 WARN_ON (f6i -> rt6i_node );
175176
@@ -201,6 +202,10 @@ void fib6_info_destroy(struct rt6_info *f6i)
201202 if (f6i -> fib6_nh .nh_dev )
202203 dev_put (f6i -> fib6_nh .nh_dev );
203204
205+ m = f6i -> fib6_metrics ;
206+ if (m != & dst_default_metrics && refcount_dec_and_test (& m -> refcnt ))
207+ kfree (m );
208+
204209 kfree (f6i );
205210}
206211EXPORT_SYMBOL_GPL (fib6_info_destroy );
@@ -714,7 +719,7 @@ static struct fib6_node *fib6_add_1(struct net *net,
714719 /* clean up an intermediate node */
715720 if (!(fn -> fn_flags & RTN_RTINFO )) {
716721 RCU_INIT_POINTER (fn -> leaf , NULL );
717- rt6_release (leaf );
722+ fib6_info_release (leaf );
718723 /* remove null_entry in the root node */
719724 } else if (fn -> fn_flags & RTN_TL_ROOT &&
720725 rcu_access_pointer (fn -> leaf ) ==
@@ -898,12 +903,32 @@ static void fib6_purge_rt(struct rt6_info *rt, struct fib6_node *fn,
898903 if (!(fn -> fn_flags & RTN_RTINFO ) && leaf == rt ) {
899904 new_leaf = fib6_find_prefix (net , table , fn );
900905 atomic_inc (& new_leaf -> rt6i_ref );
906+
901907 rcu_assign_pointer (fn -> leaf , new_leaf );
902- rt6_release (rt );
908+ fib6_info_release (rt );
903909 }
904910 fn = rcu_dereference_protected (fn -> parent ,
905911 lockdep_is_held (& table -> tb6_lock ));
906912 }
913+
914+ if (rt -> rt6i_pcpu ) {
915+ int cpu ;
916+
917+ /* release the reference to this fib entry from
918+ * all of its cached pcpu routes
919+ */
920+ for_each_possible_cpu (cpu ) {
921+ struct rt6_info * * ppcpu_rt ;
922+ struct rt6_info * pcpu_rt ;
923+
924+ ppcpu_rt = per_cpu_ptr (rt -> rt6i_pcpu , cpu );
925+ pcpu_rt = * ppcpu_rt ;
926+ if (pcpu_rt ) {
927+ fib6_info_release (pcpu_rt -> from );
928+ pcpu_rt -> from = NULL ;
929+ }
930+ }
931+ }
907932 }
908933}
909934
@@ -1099,7 +1124,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
10991124 fib6_purge_rt (iter , fn , info -> nl_net );
11001125 if (rcu_access_pointer (fn -> rr_ptr ) == iter )
11011126 fn -> rr_ptr = NULL ;
1102- rt6_release (iter );
1127+ fib6_info_release (iter );
11031128
11041129 if (nsiblings ) {
11051130 /* Replacing an ECMP route, remove all siblings */
@@ -1115,7 +1140,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
11151140 fib6_purge_rt (iter , fn , info -> nl_net );
11161141 if (rcu_access_pointer (fn -> rr_ptr ) == iter )
11171142 fn -> rr_ptr = NULL ;
1118- rt6_release (iter );
1143+ fib6_info_release (iter );
11191144 nsiblings -- ;
11201145 info -> nl_net -> ipv6 .rt6_stats -> fib_rt_entries -- ;
11211146 } else {
@@ -1183,9 +1208,6 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,
11831208 int replace_required = 0 ;
11841209 int sernum = fib6_new_sernum (info -> nl_net );
11851210
1186- if (WARN_ON_ONCE (!atomic_read (& rt -> dst .__refcnt )))
1187- return - EINVAL ;
1188-
11891211 if (info -> nlh ) {
11901212 if (!(info -> nlh -> nlmsg_flags & NLM_F_CREATE ))
11911213 allow_create = 0 ;
@@ -1300,7 +1322,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,
13001322 if (pn_leaf == rt ) {
13011323 pn_leaf = NULL ;
13021324 RCU_INIT_POINTER (pn -> leaf , NULL );
1303- atomic_dec ( & rt -> rt6i_ref );
1325+ fib6_info_release ( rt );
13041326 }
13051327 if (!pn_leaf && !(pn -> fn_flags & RTN_RTINFO )) {
13061328 pn_leaf = fib6_find_prefix (info -> nl_net , table ,
@@ -1312,7 +1334,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,
13121334 info -> nl_net -> ipv6 .fib6_null_entry ;
13131335 }
13141336#endif
1315- atomic_inc ( & pn_leaf -> rt6i_ref );
1337+ fib6_info_hold ( pn_leaf );
13161338 rcu_assign_pointer (pn -> leaf , pn_leaf );
13171339 }
13181340 }
@@ -1334,10 +1356,6 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,
13341356 (fn -> fn_flags & RTN_TL_ROOT &&
13351357 !rcu_access_pointer (fn -> leaf ))))
13361358 fib6_repair_tree (info -> nl_net , table , fn );
1337- /* Always release dst as dst->__refcnt is guaranteed
1338- * to be taken before entering this function
1339- */
1340- dst_release_immediate (& rt -> dst );
13411359 return err ;
13421360}
13431361
@@ -1637,7 +1655,7 @@ static struct fib6_node *fib6_repair_tree(struct net *net,
16371655 new_fn_leaf = net -> ipv6 .fib6_null_entry ;
16381656 }
16391657#endif
1640- atomic_inc ( & new_fn_leaf -> rt6i_ref );
1658+ fib6_info_hold ( new_fn_leaf );
16411659 rcu_assign_pointer (fn -> leaf , new_fn_leaf );
16421660 return pn ;
16431661 }
@@ -1693,7 +1711,7 @@ static struct fib6_node *fib6_repair_tree(struct net *net,
16931711 return pn ;
16941712
16951713 RCU_INIT_POINTER (pn -> leaf , NULL );
1696- rt6_release (pn_leaf );
1714+ fib6_info_release (pn_leaf );
16971715 fn = pn ;
16981716 }
16991717}
@@ -1763,7 +1781,7 @@ static void fib6_del_route(struct fib6_table *table, struct fib6_node *fn,
17631781 call_fib6_entry_notifiers (net , FIB_EVENT_ENTRY_DEL , rt , NULL );
17641782 if (!info -> skip_notify )
17651783 inet6_rt_notify (RTM_DELROUTE , rt , info , 0 );
1766- rt6_release (rt );
1784+ fib6_info_release (rt );
17671785}
17681786
17691787/* Need to own table->tb6_lock */
@@ -2261,9 +2279,8 @@ static int ipv6_route_seq_show(struct seq_file *seq, void *v)
22612279
22622280 dev = rt -> fib6_nh .nh_dev ;
22632281 seq_printf (seq , " %08x %08x %08x %08x %8s\n" ,
2264- rt -> rt6i_metric , atomic_read (& rt -> dst .__refcnt ),
2265- rt -> dst .__use , rt -> rt6i_flags ,
2266- dev ? dev -> name : "" );
2282+ rt -> rt6i_metric , atomic_read (& rt -> rt6i_ref ), 0 ,
2283+ rt -> rt6i_flags , dev ? dev -> name : "" );
22672284 iter -> w .leaf = NULL ;
22682285 return 0 ;
22692286}
0 commit comments