Skip to content

Commit e02d494

Browse files
j-c-hdavem330
authored andcommitted
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 309795f commit e02d494

File tree

1 file changed

+42
-36
lines changed

1 file changed

+42
-36
lines changed

net/l2tp/l2tp_core.c

Lines changed: 42 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <linux/module.h>
2222
#include <linux/string.h>
2323
#include <linux/list.h>
24+
#include <linux/rculist.h>
2425
#include <linux/uaccess.h>
2526

2627
#include <linux/kernel.h>
@@ -105,9 +106,9 @@ static atomic_t l2tp_session_count;
105106
static unsigned int l2tp_net_id;
106107
struct l2tp_net {
107108
struct list_head l2tp_tunnel_list;
108-
rwlock_t l2tp_tunnel_list_lock;
109+
spinlock_t l2tp_tunnel_list_lock;
109110
struct hlist_head l2tp_session_hlist[L2TP_HASH_SIZE_2];
110-
rwlock_t l2tp_session_hlist_lock;
111+
spinlock_t l2tp_session_hlist_lock;
111112
};
112113

113114
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)
139140
struct l2tp_session *session;
140141
struct hlist_node *walk;
141142

142-
read_lock_bh(&pn->l2tp_session_hlist_lock);
143-
hlist_for_each_entry(session, walk, session_list, global_hlist) {
143+
rcu_read_lock_bh();
144+
hlist_for_each_entry_rcu(session, walk, session_list, global_hlist) {
144145
if (session->session_id == session_id) {
145-
read_unlock_bh(&pn->l2tp_session_hlist_lock);
146+
rcu_read_unlock_bh();
146147
return session;
147148
}
148149
}
149-
read_unlock_bh(&pn->l2tp_session_hlist_lock);
150+
rcu_read_unlock_bh();
150151

151152
return NULL;
152153
}
@@ -225,17 +226,17 @@ struct l2tp_session *l2tp_session_find_by_ifname(struct net *net, char *ifname)
225226
struct hlist_node *walk;
226227
struct l2tp_session *session;
227228

228-
read_lock_bh(&pn->l2tp_session_hlist_lock);
229+
rcu_read_lock_bh();
229230
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) {
231232
if (!strcmp(session->ifname, ifname)) {
232-
read_unlock_bh(&pn->l2tp_session_hlist_lock);
233+
rcu_read_unlock_bh();
233234
return session;
234235
}
235236
}
236237
}
237238

238-
read_unlock_bh(&pn->l2tp_session_hlist_lock);
239+
rcu_read_unlock_bh();
239240

240241
return NULL;
241242
}
@@ -248,14 +249,14 @@ struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id)
248249
struct l2tp_tunnel *tunnel;
249250
struct l2tp_net *pn = l2tp_pernet(net);
250251

251-
read_lock_bh(&pn->l2tp_tunnel_list_lock);
252-
list_for_each_entry(tunnel, &pn->l2tp_tunnel_list, list) {
252+
rcu_read_lock_bh();
253+
list_for_each_entry_rcu(tunnel, &pn->l2tp_tunnel_list, list) {
253254
if (tunnel->tunnel_id == tunnel_id) {
254-
read_unlock_bh(&pn->l2tp_tunnel_list_lock);
255+
rcu_read_unlock_bh();
255256
return tunnel;
256257
}
257258
}
258-
read_unlock_bh(&pn->l2tp_tunnel_list_lock);
259+
rcu_read_unlock_bh();
259260

260261
return NULL;
261262
}
@@ -267,15 +268,15 @@ struct l2tp_tunnel *l2tp_tunnel_find_nth(struct net *net, int nth)
267268
struct l2tp_tunnel *tunnel;
268269
int count = 0;
269270

270-
read_lock_bh(&pn->l2tp_tunnel_list_lock);
271-
list_for_each_entry(tunnel, &pn->l2tp_tunnel_list, list) {
271+
rcu_read_lock_bh();
272+
list_for_each_entry_rcu(tunnel, &pn->l2tp_tunnel_list, list) {
272273
if (++count > nth) {
273-
read_unlock_bh(&pn->l2tp_tunnel_list_lock);
274+
rcu_read_unlock_bh();
274275
return tunnel;
275276
}
276277
}
277278

278-
read_unlock_bh(&pn->l2tp_tunnel_list_lock);
279+
rcu_read_unlock_bh();
279280

280281
return NULL;
281282
}
@@ -1167,9 +1168,10 @@ void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel)
11671168
if (tunnel->version != L2TP_HDR_VER_2) {
11681169
struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net);
11691170

