Commit 1ca050d9 authored by Oliver Hartkopp's avatar Oliver Hartkopp Committed by David S. Miller

can: convert protocol handling to RCU

This patch removes spin_locks at CAN socket creation time by using RCU.

Inspired by the discussion with Kurt van Dijck and Eric Dumazet the RCU code
was partly derived from af_phonet.c
Signed-off-by: default avatarOliver Hartkopp <socketcan@hartkopp.net>
Reviewed-by: default avatarEric Dumazet <eric.dumazet@gmail.com>
Acked-by: default avatarKurt Van Dijck <kurt.van.dijck@eia.be>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4c844d97
...@@ -85,7 +85,7 @@ static struct kmem_cache *rcv_cache __read_mostly; ...@@ -85,7 +85,7 @@ static struct kmem_cache *rcv_cache __read_mostly;
/* table of registered CAN protocols */ /* table of registered CAN protocols */
static struct can_proto *proto_tab[CAN_NPROTO] __read_mostly; static struct can_proto *proto_tab[CAN_NPROTO] __read_mostly;
static DEFINE_SPINLOCK(proto_tab_lock); static DEFINE_MUTEX(proto_tab_lock);
struct timer_list can_stattimer; /* timer for statistics update */ struct timer_list can_stattimer; /* timer for statistics update */
struct s_stats can_stats; /* packet statistics */ struct s_stats can_stats; /* packet statistics */
...@@ -115,6 +115,19 @@ static void can_sock_destruct(struct sock *sk) ...@@ -115,6 +115,19 @@ static void can_sock_destruct(struct sock *sk)
skb_queue_purge(&sk->sk_receive_queue); skb_queue_purge(&sk->sk_receive_queue);
} }
static struct can_proto *can_try_module_get(int protocol)
{
struct can_proto *cp;
rcu_read_lock();
cp = rcu_dereference(proto_tab[protocol]);
if (cp && !try_module_get(cp->prot->owner))
cp = NULL;
rcu_read_unlock();
return cp;
}
static int can_create(struct net *net, struct socket *sock, int protocol, static int can_create(struct net *net, struct socket *sock, int protocol,
int kern) int kern)
{ {
...@@ -130,9 +143,12 @@ static int can_create(struct net *net, struct socket *sock, int protocol, ...@@ -130,9 +143,12 @@ static int can_create(struct net *net, struct socket *sock, int protocol,
if (!net_eq(net, &init_net)) if (!net_eq(net, &init_net))
return -EAFNOSUPPORT; return -EAFNOSUPPORT;
cp = can_try_module_get(protocol);
#ifdef CONFIG_MODULES #ifdef CONFIG_MODULES
/* try to load protocol module kernel is modular */ if (!cp) {
if (!proto_tab[protocol]) { /* try to load protocol module if kernel is modular */
err = request_module("can-proto-%d", protocol); err = request_module("can-proto-%d", protocol);
/* /*
...@@ -143,22 +159,18 @@ static int can_create(struct net *net, struct socket *sock, int protocol, ...@@ -143,22 +159,18 @@ static int can_create(struct net *net, struct socket *sock, int protocol,
if (err && printk_ratelimit()) if (err && printk_ratelimit())
printk(KERN_ERR "can: request_module " printk(KERN_ERR "can: request_module "
"(can-proto-%d) failed.\n", protocol); "(can-proto-%d) failed.\n", protocol);
cp = can_try_module_get(protocol);
} }
#endif #endif
spin_lock(&proto_tab_lock);
cp = proto_tab[protocol];
if (cp && !try_module_get(cp->prot->owner))
cp = NULL;
spin_unlock(&proto_tab_lock);
/* check for available protocol and correct usage */ /* check for available protocol and correct usage */
if (!cp) if (!cp)
return -EPROTONOSUPPORT; return -EPROTONOSUPPORT;
if (cp->type != sock->type) { if (cp->type != sock->type) {
err = -EPROTONOSUPPORT; err = -EPROTOTYPE;
goto errout; goto errout;
} }
...@@ -694,15 +706,16 @@ int can_proto_register(struct can_proto *cp) ...@@ -694,15 +706,16 @@ int can_proto_register(struct can_proto *cp)
if (err < 0) if (err < 0)
return err; return err;
spin_lock(&proto_tab_lock); mutex_lock(&proto_tab_lock);
if (proto_tab[proto]) { if (proto_tab[proto]) {
printk(KERN_ERR "can: protocol %d already registered\n", printk(KERN_ERR "can: protocol %d already registered\n",
proto); proto);
err = -EBUSY; err = -EBUSY;
} else } else
proto_tab[proto] = cp; rcu_assign_pointer(proto_tab[proto], cp);
spin_unlock(&proto_tab_lock); mutex_unlock(&proto_tab_lock);
if (err < 0) if (err < 0)
proto_unregister(cp->prot); proto_unregister(cp->prot);
...@@ -719,13 +732,12 @@ void can_proto_unregister(struct can_proto *cp) ...@@ -719,13 +732,12 @@ void can_proto_unregister(struct can_proto *cp)
{ {
int proto = cp->protocol; int proto = cp->protocol;
spin_lock(&proto_tab_lock); mutex_lock(&proto_tab_lock);
if (!proto_tab[proto]) { BUG_ON(proto_tab[proto] != cp);
printk(KERN_ERR "BUG: can: protocol %d is not registered\n", rcu_assign_pointer(proto_tab[proto], NULL);
proto); mutex_unlock(&proto_tab_lock);
}
proto_tab[proto] = NULL; synchronize_rcu();
spin_unlock(&proto_tab_lock);
proto_unregister(cp->prot); proto_unregister(cp->prot);
} }
......
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