--- y/net/ipv4/inet_hashtables.c +++ x/net/ipv4/inet_hashtables.c @@ -148,6 +148,7 @@ void inet_bind_hash(struct sock *sk, str inet_csk(sk)->icsk_bind2_hash = tb2; } +static DEFINE_SPINLOCK(tb2_hash_lock); /* * Get rid of any references to a local port held by the given sock. */ @@ -167,12 +168,14 @@ static void __inet_put_port(struct sock inet_sk(sk)->inet_num = 0; inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb); + spin_lock(&tb2_hash_lock); if (inet_csk(sk)->icsk_bind2_hash) { tb2 = inet_csk(sk)->icsk_bind2_hash; __sk_del_bind2_node(sk); inet_csk(sk)->icsk_bind2_hash = NULL; inet_bind2_bucket_destroy(hashinfo->bind2_bucket_cachep, tb2); } + spin_unlock(&tb2_hash_lock); spin_unlock(&head->lock); } @@ -197,6 +200,7 @@ int __inet_inherit_port(const struct soc struct inet_bind2_bucket *tb2; struct inet_bind_bucket *tb; int l3mdev; + int tb2_locked = 0; spin_lock(&head->lock); tb = inet_csk(sk)->icsk_bind_hash; @@ -233,6 +237,8 @@ int __inet_inherit_port(const struct soc l3mdev = inet_sk_bound_l3mdev(sk); bhash2_find: + spin_lock(&tb2_hash_lock); + tb2_locked = 1; tb2 = inet_bind2_bucket_find(table, net, port, l3mdev, child, &head_bhash2); if (!tb2) { @@ -244,11 +250,15 @@ bhash2_find: } } inet_bind_hash(child, tb, tb2, port); + if (tb2_locked) + spin_unlock(&tb2_hash_lock); spin_unlock(&head->lock); return 0; error: + if (tb2_locked) + spin_unlock(&tb2_hash_lock); if (created_inet_bind_bucket) inet_bind_bucket_destroy(table->bind_bucket_cachep, tb); spin_unlock(&head->lock); @@ -946,12 +956,15 @@ ok: /* Find the corresponding tb2 bucket since we need to * add the socket to the bhash2 table as well */ + spin_lock(&tb2_hash_lock); tb2 = inet_bind2_bucket_find(hinfo, net, port, l3mdev, sk, &head2); if (!tb2) { tb2 = inet_bind2_bucket_create(hinfo->bind2_bucket_cachep, net, head2, port, l3mdev, sk); - if (!tb2) + if (!tb2) { + spin_unlock(&tb2_hash_lock); goto error; + } } /* Here we want to add a little bit of randomness to the next source @@ -970,6 +983,7 @@ ok: } if (tw) inet_twsk_bind_unhash(tw, hinfo); + spin_unlock(&tb2_hash_lock); spin_unlock(&head->lock); if (tw) inet_twsk_deschedule_put(tw);