diff options
author | Peter Oberparleiter <peter.oberparleiter@de.ibm.com> | 2009-12-07 06:51:15 -0500 |
---|---|---|
committer | Martin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com> | 2009-12-07 06:51:29 -0500 |
commit | 48e4c385c5f54626651cca027afe242439281899 (patch) | |
tree | a2c2b698726fcc0f5b03ee49058fad25c48a746f /drivers | |
parent | cf87b7439ec81b9374e7772e44e9cb2eb9e57160 (diff) |
[S390] cio: fix double free in case of probe failure
io_subchannel_probe() frees memory for sch->private which is later
freed again when io_subchannel_remove() is called. Fix this problem
by removing the cleanup in io_subchannel_probe().
Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/s390/cio/device.c | 11 |
1 files changed, 5 insertions, 6 deletions
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 2490b741e16a..55f997308e42 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -1292,7 +1292,7 @@ static int io_subchannel_probe(struct subchannel *sch) | |||
1292 | sch->private = kzalloc(sizeof(struct io_subchannel_private), | 1292 | sch->private = kzalloc(sizeof(struct io_subchannel_private), |
1293 | GFP_KERNEL | GFP_DMA); | 1293 | GFP_KERNEL | GFP_DMA); |
1294 | if (!sch->private) | 1294 | if (!sch->private) |
1295 | goto out_err; | 1295 | goto out_schedule; |
1296 | /* | 1296 | /* |
1297 | * First check if a fitting device may be found amongst the | 1297 | * First check if a fitting device may be found amongst the |
1298 | * disconnected devices or in the orphanage. | 1298 | * disconnected devices or in the orphanage. |
@@ -1317,7 +1317,7 @@ static int io_subchannel_probe(struct subchannel *sch) | |||
1317 | } | 1317 | } |
1318 | cdev = io_subchannel_create_ccwdev(sch); | 1318 | cdev = io_subchannel_create_ccwdev(sch); |
1319 | if (IS_ERR(cdev)) | 1319 | if (IS_ERR(cdev)) |
1320 | goto out_err; | 1320 | goto out_schedule; |
1321 | rc = io_subchannel_recog(cdev, sch); | 1321 | rc = io_subchannel_recog(cdev, sch); |
1322 | if (rc) { | 1322 | if (rc) { |
1323 | spin_lock_irqsave(sch->lock, flags); | 1323 | spin_lock_irqsave(sch->lock, flags); |
@@ -1325,9 +1325,7 @@ static int io_subchannel_probe(struct subchannel *sch) | |||
1325 | spin_unlock_irqrestore(sch->lock, flags); | 1325 | spin_unlock_irqrestore(sch->lock, flags); |
1326 | } | 1326 | } |
1327 | return 0; | 1327 | return 0; |
1328 | out_err: | 1328 | |
1329 | kfree(sch->private); | ||
1330 | sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group); | ||
1331 | out_schedule: | 1329 | out_schedule: |
1332 | io_subchannel_schedule_removal(sch); | 1330 | io_subchannel_schedule_removal(sch); |
1333 | return 0; | 1331 | return 0; |
@@ -1341,13 +1339,14 @@ io_subchannel_remove (struct subchannel *sch) | |||
1341 | 1339 | ||
1342 | cdev = sch_get_cdev(sch); | 1340 | cdev = sch_get_cdev(sch); |
1343 | if (!cdev) | 1341 | if (!cdev) |
1344 | return 0; | 1342 | goto out_free; |
1345 | /* Set ccw device to not operational and drop reference. */ | 1343 | /* Set ccw device to not operational and drop reference. */ |
1346 | spin_lock_irqsave(cdev->ccwlock, flags); | 1344 | spin_lock_irqsave(cdev->ccwlock, flags); |
1347 | sch_set_cdev(sch, NULL); | 1345 | sch_set_cdev(sch, NULL); |
1348 | cdev->private->state = DEV_STATE_NOT_OPER; | 1346 | cdev->private->state = DEV_STATE_NOT_OPER; |
1349 | spin_unlock_irqrestore(cdev->ccwlock, flags); | 1347 | spin_unlock_irqrestore(cdev->ccwlock, flags); |
1350 | ccw_device_unregister(cdev); | 1348 | ccw_device_unregister(cdev); |
1349 | out_free: | ||
1351 | kfree(sch->private); | 1350 | kfree(sch->private); |
1352 | sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group); | 1351 | sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group); |
1353 | return 0; | 1352 | return 0; |