Skip to content

Commit

Permalink
af_unix: Add helpers to calculate hashes.
Browse files Browse the repository at this point in the history
This patch adds three helper functions that calculate hashes for unbound
sockets and bound sockets with BSD/abstract addresses.

Signed-off-by: Kuniyuki Iwashima <[email protected]>
Signed-off-by: Jakub Kicinski <[email protected]>
  • Loading branch information
q2ven authored and kuba-moo committed Nov 27, 2021
1 parent 5ce7ab4 commit f452be4
Showing 1 changed file with 35 additions and 29 deletions.
64 changes: 35 additions & 29 deletions net/unix/af_unix.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,15 +123,38 @@ DEFINE_SPINLOCK(unix_table_lock);
EXPORT_SYMBOL_GPL(unix_table_lock);
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 >> 8;
hash %= UNIX_HASH_SIZE;
return &unix_socket_table[UNIX_HASH_SIZE + hash];
hash ^= sk->sk_type;

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
Expand Down Expand Up @@ -162,20 +185,6 @@ static inline bool unix_secdata_eq(struct scm_cookie *scm, struct sk_buff *skb)
}
#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)

static inline int unix_our_peer(struct sock *sk, struct sock *osk)
Expand Down Expand Up @@ -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)
{
unsigned int hash = unix_bsd_hash(i);
struct sock *s;

spin_lock(&unix_table_lock);
sk_for_each(s,
&unix_socket_table[i->i_ino & (UNIX_HASH_SIZE - 1)]) {
sk_for_each(s, &unix_socket_table[hash]) {
struct dentry *dentry = unix_sk(s)->path.dentry;

if (dentry && d_backing_inode(dentry) == i) {
Expand Down Expand Up @@ -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_func_entry(&u->peer_wake, unix_dgram_peer_wake_relay);
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);

Expand Down Expand Up @@ -1010,11 +1019,11 @@ static struct sock *unix_find_abstract(struct net *net,
struct sockaddr_un *sunaddr,
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 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)
return ERR_PTR(-ECONNREFUSED);

Expand Down Expand Up @@ -1066,8 +1075,7 @@ static int unix_autobind(struct sock *sk)
retry:
addr->len = sprintf(addr->name->sun_path + 1, "%05x", ordernum) +
offsetof(struct sockaddr_un, sun_path) + 1;
addr->hash = unix_hash_fold(csum_partial(addr->name, addr->len, 0));
addr->hash ^= sk->sk_type;
addr->hash = unix_abstract_hash(addr->name, addr->len, sk->sk_type);

spin_lock(&unix_table_lock);
ordernum = (ordernum+1)&0xFFFFF;
Expand Down Expand Up @@ -1144,7 +1152,7 @@ static int unix_bind_bsd(struct sock *sk, struct sockaddr_un *sunaddr,
goto out_unlock;

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);
u->path.mnt = mntget(parent.mnt);
u->path.dentry = dget(dentry);
Expand Down Expand Up @@ -1187,9 +1195,7 @@ static int unix_bind_abstract(struct sock *sk, struct sockaddr_un *sunaddr,
goto out_mutex;
}

addr->hash = unix_hash_fold(csum_partial(addr->name, addr->len, 0));
addr->hash ^= sk->sk_type;

addr->hash = unix_abstract_hash(addr->name, addr->len, sk->sk_type);
spin_lock(&unix_table_lock);

if (__unix_find_socket_byname(sock_net(sk), addr->name, addr->len,
Expand Down

0 comments on commit f452be4

Please sign in to comment.