diff options
author | Oliver Hartkopp <socketcan@hartkopp.net> | 2011-04-05 04:01:16 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-04-06 15:35:51 -0400 |
commit | 1ca050d909add6825224c015d8cec2425b3edf27 (patch) | |
tree | 27a95196fbd913e0ae4ecc69132c40d787a90245 /net/can | |
parent | 4c844d97d269a7ec4a6ba7d530aa876ac64dfb76 (diff) |
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: Oliver Hartkopp <socketcan@hartkopp.net>
Reviewed-by: Eric Dumazet <eric.dumazet@gmail.com>
Acked-by: Kurt Van Dijck <kurt.van.dijck@eia.be>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/can')
-rw-r--r-- | net/can/af_can.c | 52 |
1 files changed, 32 insertions, 20 deletions
diff --git a/net/can/af_can.c b/net/can/af_can.c index 733d66f1b05a..a8dcaa49675a 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c | |||
@@ -85,7 +85,7 @@ static struct kmem_cache *rcv_cache __read_mostly; | |||
85 | 85 | ||
86 | /* table of registered CAN protocols */ | 86 | /* table of registered CAN protocols */ |
87 | static struct can_proto *proto_tab[CAN_NPROTO] __read_mostly; | 87 | static struct can_proto *proto_tab[CAN_NPROTO] __read_mostly; |
88 | static DEFINE_SPINLOCK(proto_tab_lock); | 88 | static DEFINE_MUTEX(proto_tab_lock); |
89 | 89 | ||
90 | struct timer_list can_stattimer; /* timer for statistics update */ | 90 | struct timer_list can_stattimer; /* timer for statistics update */ |
91 | struct s_stats can_stats; /* packet statistics */ | 91 | struct s_stats can_stats; /* packet statistics */ |
@@ -115,6 +115,19 @@ static void can_sock_destruct(struct sock *sk) | |||
115 | skb_queue_purge(&sk->sk_receive_queue); | 115 | skb_queue_purge(&sk->sk_receive_queue); |
116 | } | 116 | } |
117 | 117 | ||
118 | static struct can_proto *can_try_module_get(int protocol) | ||
119 | { | ||
120 | struct can_proto *cp; | ||
121 | |||
122 | rcu_read_lock(); | ||
123 | cp = rcu_dereference(proto_tab[protocol]); | ||
124 | if (cp && !try_module_get(cp->prot->owner)) | ||
125 | cp = NULL; | ||
126 | rcu_read_unlock(); | ||
127 | |||
128 | return cp; | ||
129 | } | ||
130 | |||
118 | static int can_create(struct net *net, struct socket *sock, int protocol, | 131 | static int can_create(struct net *net, struct socket *sock, int protocol, |
119 | int kern) | 132 | int kern) |
120 | { | 133 | { |
@@ -130,9 +143,12 @@ static int can_create(struct net *net, struct socket *sock, int protocol, | |||
130 | if (!net_eq(net, &init_net)) | 143 | if (!net_eq(net, &init_net)) |
131 | return -EAFNOSUPPORT; | 144 | return -EAFNOSUPPORT; |
132 | 145 | ||
146 | cp = can_try_module_get(protocol); | ||
147 | |||
133 | #ifdef CONFIG_MODULES | 148 | #ifdef CONFIG_MODULES |
134 | /* try to load protocol module kernel is modular */ | 149 | if (!cp) { |
135 | if (!proto_tab[protocol]) { | 150 | /* try to load protocol module if kernel is modular */ |
151 | |||
136 | err = request_module("can-proto-%d", protocol); | 152 | err = request_module("can-proto-%d", protocol); |
137 | 153 | ||
138 | /* | 154 | /* |
@@ -143,22 +159,18 @@ static int can_create(struct net *net, struct socket *sock, int protocol, | |||
143 | if (err && printk_ratelimit()) | 159 | if (err && printk_ratelimit()) |
144 | printk(KERN_ERR "can: request_module " | 160 | printk(KERN_ERR "can: request_module " |
145 | "(can-proto-%d) failed.\n", protocol); | 161 | "(can-proto-%d) failed.\n", protocol); |
162 | |||
163 | cp = can_try_module_get(protocol); | ||
146 | } | 164 | } |
147 | #endif | 165 | #endif |
148 | 166 | ||
149 | spin_lock(&proto_tab_lock); | ||
150 | cp = proto_tab[protocol]; | ||
151 | if (cp && !try_module_get(cp->prot->owner)) | ||
152 | cp = NULL; | ||
153 | spin_unlock(&proto_tab_lock); | ||
154 | |||
155 | /* check for available protocol and correct usage */ | 167 | /* check for available protocol and correct usage */ |
156 | 168 | ||
157 | if (!cp) | 169 | if (!cp) |
158 | return -EPROTONOSUPPORT; | 170 | return -EPROTONOSUPPORT; |
159 | 171 | ||
160 | if (cp->type != sock->type) { | 172 | if (cp->type != sock->type) { |
161 | err = -EPROTONOSUPPORT; | 173 | err = -EPROTOTYPE; |
162 | goto errout; | 174 | goto errout; |
163 | } | 175 | } |
164 | 176 | ||
@@ -694,15 +706,16 @@ int can_proto_register(struct can_proto *cp) | |||
694 | if (err < 0) | 706 | if (err < 0) |
695 | return err; | 707 | return err; |
696 | 708 | ||
697 | spin_lock(&proto_tab_lock); | 709 | mutex_lock(&proto_tab_lock); |
710 | |||
698 | if (proto_tab[proto]) { | 711 | if (proto_tab[proto]) { |
699 | printk(KERN_ERR "can: protocol %d already registered\n", | 712 | printk(KERN_ERR "can: protocol %d already registered\n", |
700 | proto); | 713 | proto); |
701 | err = -EBUSY; | 714 | err = -EBUSY; |
702 | } else | 715 | } else |
703 | proto_tab[proto] = cp; | 716 | rcu_assign_pointer(proto_tab[proto], cp); |
704 | 717 | ||
705 | spin_unlock(&proto_tab_lock); | 718 | mutex_unlock(&proto_tab_lock); |
706 | 719 | ||
707 | if (err < 0) | 720 | if (err < 0) |
708 | proto_unregister(cp->prot); | 721 | proto_unregister(cp->prot); |
@@ -719,13 +732,12 @@ void can_proto_unregister(struct can_proto *cp) | |||
719 | { | 732 | { |
720 | int proto = cp->protocol; | 733 | int proto = cp->protocol; |
721 | 734 | ||
722 | spin_lock(&proto_tab_lock); | 735 | mutex_lock(&proto_tab_lock); |
723 | if (!proto_tab[proto]) { | 736 | BUG_ON(proto_tab[proto] != cp); |
724 | printk(KERN_ERR "BUG: can: protocol %d is not registered\n", | 737 | rcu_assign_pointer(proto_tab[proto], NULL); |
725 | proto); | 738 | mutex_unlock(&proto_tab_lock); |
726 | } | 739 | |
727 | proto_tab[proto] = NULL; | 740 | synchronize_rcu(); |
728 | spin_unlock(&proto_tab_lock); | ||
729 | 741 | ||
730 | proto_unregister(cp->prot); | 742 | proto_unregister(cp->prot); |
731 | } | 743 | } |