diff options
author | Jiri Slaby <jslaby@suse.cz> | 2010-03-16 10:57:44 -0400 |
---|---|---|
committer | Dominik Brodowski <linux@dominikbrodowski.net> | 2010-03-16 12:54:58 -0400 |
commit | 4e06e240dcbb803433ee31bfe89a3e785a77cd3b (patch) | |
tree | d303884800eabb74641591383746f440c215891d /drivers/pcmcia | |
parent | e794c01b7de40d180417eacbd910e8f31f2fafeb (diff) |
PCMCIA: resource, fix lock imbalance
Stanse found that one error path (when alloc_skb fails) in netdev_tx
omits to unlock hw_priv->hwlock. Fix that by moving away from unlock in
each fail path. Unlock at one place instead.
Introduced in 94a819f80297e1f635a7cde4ed5317612e512ba7
(pcmcia: assert locking to struct pcmcia_device)
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
Diffstat (limited to 'drivers/pcmcia')
-rw-r--r-- | drivers/pcmcia/pcmcia_resource.c | 28 |
1 files changed, 16 insertions, 12 deletions
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index ef782c09f029..c4612c52e4cb 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c | |||
@@ -256,6 +256,7 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev, | |||
256 | { | 256 | { |
257 | struct pcmcia_socket *s; | 257 | struct pcmcia_socket *s; |
258 | config_t *c; | 258 | config_t *c; |
259 | int ret; | ||
259 | 260 | ||
260 | s = p_dev->socket; | 261 | s = p_dev->socket; |
261 | 262 | ||
@@ -264,13 +265,13 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev, | |||
264 | 265 | ||
265 | if (!(s->state & SOCKET_PRESENT)) { | 266 | if (!(s->state & SOCKET_PRESENT)) { |
266 | dev_dbg(&s->dev, "No card present\n"); | 267 | dev_dbg(&s->dev, "No card present\n"); |
267 | mutex_unlock(&s->ops_mutex); | 268 | ret = -ENODEV; |
268 | return -ENODEV; | 269 | goto unlock; |
269 | } | 270 | } |
270 | if (!(c->state & CONFIG_LOCKED)) { | 271 | if (!(c->state & CONFIG_LOCKED)) { |
271 | dev_dbg(&s->dev, "Configuration isnt't locked\n"); | 272 | dev_dbg(&s->dev, "Configuration isnt't locked\n"); |
272 | mutex_unlock(&s->ops_mutex); | 273 | ret = -EACCES; |
273 | return -EACCES; | 274 | goto unlock; |
274 | } | 275 | } |
275 | 276 | ||
276 | if (mod->Attributes & CONF_IRQ_CHANGE_VALID) { | 277 | if (mod->Attributes & CONF_IRQ_CHANGE_VALID) { |
@@ -286,7 +287,8 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev, | |||
286 | 287 | ||
287 | if (mod->Attributes & CONF_VCC_CHANGE_VALID) { | 288 | if (mod->Attributes & CONF_VCC_CHANGE_VALID) { |
288 | dev_dbg(&s->dev, "changing Vcc is not allowed at this time\n"); | 289 | dev_dbg(&s->dev, "changing Vcc is not allowed at this time\n"); |
289 | return -EINVAL; | 290 | ret = -EINVAL; |
291 | goto unlock; | ||
290 | } | 292 | } |
291 | 293 | ||
292 | /* We only allow changing Vpp1 and Vpp2 to the same value */ | 294 | /* We only allow changing Vpp1 and Vpp2 to the same value */ |
@@ -294,21 +296,21 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev, | |||
294 | (mod->Attributes & CONF_VPP2_CHANGE_VALID)) { | 296 | (mod->Attributes & CONF_VPP2_CHANGE_VALID)) { |
295 | if (mod->Vpp1 != mod->Vpp2) { | 297 | if (mod->Vpp1 != mod->Vpp2) { |
296 | dev_dbg(&s->dev, "Vpp1 and Vpp2 must be the same\n"); | 298 | dev_dbg(&s->dev, "Vpp1 and Vpp2 must be the same\n"); |
297 | mutex_unlock(&s->ops_mutex); | 299 | ret = -EINVAL; |
298 | return -EINVAL; | 300 | goto unlock; |
299 | } | 301 | } |
300 | s->socket.Vpp = mod->Vpp1; | 302 | s->socket.Vpp = mod->Vpp1; |
301 | if (s->ops->set_socket(s, &s->socket)) { | 303 | if (s->ops->set_socket(s, &s->socket)) { |
302 | mutex_unlock(&s->ops_mutex); | ||
303 | dev_printk(KERN_WARNING, &s->dev, | 304 | dev_printk(KERN_WARNING, &s->dev, |
304 | "Unable to set VPP\n"); | 305 | "Unable to set VPP\n"); |
305 | return -EIO; | 306 | ret = -EIO; |
307 | goto unlock; | ||
306 | } | 308 | } |
307 | } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) || | 309 | } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) || |
308 | (mod->Attributes & CONF_VPP2_CHANGE_VALID)) { | 310 | (mod->Attributes & CONF_VPP2_CHANGE_VALID)) { |
309 | dev_dbg(&s->dev, "changing Vcc is not allowed at this time\n"); | 311 | dev_dbg(&s->dev, "changing Vcc is not allowed at this time\n"); |
310 | mutex_unlock(&s->ops_mutex); | 312 | ret = -EINVAL; |
311 | return -EINVAL; | 313 | goto unlock; |
312 | } | 314 | } |
313 | 315 | ||
314 | if (mod->Attributes & CONF_IO_CHANGE_WIDTH) { | 316 | if (mod->Attributes & CONF_IO_CHANGE_WIDTH) { |
@@ -332,9 +334,11 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev, | |||
332 | s->ops->set_io_map(s, &io_on); | 334 | s->ops->set_io_map(s, &io_on); |
333 | } | 335 | } |
334 | } | 336 | } |
337 | ret = 0; | ||
338 | unlock: | ||
335 | mutex_unlock(&s->ops_mutex); | 339 | mutex_unlock(&s->ops_mutex); |
336 | 340 | ||
337 | return 0; | 341 | return ret; |
338 | } /* modify_configuration */ | 342 | } /* modify_configuration */ |
339 | EXPORT_SYMBOL(pcmcia_modify_configuration); | 343 | EXPORT_SYMBOL(pcmcia_modify_configuration); |
340 | 344 | ||