Commit 2d8c4ce5 authored by Arnaldo Carvalho de Melo's avatar Arnaldo Carvalho de Melo Committed by David S. Miller

[INET]: Generalise tcp_bind_hash & tcp_inherit_port

This required moving tcp_bucket_cachep to inet_hashinfo.
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@ghostprotocols.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ff21d577
...@@ -14,12 +14,15 @@ ...@@ -14,12 +14,15 @@
#ifndef _INET_HASHTABLES_H #ifndef _INET_HASHTABLES_H
#define _INET_HASHTABLES_H #define _INET_HASHTABLES_H
#include <linux/interrupt.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/types.h> #include <linux/types.h>
#include <net/sock.h>
/* This is for all connections with a full identity, no wildcards. /* This is for all connections with a full identity, no wildcards.
* New scheme, half the table is for TIME_WAIT, the other half is * New scheme, half the table is for TIME_WAIT, the other half is
* for the rest. I'll experiment with dynamic table growth later. * for the rest. I'll experiment with dynamic table growth later.
...@@ -113,6 +116,7 @@ struct inet_hashinfo { ...@@ -113,6 +116,7 @@ struct inet_hashinfo {
atomic_t lhash_users; atomic_t lhash_users;
wait_queue_head_t lhash_wait; wait_queue_head_t lhash_wait;
spinlock_t portalloc_lock; spinlock_t portalloc_lock;
kmem_cache_t *bind_bucket_cachep;
}; };
static inline int inet_ehashfn(const __u32 laddr, const __u16 lport, static inline int inet_ehashfn(const __u32 laddr, const __u16 lport,
...@@ -148,6 +152,9 @@ static inline int inet_bhashfn(const __u16 lport, const int bhash_size) ...@@ -148,6 +152,9 @@ static inline int inet_bhashfn(const __u16 lport, const int bhash_size)
return lport & (bhash_size - 1); return lport & (bhash_size - 1);
} }
extern 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. */ /* These can have wildcards, don't try too hard. */
static inline int inet_lhashfn(const unsigned short num) static inline int inet_lhashfn(const unsigned short num)
{ {
...@@ -159,4 +166,29 @@ static inline int inet_sk_listen_hashfn(const struct sock *sk) ...@@ -159,4 +166,29 @@ static inline int inet_sk_listen_hashfn(const struct sock *sk)
return inet_lhashfn(inet_sk(sk)->num); return inet_lhashfn(inet_sk(sk)->num);
} }
/* Caller must disable local BH processing. */
static inline void __inet_inherit_port(struct inet_hashinfo *table,
struct sock *sk, struct sock *child)
{
const int bhash = inet_bhashfn(inet_sk(child)->num, table->bhash_size);
struct inet_bind_hashbucket *head = &table->bhash[bhash];
struct inet_bind_bucket *tb;
spin_lock(&head->lock);
tb = inet_sk(sk)->bind_hash;
sk_add_bind_node(child, &tb->owners);
inet_sk(child)->bind_hash = tb;
spin_unlock(&head->lock);
}
static inline void inet_inherit_port(struct inet_hashinfo *table,
struct sock *sk, struct sock *child)
{
local_bh_disable();
__inet_inherit_port(table, sk, child);
local_bh_enable();
}
extern void inet_put_port(struct inet_hashinfo *table, struct sock *sk);
#endif /* _INET_HASHTABLES_H */ #endif /* _INET_HASHTABLES_H */
...@@ -51,14 +51,10 @@ extern struct inet_hashinfo tcp_hashinfo; ...@@ -51,14 +51,10 @@ extern struct inet_hashinfo tcp_hashinfo;
#define tcp_lhash_users (tcp_hashinfo.lhash_users) #define tcp_lhash_users (tcp_hashinfo.lhash_users)
#define tcp_lhash_wait (tcp_hashinfo.lhash_wait) #define tcp_lhash_wait (tcp_hashinfo.lhash_wait)
#define tcp_portalloc_lock (tcp_hashinfo.portalloc_lock) #define tcp_portalloc_lock (tcp_hashinfo.portalloc_lock)
#define tcp_bucket_cachep (tcp_hashinfo.bind_bucket_cachep)
extern kmem_cache_t *tcp_bucket_cachep;
extern int tcp_port_rover; extern int tcp_port_rover;
extern void tcp_bind_hash(struct sock *sk, struct inet_bind_bucket *tb,
unsigned short snum);
#if (BITS_PER_LONG == 64) #if (BITS_PER_LONG == 64)
#define TCP_ADDRCMP_ALIGN_BYTES 8 #define TCP_ADDRCMP_ALIGN_BYTES 8
#else #else
...@@ -549,9 +545,6 @@ DECLARE_SNMP_STAT(struct tcp_mib, tcp_statistics); ...@@ -549,9 +545,6 @@ DECLARE_SNMP_STAT(struct tcp_mib, tcp_statistics);
#define TCP_ADD_STATS_BH(field, val) SNMP_ADD_STATS_BH(tcp_statistics, field, val) #define TCP_ADD_STATS_BH(field, val) SNMP_ADD_STATS_BH(tcp_statistics, field, val)
#define TCP_ADD_STATS_USER(field, val) SNMP_ADD_STATS_USER(tcp_statistics, field, val) #define TCP_ADD_STATS_USER(field, val) SNMP_ADD_STATS_USER(tcp_statistics, field, val)
extern void tcp_put_port(struct sock *sk);
extern void tcp_inherit_port(struct sock *sk, struct sock *child);
extern void tcp_v4_err(struct sk_buff *skb, u32); extern void tcp_v4_err(struct sk_buff *skb, u32);
extern void tcp_shutdown (struct sock *sk, int how); extern void tcp_shutdown (struct sock *sk, int how);
...@@ -1268,7 +1261,7 @@ static __inline__ void tcp_set_state(struct sock *sk, int state) ...@@ -1268,7 +1261,7 @@ static __inline__ void tcp_set_state(struct sock *sk, int state)
sk->sk_prot->unhash(sk); sk->sk_prot->unhash(sk);
if (inet_sk(sk)->bind_hash && if (inet_sk(sk)->bind_hash &&
!(sk->sk_userlocks & SOCK_BINDPORT_LOCK)) !(sk->sk_userlocks & SOCK_BINDPORT_LOCK))
tcp_put_port(sk); inet_put_port(&tcp_hashinfo, sk);
/* fall through */ /* fall through */
default: default:
if (oldstate==TCP_ESTABLISHED) if (oldstate==TCP_ESTABLISHED)
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <net/inet_hashtables.h> #include <net/inet_hashtables.h>
...@@ -49,3 +50,42 @@ void inet_bind_bucket_destroy(kmem_cache_t *cachep, struct inet_bind_bucket *tb) ...@@ -49,3 +50,42 @@ void inet_bind_bucket_destroy(kmem_cache_t *cachep, struct inet_bind_bucket *tb)
kmem_cache_free(cachep, tb); kmem_cache_free(cachep, tb);
} }
} }
void inet_bind_hash(struct sock *sk, struct inet_bind_bucket *tb,
const unsigned short snum)
{
struct inet_sock *inet = inet_sk(sk);
inet->num = snum;
sk_add_bind_node(sk, &tb->owners);
inet->bind_hash = tb;
}
EXPORT_SYMBOL(inet_bind_hash);
/*
* Get rid of any references to a local port held by the given sock.
*/
static void __inet_put_port(struct inet_hashinfo *hashinfo, struct sock *sk)
{
struct inet_sock *inet = inet_sk(sk);
const int bhash = inet_bhashfn(inet->num, hashinfo->bhash_size);
struct inet_bind_hashbucket *head = &hashinfo->bhash[bhash];
struct inet_bind_bucket *tb;
spin_lock(&head->lock);
tb = inet->bind_hash;
__sk_del_bind_node(sk);
inet->bind_hash = NULL;
inet->num = 0;
inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb);
spin_unlock(&head->lock);
}
void inet_put_port(struct inet_hashinfo *hashinfo, struct sock *sk)
{
local_bh_disable();
__inet_put_port(hashinfo, sk);
local_bh_enable();
}
EXPORT_SYMBOL(inet_put_port);
...@@ -271,10 +271,6 @@ int sysctl_tcp_fin_timeout = TCP_FIN_TIMEOUT; ...@@ -271,10 +271,6 @@ int sysctl_tcp_fin_timeout = TCP_FIN_TIMEOUT;
DEFINE_SNMP_STAT(struct tcp_mib, tcp_statistics); DEFINE_SNMP_STAT(struct tcp_mib, tcp_statistics);
kmem_cache_t *tcp_bucket_cachep;
EXPORT_SYMBOL_GPL(tcp_bucket_cachep);
kmem_cache_t *tcp_timewait_cachep; kmem_cache_t *tcp_timewait_cachep;
atomic_t tcp_orphan_count = ATOMIC_INIT(0); atomic_t tcp_orphan_count = ATOMIC_INIT(0);
......
...@@ -104,37 +104,6 @@ struct inet_hashinfo __cacheline_aligned tcp_hashinfo = { ...@@ -104,37 +104,6 @@ struct inet_hashinfo __cacheline_aligned tcp_hashinfo = {
int sysctl_local_port_range[2] = { 1024, 4999 }; int sysctl_local_port_range[2] = { 1024, 4999 };
int tcp_port_rover = 1024 - 1; int tcp_port_rover = 1024 - 1;
/* Caller must disable local BH processing. */
static __inline__ void __tcp_inherit_port(struct sock *sk, struct sock *child)
{
struct inet_bind_hashbucket *head =
&tcp_bhash[inet_bhashfn(inet_sk(child)->num,
tcp_bhash_size)];
struct inet_bind_bucket *tb;
spin_lock(&head->lock);
tb = inet_sk(sk)->bind_hash;
sk_add_bind_node(child, &tb->owners);
inet_sk(child)->bind_hash = tb;
spin_unlock(&head->lock);
}
inline void tcp_inherit_port(struct sock *sk, struct sock *child)
{
local_bh_disable();
__tcp_inherit_port(sk, child);
local_bh_enable();
}
void tcp_bind_hash(struct sock *sk, struct inet_bind_bucket *tb,
const unsigned short snum)
{
struct inet_sock *inet = inet_sk(sk);
inet->num = snum;
sk_add_bind_node(sk, &tb->owners);
inet->bind_hash = tb;
}
static inline int tcp_bind_conflict(struct sock *sk, struct inet_bind_bucket *tb) static inline int tcp_bind_conflict(struct sock *sk, struct inet_bind_bucket *tb)
{ {
const u32 sk_rcv_saddr = tcp_v4_rcv_saddr(sk); const u32 sk_rcv_saddr = tcp_v4_rcv_saddr(sk);
...@@ -248,7 +217,7 @@ static int tcp_v4_get_port(struct sock *sk, unsigned short snum) ...@@ -248,7 +217,7 @@ static int tcp_v4_get_port(struct sock *sk, unsigned short snum)
tb->fastreuse = 0; tb->fastreuse = 0;
success: success:
if (!inet_sk(sk)->bind_hash) if (!inet_sk(sk)->bind_hash)
tcp_bind_hash(sk, tb, snum); inet_bind_hash(sk, tb, snum);
BUG_TRAP(inet_sk(sk)->bind_hash == tb); BUG_TRAP(inet_sk(sk)->bind_hash == tb);
ret = 0; ret = 0;
...@@ -259,32 +228,6 @@ static int tcp_v4_get_port(struct sock *sk, unsigned short snum) ...@@ -259,32 +228,6 @@ static int tcp_v4_get_port(struct sock *sk, unsigned short snum)
return ret; return ret;
} }
/* Get rid of any references to a local port held by the
* given sock.
*/
static void __tcp_put_port(struct sock *sk)
{
struct inet_sock *inet = inet_sk(sk);
struct inet_bind_hashbucket *head = &tcp_bhash[inet_bhashfn(inet->num,
tcp_bhash_size)];
struct inet_bind_bucket *tb;
spin_lock(&head->lock);
tb = inet->bind_hash;
__sk_del_bind_node(sk);
inet->bind_hash = NULL;
inet->num = 0;
inet_bind_bucket_destroy(tcp_bucket_cachep, tb);
spin_unlock(&head->lock);
}
void tcp_put_port(struct sock *sk)
{
local_bh_disable();
__tcp_put_port(sk);
local_bh_enable();
}
/* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it can be very bad on SMP. /* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it can be very bad on SMP.
* Look, when several writers sleep and reader wakes them up, all but one * Look, when several writers sleep and reader wakes them up, all but one
* immediately hit write lock and grab all the cpus. Exclusive sleep solves * immediately hit write lock and grab all the cpus. Exclusive sleep solves
...@@ -678,7 +621,7 @@ static inline int tcp_v4_hash_connect(struct sock *sk) ...@@ -678,7 +621,7 @@ static inline int tcp_v4_hash_connect(struct sock *sk)
hint += i; hint += i;
/* Head lock still held and bh's disabled */ /* Head lock still held and bh's disabled */
tcp_bind_hash(sk, tb, port); inet_bind_hash(sk, tb, port);
if (sk_unhashed(sk)) { if (sk_unhashed(sk)) {
inet_sk(sk)->sport = htons(port); inet_sk(sk)->sport = htons(port);
__tcp_v4_hash(sk, 0); __tcp_v4_hash(sk, 0);
...@@ -1537,7 +1480,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, ...@@ -1537,7 +1480,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
tcp_initialize_rcv_mss(newsk); tcp_initialize_rcv_mss(newsk);
__tcp_v4_hash(newsk, 0); __tcp_v4_hash(newsk, 0);
__tcp_inherit_port(sk, newsk); __inet_inherit_port(&tcp_hashinfo, sk, newsk);
return newsk; return newsk;
...@@ -1942,7 +1885,7 @@ int tcp_v4_destroy_sock(struct sock *sk) ...@@ -1942,7 +1885,7 @@ int tcp_v4_destroy_sock(struct sock *sk)
/* Clean up a referenced TCP bind bucket. */ /* Clean up a referenced TCP bind bucket. */
if (inet_sk(sk)->bind_hash) if (inet_sk(sk)->bind_hash)
tcp_put_port(sk); inet_put_port(&tcp_hashinfo, sk);
/* /*
* If sendmsg cached page exists, toss it. * If sendmsg cached page exists, toss it.
...@@ -2486,14 +2429,11 @@ void __init tcp_v4_init(struct net_proto_family *ops) ...@@ -2486,14 +2429,11 @@ void __init tcp_v4_init(struct net_proto_family *ops)
} }
EXPORT_SYMBOL(ipv4_specific); EXPORT_SYMBOL(ipv4_specific);
EXPORT_SYMBOL(tcp_bind_hash);
EXPORT_SYMBOL(inet_bind_bucket_create); EXPORT_SYMBOL(inet_bind_bucket_create);
EXPORT_SYMBOL(tcp_hashinfo); EXPORT_SYMBOL(tcp_hashinfo);
EXPORT_SYMBOL(tcp_inherit_port);
EXPORT_SYMBOL(tcp_listen_wlock); EXPORT_SYMBOL(tcp_listen_wlock);
EXPORT_SYMBOL(tcp_port_rover); EXPORT_SYMBOL(tcp_port_rover);
EXPORT_SYMBOL(tcp_prot); EXPORT_SYMBOL(tcp_prot);
EXPORT_SYMBOL(tcp_put_port);
EXPORT_SYMBOL(tcp_unhash); EXPORT_SYMBOL(tcp_unhash);
EXPORT_SYMBOL(tcp_v4_conn_request); EXPORT_SYMBOL(tcp_v4_conn_request);
EXPORT_SYMBOL(tcp_v4_connect); EXPORT_SYMBOL(tcp_v4_connect);
......
...@@ -205,7 +205,7 @@ static int tcp_v6_get_port(struct sock *sk, unsigned short snum) ...@@ -205,7 +205,7 @@ static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
success: success:
if (!inet_sk(sk)->bind_hash) if (!inet_sk(sk)->bind_hash)
tcp_bind_hash(sk, tb, snum); inet_bind_hash(sk, tb, snum);
BUG_TRAP(inet_sk(sk)->bind_hash == tb); BUG_TRAP(inet_sk(sk)->bind_hash == tb);
ret = 0; ret = 0;
...@@ -597,7 +597,7 @@ static int tcp_v6_hash_connect(struct sock *sk) ...@@ -597,7 +597,7 @@ static int tcp_v6_hash_connect(struct sock *sk)
hint += i; hint += i;
/* Head lock still held and bh's disabled */ /* Head lock still held and bh's disabled */
tcp_bind_hash(sk, tb, port); inet_bind_hash(sk, tb, port);
if (sk_unhashed(sk)) { if (sk_unhashed(sk)) {
inet_sk(sk)->sport = htons(port); inet_sk(sk)->sport = htons(port);
__tcp_v6_hash(sk); __tcp_v6_hash(sk);
...@@ -1536,7 +1536,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, ...@@ -1536,7 +1536,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6; newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6;
__tcp_v6_hash(newsk); __tcp_v6_hash(newsk);
tcp_inherit_port(sk, newsk); inet_inherit_port(&tcp_hashinfo, sk, newsk);
return newsk; return newsk;
......
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