2323 */
2424#include <linux/module.h>
2525#include <linux/xfrm.h>
26- #include <linux/list .h>
26+ #include <linux/rculist .h>
2727#include <net/ip.h>
2828#include <net/xfrm.h>
2929#include <net/ipv6.h>
3636 * per xfrm_address_t.
3737 */
3838struct xfrm6_tunnel_spi {
39- struct hlist_node list_byaddr ;
40- struct hlist_node list_byspi ;
41- xfrm_address_t addr ;
42- u32 spi ;
43- atomic_t refcnt ;
39+ struct hlist_node list_byaddr ;
40+ struct hlist_node list_byspi ;
41+ xfrm_address_t addr ;
42+ u32 spi ;
43+ atomic_t refcnt ;
44+ struct rcu_head rcu_head ;
4445};
4546
46- static DEFINE_RWLOCK (xfrm6_tunnel_spi_lock );
47+ static DEFINE_SPINLOCK (xfrm6_tunnel_spi_lock );
4748
4849static u32 xfrm6_tunnel_spi ;
4950
@@ -107,6 +108,7 @@ static void xfrm6_tunnel_spi_fini(void)
107108 if (!hlist_empty (& xfrm6_tunnel_spi_byspi [i ]))
108109 return ;
109110 }
111+ rcu_barrier ();
110112 kmem_cache_destroy (xfrm6_tunnel_spi_kmem );
111113 xfrm6_tunnel_spi_kmem = NULL ;
112114}
@@ -116,7 +118,7 @@ static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr)
116118 struct xfrm6_tunnel_spi * x6spi ;
117119 struct hlist_node * pos ;
118120
119- hlist_for_each_entry (x6spi , pos ,
121+ hlist_for_each_entry_rcu (x6spi , pos ,
120122 & xfrm6_tunnel_spi_byaddr [xfrm6_tunnel_spi_hash_byaddr (saddr )],
121123 list_byaddr ) {
122124 if (memcmp (& x6spi -> addr , saddr , sizeof (x6spi -> addr )) == 0 )
@@ -131,10 +133,10 @@ __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr)
131133 struct xfrm6_tunnel_spi * x6spi ;
132134 u32 spi ;
133135
134- read_lock_bh ( & xfrm6_tunnel_spi_lock );
136+ rcu_read_lock_bh ( );
135137 x6spi = __xfrm6_tunnel_spi_lookup (saddr );
136138 spi = x6spi ? x6spi -> spi : 0 ;
137- read_unlock_bh ( & xfrm6_tunnel_spi_lock );
139+ rcu_read_unlock_bh ( );
138140 return htonl (spi );
139141}
140142
@@ -185,14 +187,15 @@ static u32 __xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr)
185187 if (!x6spi )
186188 goto out ;
187189
190+ INIT_RCU_HEAD (& x6spi -> rcu_head );
188191 memcpy (& x6spi -> addr , saddr , sizeof (x6spi -> addr ));
189192 x6spi -> spi = spi ;
190193 atomic_set (& x6spi -> refcnt , 1 );
191194
192- hlist_add_head (& x6spi -> list_byspi , & xfrm6_tunnel_spi_byspi [index ]);
195+ hlist_add_head_rcu (& x6spi -> list_byspi , & xfrm6_tunnel_spi_byspi [index ]);
193196
194197 index = xfrm6_tunnel_spi_hash_byaddr (saddr );
195- hlist_add_head (& x6spi -> list_byaddr , & xfrm6_tunnel_spi_byaddr [index ]);
198+ hlist_add_head_rcu (& x6spi -> list_byaddr , & xfrm6_tunnel_spi_byaddr [index ]);
196199out :
197200 return spi ;
198201}
@@ -202,41 +205,47 @@ __be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr)
202205 struct xfrm6_tunnel_spi * x6spi ;
203206 u32 spi ;
204207
205- write_lock_bh (& xfrm6_tunnel_spi_lock );
208+ spin_lock_bh (& xfrm6_tunnel_spi_lock );
206209 x6spi = __xfrm6_tunnel_spi_lookup (saddr );
207210 if (x6spi ) {
208211 atomic_inc (& x6spi -> refcnt );
209212 spi = x6spi -> spi ;
210213 } else
211214 spi = __xfrm6_tunnel_alloc_spi (saddr );
212- write_unlock_bh (& xfrm6_tunnel_spi_lock );
215+ spin_unlock_bh (& xfrm6_tunnel_spi_lock );
213216
214217 return htonl (spi );
215218}
216219
217220EXPORT_SYMBOL (xfrm6_tunnel_alloc_spi );
218221
222+ static void x6spi_destroy_rcu (struct rcu_head * head )
223+ {
224+ kmem_cache_free (xfrm6_tunnel_spi_kmem ,
225+ container_of (head , struct xfrm6_tunnel_spi , rcu_head ));
226+ }
227+
219228void xfrm6_tunnel_free_spi (xfrm_address_t * saddr )
220229{
221230 struct xfrm6_tunnel_spi * x6spi ;
222231 struct hlist_node * pos , * n ;
223232
224- write_lock_bh (& xfrm6_tunnel_spi_lock );
233+ spin_lock_bh (& xfrm6_tunnel_spi_lock );
225234
226235 hlist_for_each_entry_safe (x6spi , pos , n ,
227236 & xfrm6_tunnel_spi_byaddr [xfrm6_tunnel_spi_hash_byaddr (saddr )],
228237 list_byaddr )
229238 {
230239 if (memcmp (& x6spi -> addr , saddr , sizeof (x6spi -> addr )) == 0 ) {
231240 if (atomic_dec_and_test (& x6spi -> refcnt )) {
232- hlist_del (& x6spi -> list_byaddr );
233- hlist_del (& x6spi -> list_byspi );
234- kmem_cache_free ( xfrm6_tunnel_spi_kmem , x6spi );
241+ hlist_del_rcu (& x6spi -> list_byaddr );
242+ hlist_del_rcu (& x6spi -> list_byspi );
243+ call_rcu ( & x6spi -> rcu_head , x6spi_destroy_rcu );
235244 break ;
236245 }
237246 }
238247 }
239- write_unlock_bh (& xfrm6_tunnel_spi_lock );
248+ spin_unlock_bh (& xfrm6_tunnel_spi_lock );
240249}
241250
242251EXPORT_SYMBOL (xfrm6_tunnel_free_spi );
0 commit comments