Phonet: convert bound sockets hash list to RCU
This gets rid of the last spinlock in the Phonet stack proper. Signed-off-by: Rémi Denis-Courmont <remi.denis-courmont@nokia.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
fce55922f5
commit
44f4d5a27e
1 changed files with 21 additions and 24 deletions
|
@ -52,7 +52,7 @@ static int pn_socket_release(struct socket *sock)
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
struct hlist_head hlist[PN_HASHSIZE];
|
struct hlist_head hlist[PN_HASHSIZE];
|
||||||
spinlock_t lock;
|
struct mutex lock;
|
||||||
} pnsocks;
|
} pnsocks;
|
||||||
|
|
||||||
void __init pn_sock_init(void)
|
void __init pn_sock_init(void)
|
||||||
|
@ -61,7 +61,7 @@ void __init pn_sock_init(void)
|
||||||
|
|
||||||
for (i = 0; i < PN_HASHSIZE; i++)
|
for (i = 0; i < PN_HASHSIZE; i++)
|
||||||
INIT_HLIST_HEAD(pnsocks.hlist + i);
|
INIT_HLIST_HEAD(pnsocks.hlist + i);
|
||||||
spin_lock_init(&pnsocks.lock);
|
mutex_init(&pnsocks.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct hlist_head *pn_hash_list(u16 obj)
|
static struct hlist_head *pn_hash_list(u16 obj)
|
||||||
|
@ -82,9 +82,8 @@ struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn)
|
||||||
u8 res = spn->spn_resource;
|
u8 res = spn->spn_resource;
|
||||||
struct hlist_head *hlist = pn_hash_list(obj);
|
struct hlist_head *hlist = pn_hash_list(obj);
|
||||||
|
|
||||||
spin_lock_bh(&pnsocks.lock);
|
rcu_read_lock();
|
||||||
|
sk_for_each_rcu(sknode, node, hlist) {
|
||||||
sk_for_each(sknode, node, hlist) {
|
|
||||||
struct pn_sock *pn = pn_sk(sknode);
|
struct pn_sock *pn = pn_sk(sknode);
|
||||||
BUG_ON(!pn->sobject); /* unbound socket */
|
BUG_ON(!pn->sobject); /* unbound socket */
|
||||||
|
|
||||||
|
@ -107,8 +106,7 @@ struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn)
|
||||||
sock_hold(sknode);
|
sock_hold(sknode);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
spin_unlock_bh(&pnsocks.lock);
|
|
||||||
|
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
@ -119,7 +117,7 @@ void pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb)
|
||||||
struct hlist_head *hlist = pnsocks.hlist;
|
struct hlist_head *hlist = pnsocks.hlist;
|
||||||
unsigned h;
|
unsigned h;
|
||||||
|
|
||||||
spin_lock(&pnsocks.lock);
|
rcu_read_lock();
|
||||||
for (h = 0; h < PN_HASHSIZE; h++) {
|
for (h = 0; h < PN_HASHSIZE; h++) {
|
||||||
struct hlist_node *node;
|
struct hlist_node *node;
|
||||||
struct sock *sknode;
|
struct sock *sknode;
|
||||||
|
@ -140,25 +138,26 @@ void pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb)
|
||||||
}
|
}
|
||||||
hlist++;
|
hlist++;
|
||||||
}
|
}
|
||||||
spin_unlock(&pnsocks.lock);
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pn_sock_hash(struct sock *sk)
|
void pn_sock_hash(struct sock *sk)
|
||||||
{
|
{
|
||||||
struct hlist_head *hlist = pn_hash_list(pn_sk(sk)->sobject);
|
struct hlist_head *hlist = pn_hash_list(pn_sk(sk)->sobject);
|
||||||
|
|
||||||
spin_lock_bh(&pnsocks.lock);
|
mutex_lock(&pnsocks.lock);
|
||||||
sk_add_node(sk, hlist);
|
sk_add_node_rcu(sk, hlist);
|
||||||
spin_unlock_bh(&pnsocks.lock);
|
mutex_unlock(&pnsocks.lock);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(pn_sock_hash);
|
EXPORT_SYMBOL(pn_sock_hash);
|
||||||
|
|
||||||
void pn_sock_unhash(struct sock *sk)
|
void pn_sock_unhash(struct sock *sk)
|
||||||
{
|
{
|
||||||
spin_lock_bh(&pnsocks.lock);
|
mutex_lock(&pnsocks.lock);
|
||||||
sk_del_node_init(sk);
|
sk_del_node_init_rcu(sk);
|
||||||
spin_unlock_bh(&pnsocks.lock);
|
mutex_unlock(&pnsocks.lock);
|
||||||
pn_sock_unbind_all_res(sk);
|
pn_sock_unbind_all_res(sk);
|
||||||
|
synchronize_rcu();
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(pn_sock_unhash);
|
EXPORT_SYMBOL(pn_sock_unhash);
|
||||||
|
|
||||||
|
@ -548,7 +547,7 @@ static struct sock *pn_sock_get_idx(struct seq_file *seq, loff_t pos)
|
||||||
unsigned h;
|
unsigned h;
|
||||||
|
|
||||||
for (h = 0; h < PN_HASHSIZE; h++) {
|
for (h = 0; h < PN_HASHSIZE; h++) {
|
||||||
sk_for_each(sknode, node, hlist) {
|
sk_for_each_rcu(sknode, node, hlist) {
|
||||||
if (!net_eq(net, sock_net(sknode)))
|
if (!net_eq(net, sock_net(sknode)))
|
||||||
continue;
|
continue;
|
||||||
if (!pos)
|
if (!pos)
|
||||||
|
@ -572,9 +571,9 @@ static struct sock *pn_sock_get_next(struct seq_file *seq, struct sock *sk)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *pn_sock_seq_start(struct seq_file *seq, loff_t *pos)
|
static void *pn_sock_seq_start(struct seq_file *seq, loff_t *pos)
|
||||||
__acquires(pnsocks.lock)
|
__acquires(rcu)
|
||||||
{
|
{
|
||||||
spin_lock_bh(&pnsocks.lock);
|
rcu_read_lock();
|
||||||
return *pos ? pn_sock_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
|
return *pos ? pn_sock_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -591,9 +590,9 @@ static void *pn_sock_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pn_sock_seq_stop(struct seq_file *seq, void *v)
|
static void pn_sock_seq_stop(struct seq_file *seq, void *v)
|
||||||
__releases(pnsocks.lock)
|
__releases(rcu)
|
||||||
{
|
{
|
||||||
spin_unlock_bh(&pnsocks.lock);
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pn_sock_seq_show(struct seq_file *seq, void *v)
|
static int pn_sock_seq_show(struct seq_file *seq, void *v)
|
||||||
|
@ -721,13 +720,11 @@ void pn_sock_unbind_all_res(struct sock *sk)
|
||||||
}
|
}
|
||||||
mutex_unlock(&resource_mutex);
|
mutex_unlock(&resource_mutex);
|
||||||
|
|
||||||
if (match == 0)
|
|
||||||
return;
|
|
||||||
synchronize_rcu();
|
|
||||||
while (match > 0) {
|
while (match > 0) {
|
||||||
sock_put(sk);
|
__sock_put(sk);
|
||||||
match--;
|
match--;
|
||||||
}
|
}
|
||||||
|
/* Caller is responsible for RCU sync before final sock_put() */
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PROC_FS
|
#ifdef CONFIG_PROC_FS
|
||||||
|
|
Loading…
Reference in a new issue