aboutsummaryrefslogtreecommitdiffstats
path: root/net/l2tp/l2tp_core.c
diff options
context:
space:
mode:
authorJames Chapman <jchapman@katalix.com>2010-04-02 02:19:16 -0400
committerDavid S. Miller <davem@davemloft.net>2010-04-03 17:56:06 -0400
commite02d494d2c60746ee6583132904ac1791f5bc9a6 (patch)
tree68a3c19ce392998693b83f7db96c4ed1bc140406 /net/l2tp/l2tp_core.c
parent309795f4bec2d69cd507a631f82065c2198a0825 (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/l2tp_core.c')
-rw-r--r--net/l2tp/l2tp_core.c78
1 files changed, 42 insertions, 36 deletions
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index fbd1f2119fe9..473cf2d63905 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;
105static unsigned int l2tp_net_id; 106static unsigned int l2tp_net_id;
106struct l2tp_net { 107struct 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
113static inline struct l2tp_net *l2tp_pernet(struct net *net) 114static 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)