diff options
author | James Chapman <jchapman@katalix.com> | 2010-04-02 02:19:16 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-04-03 17:56:06 -0400 |
commit | e02d494d2c60746ee6583132904ac1791f5bc9a6 (patch) | |
tree | 68a3c19ce392998693b83f7db96c4ed1bc140406 /net/l2tp | |
parent | 309795f4bec2d69cd507a631f82065c2198a0825 (diff) |
l2tp: Convert rwlock to RCU
Reader/write locks are discouraged because they are slower than spin
locks. So this patch converts the rwlocks used in the per_net structs
to rcu.
Signed-off-by: James Chapman <jchapman@katalix.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/l2tp')
-rw-r--r-- | net/l2tp/l2tp_core.c | 78 |
1 files changed, 42 insertions, 36 deletions
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index fbd1f2119fe..473cf2d6390 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/string.h> | 22 | #include <linux/string.h> |
23 | #include <linux/list.h> | 23 | #include <linux/list.h> |
24 | #include <linux/rculist.h> | ||
24 | #include <linux/uaccess.h> | 25 | #include <linux/uaccess.h> |
25 | 26 | ||
26 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
@@ -105,9 +106,9 @@ static atomic_t l2tp_session_count; | |||
105 | static unsigned int l2tp_net_id; | 106 | static unsigned int l2tp_net_id; |
106 | struct l2tp_net { | 107 | struct l2tp_net { |
107 | struct list_head l2tp_tunnel_list; | 108 | struct list_head l2tp_tunnel_list; |
108 | rwlock_t l2tp_tunnel_list_lock; | 109 | spinlock_t l2tp_tunnel_list_lock; |
109 | struct hlist_head l2tp_session_hlist[L2TP_HASH_SIZE_2]; | 110 | struct hlist_head l2tp_session_hlist[L2TP_HASH_SIZE_2]; |
110 | rwlock_t l2tp_session_hlist_lock; | 111 | spinlock_t l2tp_session_hlist_lock; |
111 | }; | 112 | }; |
112 | 113 | ||
113 | static inline struct l2tp_net *l2tp_pernet(struct net *net) | 114 | static inline struct l2tp_net *l2tp_pernet(struct net *net) |
@@ -139,14 +140,14 @@ static struct l2tp_session *l2tp_session_find_2(struct net *net, u32 session_id) | |||
139 | struct l2tp_session *session; | 140 | struct l2tp_session *session; |
140 | struct hlist_node *walk; | 141 | struct hlist_node *walk; |
141 | 142 | ||
142 | read_lock_bh(&pn->l2tp_session_hlist_lock); | 143 | rcu_read_lock_bh(); |
143 | hlist_for_each_entry(session, walk, session_list, global_hlist) { | 144 | hlist_for_each_entry_rcu(session, walk, session_list, global_hlist) { |
144 | if (session->session_id == session_id) { | 145 | if (session->session_id == session_id) { |
145 | read_unlock_bh(&pn->l2tp_session_hlist_lock); | 146 | rcu_read_unlock_bh(); |
146 | return session; | 147 | return session; |
147 | } | 148 | } |
148 | } | 149 | } |
149 | read_unlock_bh(&pn->l2tp_session_hlist_lock); | 150 | rcu_read_unlock_bh(); |
150 | 151 | ||
151 | return NULL; | 152 | return NULL; |
152 | } | 153 | } |
@@ -225,17 +226,17 @@ struct l2tp_session *l2tp_session_find_by_ifname(struct net *net, char *ifname) | |||
225 | struct hlist_node *walk; | 226 | struct hlist_node *walk; |
226 | struct l2tp_session *session; | 227 | struct l2tp_session *session; |
227 | 228 | ||
228 | read_lock_bh(&pn->l2tp_session_hlist_lock); | 229 | rcu_read_lock_bh(); |
229 | for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++) { | 230 | for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++) { |
230 | hlist_for_each_entry(session, walk, &pn->l2tp_session_hlist[hash], global_hlist) { | 231 | hlist_for_each_entry_rcu(session, walk, &pn->l2tp_session_hlist[hash], global_hlist) { |
231 | if (!strcmp(session->ifname, ifname)) { | 232 | if (!strcmp(session->ifname, ifname)) { |
232 | read_unlock_bh(&pn->l2tp_session_hlist_lock); | 233 | rcu_read_unlock_bh(); |
233 | return session; | 234 | return session; |
234 | } | 235 | } |
235 | } | 236 | } |
236 | } | 237 | } |
237 | 238 | ||
238 | read_unlock_bh(&pn->l2tp_session_hlist_lock); | 239 | rcu_read_unlock_bh(); |
239 | 240 | ||
240 | return NULL; | 241 | return NULL; |
241 | } | 242 | } |
@@ -248,14 +249,14 @@ struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id) | |||
248 | struct l2tp_tunnel *tunnel; | 249 | struct l2tp_tunnel *tunnel; |
249 | struct l2tp_net *pn = l2tp_pernet(net); | 250 | struct l2tp_net *pn = l2tp_pernet(net); |
250 | 251 | ||
251 | read_lock_bh(&pn->l2tp_tunnel_list_lock); | 252 | rcu_read_lock_bh(); |
252 | list_for_each_entry(tunnel, &pn->l2tp_tunnel_list, list) { | 253 | list_for_each_entry_rcu(tunnel, &pn->l2tp_tunnel_list, list) { |
253 | if (tunnel->tunnel_id == tunnel_id) { | 254 | if (tunnel->tunnel_id == tunnel_id) { |
254 | read_unlock_bh(&pn->l2tp_tunnel_list_lock); | 255 | rcu_read_unlock_bh(); |
255 | return tunnel; | 256 | return tunnel; |
256 | } | 257 | } |
257 | } | 258 | } |
258 | read_unlock_bh(&pn->l2tp_tunnel_list_lock); | 259 | rcu_read_unlock_bh(); |
259 | 260 | ||
260 | return NULL; | 261 | return NULL; |
261 | } | 262 | } |
@@ -267,15 +268,15 @@ struct l2tp_tunnel *l2tp_tunnel_find_nth(struct net *net, int nth) | |||
267 | struct l2tp_tunnel *tunnel; | 268 | struct l2tp_tunnel *tunnel; |
268 | int count = 0; | 269 | int count = 0; |
269 | 270 | ||
270 | read_lock_bh(&pn->l2tp_tunnel_list_lock); | 271 | rcu_read_lock_bh(); |
271 | list_for_each_entry(tunnel, &pn->l2tp_tunnel_list, list) { | 272 | list_for_each_entry_rcu(tunnel, &pn->l2tp_tunnel_list, list) { |
272 | if (++count > nth) { | 273 | if (++count > nth) { |
273 | read_unlock_bh(&pn->l2tp_tunnel_list_lock); | 274 | rcu_read_unlock_bh(); |
274 | return tunnel; | 275 | return tunnel; |
275 | } | 276 | } |
276 | } | 277 | } |
277 | 278 | ||
278 | read_unlock_bh(&pn->l2tp_tunnel_list_lock); | 279 | rcu_read_unlock_bh(); |
279 | 280 | ||
280 | return NULL; | 281 | return NULL; |
281 | } | 282 | } |
@@ -1167,9 +1168,10 @@ again: | |||
1167 | if (tunnel->version != L2TP_HDR_VER_2) { | 1168 | if (tunnel->version != L2TP_HDR_VER_2) { |
1168 | struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net); | 1169 | struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net); |
1169 | 1170 | ||
1170 | write_lock_bh(&pn->l2tp_session_hlist_lock); | 1171 | spin_lock_bh(&pn->l2tp_session_hlist_lock); |
1171 | hlist_del_init(&session->global_hlist); | 1172 | hlist_del_init_rcu(&session->global_hlist); |
1172 | write_unlock_bh(&pn->l2tp_session_hlist_lock); | 1173 | spin_unlock_bh(&pn->l2tp_session_hlist_lock); |
1174 | synchronize_rcu(); | ||
1173 | } | 1175 | } |
1174 | 1176 | ||
1175 | if (session->session_close != NULL) | 1177 | if (session->session_close != NULL) |
@@ -1206,9 +1208,10 @@ void l2tp_tunnel_free(struct l2tp_tunnel *tunnel) | |||
1206 | "%s: free...\n", tunnel->name); | 1208 | "%s: free...\n", tunnel->name); |
1207 | 1209 | ||
1208 | /* Remove from tunnel list */ | 1210 | /* Remove from tunnel list */ |
1209 | write_lock_bh(&pn->l2tp_tunnel_list_lock); | 1211 | spin_lock_bh(&pn->l2tp_tunnel_list_lock); |
1210 | list_del_init(&tunnel->list); | 1212 | list_del_rcu(&tunnel->list); |
1211 | write_unlock_bh(&pn->l2tp_tunnel_list_lock); | 1213 | spin_unlock_bh(&pn->l2tp_tunnel_list_lock); |
1214 | synchronize_rcu(); | ||
1212 | 1215 | ||
1213 | atomic_dec(&l2tp_tunnel_count); | 1216 | atomic_dec(&l2tp_tunnel_count); |
1214 | kfree(tunnel); | 1217 | kfree(tunnel); |
@@ -1310,9 +1313,10 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 | |||
1310 | 1313 | ||
1311 | /* Add tunnel to our list */ | 1314 | /* Add tunnel to our list */ |
1312 | INIT_LIST_HEAD(&tunnel->list); | 1315 | INIT_LIST_HEAD(&tunnel->list); |
1313 | write_lock_bh(&pn->l2tp_tunnel_list_lock); | 1316 | spin_lock_bh(&pn->l2tp_tunnel_list_lock); |
1314 | list_add(&tunnel->list, &pn->l2tp_tunnel_list); | 1317 | list_add_rcu(&tunnel->list, &pn->l2tp_tunnel_list); |
1315 | write_unlock_bh(&pn->l2tp_tunnel_list_lock); | 1318 | spin_unlock_bh(&pn->l2tp_tunnel_list_lock); |
1319 | synchronize_rcu(); | ||
1316 | atomic_inc(&l2tp_tunnel_count); | 1320 | atomic_inc(&l2tp_tunnel_count); |
1317 | 1321 | ||
1318 | /* Bump the reference count. The tunnel context is deleted | 1322 | /* Bump the reference count. The tunnel context is deleted |
@@ -1370,9 +1374,10 @@ void l2tp_session_free(struct l2tp_session *session) | |||
1370 | if (tunnel->version != L2TP_HDR_VER_2) { | 1374 | if (tunnel->version != L2TP_HDR_VER_2) { |
1371 | struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net); | 1375 | struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net); |
1372 | 1376 | ||
1373 | write_lock_bh(&pn->l2tp_session_hlist_lock); | 1377 | spin_lock_bh(&pn->l2tp_session_hlist_lock); |
1374 | hlist_del_init(&session->global_hlist); | 1378 | hlist_del_init_rcu(&session->global_hlist); |
1375 | write_unlock_bh(&pn->l2tp_session_hlist_lock); | 1379 | spin_unlock_bh(&pn->l2tp_session_hlist_lock); |
1380 | synchronize_rcu(); | ||
1376 | } | 1381 | } |
1377 | 1382 | ||
1378 | if (session->session_id != 0) | 1383 | if (session->session_id != 0) |
@@ -1494,10 +1499,11 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn | |||
1494 | if (tunnel->version != L2TP_HDR_VER_2) { | 1499 | if (tunnel->version != L2TP_HDR_VER_2) { |
1495 | struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net); | 1500 | struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net); |
1496 | 1501 | ||
1497 | write_lock_bh(&pn->l2tp_session_hlist_lock); | 1502 | spin_lock_bh(&pn->l2tp_session_hlist_lock); |
1498 | hlist_add_head(&session->global_hlist, | 1503 | hlist_add_head_rcu(&session->global_hlist, |
1499 | l2tp_session_id_hash_2(pn, session_id)); | 1504 | l2tp_session_id_hash_2(pn, session_id)); |
1500 | write_unlock_bh(&pn->l2tp_session_hlist_lock); | 1505 | spin_unlock_bh(&pn->l2tp_session_hlist_lock); |
1506 | synchronize_rcu(); | ||
1501 | } | 1507 | } |
1502 | 1508 | ||
1503 | /* Ignore management session in session count value */ | 1509 | /* Ignore management session in session count value */ |
@@ -1524,12 +1530,12 @@ static __net_init int l2tp_init_net(struct net *net) | |||
1524 | return -ENOMEM; | 1530 | return -ENOMEM; |
1525 | 1531 | ||
1526 | INIT_LIST_HEAD(&pn->l2tp_tunnel_list); | 1532 | INIT_LIST_HEAD(&pn->l2tp_tunnel_list); |
1527 | rwlock_init(&pn->l2tp_tunnel_list_lock); | 1533 | spin_lock_init(&pn->l2tp_tunnel_list_lock); |
1528 | 1534 | ||
1529 | for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++) | 1535 | for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++) |
1530 | INIT_HLIST_HEAD(&pn->l2tp_session_hlist[hash]); | 1536 | INIT_HLIST_HEAD(&pn->l2tp_session_hlist[hash]); |
1531 | 1537 | ||
1532 | rwlock_init(&pn->l2tp_session_hlist_lock); | 1538 | spin_lock_init(&pn->l2tp_session_hlist_lock); |
1533 | 1539 | ||
1534 | err = net_assign_generic(net, l2tp_net_id, pn); | 1540 | err = net_assign_generic(net, l2tp_net_id, pn); |
1535 | if (err) | 1541 | if (err) |