tcp: relax listening_hash operations
softirq handlers use RCU protection to lookup listeners, and write operations all happen from process context. We do not need to block BH for dump operations. Also SYN_RECV since request sockets are stored in the ehash table : 1) inet_diag_dump_icsk() no longer need to clear cb->args[3] and cb->args[4] that were used as cursors while iterating the old per listener hash table. 2) Also factorize a test : No need to scan listening_hash[] if r->id.idiag_dport is not zero. Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
25c07e2c5e
commit
9652dc2eb9
|
@ -863,7 +863,7 @@ void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb,
|
||||||
s_num = num = cb->args[2];
|
s_num = num = cb->args[2];
|
||||||
|
|
||||||
if (cb->args[0] == 0) {
|
if (cb->args[0] == 0) {
|
||||||
if (!(idiag_states & TCPF_LISTEN))
|
if (!(idiag_states & TCPF_LISTEN) || r->id.idiag_dport)
|
||||||
goto skip_listen_ht;
|
goto skip_listen_ht;
|
||||||
|
|
||||||
for (i = s_i; i < INET_LHTABLE_SIZE; i++) {
|
for (i = s_i; i < INET_LHTABLE_SIZE; i++) {
|
||||||
|
@ -872,7 +872,7 @@ void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb,
|
||||||
|
|
||||||
num = 0;
|
num = 0;
|
||||||
ilb = &hashinfo->listening_hash[i];
|
ilb = &hashinfo->listening_hash[i];
|
||||||
spin_lock_bh(&ilb->lock);
|
spin_lock(&ilb->lock);
|
||||||
sk_for_each(sk, &ilb->head) {
|
sk_for_each(sk, &ilb->head) {
|
||||||
struct inet_sock *inet = inet_sk(sk);
|
struct inet_sock *inet = inet_sk(sk);
|
||||||
|
|
||||||
|
@ -892,26 +892,18 @@ void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb,
|
||||||
r->id.idiag_sport)
|
r->id.idiag_sport)
|
||||||
goto next_listen;
|
goto next_listen;
|
||||||
|
|
||||||
if (r->id.idiag_dport ||
|
|
||||||
cb->args[3] > 0)
|
|
||||||
goto next_listen;
|
|
||||||
|
|
||||||
if (inet_csk_diag_dump(sk, skb, cb, r,
|
if (inet_csk_diag_dump(sk, skb, cb, r,
|
||||||
bc, net_admin) < 0) {
|
bc, net_admin) < 0) {
|
||||||
spin_unlock_bh(&ilb->lock);
|
spin_unlock(&ilb->lock);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
next_listen:
|
next_listen:
|
||||||
cb->args[3] = 0;
|
|
||||||
cb->args[4] = 0;
|
|
||||||
++num;
|
++num;
|
||||||
}
|
}
|
||||||
spin_unlock_bh(&ilb->lock);
|
spin_unlock(&ilb->lock);
|
||||||
|
|
||||||
s_num = 0;
|
s_num = 0;
|
||||||
cb->args[3] = 0;
|
|
||||||
cb->args[4] = 0;
|
|
||||||
}
|
}
|
||||||
skip_listen_ht:
|
skip_listen_ht:
|
||||||
cb->args[0] = 1;
|
cb->args[0] = 1;
|
||||||
|
|
|
@ -1893,7 +1893,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur)
|
||||||
if (!sk) {
|
if (!sk) {
|
||||||
get_head:
|
get_head:
|
||||||
ilb = &tcp_hashinfo.listening_hash[st->bucket];
|
ilb = &tcp_hashinfo.listening_hash[st->bucket];
|
||||||
spin_lock_bh(&ilb->lock);
|
spin_lock(&ilb->lock);
|
||||||
sk = sk_head(&ilb->head);
|
sk = sk_head(&ilb->head);
|
||||||
st->offset = 0;
|
st->offset = 0;
|
||||||
goto get_sk;
|
goto get_sk;
|
||||||
|
@ -1911,7 +1911,7 @@ get_sk:
|
||||||
return sk;
|
return sk;
|
||||||
icsk = inet_csk(sk);
|
icsk = inet_csk(sk);
|
||||||
}
|
}
|
||||||
spin_unlock_bh(&ilb->lock);
|
spin_unlock(&ilb->lock);
|
||||||
st->offset = 0;
|
st->offset = 0;
|
||||||
if (++st->bucket < INET_LHTABLE_SIZE)
|
if (++st->bucket < INET_LHTABLE_SIZE)
|
||||||
goto get_head;
|
goto get_head;
|
||||||
|
@ -2119,7 +2119,7 @@ static void tcp_seq_stop(struct seq_file *seq, void *v)
|
||||||
switch (st->state) {
|
switch (st->state) {
|
||||||
case TCP_SEQ_STATE_LISTENING:
|
case TCP_SEQ_STATE_LISTENING:
|
||||||
if (v != SEQ_START_TOKEN)
|
if (v != SEQ_START_TOKEN)
|
||||||
spin_unlock_bh(&tcp_hashinfo.listening_hash[st->bucket].lock);
|
spin_unlock(&tcp_hashinfo.listening_hash[st->bucket].lock);
|
||||||
break;
|
break;
|
||||||
case TCP_SEQ_STATE_ESTABLISHED:
|
case TCP_SEQ_STATE_ESTABLISHED:
|
||||||
if (v)
|
if (v)
|
||||||
|
|
Loading…
Reference in a new issue