diff options
Diffstat (limited to 'net/can/af_can.c')
-rw-r--r-- | net/can/af_can.c | 67 |
1 files changed, 42 insertions, 25 deletions
diff --git a/net/can/af_can.c b/net/can/af_can.c index 733d66f1b05a..094fc5332d42 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c | |||
@@ -84,8 +84,8 @@ static DEFINE_SPINLOCK(can_rcvlists_lock); | |||
84 | static struct kmem_cache *rcv_cache __read_mostly; | 84 | 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 const 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,11 +115,29 @@ 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 const struct can_proto *can_get_proto(int protocol) | ||
119 | { | ||
120 | const 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 | |||
131 | static inline void can_put_proto(const struct can_proto *cp) | ||
132 | { | ||
133 | module_put(cp->prot->owner); | ||
134 | } | ||
135 | |||
118 | static int can_create(struct net *net, struct socket *sock, int protocol, | 136 | static int can_create(struct net *net, struct socket *sock, int protocol, |
119 | int kern) | 137 | int kern) |
120 | { | 138 | { |
121 | struct sock *sk; | 139 | struct sock *sk; |
122 | struct can_proto *cp; | 140 | const struct can_proto *cp; |
123 | int err = 0; | 141 | int err = 0; |
124 | 142 | ||
125 | sock->state = SS_UNCONNECTED; | 143 | sock->state = SS_UNCONNECTED; |
@@ -130,9 +148,12 @@ static int can_create(struct net *net, struct socket *sock, int protocol, | |||
130 | if (!net_eq(net, &init_net)) | 148 | if (!net_eq(net, &init_net)) |
131 | return -EAFNOSUPPORT; | 149 | return -EAFNOSUPPORT; |
132 | 150 | ||
151 | cp = can_get_proto(protocol); | ||
152 | |||
133 | #ifdef CONFIG_MODULES | 153 | #ifdef CONFIG_MODULES |
134 | /* try to load protocol module kernel is modular */ | 154 | if (!cp) { |
135 | if (!proto_tab[protocol]) { | 155 | /* try to load protocol module if kernel is modular */ |
156 | |||
136 | err = request_module("can-proto-%d", protocol); | 157 | err = request_module("can-proto-%d", protocol); |
137 | 158 | ||
138 | /* | 159 | /* |
@@ -143,22 +164,18 @@ static int can_create(struct net *net, struct socket *sock, int protocol, | |||
143 | if (err && printk_ratelimit()) | 164 | if (err && printk_ratelimit()) |
144 | printk(KERN_ERR "can: request_module " | 165 | printk(KERN_ERR "can: request_module " |
145 | "(can-proto-%d) failed.\n", protocol); | 166 | "(can-proto-%d) failed.\n", protocol); |
167 | |||
168 | cp = can_get_proto(protocol); | ||
146 | } | 169 | } |
147 | #endif | 170 | #endif |
148 | 171 | ||
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 */ | 172 | /* check for available protocol and correct usage */ |
156 | 173 | ||
157 | if (!cp) | 174 | if (!cp) |
158 | return -EPROTONOSUPPORT; | 175 | return -EPROTONOSUPPORT; |
159 | 176 | ||
160 | if (cp->type != sock->type) { | 177 | if (cp->type != sock->type) { |
161 | err = -EPROTONOSUPPORT; | 178 | err = -EPROTOTYPE; |
162 | goto errout; | 179 | goto errout; |
163 | } | 180 | } |
164 | 181 | ||
@@ -183,7 +200,7 @@ static int can_create(struct net *net, struct socket *sock, int protocol, | |||
183 | } | 200 | } |
184 | 201 | ||
185 | errout: | 202 | errout: |
186 | module_put(cp->prot->owner); | 203 | can_put_proto(cp); |
187 | return err; | 204 | return err; |
188 | } | 205 | } |
189 | 206 | ||
@@ -679,7 +696,7 @@ drop: | |||
679 | * -EBUSY protocol already in use | 696 | * -EBUSY protocol already in use |
680 | * -ENOBUF if proto_register() fails | 697 | * -ENOBUF if proto_register() fails |
681 | */ | 698 | */ |
682 | int can_proto_register(struct can_proto *cp) | 699 | int can_proto_register(const struct can_proto *cp) |
683 | { | 700 | { |
684 | int proto = cp->protocol; | 701 | int proto = cp->protocol; |
685 | int err = 0; | 702 | int err = 0; |
@@ -694,15 +711,16 @@ int can_proto_register(struct can_proto *cp) | |||
694 | if (err < 0) | 711 | if (err < 0) |
695 | return err; | 712 | return err; |
696 | 713 | ||
697 | spin_lock(&proto_tab_lock); | 714 | mutex_lock(&proto_tab_lock); |
715 | |||
698 | if (proto_tab[proto]) { | 716 | if (proto_tab[proto]) { |
699 | printk(KERN_ERR "can: protocol %d already registered\n", | 717 | printk(KERN_ERR "can: protocol %d already registered\n", |
700 | proto); | 718 | proto); |
701 | err = -EBUSY; | 719 | err = -EBUSY; |
702 | } else | 720 | } else |
703 | proto_tab[proto] = cp; | 721 | rcu_assign_pointer(proto_tab[proto], cp); |
704 | 722 | ||
705 | spin_unlock(&proto_tab_lock); | 723 | mutex_unlock(&proto_tab_lock); |
706 | 724 | ||
707 | if (err < 0) | 725 | if (err < 0) |
708 | proto_unregister(cp->prot); | 726 | proto_unregister(cp->prot); |
@@ -715,17 +733,16 @@ EXPORT_SYMBOL(can_proto_register); | |||
715 | * can_proto_unregister - unregister CAN transport protocol | 733 | * can_proto_unregister - unregister CAN transport protocol |
716 | * @cp: pointer to CAN protocol structure | 734 | * @cp: pointer to CAN protocol structure |
717 | */ | 735 | */ |
718 | void can_proto_unregister(struct can_proto *cp) | 736 | void can_proto_unregister(const struct can_proto *cp) |
719 | { | 737 | { |
720 | int proto = cp->protocol; | 738 | int proto = cp->protocol; |
721 | 739 | ||
722 | spin_lock(&proto_tab_lock); | 740 | mutex_lock(&proto_tab_lock); |
723 | if (!proto_tab[proto]) { | 741 | BUG_ON(proto_tab[proto] != cp); |
724 | printk(KERN_ERR "BUG: can: protocol %d is not registered\n", | 742 | rcu_assign_pointer(proto_tab[proto], NULL); |
725 | proto); | 743 | mutex_unlock(&proto_tab_lock); |
726 | } | 744 | |
727 | proto_tab[proto] = NULL; | 745 | synchronize_rcu(); |
728 | spin_unlock(&proto_tab_lock); | ||
729 | 746 | ||
730 | proto_unregister(cp->prot); | 747 | proto_unregister(cp->prot); |
731 | } | 748 | } |