aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pcmcia
diff options
context:
space:
mode:
authorJiri Slaby <jslaby@suse.cz>2010-03-16 10:57:44 -0400
committerDominik Brodowski <linux@dominikbrodowski.net>2010-03-16 12:54:58 -0400
commit4e06e240dcbb803433ee31bfe89a3e785a77cd3b (patch)
treed303884800eabb74641591383746f440c215891d /drivers/pcmcia
parente794c01b7de40d180417eacbd910e8f31f2fafeb (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.c28
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;
338unlock:
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 */
339EXPORT_SYMBOL(pcmcia_modify_configuration); 343EXPORT_SYMBOL(pcmcia_modify_configuration);
340 344