Commit f452be49 authored by Kuniyuki Iwashima's avatar Kuniyuki Iwashima Committed by Jakub Kicinski

af_unix: Add helpers to calculate hashes.

This patch adds three helper functions that calculate hashes for unbound
sockets and bound sockets with BSD/abstract addresses.
Signed-off-by: default avatarKuniyuki Iwashima <kuniyu@amazon.co.jp>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 5ce7ab49
...@@ -123,15 +123,38 @@ DEFINE_SPINLOCK(unix_table_lock); ...@@ -123,15 +123,38 @@ DEFINE_SPINLOCK(unix_table_lock);
EXPORT_SYMBOL_GPL(unix_table_lock); EXPORT_SYMBOL_GPL(unix_table_lock);
static atomic_long_t unix_nr_socks; static atomic_long_t unix_nr_socks;
/* SMP locking strategy:
* hash table is protected with spinlock unix_table_lock
* each socket state is protected by separate spin lock.
*/
static struct hlist_head *unix_sockets_unbound(void *addr) static unsigned int unix_unbound_hash(struct sock *sk)
{ {
unsigned long hash = (unsigned long)addr; unsigned long hash = (unsigned long)sk;
hash ^= hash >> 16; hash ^= hash >> 16;
hash ^= hash >> 8; hash ^= hash >> 8;
hash %= UNIX_HASH_SIZE; hash ^= sk->sk_type;
return &unix_socket_table[UNIX_HASH_SIZE + hash];
return UNIX_HASH_SIZE + (hash & (UNIX_HASH_SIZE - 1));
}
static unsigned int unix_bsd_hash(struct inode *i)
{
return i->i_ino & (UNIX_HASH_SIZE - 1);
}
static unsigned int unix_abstract_hash(struct sockaddr_un *sunaddr,
int addr_len, int type)
{
__wsum csum = csum_partial(sunaddr, addr_len, 0);
unsigned int hash;
hash = (__force unsigned int)csum_fold(csum);
hash ^= hash >> 8;
hash ^= type;
return hash & (UNIX_HASH_SIZE - 1);
} }
#ifdef CONFIG_SECURITY_NETWORK #ifdef CONFIG_SECURITY_NETWORK
...@@ -162,20 +185,6 @@ static inline bool unix_secdata_eq(struct scm_cookie *scm, struct sk_buff *skb) ...@@ -162,20 +185,6 @@ static inline bool unix_secdata_eq(struct scm_cookie *scm, struct sk_buff *skb)
} }
#endif /* CONFIG_SECURITY_NETWORK */ #endif /* CONFIG_SECURITY_NETWORK */
/*
* SMP locking strategy:
* hash table is protected with spinlock unix_table_lock
* each socket state is protected by separate spin lock.
*/
static inline unsigned int unix_hash_fold(__wsum n)
{
unsigned int hash = (__force unsigned int)csum_fold(n);
hash ^= hash>>8;
return hash&(UNIX_HASH_SIZE-1);
}
#define unix_peer(sk) (unix_sk(sk)->peer) #define unix_peer(sk) (unix_sk(sk)->peer)
static inline int unix_our_peer(struct sock *sk, struct sock *osk) static inline int unix_our_peer(struct sock *sk, struct sock *osk)
...@@ -334,11 +343,11 @@ static inline struct sock *unix_find_socket_byname(struct net *net, ...@@ -334,11 +343,11 @@ static inline struct sock *unix_find_socket_byname(struct net *net,
static struct sock *unix_find_socket_byinode(struct inode *i) static struct sock *unix_find_socket_byinode(struct inode *i)
{ {
unsigned int hash = unix_bsd_hash(i);
struct sock *s; struct sock *s;
spin_lock(&unix_table_lock); spin_lock(&unix_table_lock);
sk_for_each(s, sk_for_each(s, &unix_socket_table[hash]) {
&unix_socket_table[i->i_ino & (UNIX_HASH_SIZE - 1)]) {
struct dentry *dentry = unix_sk(s)->path.dentry; struct dentry *dentry = unix_sk(s)->path.dentry;
if (dentry && d_backing_inode(dentry) == i) { if (dentry && d_backing_inode(dentry) == i) {
...@@ -899,7 +908,7 @@ static struct sock *unix_create1(struct net *net, struct socket *sock, int kern, ...@@ -899,7 +908,7 @@ static struct sock *unix_create1(struct net *net, struct socket *sock, int kern,
init_waitqueue_head(&u->peer_wait); init_waitqueue_head(&u->peer_wait);
init_waitqueue_func_entry(&u->peer_wake, unix_dgram_peer_wake_relay); init_waitqueue_func_entry(&u->peer_wake, unix_dgram_peer_wake_relay);
memset(&u->scm_stat, 0, sizeof(struct scm_stat)); memset(&u->scm_stat, 0, sizeof(struct scm_stat));
unix_insert_socket(unix_sockets_unbound(sk), sk); unix_insert_socket(&unix_socket_table[unix_unbound_hash(sk)], sk);
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
...@@ -1010,11 +1019,11 @@ static struct sock *unix_find_abstract(struct net *net, ...@@ -1010,11 +1019,11 @@ static struct sock *unix_find_abstract(struct net *net,
struct sockaddr_un *sunaddr, struct sockaddr_un *sunaddr,
int addr_len, int type) int addr_len, int type)
{ {
unsigned int hash = unix_hash_fold(csum_partial(sunaddr, addr_len, 0)); unsigned int hash = unix_abstract_hash(sunaddr, addr_len, type);
struct dentry *dentry; struct dentry *dentry;
struct sock *sk; struct sock *sk;
sk = unix_find_socket_byname(net, sunaddr, addr_len, type ^ hash); sk = unix_find_socket_byname(net, sunaddr, addr_len, hash);
if (!sk) if (!sk)
return ERR_PTR(-ECONNREFUSED); return ERR_PTR(-ECONNREFUSED);
...@@ -1066,8 +1075,7 @@ static int unix_autobind(struct sock *sk) ...@@ -1066,8 +1075,7 @@ static int unix_autobind(struct sock *sk)
retry: retry:
addr->len = sprintf(addr->name->sun_path + 1, "%05x", ordernum) + addr->len = sprintf(addr->name->sun_path + 1, "%05x", ordernum) +
offsetof(struct sockaddr_un, sun_path) + 1; offsetof(struct sockaddr_un, sun_path) + 1;
addr->hash = unix_hash_fold(csum_partial(addr->name, addr->len, 0)); addr->hash = unix_abstract_hash(addr->name, addr->len, sk->sk_type);
addr->hash ^= sk->sk_type;
spin_lock(&unix_table_lock); spin_lock(&unix_table_lock);
ordernum = (ordernum+1)&0xFFFFF; ordernum = (ordernum+1)&0xFFFFF;
...@@ -1144,7 +1152,7 @@ static int unix_bind_bsd(struct sock *sk, struct sockaddr_un *sunaddr, ...@@ -1144,7 +1152,7 @@ static int unix_bind_bsd(struct sock *sk, struct sockaddr_un *sunaddr,
goto out_unlock; goto out_unlock;
addr->hash = UNIX_HASH_SIZE; addr->hash = UNIX_HASH_SIZE;
hash = d_backing_inode(dentry)->i_ino & (UNIX_HASH_SIZE - 1); hash = unix_bsd_hash(d_backing_inode(dentry));
spin_lock(&unix_table_lock); spin_lock(&unix_table_lock);
u->path.mnt = mntget(parent.mnt); u->path.mnt = mntget(parent.mnt);
u->path.dentry = dget(dentry); u->path.dentry = dget(dentry);
...@@ -1187,9 +1195,7 @@ static int unix_bind_abstract(struct sock *sk, struct sockaddr_un *sunaddr, ...@@ -1187,9 +1195,7 @@ static int unix_bind_abstract(struct sock *sk, struct sockaddr_un *sunaddr,
goto out_mutex; goto out_mutex;
} }
addr->hash = unix_hash_fold(csum_partial(addr->name, addr->len, 0)); addr->hash = unix_abstract_hash(addr->name, addr->len, sk->sk_type);
addr->hash ^= sk->sk_type;
spin_lock(&unix_table_lock); spin_lock(&unix_table_lock);
if (__unix_find_socket_byname(sock_net(sk), addr->name, addr->len, if (__unix_find_socket_byname(sock_net(sk), addr->name, addr->len,
......
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