Skip to content

Commit 9db66bd

Browse files
Eric Dumazetdavem330
authored andcommitted
net: convert TCP/DCCP ehash rwlocks to spinlocks
Now TCP & DCCP use RCU lookups, we can convert ehash rwlocks to spinlocks. /proc/net/tcp and other seq_file 'readers' can safely be converted to 'writers'. This should speedup writers, since spin_lock()/spin_unlock() only use one atomic operation instead of two for write_lock()/write_unlock() Signed-off-by: Eric Dumazet <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent b8c26a3 commit 9db66bd

File tree

5 files changed

+41
-43
lines changed

5 files changed

+41
-43
lines changed

include/net/inet_hashtables.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ struct inet_hashinfo {
116116
* TIME_WAIT sockets use a separate chain (twchain).
117117
*/
118118
struct inet_ehash_bucket *ehash;
119-
rwlock_t *ehash_locks;
119+
spinlock_t *ehash_locks;
120120
unsigned int ehash_size;
121121
unsigned int ehash_locks_mask;
122122

@@ -152,7 +152,7 @@ static inline struct inet_ehash_bucket *inet_ehash_bucket(
152152
return &hashinfo->ehash[hash & (hashinfo->ehash_size - 1)];
153153
}
154154

155-
static inline rwlock_t *inet_ehash_lockp(
155+
static inline spinlock_t *inet_ehash_lockp(
156156
struct inet_hashinfo *hashinfo,
157157
unsigned int hash)
158158
{
@@ -177,16 +177,16 @@ static inline int inet_ehash_locks_alloc(struct inet_hashinfo *hashinfo)
177177
size = 4096;
178178
if (sizeof(rwlock_t) != 0) {
179179
#ifdef CONFIG_NUMA
180-
if (size * sizeof(rwlock_t) > PAGE_SIZE)
181-
hashinfo->ehash_locks = vmalloc(size * sizeof(rwlock_t));
180+
if (size * sizeof(spinlock_t) > PAGE_SIZE)
181+
hashinfo->ehash_locks = vmalloc(size * sizeof(spinlock_t));
182182
else
183183
#endif
184-
hashinfo->ehash_locks = kmalloc(size * sizeof(rwlock_t),
184+
hashinfo->ehash_locks = kmalloc(size * sizeof(spinlock_t),
185185
GFP_KERNEL);
186186
if (!hashinfo->ehash_locks)
187187
return ENOMEM;
188188
for (i = 0; i < size; i++)
189-
rwlock_init(&hashinfo->ehash_locks[i]);
189+
spin_lock_init(&hashinfo->ehash_locks[i]);
190190
}
191191
hashinfo->ehash_locks_mask = size - 1;
192192
return 0;
@@ -197,7 +197,7 @@ static inline void inet_ehash_locks_free(struct inet_hashinfo *hashinfo)
197197
if (hashinfo->ehash_locks) {
198198
#ifdef CONFIG_NUMA
199199
unsigned int size = (hashinfo->ehash_locks_mask + 1) *
200-
sizeof(rwlock_t);
200+
sizeof(spinlock_t);
201201
if (size > PAGE_SIZE)
202202
vfree(hashinfo->ehash_locks);
203203
else

net/ipv4/inet_hashtables.c

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -271,13 +271,12 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row,
271271
struct net *net = sock_net(sk);
272272
unsigned int hash = inet_ehashfn(net, daddr, lport, saddr, inet->dport);
273273
struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash);
274-
rwlock_t *lock = inet_ehash_lockp(hinfo, hash);
274+
spinlock_t *lock = inet_ehash_lockp(hinfo, hash);
275275
struct sock *sk2;
276276
const struct hlist_nulls_node *node;
277277
struct inet_timewait_sock *tw;
278278

279-
prefetch(head->chain.first);
280-
write_lock(lock);
279+
spin_lock(lock);
281280

282281
/* Check TIME-WAIT sockets first. */
283282
sk_nulls_for_each(sk2, node, &head->twchain) {
@@ -308,8 +307,8 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row,
308307
sk->sk_hash = hash;
309308
WARN_ON(!sk_unhashed(sk));
310309
__sk_nulls_add_node_rcu(sk, &head->chain);
310+
spin_unlock(lock);
311311
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
312-
write_unlock(lock);
313312

314313
if (twp) {
315314
*twp = tw;
@@ -325,7 +324,7 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row,
325324
return 0;
326325

327326
not_unique:
328-
write_unlock(lock);
327+
spin_unlock(lock);
329328
return -EADDRNOTAVAIL;
330329
}
331330

@@ -340,7 +339,7 @@ void __inet_hash_nolisten(struct sock *sk)
340339
{
341340
struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo;
342341
struct hlist_nulls_head *list;
343-
rwlock_t *lock;
342+
spinlock_t *lock;
344343
struct inet_ehash_bucket *head;
345344

346345
WARN_ON(!sk_unhashed(sk));
@@ -350,10 +349,10 @@ void __inet_hash_nolisten(struct sock *sk)
350349
list = &head->chain;
351350
lock = inet_ehash_lockp(hashinfo, sk->sk_hash);
352351

353-
write_lock(lock);
352+
spin_lock(lock);
354353
__sk_nulls_add_node_rcu(sk, list);
354+
spin_unlock(lock);
355355
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
356-
write_unlock(lock);
357356
}
358357
EXPORT_SYMBOL_GPL(__inet_hash_nolisten);
359358

@@ -402,12 +401,12 @@ void inet_unhash(struct sock *sk)
402401
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
403402
spin_unlock_bh(&ilb->lock);
404403
} else {
405-
rwlock_t *lock = inet_ehash_lockp(hashinfo, sk->sk_hash);
404+
spinlock_t *lock = inet_ehash_lockp(hashinfo, sk->sk_hash);
406405

407-
write_lock_bh(lock);
406+
spin_lock_bh(lock);
408407
if (__sk_nulls_del_node_init_rcu(sk))
409408
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
410-
write_unlock_bh(lock);
409+
spin_unlock_bh(lock);
411410
}
412411
}
413412
EXPORT_SYMBOL_GPL(inet_unhash);

net/ipv4/inet_timewait_sock.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,16 @@ static void __inet_twsk_kill(struct inet_timewait_sock *tw,
2020
struct inet_bind_hashbucket *bhead;
2121
struct inet_bind_bucket *tb;
2222
/* Unlink from established hashes. */
23-
rwlock_t *lock = inet_ehash_lockp(hashinfo, tw->tw_hash);
23+
spinlock_t *lock = inet_ehash_lockp(hashinfo, tw->tw_hash);
2424

25-
write_lock(lock);
25+
spin_lock(lock);
2626
if (hlist_nulls_unhashed(&tw->tw_node)) {
27-
write_unlock(lock);
27+
spin_unlock(lock);
2828
return;
2929
}
3030
hlist_nulls_del_rcu(&tw->tw_node);
3131
sk_nulls_node_init(&tw->tw_node);
32-
write_unlock(lock);
32+
spin_unlock(lock);
3333

3434
/* Disassociate with bind bucket. */
3535
bhead = &hashinfo->bhash[inet_bhashfn(twsk_net(tw), tw->tw_num,
@@ -76,7 +76,7 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk,
7676
const struct inet_sock *inet = inet_sk(sk);
7777
const struct inet_connection_sock *icsk = inet_csk(sk);
7878
struct inet_ehash_bucket *ehead = inet_ehash_bucket(hashinfo, sk->sk_hash);
79-
rwlock_t *lock = inet_ehash_lockp(hashinfo, sk->sk_hash);
79+
spinlock_t *lock = inet_ehash_lockp(hashinfo, sk->sk_hash);
8080
struct inet_bind_hashbucket *bhead;
8181
/* Step 1: Put TW into bind hash. Original socket stays there too.
8282
Note, that any socket with inet->num != 0 MUST be bound in
@@ -90,7 +90,7 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk,
9090
inet_twsk_add_bind_node(tw, &tw->tw_tb->owners);
9191
spin_unlock(&bhead->lock);
9292

93-
write_lock(lock);
93+
spin_lock(lock);
9494

9595
/*
9696
* Step 2: Hash TW into TIMEWAIT chain.
@@ -104,7 +104,7 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk,
104104
if (__sk_nulls_del_node_init_rcu(sk))
105105
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
106106

107-
write_unlock(lock);
107+
spin_unlock(lock);
108108
}
109109

110110
EXPORT_SYMBOL_GPL(__inet_twsk_hashdance);
@@ -427,9 +427,9 @@ void inet_twsk_purge(struct net *net, struct inet_hashinfo *hashinfo,
427427
for (h = 0; h < (hashinfo->ehash_size); h++) {
428428
struct inet_ehash_bucket *head =
429429
inet_ehash_bucket(hashinfo, h);
430-
rwlock_t *lock = inet_ehash_lockp(hashinfo, h);
430+
spinlock_t *lock = inet_ehash_lockp(hashinfo, h);
431431
restart:
432-
write_lock(lock);
432+
spin_lock(lock);
433433
sk_nulls_for_each(sk, node, &head->twchain) {
434434

435435
tw = inet_twsk(sk);
@@ -438,13 +438,13 @@ void inet_twsk_purge(struct net *net, struct inet_hashinfo *hashinfo,
438438
continue;
439439

440440
atomic_inc(&tw->tw_refcnt);
441-
write_unlock(lock);
441+
spin_unlock(lock);
442442
inet_twsk_deschedule(tw, twdr);
443443
inet_twsk_put(tw);
444444

445445
goto restart;
446446
}
447-
write_unlock(lock);
447+
spin_unlock(lock);
448448
}
449449
local_bh_enable();
450450
}

net/ipv4/tcp_ipv4.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1970,13 +1970,13 @@ static void *established_get_first(struct seq_file *seq)
19701970
struct sock *sk;
19711971
struct hlist_nulls_node *node;
19721972
struct inet_timewait_sock *tw;
1973-
rwlock_t *lock = inet_ehash_lockp(&tcp_hashinfo, st->bucket);
1973+
spinlock_t *lock = inet_ehash_lockp(&tcp_hashinfo, st->bucket);
19741974

19751975
/* Lockless fast path for the common case of empty buckets */
19761976
if (empty_bucket(st))
19771977
continue;
19781978

1979-
read_lock_bh(lock);
1979+
spin_lock_bh(lock);
19801980
sk_nulls_for_each(sk, node, &tcp_hashinfo.ehash[st->bucket].chain) {
19811981
if (sk->sk_family != st->family ||
19821982
!net_eq(sock_net(sk), net)) {
@@ -1995,7 +1995,7 @@ static void *established_get_first(struct seq_file *seq)
19951995
rc = tw;
19961996
goto out;
19971997
}
1998-
read_unlock_bh(lock);
1998+
spin_unlock_bh(lock);
19991999
st->state = TCP_SEQ_STATE_ESTABLISHED;
20002000
}
20012001
out:
@@ -2023,7 +2023,7 @@ static void *established_get_next(struct seq_file *seq, void *cur)
20232023
cur = tw;
20242024
goto out;
20252025
}
2026-
read_unlock_bh(inet_ehash_lockp(&tcp_hashinfo, st->bucket));
2026+
spin_unlock_bh(inet_ehash_lockp(&tcp_hashinfo, st->bucket));
20272027
st->state = TCP_SEQ_STATE_ESTABLISHED;
20282028

20292029
/* Look for next non empty bucket */
@@ -2033,7 +2033,7 @@ static void *established_get_next(struct seq_file *seq, void *cur)
20332033
if (st->bucket >= tcp_hashinfo.ehash_size)
20342034
return NULL;
20352035

2036-
read_lock_bh(inet_ehash_lockp(&tcp_hashinfo, st->bucket));
2036+
spin_lock_bh(inet_ehash_lockp(&tcp_hashinfo, st->bucket));
20372037
sk = sk_nulls_head(&tcp_hashinfo.ehash[st->bucket].chain);
20382038
} else
20392039
sk = sk_nulls_next(sk);
@@ -2134,7 +2134,7 @@ static void tcp_seq_stop(struct seq_file *seq, void *v)
21342134
case TCP_SEQ_STATE_TIME_WAIT:
21352135
case TCP_SEQ_STATE_ESTABLISHED:
21362136
if (v)
2137-
read_unlock_bh(inet_ehash_lockp(&tcp_hashinfo, st->bucket));
2137+
spin_unlock_bh(inet_ehash_lockp(&tcp_hashinfo, st->bucket));
21382138
break;
21392139
}
21402140
}

net/ipv6/inet6_hashtables.c

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@ void __inet6_hash(struct sock *sk)
3838
} else {
3939
unsigned int hash;
4040
struct hlist_nulls_head *list;
41-
rwlock_t *lock;
41+
spinlock_t *lock;
4242

4343
sk->sk_hash = hash = inet6_sk_ehashfn(sk);
4444
list = &inet_ehash_bucket(hashinfo, hash)->chain;
4545
lock = inet_ehash_lockp(hashinfo, hash);
46-
write_lock(lock);
46+
spin_lock(lock);
4747
__sk_nulls_add_node_rcu(sk, list);
48-
write_unlock(lock);
48+
spin_unlock(lock);
4949
}
5050

5151
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
@@ -195,13 +195,12 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
195195
const unsigned int hash = inet6_ehashfn(net, daddr, lport, saddr,
196196
inet->dport);
197197
struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash);
198-
rwlock_t *lock = inet_ehash_lockp(hinfo, hash);
198+
spinlock_t *lock = inet_ehash_lockp(hinfo, hash);
199199
struct sock *sk2;
200200
const struct hlist_nulls_node *node;
201201
struct inet_timewait_sock *tw;
202202

203-
prefetch(head->chain.first);
204-
write_lock(lock);
203+
spin_lock(lock);
205204

206205
/* Check TIME-WAIT sockets first. */
207206
sk_nulls_for_each(sk2, node, &head->twchain) {
@@ -230,8 +229,8 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
230229
WARN_ON(!sk_unhashed(sk));
231230
__sk_nulls_add_node_rcu(sk, &head->chain);
232231
sk->sk_hash = hash;
232+
spin_unlock(lock);
233233
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
234-
write_unlock(lock);
235234

236235
if (twp != NULL) {
237236
*twp = tw;
@@ -246,7 +245,7 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
246245
return 0;
247246

248247
not_unique:
249-
write_unlock(lock);
248+
spin_unlock(lock);
250249
return -EADDRNOTAVAIL;
251250
}
252251

0 commit comments

Comments
 (0)