@@ -240,15 +240,22 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct net *net,
240240 return NULL ;
241241}
242242
243+ static DEFINE_SPINLOCK (ipip6_prl_lock );
244+
245+ #define for_each_prl_rcu (start ) \
246+ for (prl = rcu_dereference(start); \
247+ prl; \
248+ prl = rcu_dereference(prl->next))
249+
243250static struct ip_tunnel_prl_entry *
244251__ipip6_tunnel_locate_prl (struct ip_tunnel * t , __be32 addr )
245252{
246- struct ip_tunnel_prl_entry * p = ( struct ip_tunnel_prl_entry * ) NULL ;
253+ struct ip_tunnel_prl_entry * prl ;
247254
248- for ( p = t -> prl ; p ; p = p -> next )
249- if (p -> addr == addr )
255+ for_each_prl_rcu ( t -> prl )
256+ if (prl -> addr == addr )
250257 break ;
251- return p ;
258+ return prl ;
252259
253260}
254261
@@ -273,7 +280,7 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t,
273280 kcalloc (cmax , sizeof (* kp ), GFP_KERNEL ) :
274281 NULL ;
275282
276- read_lock ( & ipip6_lock );
283+ rcu_read_lock ( );
277284
278285 ca = t -> prl_count < cmax ? t -> prl_count : cmax ;
279286
@@ -291,7 +298,7 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t,
291298 }
292299
293300 c = 0 ;
294- for ( prl = t -> prl ; prl ; prl = prl -> next ) {
301+ for_each_prl_rcu ( t -> prl ) {
295302 if (c >= cmax )
296303 break ;
297304 if (kprl .addr != htonl (INADDR_ANY ) && prl -> addr != kprl .addr )
@@ -303,7 +310,7 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t,
303310 break ;
304311 }
305312out :
306- read_unlock ( & ipip6_lock );
313+ rcu_read_unlock ( );
307314
308315 len = sizeof (* kp ) * c ;
309316 ret = 0 ;
@@ -324,12 +331,14 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
324331 if (a -> addr == htonl (INADDR_ANY ))
325332 return - EINVAL ;
326333
327- write_lock ( & ipip6_lock );
334+ spin_lock ( & ipip6_prl_lock );
328335
329336 for (p = t -> prl ; p ; p = p -> next ) {
330337 if (p -> addr == a -> addr ) {
331- if (chg )
332- goto update ;
338+ if (chg ) {
339+ p -> flags = a -> flags ;
340+ goto out ;
341+ }
333342 err = - EEXIST ;
334343 goto out ;
335344 }
@@ -346,46 +355,63 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
346355 goto out ;
347356 }
348357
358+ INIT_RCU_HEAD (& p -> rcu_head );
349359 p -> next = t -> prl ;
350- t -> prl = p ;
351- t -> prl_count ++ ;
352- update :
353360 p -> addr = a -> addr ;
354361 p -> flags = a -> flags ;
362+ t -> prl_count ++ ;
363+ rcu_assign_pointer (t -> prl , p );
355364out :
356- write_unlock ( & ipip6_lock );
365+ spin_unlock ( & ipip6_prl_lock );
357366 return err ;
358367}
359368
369+ static void prl_entry_destroy_rcu (struct rcu_head * head )
370+ {
371+ kfree (container_of (head , struct ip_tunnel_prl_entry , rcu_head ));
372+ }
373+
374+ static void prl_list_destroy_rcu (struct rcu_head * head )
375+ {
376+ struct ip_tunnel_prl_entry * p , * n ;
377+
378+ p = container_of (head , struct ip_tunnel_prl_entry , rcu_head );
379+ do {
380+ n = p -> next ;
381+ kfree (p );
382+ p = n ;
383+ } while (p );
384+ }
385+
360386static int
361387ipip6_tunnel_del_prl (struct ip_tunnel * t , struct ip_tunnel_prl * a )
362388{
363389 struct ip_tunnel_prl_entry * x , * * p ;
364390 int err = 0 ;
365391
366- write_lock ( & ipip6_lock );
392+ spin_lock ( & ipip6_prl_lock );
367393
368394 if (a && a -> addr != htonl (INADDR_ANY )) {
369395 for (p = & t -> prl ; * p ; p = & (* p )-> next ) {
370396 if ((* p )-> addr == a -> addr ) {
371397 x = * p ;
372398 * p = x -> next ;
373- kfree ( x );
399+ call_rcu ( & x -> rcu_head , prl_entry_destroy_rcu );
374400 t -> prl_count -- ;
375401 goto out ;
376402 }
377403 }
378404 err = - ENXIO ;
379405 } else {
380- while (t -> prl ) {
406+ if (t -> prl ) {
407+ t -> prl_count = 0 ;
381408 x = t -> prl ;
382- t -> prl = t -> prl -> next ;
383- kfree (x );
384- t -> prl_count -- ;
409+ call_rcu (& x -> rcu_head , prl_list_destroy_rcu );
410+ t -> prl = NULL ;
385411 }
386412 }
387413out :
388- write_unlock ( & ipip6_lock );
414+ spin_unlock ( & ipip6_prl_lock );
389415 return err ;
390416}
391417
@@ -395,7 +421,7 @@ isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t)
395421 struct ip_tunnel_prl_entry * p ;
396422 int ok = 1 ;
397423
398- read_lock ( & ipip6_lock );
424+ rcu_read_lock ( );
399425 p = __ipip6_tunnel_locate_prl (t , iph -> saddr );
400426 if (p ) {
401427 if (p -> flags & PRL_DEFAULT )
@@ -411,7 +437,7 @@ isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t)
411437 else
412438 ok = 0 ;
413439 }
414- read_unlock ( & ipip6_lock );
440+ rcu_read_unlock ( );
415441 return ok ;
416442}
417443
@@ -1192,6 +1218,7 @@ static void __exit sit_cleanup(void)
11921218 xfrm4_tunnel_deregister (& sit_handler , AF_INET6 );
11931219
11941220 unregister_pernet_gen_device (sit_net_id , & sit_net_ops );
1221+ rcu_barrier (); /* Wait for completion of call_rcu()'s */
11951222}
11961223
11971224static int __init sit_init (void )
0 commit comments