1170-
write_lock_bh(&pn->l2tp_session_hlist_lock);
1171-
hlist_del_init(&session->global_hlist);
1172-
write_unlock_bh(&pn->l2tp_session_hlist_lock);
1171+
spin_lock_bh(&pn->l2tp_session_hlist_lock);
1172+
hlist_del_init_rcu(&session->global_hlist);
1173+
spin_unlock_bh(&pn->l2tp_session_hlist_lock);
1174+
synchronize_rcu();
11731175
}
11741176

11751177
if (session->session_close != NULL)
@@ -1206,9 +1208,10 @@ void l2tp_tunnel_free(struct l2tp_tunnel *tunnel)
12061208
"%s: free...\n", tunnel->name);
12071209

12081210
/* Remove from tunnel list */
1209-
write_lock_bh(&pn->l2tp_tunnel_list_lock);
1210-
list_del_init(&tunnel->list);
1211-
write_unlock_bh(&pn->l2tp_tunnel_list_lock);
1211+
spin_lock_bh(&pn->l2tp_tunnel_list_lock);
1212+
list_del_rcu(&tunnel->list);
1213+
spin_unlock_bh(&pn->l2tp_tunnel_list_lock);
1214+
synchronize_rcu();
12121215

12131216
atomic_dec(&l2tp_tunnel_count);
12141217
kfree(tunnel);
@@ -1310,9 +1313,10 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
13101313

13111314
/* Add tunnel to our list */
13121315
INIT_LIST_HEAD(&tunnel->list);
1313-
write_lock_bh(&pn->l2tp_tunnel_list_lock);
1314-
list_add(&tunnel->list, &pn->l2tp_tunnel_list);
1315-
write_unlock_bh(&pn->l2tp_tunnel_list_lock);
1316+
spin_lock_bh(&pn->l2tp_tunnel_list_lock);
1317+
list_add_rcu(&tunnel->list, &pn->l2tp_tunnel_list);
1318+
spin_unlock_bh(&pn->l2tp_tunnel_list_lock);
1319+
synchronize_rcu();
13161320
atomic_inc(&l2tp_tunnel_count);
13171321

13181322
/* Bump the reference count. The tunnel context is deleted
@@ -1370,9 +1374,10 @@ void l2tp_session_free(struct l2tp_session *session)
13701374
if (tunnel->version != L2TP_HDR_VER_2) {
13711375
struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net);
13721376

1373-
write_lock_bh(&pn->l2tp_session_hlist_lock);
1374-
hlist_del_init(&session->global_hlist);
1375-
write_unlock_bh(&pn->l2tp_session_hlist_lock);
1377+
spin_lock_bh(&pn->l2tp_session_hlist_lock);
1378+
hlist_del_init_rcu(&session->global_hlist);
1379+
spin_unlock_bh(&pn->l2tp_session_hlist_lock);
1380+
synchronize_rcu();
13761381
}
13771382

13781383
if (session->session_id != 0)
@@ -1494,10 +1499,11 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn
14941499
if (tunnel->version != L2TP_HDR_VER_2) {
14951500
struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net);
14961501

1497-
write_lock_bh(&pn->l2tp_session_hlist_lock);
1498-
hlist_add_head(&session->global_hlist,
1499-
l2tp_session_id_hash_2(pn, session_id));
1500-
write_unlock_bh(&pn->l2tp_session_hlist_lock);
1502+
spin_lock_bh(&pn->l2tp_session_hlist_lock);
1503+
hlist_add_head_rcu(&session->global_hlist,
1504+
l2tp_session_id_hash_2(pn, session_id));
1505+
spin_unlock_bh(&pn->l2tp_session_hlist_lock);
1506+
synchronize_rcu();
15011507
}
15021508

15031509
/* Ignore management session in session count value */
@@ -1524,12 +1530,12 @@ static __net_init int l2tp_init_net(struct net *net)
15241530
return -ENOMEM;
15251531

15261532
INIT_LIST_HEAD(&pn->l2tp_tunnel_list);
1527-
rwlock_init(&pn->l2tp_tunnel_list_lock);
1533+
spin_lock_init(&pn->l2tp_tunnel_list_lock);
15281534

15291535
for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++)
15301536
INIT_HLIST_HEAD(&pn->l2tp_session_hlist[hash]);
15311537

1532-
rwlock_init(&pn->l2tp_session_hlist_lock);
1538+
spin_lock_init(&pn->l2tp_session_hlist_lock);
15331539

15341540
err = net_assign_generic(net, l2tp_net_id, pn);
15351541
if (err)

0 commit comments

Comments
 (0)