Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+32 −20
Original line number Diff line number Diff line
@@ -85,7 +85,7 @@ static struct kmem_cache *rcv_cache __read_mostly;

/* table of registered CAN protocols */
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 s_stats    can_stats;       /* packet statistics */
@@ -115,6 +115,19 @@ static void can_sock_destruct(struct sock *sk)
	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,
		      int kern)
{
@@ -130,9 +143,12 @@ static int can_create(struct net *net, struct socket *sock, int protocol,
	if (!net_eq(net, &init_net))
		return -EAFNOSUPPORT;

	cp = can_try_module_get(protocol);

#ifdef CONFIG_MODULES
	/* try to load protocol module kernel is modular */
	if (!proto_tab[protocol]) {
	if (!cp) {
		/* try to load protocol module if kernel is modular */

		err = request_module("can-proto-%d", protocol);

		/*
@@ -143,22 +159,18 @@ static int can_create(struct net *net, struct socket *sock, int protocol,
		if (err && printk_ratelimit())
			printk(KERN_ERR "can: request_module "
			       "(can-proto-%d) failed.\n", protocol);

		cp = can_try_module_get(protocol);
	}
#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 */

	if (!cp)
		return -EPROTONOSUPPORT;

	if (cp->type != sock->type) {
		err = -EPROTONOSUPPORT;
		err = -EPROTOTYPE;
		goto errout;
	}

@@ -694,15 +706,16 @@ int can_proto_register(struct can_proto *cp)
	if (err < 0)
		return err;

	spin_lock(&proto_tab_lock);
	mutex_lock(&proto_tab_lock);

	if (proto_tab[proto]) {
		printk(KERN_ERR "can: protocol %d already registered\n",
		       proto);
		err = -EBUSY;
	} 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)
		proto_unregister(cp->prot);
@@ -719,13 +732,12 @@ void can_proto_unregister(struct can_proto *cp)
{
	int proto = cp->protocol;

	spin_lock(&proto_tab_lock);
	if (!proto_tab[proto]) {
		printk(KERN_ERR "BUG: can: protocol %d is not registered\n",
		       proto);
	}
	proto_tab[proto] = NULL;
	spin_unlock(&proto_tab_lock);
	mutex_lock(&proto_tab_lock);
	BUG_ON(proto_tab[proto] != cp);
	rcu_assign_pointer(proto_tab[proto], NULL);
	mutex_unlock(&proto_tab_lock);

	synchronize_rcu();

	proto_unregister(cp->prot);
}