Add RCU protection to inet_bind2_bucket structure akin to commit d186f405fdf4 ("tcp: add RCU management to inet_bind_bucket"). This prepares us for walking (struct inet_bind_bucket *)->bhash2 list without holding inet_bind_hashbucket spinlock. Signed-off-by: Jakub Sitnicki --- include/net/inet_hashtables.h | 4 ++-- include/net/inet_timewait_sock.h | 3 +-- net/ipv4/inet_connection_sock.c | 2 +- net/ipv4/inet_hashtables.c | 16 ++++++++-------- net/ipv4/inet_timewait_sock.c | 8 +++----- 5 files changed, 15 insertions(+), 18 deletions(-) diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index 19dbd9081d5a..a2ff18eea990 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h @@ -108,6 +108,7 @@ struct inet_bind2_bucket { struct hlist_node bhash_node; /* List of sockets hashed to this bucket */ struct hlist_head owners; + struct rcu_head rcu; }; static inline struct net *ib_net(const struct inet_bind_bucket *ib) @@ -228,8 +229,7 @@ inet_bind2_bucket_create(struct kmem_cache *cachep, struct net *net, struct inet_bind_bucket *tb, const struct sock *sk); -void inet_bind2_bucket_destroy(struct kmem_cache *cachep, - struct inet_bind2_bucket *tb); +void inet_bind2_bucket_destroy(struct inet_bind2_bucket *tb); struct inet_bind2_bucket * inet_bind2_bucket_find(const struct inet_bind_hashbucket *head, diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h index 67a313575780..4f4e96b10cf3 100644 --- a/include/net/inet_timewait_sock.h +++ b/include/net/inet_timewait_sock.h @@ -92,8 +92,7 @@ static inline struct inet_timewait_sock *inet_twsk(const struct sock *sk) void inet_twsk_free(struct inet_timewait_sock *tw); void inet_twsk_put(struct inet_timewait_sock *tw); -void inet_twsk_bind_unhash(struct inet_timewait_sock *tw, - struct inet_hashinfo *hashinfo); +void inet_twsk_bind_unhash(struct inet_timewait_sock *tw); struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, struct inet_timewait_death_row *dr, diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 1e2df51427fe..f58b93d3fa0e 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -593,7 +593,7 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum) fail_unlock: if (ret) { if (bhash2_created) - inet_bind2_bucket_destroy(hinfo->bind2_bucket_cachep, tb2); + inet_bind2_bucket_destroy(tb2); if (bhash_created) inet_bind_bucket_destroy(tb); } diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index ceeeec9b7290..d3ce6d0a514e 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -123,7 +123,7 @@ static void inet_bind2_bucket_init(struct inet_bind2_bucket *tb2, #endif INIT_HLIST_HEAD(&tb2->owners); hlist_add_head(&tb2->node, &head->chain); - hlist_add_head(&tb2->bhash_node, &tb->bhash2); + hlist_add_head_rcu(&tb2->bhash_node, &tb->bhash2); } struct inet_bind2_bucket *inet_bind2_bucket_create(struct kmem_cache *cachep, @@ -141,12 +141,12 @@ struct inet_bind2_bucket *inet_bind2_bucket_create(struct kmem_cache *cachep, } /* Caller must hold hashbucket lock for this tb with local BH disabled */ -void inet_bind2_bucket_destroy(struct kmem_cache *cachep, struct inet_bind2_bucket *tb) +void inet_bind2_bucket_destroy(struct inet_bind2_bucket *tb) { if (hlist_empty(&tb->owners)) { __hlist_del(&tb->node); - __hlist_del(&tb->bhash_node); - kmem_cache_free(cachep, tb); + hlist_del_rcu(&tb->bhash_node); + kfree_rcu(tb, rcu); } } @@ -198,7 +198,7 @@ static void __inet_put_port(struct sock *sk) __sk_del_bind_node(sk); inet_csk(sk)->icsk_bind2_hash = NULL; - inet_bind2_bucket_destroy(hashinfo->bind2_bucket_cachep, tb2); + inet_bind2_bucket_destroy(tb2); } spin_unlock(&head2->lock); @@ -951,7 +951,7 @@ static int __inet_bhash2_update_saddr(struct sock *sk, void *saddr, int family, spin_lock(&head2->lock); __sk_del_bind_node(sk); - inet_bind2_bucket_destroy(hinfo->bind2_bucket_cachep, inet_csk(sk)->icsk_bind2_hash); + inet_bind2_bucket_destroy(inet_csk(sk)->icsk_bind2_hash); spin_unlock(&head2->lock); if (reset) @@ -1154,7 +1154,7 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row, inet_ehash_nolisten(sk, (struct sock *)tw, NULL); } if (tw) - inet_twsk_bind_unhash(tw, hinfo); + inet_twsk_bind_unhash(tw); spin_unlock(&head2->lock); spin_unlock(&head->lock); @@ -1179,7 +1179,7 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row, inet_sk(sk)->inet_num = 0; if (tw) - inet_twsk_bind_unhash(tw, hinfo); + inet_twsk_bind_unhash(tw); } spin_unlock(&head2->lock); diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index 875ff923a8ed..ff286b179f4a 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -20,14 +20,12 @@ /** * inet_twsk_bind_unhash - unhash a timewait socket from bind hash * @tw: timewait socket - * @hashinfo: hashinfo pointer * * unhash a timewait socket from bind hash, if hashed. * bind hash lock must be held by caller. * Returns 1 if caller should call inet_twsk_put() after lock release. */ -void inet_twsk_bind_unhash(struct inet_timewait_sock *tw, - struct inet_hashinfo *hashinfo) +void inet_twsk_bind_unhash(struct inet_timewait_sock *tw) { struct inet_bind2_bucket *tb2 = tw->tw_tb2; struct inet_bind_bucket *tb = tw->tw_tb; @@ -38,7 +36,7 @@ void inet_twsk_bind_unhash(struct inet_timewait_sock *tw, __sk_del_bind_node((struct sock *)tw); tw->tw_tb = NULL; tw->tw_tb2 = NULL; - inet_bind2_bucket_destroy(hashinfo->bind2_bucket_cachep, tb2); + inet_bind2_bucket_destroy(tb2); inet_bind_bucket_destroy(tb); __sock_put((struct sock *)tw); @@ -63,7 +61,7 @@ static void inet_twsk_kill(struct inet_timewait_sock *tw) spin_lock(&bhead->lock); spin_lock(&bhead2->lock); - inet_twsk_bind_unhash(tw, hashinfo); + inet_twsk_bind_unhash(tw); spin_unlock(&bhead2->lock); spin_unlock(&bhead->lock); -- 2.43.0