23
23
*/
24
24
#include <linux/module.h>
25
25
#include <linux/xfrm.h>
26
- #include <linux/list .h>
26
+ #include <linux/rculist .h>
27
27
#include <net/ip.h>
28
28
#include <net/xfrm.h>
29
29
#include <net/ipv6.h>
36
36
* per xfrm_address_t.
37
37
*/
38
38
struct 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 ;
44
45
};
45
46
46
- static DEFINE_RWLOCK (xfrm6_tunnel_spi_lock );
47
+ static DEFINE_SPINLOCK (xfrm6_tunnel_spi_lock );
47
48
48
49
static u32 xfrm6_tunnel_spi ;
49
50
@@ -107,6 +108,7 @@ static void xfrm6_tunnel_spi_fini(void)
107
108
if (!hlist_empty (& xfrm6_tunnel_spi_byspi [i ]))
108
109
return ;
109
110
}
111
+ rcu_barrier ();
110
112
kmem_cache_destroy (xfrm6_tunnel_spi_kmem );
111
113
xfrm6_tunnel_spi_kmem = NULL ;
112
114
}
@@ -116,7 +118,7 @@ static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr)
116
118
struct xfrm6_tunnel_spi * x6spi ;
117
119
struct hlist_node * pos ;
118
120
119
- hlist_for_each_entry (x6spi , pos ,
121
+ hlist_for_each_entry_rcu (x6spi , pos ,
120
122
& xfrm6_tunnel_spi_byaddr [xfrm6_tunnel_spi_hash_byaddr (saddr )],
121
123
list_byaddr ) {
122
124
if (memcmp (& x6spi -> addr , saddr , sizeof (x6spi -> addr )) == 0 )
@@ -131,10 +133,10 @@ __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr)
131
133
struct xfrm6_tunnel_spi * x6spi ;
132
134
u32 spi ;
133
135
134
- read_lock_bh ( & xfrm6_tunnel_spi_lock );
136
+ rcu_read_lock_bh ( );
135
137
x6spi = __xfrm6_tunnel_spi_lookup (saddr );
136
138
spi = x6spi ? x6spi -> spi : 0 ;
137
- read_unlock_bh ( & xfrm6_tunnel_spi_lock );
139
+ rcu_read_unlock_bh ( );
138
140
return htonl (spi );
139
141
}
140
142
@@ -185,14 +187,15 @@ static u32 __xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr)
185
187
if (!x6spi )
186
188
goto out ;
187
189
190
+ INIT_RCU_HEAD (& x6spi -> rcu_head );
188
191
memcpy (& x6spi -> addr , saddr , sizeof (x6spi -> addr ));
189
192
x6spi -> spi = spi ;
190
193
atomic_set (& x6spi -> refcnt , 1 );
191
194
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 ]);
193
196
194
197
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 ]);
196
199
out :
197
200
return spi ;
198
201
}
@@ -202,41 +205,47 @@ __be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr)
202
205
struct xfrm6_tunnel_spi * x6spi ;
203
206
u32 spi ;
204
207
205
- write_lock_bh (& xfrm6_tunnel_spi_lock );
208
+ spin_lock_bh (& xfrm6_tunnel_spi_lock );
206
209
x6spi = __xfrm6_tunnel_spi_lookup (saddr );
207
210
if (x6spi ) {
208
211
atomic_inc (& x6spi -> refcnt );
209
212
spi = x6spi -> spi ;
210
213
} else
211
214
spi = __xfrm6_tunnel_alloc_spi (saddr );
212
- write_unlock_bh (& xfrm6_tunnel_spi_lock );
215
+ spin_unlock_bh (& xfrm6_tunnel_spi_lock );
213
216
214
217
return htonl (spi );
215
218
}
216
219
217
220
EXPORT_SYMBOL (xfrm6_tunnel_alloc_spi );
218
221
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
+
219
228
void xfrm6_tunnel_free_spi (xfrm_address_t * saddr )
220
229
{
221
230
struct xfrm6_tunnel_spi * x6spi ;
222
231
struct hlist_node * pos , * n ;
223
232
224
- write_lock_bh (& xfrm6_tunnel_spi_lock );
233
+ spin_lock_bh (& xfrm6_tunnel_spi_lock );
225
234
226
235
hlist_for_each_entry_safe (x6spi , pos , n ,
227
236
& xfrm6_tunnel_spi_byaddr [xfrm6_tunnel_spi_hash_byaddr (saddr )],
228
237
list_byaddr )
229
238
{
230
239
if (memcmp (& x6spi -> addr , saddr , sizeof (x6spi -> addr )) == 0 ) {
231
240
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 );
235
244
break ;
236
245
}
237
246
}
238
247
}
239
- write_unlock_bh (& xfrm6_tunnel_spi_lock );
248
+ spin_unlock_bh (& xfrm6_tunnel_spi_lock );
240
249
}
241
250
242
251
EXPORT_SYMBOL (xfrm6_tunnel_free_spi );
0 commit comments