mirror of
https://github.com/hardkernel/linux.git
synced 2026-03-25 20:10:23 +09:00
Revert "net: inet: Retire port only listening_hash"
This reverts commit427165421cwhich is commitcae3873c5bupstream. It breaks the Android kernel abi and can be brought back in the future in an abi-safe way if it is really needed. Bug: 161946584 Change-Id: I442c411d2dd2a01f30d3d9cba5f83510e3fdc2e1 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
@@ -69,6 +69,7 @@ struct inet_connection_sock_af_ops {
|
||||
* @icsk_ulp_ops Pluggable ULP control hook
|
||||
* @icsk_ulp_data ULP private data
|
||||
* @icsk_clean_acked Clean acked data hook
|
||||
* @icsk_listen_portaddr_node hash to the portaddr listener hashtable
|
||||
* @icsk_ca_state: Congestion control state
|
||||
* @icsk_retransmits: Number of unrecovered [RTO] timeouts
|
||||
* @icsk_pending: Scheduled timer event
|
||||
@@ -98,6 +99,7 @@ struct inet_connection_sock {
|
||||
const struct tcp_ulp_ops *icsk_ulp_ops;
|
||||
void __rcu *icsk_ulp_data;
|
||||
void (*icsk_clean_acked)(struct sock *sk, u32 acked_seq);
|
||||
struct hlist_node icsk_listen_portaddr_node;
|
||||
unsigned int (*icsk_sync_mss)(struct sock *sk, u32 pmtu);
|
||||
__u8 icsk_ca_state:5,
|
||||
icsk_ca_initialized:1,
|
||||
|
||||
@@ -111,7 +111,10 @@ struct inet_bind_hashbucket {
|
||||
#define LISTENING_NULLS_BASE (1U << 29)
|
||||
struct inet_listen_hashbucket {
|
||||
spinlock_t lock;
|
||||
struct hlist_nulls_head nulls_head;
|
||||
union {
|
||||
struct hlist_head head;
|
||||
struct hlist_nulls_head nulls_head;
|
||||
};
|
||||
};
|
||||
|
||||
/* This is for listening sockets, thus all sockets which possess wildcards. */
|
||||
@@ -139,8 +142,32 @@ struct inet_hashinfo {
|
||||
/* The 2nd listener table hashed by local port and address */
|
||||
unsigned int lhash2_mask;
|
||||
struct inet_listen_hashbucket *lhash2;
|
||||
|
||||
/* All the above members are written once at bootup and
|
||||
* never written again _or_ are predominantly read-access.
|
||||
*
|
||||
* Now align to a new cache line as all the following members
|
||||
* might be often dirty.
|
||||
*/
|
||||
/* All sockets in TCP_LISTEN state will be in listening_hash.
|
||||
* This is the only table where wildcard'd TCP sockets can
|
||||
* exist. listening_hash is only hashed by local port number.
|
||||
* If lhash2 is initialized, the same socket will also be hashed
|
||||
* to lhash2 by port and address.
|
||||
*/
|
||||
struct inet_listen_hashbucket listening_hash[INET_LHTABLE_SIZE]
|
||||
____cacheline_aligned_in_smp;
|
||||
};
|
||||
|
||||
#define inet_lhash2_for_each_icsk_continue(__icsk) \
|
||||
hlist_for_each_entry_continue(__icsk, icsk_listen_portaddr_node)
|
||||
|
||||
#define inet_lhash2_for_each_icsk(__icsk, list) \
|
||||
hlist_for_each_entry(__icsk, list, icsk_listen_portaddr_node)
|
||||
|
||||
#define inet_lhash2_for_each_icsk_rcu(__icsk, list) \
|
||||
hlist_for_each_entry_rcu(__icsk, list, icsk_listen_portaddr_node)
|
||||
|
||||
static inline struct inet_listen_hashbucket *
|
||||
inet_lhash2_bucket(struct inet_hashinfo *h, u32 hash)
|
||||
{
|
||||
@@ -191,11 +218,23 @@ static inline u32 inet_bhashfn(const struct net *net, const __u16 lport,
|
||||
void inet_bind_hash(struct sock *sk, struct inet_bind_bucket *tb,
|
||||
const unsigned short snum);
|
||||
|
||||
/* These can have wildcards, don't try too hard. */
|
||||
static inline u32 inet_lhashfn(const struct net *net, const unsigned short num)
|
||||
{
|
||||
return (num + net_hash_mix(net)) & (INET_LHTABLE_SIZE - 1);
|
||||
}
|
||||
|
||||
static inline int inet_sk_listen_hashfn(const struct sock *sk)
|
||||
{
|
||||
return inet_lhashfn(sock_net(sk), inet_sk(sk)->inet_num);
|
||||
}
|
||||
|
||||
/* Caller must disable local BH processing. */
|
||||
int __inet_inherit_port(const struct sock *sk, struct sock *child);
|
||||
|
||||
void inet_put_port(struct sock *sk);
|
||||
|
||||
void inet_hashinfo_init(struct inet_hashinfo *h);
|
||||
void inet_hashinfo2_init(struct inet_hashinfo *h, const char *name,
|
||||
unsigned long numentries, int scale,
|
||||
unsigned long low_limit,
|
||||
|
||||
@@ -1131,6 +1131,7 @@ static int __init dccp_init(void)
|
||||
|
||||
BUILD_BUG_ON(sizeof(struct dccp_skb_cb) >
|
||||
sizeof_field(struct sk_buff, cb));
|
||||
inet_hashinfo_init(&dccp_hashinfo);
|
||||
rc = inet_hashinfo2_init_mod(&dccp_hashinfo);
|
||||
if (rc)
|
||||
goto out_fail;
|
||||
|
||||
@@ -1028,13 +1028,12 @@ void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb,
|
||||
if (!(idiag_states & TCPF_LISTEN) || r->id.idiag_dport)
|
||||
goto skip_listen_ht;
|
||||
|
||||
for (i = s_i; i <= hashinfo->lhash2_mask; i++) {
|
||||
for (i = s_i; i < INET_LHTABLE_SIZE; i++) {
|
||||
struct inet_listen_hashbucket *ilb;
|
||||
struct hlist_nulls_node *node;
|
||||
|
||||
num = 0;
|
||||
ilb = &hashinfo->lhash2[i];
|
||||
|
||||
ilb = &hashinfo->listening_hash[i];
|
||||
spin_lock(&ilb->lock);
|
||||
sk_nulls_for_each(sk, node, &ilb->nulls_head) {
|
||||
struct inet_sock *inet = inet_sk(sk);
|
||||
|
||||
@@ -246,11 +246,12 @@ static struct sock *inet_lhash2_lookup(struct net *net,
|
||||
const __be32 daddr, const unsigned short hnum,
|
||||
const int dif, const int sdif)
|
||||
{
|
||||
struct inet_connection_sock *icsk;
|
||||
struct sock *sk, *result = NULL;
|
||||
struct hlist_nulls_node *node;
|
||||
int score, hiscore = 0;
|
||||
|
||||
sk_nulls_for_each_rcu(sk, node, &ilb2->nulls_head) {
|
||||
inet_lhash2_for_each_icsk_rcu(icsk, &ilb2->head) {
|
||||
sk = (struct sock *)icsk;
|
||||
score = compute_score(sk, net, hnum, daddr, dif, sdif);
|
||||
if (score > hiscore) {
|
||||
result = lookup_reuseport(net, sk, skb, doff,
|
||||
@@ -592,6 +593,7 @@ int __inet_hash(struct sock *sk, struct sock *osk)
|
||||
{
|
||||
struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo;
|
||||
struct inet_listen_hashbucket *ilb2;
|
||||
struct inet_listen_hashbucket *ilb;
|
||||
int err = 0;
|
||||
|
||||
if (sk->sk_state != TCP_LISTEN) {
|
||||
@@ -601,23 +603,31 @@ int __inet_hash(struct sock *sk, struct sock *osk)
|
||||
return 0;
|
||||
}
|
||||
WARN_ON(!sk_unhashed(sk));
|
||||
ilb = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)];
|
||||
ilb2 = inet_lhash2_bucket_sk(hashinfo, sk);
|
||||
|
||||
spin_lock(&ilb->lock);
|
||||
spin_lock(&ilb2->lock);
|
||||
if (sk->sk_reuseport) {
|
||||
err = inet_reuseport_add_sock(sk, ilb2);
|
||||
err = inet_reuseport_add_sock(sk, ilb);
|
||||
if (err)
|
||||
goto unlock;
|
||||
}
|
||||
if (IS_ENABLED(CONFIG_IPV6) && sk->sk_reuseport &&
|
||||
sk->sk_family == AF_INET6)
|
||||
__sk_nulls_add_node_tail_rcu(sk, &ilb2->nulls_head);
|
||||
else
|
||||
__sk_nulls_add_node_rcu(sk, &ilb2->nulls_head);
|
||||
sk->sk_family == AF_INET6) {
|
||||
hlist_add_tail_rcu(&inet_csk(sk)->icsk_listen_portaddr_node,
|
||||
&ilb2->head);
|
||||
__sk_nulls_add_node_tail_rcu(sk, &ilb->nulls_head);
|
||||
} else {
|
||||
hlist_add_head_rcu(&inet_csk(sk)->icsk_listen_portaddr_node,
|
||||
&ilb2->head);
|
||||
__sk_nulls_add_node_rcu(sk, &ilb->nulls_head);
|
||||
}
|
||||
sock_set_flag(sk, SOCK_RCU_FREE);
|
||||
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
|
||||
unlock:
|
||||
spin_unlock(&ilb2->lock);
|
||||
spin_unlock(&ilb->lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -643,23 +653,29 @@ void inet_unhash(struct sock *sk)
|
||||
|
||||
if (sk->sk_state == TCP_LISTEN) {
|
||||
struct inet_listen_hashbucket *ilb2;
|
||||
struct inet_listen_hashbucket *ilb;
|
||||
|
||||
ilb = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)];
|
||||
ilb2 = inet_lhash2_bucket_sk(hashinfo, sk);
|
||||
/* Don't disable bottom halves while acquiring the lock to
|
||||
* avoid circular locking dependency on PREEMPT_RT.
|
||||
*/
|
||||
spin_lock(&ilb->lock);
|
||||
spin_lock(&ilb2->lock);
|
||||
if (sk_unhashed(sk)) {
|
||||
spin_unlock(&ilb2->lock);
|
||||
spin_unlock(&ilb->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rcu_access_pointer(sk->sk_reuseport_cb))
|
||||
reuseport_stop_listen_sock(sk);
|
||||
|
||||
hlist_del_init_rcu(&inet_csk(sk)->icsk_listen_portaddr_node);
|
||||
__sk_nulls_del_node_init_rcu(sk);
|
||||
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
|
||||
spin_unlock(&ilb2->lock);
|
||||
spin_unlock(&ilb->lock);
|
||||
} else {
|
||||
spinlock_t *lock = inet_ehash_lockp(hashinfo, sk->sk_hash);
|
||||
|
||||
@@ -817,14 +833,27 @@ int inet_hash_connect(struct inet_timewait_death_row *death_row,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(inet_hash_connect);
|
||||
|
||||
void inet_hashinfo_init(struct inet_hashinfo *h)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < INET_LHTABLE_SIZE; i++) {
|
||||
spin_lock_init(&h->listening_hash[i].lock);
|
||||
INIT_HLIST_NULLS_HEAD(&h->listening_hash[i].nulls_head,
|
||||
i + LISTENING_NULLS_BASE);
|
||||
}
|
||||
|
||||
h->lhash2 = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(inet_hashinfo_init);
|
||||
|
||||
static void init_hashinfo_lhash2(struct inet_hashinfo *h)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= h->lhash2_mask; i++) {
|
||||
spin_lock_init(&h->lhash2[i].lock);
|
||||
INIT_HLIST_NULLS_HEAD(&h->lhash2[i].nulls_head,
|
||||
i + LISTENING_NULLS_BASE);
|
||||
INIT_HLIST_HEAD(&h->lhash2[i].head);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4559,6 +4559,7 @@ void __init tcp_init(void)
|
||||
timer_setup(&tcp_orphan_timer, tcp_orphan_update, TIMER_DEFERRABLE);
|
||||
mod_timer(&tcp_orphan_timer, jiffies + TCP_ORPHAN_TIMER_PERIOD);
|
||||
|
||||
inet_hashinfo_init(&tcp_hashinfo);
|
||||
inet_hashinfo2_init(&tcp_hashinfo, "tcp_listen_portaddr_hash",
|
||||
thash_entries, 21, /* one slot per 2 MB*/
|
||||
0, 64 * 1024);
|
||||
|
||||
@@ -2343,15 +2343,16 @@ static void *listening_get_first(struct seq_file *seq)
|
||||
st->offset = 0;
|
||||
for (; st->bucket <= tcp_hashinfo.lhash2_mask; st->bucket++) {
|
||||
struct inet_listen_hashbucket *ilb2;
|
||||
struct hlist_nulls_node *node;
|
||||
struct inet_connection_sock *icsk;
|
||||
struct sock *sk;
|
||||
|
||||
ilb2 = &tcp_hashinfo.lhash2[st->bucket];
|
||||
if (hlist_nulls_empty(&ilb2->nulls_head))
|
||||
if (hlist_empty(&ilb2->head))
|
||||
continue;
|
||||
|
||||
spin_lock(&ilb2->lock);
|
||||
sk_nulls_for_each(sk, node, &ilb2->nulls_head) {
|
||||
inet_lhash2_for_each_icsk(icsk, &ilb2->head) {
|
||||
sk = (struct sock *)icsk;
|
||||
if (seq_sk_match(seq, sk))
|
||||
return sk;
|
||||
}
|
||||
@@ -2370,14 +2371,15 @@ static void *listening_get_next(struct seq_file *seq, void *cur)
|
||||
{
|
||||
struct tcp_iter_state *st = seq->private;
|
||||
struct inet_listen_hashbucket *ilb2;
|
||||
struct hlist_nulls_node *node;
|
||||
struct inet_connection_sock *icsk;
|
||||
struct sock *sk = cur;
|
||||
|
||||
++st->num;
|
||||
++st->offset;
|
||||
|
||||
sk = sk_nulls_next(sk);
|
||||
sk_nulls_for_each_from(sk, node) {
|
||||
icsk = inet_csk(sk);
|
||||
inet_lhash2_for_each_icsk_continue(icsk) {
|
||||
sk = (struct sock *)icsk;
|
||||
if (seq_sk_match(seq, sk))
|
||||
return sk;
|
||||
}
|
||||
@@ -2786,15 +2788,16 @@ static unsigned int bpf_iter_tcp_listening_batch(struct seq_file *seq,
|
||||
{
|
||||
struct bpf_tcp_iter_state *iter = seq->private;
|
||||
struct tcp_iter_state *st = &iter->state;
|
||||
struct hlist_nulls_node *node;
|
||||
struct inet_connection_sock *icsk;
|
||||
unsigned int expected = 1;
|
||||
struct sock *sk;
|
||||
|
||||
sock_hold(start_sk);
|
||||
iter->batch[iter->end_sk++] = start_sk;
|
||||
|
||||
sk = sk_nulls_next(start_sk);
|
||||
sk_nulls_for_each_from(sk, node) {
|
||||
icsk = inet_csk(start_sk);
|
||||
inet_lhash2_for_each_icsk_continue(icsk) {
|
||||
sk = (struct sock *)icsk;
|
||||
if (seq_sk_match(seq, sk)) {
|
||||
if (iter->end_sk < iter->max_sk) {
|
||||
sock_hold(sk);
|
||||
|
||||
@@ -138,11 +138,12 @@ static struct sock *inet6_lhash2_lookup(struct net *net,
|
||||
const __be16 sport, const struct in6_addr *daddr,
|
||||
const unsigned short hnum, const int dif, const int sdif)
|
||||
{
|
||||
struct inet_connection_sock *icsk;
|
||||
struct sock *sk, *result = NULL;
|
||||
struct hlist_nulls_node *node;
|
||||
int score, hiscore = 0;
|
||||
|
||||
sk_nulls_for_each_rcu(sk, node, &ilb2->nulls_head) {
|
||||
inet_lhash2_for_each_icsk_rcu(icsk, &ilb2->head) {
|
||||
sk = (struct sock *)icsk;
|
||||
score = compute_score(sk, net, hnum, daddr, dif, sdif);
|
||||
if (score > hiscore) {
|
||||
result = lookup_reuseport(net, sk, skb, doff,
|
||||
|
||||
@@ -83,13 +83,13 @@ static void mptcp_diag_dump_listeners(struct sk_buff *skb, struct netlink_callba
|
||||
struct net *net = sock_net(skb->sk);
|
||||
int i;
|
||||
|
||||
for (i = diag_ctx->l_slot; i <= tcp_hashinfo.lhash2_mask; i++) {
|
||||
for (i = diag_ctx->l_slot; i < INET_LHTABLE_SIZE; i++) {
|
||||
struct inet_listen_hashbucket *ilb;
|
||||
struct hlist_nulls_node *node;
|
||||
struct sock *sk;
|
||||
int num = 0;
|
||||
|
||||
ilb = &tcp_hashinfo.lhash2[i];
|
||||
ilb = &tcp_hashinfo.listening_hash[i];
|
||||
|
||||
rcu_read_lock();
|
||||
spin_lock(&ilb->lock);
|
||||
|
||||
Reference in New Issue
Block a user