Commit 5a10ecec authored by David S. Miller's avatar David S. Miller

Merge branch 'tw_cleanups'

Eric Dumazet says:

====================
inet: timewait cleanups

Another round of patches to make tw handling simpler.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 8b58a398 dbe7faa4
...@@ -205,8 +205,8 @@ void inet_put_port(struct sock *sk); ...@@ -205,8 +205,8 @@ void inet_put_port(struct sock *sk);
void inet_hashinfo_init(struct inet_hashinfo *h); void inet_hashinfo_init(struct inet_hashinfo *h);
int __inet_hash_nolisten(struct sock *sk, struct inet_timewait_sock *tw); void __inet_hash_nolisten(struct sock *sk, struct sock *osk);
int __inet_hash(struct sock *sk, struct inet_timewait_sock *tw); void __inet_hash(struct sock *sk, struct sock *osk);
void inet_hash(struct sock *sk); void inet_hash(struct sock *sk);
void inet_unhash(struct sock *sk); void inet_unhash(struct sock *sk);
......
...@@ -100,9 +100,7 @@ static inline struct inet_timewait_sock *inet_twsk(const struct sock *sk) ...@@ -100,9 +100,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_free(struct inet_timewait_sock *tw);
void inet_twsk_put(struct inet_timewait_sock *tw); void inet_twsk_put(struct inet_timewait_sock *tw);
int inet_twsk_unhash(struct inet_timewait_sock *tw); void inet_twsk_bind_unhash(struct inet_timewait_sock *tw,
int inet_twsk_bind_unhash(struct inet_timewait_sock *tw,
struct inet_hashinfo *hashinfo); struct inet_hashinfo *hashinfo);
struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk,
...@@ -113,7 +111,7 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk, ...@@ -113,7 +111,7 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk,
struct inet_hashinfo *hashinfo); struct inet_hashinfo *hashinfo);
void inet_twsk_schedule(struct inet_timewait_sock *tw, const int timeo); void inet_twsk_schedule(struct inet_timewait_sock *tw, const int timeo);
void inet_twsk_deschedule(struct inet_timewait_sock *tw); void inet_twsk_deschedule_put(struct inet_timewait_sock *tw);
void inet_twsk_purge(struct inet_hashinfo *hashinfo, void inet_twsk_purge(struct inet_hashinfo *hashinfo,
struct inet_timewait_death_row *twdr, int family); struct inet_timewait_death_row *twdr, int family);
......
...@@ -33,9 +33,6 @@ static inline int twsk_unique(struct sock *sk, struct sock *sktw, void *twp) ...@@ -33,9 +33,6 @@ static inline int twsk_unique(struct sock *sk, struct sock *sktw, void *twp)
static inline void twsk_destructor(struct sock *sk) static inline void twsk_destructor(struct sock *sk)
{ {
BUG_ON(sk == NULL);
BUG_ON(sk->sk_prot == NULL);
BUG_ON(sk->sk_prot->twsk_prot == NULL);
if (sk->sk_prot->twsk_prot->twsk_destructor != NULL) if (sk->sk_prot->twsk_prot->twsk_destructor != NULL)
sk->sk_prot->twsk_prot->twsk_destructor(sk); sk->sk_prot->twsk_prot->twsk_destructor(sk);
} }
......
...@@ -343,7 +343,6 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row, ...@@ -343,7 +343,6 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row,
struct sock *sk2; struct sock *sk2;
const struct hlist_nulls_node *node; const struct hlist_nulls_node *node;
struct inet_timewait_sock *tw = NULL; struct inet_timewait_sock *tw = NULL;
int twrefcnt = 0;
spin_lock(lock); spin_lock(lock);
...@@ -371,21 +370,17 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row, ...@@ -371,21 +370,17 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row,
WARN_ON(!sk_unhashed(sk)); WARN_ON(!sk_unhashed(sk));
__sk_nulls_add_node_rcu(sk, &head->chain); __sk_nulls_add_node_rcu(sk, &head->chain);
if (tw) { if (tw) {
twrefcnt = inet_twsk_unhash(tw); sk_nulls_del_node_init_rcu((struct sock *)tw);
NET_INC_STATS_BH(net, LINUX_MIB_TIMEWAITRECYCLED); NET_INC_STATS_BH(net, LINUX_MIB_TIMEWAITRECYCLED);
} }
spin_unlock(lock); spin_unlock(lock);
if (twrefcnt)
inet_twsk_put(tw);
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
if (twp) { if (twp) {
*twp = tw; *twp = tw;
} else if (tw) { } else if (tw) {
/* Silly. Should hash-dance instead... */ /* Silly. Should hash-dance instead... */
inet_twsk_deschedule(tw); inet_twsk_deschedule_put(tw);
inet_twsk_put(tw);
} }
return 0; return 0;
...@@ -403,13 +398,12 @@ static u32 inet_sk_port_offset(const struct sock *sk) ...@@ -403,13 +398,12 @@ static u32 inet_sk_port_offset(const struct sock *sk)
inet->inet_dport); inet->inet_dport);
} }
int __inet_hash_nolisten(struct sock *sk, struct inet_timewait_sock *tw) void __inet_hash_nolisten(struct sock *sk, struct sock *osk)
{ {
struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo;
struct hlist_nulls_head *list; struct hlist_nulls_head *list;
struct inet_ehash_bucket *head; struct inet_ehash_bucket *head;
spinlock_t *lock; spinlock_t *lock;
int twrefcnt = 0;
WARN_ON(!sk_unhashed(sk)); WARN_ON(!sk_unhashed(sk));
...@@ -420,23 +414,22 @@ int __inet_hash_nolisten(struct sock *sk, struct inet_timewait_sock *tw) ...@@ -420,23 +414,22 @@ int __inet_hash_nolisten(struct sock *sk, struct inet_timewait_sock *tw)
spin_lock(lock); spin_lock(lock);
__sk_nulls_add_node_rcu(sk, list); __sk_nulls_add_node_rcu(sk, list);
if (tw) { if (osk) {
WARN_ON(sk->sk_hash != tw->tw_hash); WARN_ON(sk->sk_hash != osk->sk_hash);
twrefcnt = inet_twsk_unhash(tw); sk_nulls_del_node_init_rcu(osk);
} }
spin_unlock(lock); spin_unlock(lock);
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
return twrefcnt;
} }
EXPORT_SYMBOL_GPL(__inet_hash_nolisten); EXPORT_SYMBOL_GPL(__inet_hash_nolisten);
int __inet_hash(struct sock *sk, struct inet_timewait_sock *tw) void __inet_hash(struct sock *sk, struct sock *osk)
{ {
struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo;
struct inet_listen_hashbucket *ilb; struct inet_listen_hashbucket *ilb;
if (sk->sk_state != TCP_LISTEN) if (sk->sk_state != TCP_LISTEN)
return __inet_hash_nolisten(sk, tw); return __inet_hash_nolisten(sk, osk);
WARN_ON(!sk_unhashed(sk)); WARN_ON(!sk_unhashed(sk));
ilb = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)]; ilb = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)];
...@@ -445,7 +438,6 @@ int __inet_hash(struct sock *sk, struct inet_timewait_sock *tw) ...@@ -445,7 +438,6 @@ int __inet_hash(struct sock *sk, struct inet_timewait_sock *tw)
__sk_nulls_add_node_rcu(sk, &ilb->head); __sk_nulls_add_node_rcu(sk, &ilb->head);
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
spin_unlock(&ilb->lock); spin_unlock(&ilb->lock);
return 0;
} }
EXPORT_SYMBOL(__inet_hash); EXPORT_SYMBOL(__inet_hash);
...@@ -492,7 +484,6 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row, ...@@ -492,7 +484,6 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row,
struct inet_bind_bucket *tb; struct inet_bind_bucket *tb;
int ret; int ret;
struct net *net = sock_net(sk); struct net *net = sock_net(sk);
int twrefcnt = 1;
if (!snum) { if (!snum) {
int i, remaining, low, high, port; int i, remaining, low, high, port;
...@@ -560,19 +551,14 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row, ...@@ -560,19 +551,14 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row,
inet_bind_hash(sk, tb, port); inet_bind_hash(sk, tb, port);
if (sk_unhashed(sk)) { if (sk_unhashed(sk)) {
inet_sk(sk)->inet_sport = htons(port); inet_sk(sk)->inet_sport = htons(port);
twrefcnt += __inet_hash_nolisten(sk, tw); __inet_hash_nolisten(sk, (struct sock *)tw);
} }
if (tw) if (tw)
twrefcnt += inet_twsk_bind_unhash(tw, hinfo); inet_twsk_bind_unhash(tw, hinfo);
spin_unlock(&head->lock); spin_unlock(&head->lock);
if (tw) { if (tw)
inet_twsk_deschedule(tw); inet_twsk_deschedule_put(tw);
while (twrefcnt) {
twrefcnt--;
inet_twsk_put(tw);
}
}
ret = 0; ret = 0;
goto out; goto out;
......
...@@ -17,28 +17,6 @@ ...@@ -17,28 +17,6 @@
#include <net/ip.h> #include <net/ip.h>
/**
* inet_twsk_unhash - unhash a timewait socket from established hash
* @tw: timewait socket
*
* unhash a timewait socket from established hash, if hashed.
* ehash lock must be held by caller.
* Returns 1 if caller should call inet_twsk_put() after lock release.
*/
int inet_twsk_unhash(struct inet_timewait_sock *tw)
{
if (hlist_nulls_unhashed(&tw->tw_node))
return 0;
hlist_nulls_del_rcu(&tw->tw_node);
sk_nulls_node_init(&tw->tw_node);
/*
* We cannot call inet_twsk_put() ourself under lock,
* caller must call it for us.
*/
return 1;
}
/** /**
* inet_twsk_bind_unhash - unhash a timewait socket from bind hash * inet_twsk_bind_unhash - unhash a timewait socket from bind hash
* @tw: timewait socket * @tw: timewait socket
...@@ -48,35 +26,29 @@ int inet_twsk_unhash(struct inet_timewait_sock *tw) ...@@ -48,35 +26,29 @@ int inet_twsk_unhash(struct inet_timewait_sock *tw)
* bind hash lock must be held by caller. * bind hash lock must be held by caller.
* Returns 1 if caller should call inet_twsk_put() after lock release. * Returns 1 if caller should call inet_twsk_put() after lock release.
*/ */
int inet_twsk_bind_unhash(struct inet_timewait_sock *tw, void inet_twsk_bind_unhash(struct inet_timewait_sock *tw,
struct inet_hashinfo *hashinfo) struct inet_hashinfo *hashinfo)
{ {
struct inet_bind_bucket *tb = tw->tw_tb; struct inet_bind_bucket *tb = tw->tw_tb;
if (!tb) if (!tb)
return 0; return;
__hlist_del(&tw->tw_bind_node); __hlist_del(&tw->tw_bind_node);
tw->tw_tb = NULL; tw->tw_tb = NULL;
inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb); inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb);
/* __sock_put((struct sock *)tw);
* We cannot call inet_twsk_put() ourself under lock,
* caller must call it for us.
*/
return 1;
} }
/* Must be called with locally disabled BHs. */ /* Must be called with locally disabled BHs. */
static void inet_twsk_kill(struct inet_timewait_sock *tw) static void inet_twsk_kill(struct inet_timewait_sock *tw)
{ {
struct inet_hashinfo *hashinfo = tw->tw_dr->hashinfo; struct inet_hashinfo *hashinfo = tw->tw_dr->hashinfo;
struct inet_bind_hashbucket *bhead;
int refcnt;
/* Unlink from established hashes. */
spinlock_t *lock = inet_ehash_lockp(hashinfo, tw->tw_hash); spinlock_t *lock = inet_ehash_lockp(hashinfo, tw->tw_hash);
struct inet_bind_hashbucket *bhead;
spin_lock(lock); spin_lock(lock);
refcnt = inet_twsk_unhash(tw); sk_nulls_del_node_init_rcu((struct sock *)tw);
spin_unlock(lock); spin_unlock(lock);
/* Disassociate with bind bucket. */ /* Disassociate with bind bucket. */
...@@ -84,11 +56,9 @@ static void inet_twsk_kill(struct inet_timewait_sock *tw) ...@@ -84,11 +56,9 @@ static void inet_twsk_kill(struct inet_timewait_sock *tw)
hashinfo->bhash_size)]; hashinfo->bhash_size)];
spin_lock(&bhead->lock); spin_lock(&bhead->lock);
refcnt += inet_twsk_bind_unhash(tw, hashinfo); inet_twsk_bind_unhash(tw, hashinfo);
spin_unlock(&bhead->lock); spin_unlock(&bhead->lock);
BUG_ON(refcnt >= atomic_read(&tw->tw_refcnt));
atomic_sub(refcnt, &tw->tw_refcnt);
atomic_dec(&tw->tw_dr->tw_count); atomic_dec(&tw->tw_dr->tw_count);
inet_twsk_put(tw); inet_twsk_put(tw);
} }
...@@ -235,13 +205,17 @@ EXPORT_SYMBOL_GPL(inet_twsk_alloc); ...@@ -235,13 +205,17 @@ EXPORT_SYMBOL_GPL(inet_twsk_alloc);
* tcp_input.c to verify this. * tcp_input.c to verify this.
*/ */
/* This is for handling early-kills of TIME_WAIT sockets. */ /* This is for handling early-kills of TIME_WAIT sockets.
void inet_twsk_deschedule(struct inet_timewait_sock *tw) * Warning : consume reference.
* Caller should not access tw anymore.
*/
void inet_twsk_deschedule_put(struct inet_timewait_sock *tw)
{ {
if (del_timer_sync(&tw->tw_timer)) if (del_timer_sync(&tw->tw_timer))
inet_twsk_kill(tw); inet_twsk_kill(tw);
inet_twsk_put(tw);
} }
EXPORT_SYMBOL(inet_twsk_deschedule); EXPORT_SYMBOL(inet_twsk_deschedule_put);
void inet_twsk_schedule(struct inet_timewait_sock *tw, const int timeo) void inet_twsk_schedule(struct inet_timewait_sock *tw, const int timeo)
{ {
...@@ -311,9 +285,8 @@ void inet_twsk_purge(struct inet_hashinfo *hashinfo, ...@@ -311,9 +285,8 @@ void inet_twsk_purge(struct inet_hashinfo *hashinfo,
rcu_read_unlock(); rcu_read_unlock();
local_bh_disable(); local_bh_disable();
inet_twsk_deschedule(tw); inet_twsk_deschedule_put(tw);
local_bh_enable(); local_bh_enable();
inet_twsk_put(tw);
goto restart_rcu; goto restart_rcu;
} }
/* If the nulls value we got at the end of this lookup is /* If the nulls value we got at the end of this lookup is
......
...@@ -1683,8 +1683,7 @@ int tcp_v4_rcv(struct sk_buff *skb) ...@@ -1683,8 +1683,7 @@ int tcp_v4_rcv(struct sk_buff *skb)
iph->daddr, th->dest, iph->daddr, th->dest,
inet_iif(skb)); inet_iif(skb));
if (sk2) { if (sk2) {
inet_twsk_deschedule(inet_twsk(sk)); inet_twsk_deschedule_put(inet_twsk(sk));
inet_twsk_put(inet_twsk(sk));
sk = sk2; sk = sk2;
goto process; goto process;
} }
......
...@@ -147,8 +147,7 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb, ...@@ -147,8 +147,7 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
if (!th->fin || if (!th->fin ||
TCP_SKB_CB(skb)->end_seq != tcptw->tw_rcv_nxt + 1) { TCP_SKB_CB(skb)->end_seq != tcptw->tw_rcv_nxt + 1) {
kill_with_rst: kill_with_rst:
inet_twsk_deschedule(tw); inet_twsk_deschedule_put(tw);
inet_twsk_put(tw);
return TCP_TW_RST; return TCP_TW_RST;
} }
...@@ -198,8 +197,7 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb, ...@@ -198,8 +197,7 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
*/ */
if (sysctl_tcp_rfc1337 == 0) { if (sysctl_tcp_rfc1337 == 0) {
kill: kill:
inet_twsk_deschedule(tw); inet_twsk_deschedule_put(tw);
inet_twsk_put(tw);
return TCP_TW_SUCCESS; return TCP_TW_SUCCESS;
} }
} }
......
...@@ -207,7 +207,6 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, ...@@ -207,7 +207,6 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
struct sock *sk2; struct sock *sk2;
const struct hlist_nulls_node *node; const struct hlist_nulls_node *node;
struct inet_timewait_sock *tw = NULL; struct inet_timewait_sock *tw = NULL;
int twrefcnt = 0;
spin_lock(lock); spin_lock(lock);
...@@ -234,21 +233,17 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, ...@@ -234,21 +233,17 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
WARN_ON(!sk_unhashed(sk)); WARN_ON(!sk_unhashed(sk));
__sk_nulls_add_node_rcu(sk, &head->chain); __sk_nulls_add_node_rcu(sk, &head->chain);
if (tw) { if (tw) {
twrefcnt = inet_twsk_unhash(tw); sk_nulls_del_node_init_rcu((struct sock *)tw);
NET_INC_STATS_BH(net, LINUX_MIB_TIMEWAITRECYCLED); NET_INC_STATS_BH(net, LINUX_MIB_TIMEWAITRECYCLED);
} }
spin_unlock(lock); spin_unlock(lock);
if (twrefcnt)
inet_twsk_put(tw);
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
if (twp) { if (twp) {
*twp = tw; *twp = tw;
} else if (tw) { } else if (tw) {
/* Silly. Should hash-dance instead... */ /* Silly. Should hash-dance instead... */
inet_twsk_deschedule(tw); inet_twsk_deschedule_put(tw);
inet_twsk_put(tw);
} }
return 0; return 0;
......
...@@ -1481,8 +1481,7 @@ static int tcp_v6_rcv(struct sk_buff *skb) ...@@ -1481,8 +1481,7 @@ static int tcp_v6_rcv(struct sk_buff *skb)
ntohs(th->dest), tcp_v6_iif(skb)); ntohs(th->dest), tcp_v6_iif(skb));
if (sk2) { if (sk2) {
struct inet_timewait_sock *tw = inet_twsk(sk); struct inet_timewait_sock *tw = inet_twsk(sk);
inet_twsk_deschedule(tw); inet_twsk_deschedule_put(tw);
inet_twsk_put(tw);
sk = sk2; sk = sk2;
tcp_v6_restore_cb(skb); tcp_v6_restore_cb(skb);
goto process; goto process;
......
...@@ -272,8 +272,7 @@ tproxy_handle_time_wait4(struct sk_buff *skb, __be32 laddr, __be16 lport, ...@@ -272,8 +272,7 @@ tproxy_handle_time_wait4(struct sk_buff *skb, __be32 laddr, __be16 lport,
hp->source, lport ? lport : hp->dest, hp->source, lport ? lport : hp->dest,
skb->dev, NFT_LOOKUP_LISTENER); skb->dev, NFT_LOOKUP_LISTENER);
if (sk2) { if (sk2) {
inet_twsk_deschedule(inet_twsk(sk)); inet_twsk_deschedule_put(inet_twsk(sk));
inet_twsk_put(inet_twsk(sk));
sk = sk2; sk = sk2;
} }
} }
...@@ -437,8 +436,7 @@ tproxy_handle_time_wait6(struct sk_buff *skb, int tproto, int thoff, ...@@ -437,8 +436,7 @@ tproxy_handle_time_wait6(struct sk_buff *skb, int tproto, int thoff,
tgi->lport ? tgi->lport : hp->dest, tgi->lport ? tgi->lport : hp->dest,
skb->dev, NFT_LOOKUP_LISTENER); skb->dev, NFT_LOOKUP_LISTENER);
if (sk2) { if (sk2) {
inet_twsk_deschedule(inet_twsk(sk)); inet_twsk_deschedule_put(inet_twsk(sk));
inet_twsk_put(inet_twsk(sk));
sk = sk2; sk = sk2;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment