aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHorst Hummel <horst.hummel@de.ibm.com>2006-02-01 06:06:37 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-02-01 11:53:24 -0500
commitc2ba444d1d871d3f6cd3bc5e7d8e19c48c8c02a4 (patch)
tree668b3251195ee98521d1ef6a3f55f4d6f45e3126
parent57467195d1581e354998d5cc35dfd7a12d6e0a24 (diff)
[PATCH] s390: dasd wait for clear i/o interrupt
The sleep_on function clears a running cqr without waiting for the related interrupt. This can lead to a panic at the time the interrupt is processed because the related memory might already be freed. Wait for clear-interrupt and de-queue cqr prior to return. Signed-off-by: Horst Hummel <horst.hummel@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--drivers/s390/block/dasd.c45
1 files changed, 33 insertions, 12 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 953097c23d62..abdf1ee633e7 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -674,11 +674,8 @@ dasd_term_IO(struct dasd_ccw_req * cqr)
674 rc = ccw_device_clear(device->cdev, (long) cqr); 674 rc = ccw_device_clear(device->cdev, (long) cqr);
675 switch (rc) { 675 switch (rc) {
676 case 0: /* termination successful */ 676 case 0: /* termination successful */
677 if (cqr->retries > 0) { 677 cqr->retries--;
678 cqr->retries--; 678 cqr->status = DASD_CQR_CLEAR;
679 cqr->status = DASD_CQR_CLEAR;
680 } else
681 cqr->status = DASD_CQR_FAILED;
682 cqr->stopclk = get_clock(); 679 cqr->stopclk = get_clock();
683 DBF_DEV_EVENT(DBF_DEBUG, device, 680 DBF_DEV_EVENT(DBF_DEBUG, device,
684 "terminate cqr %p successful", 681 "terminate cqr %p successful",
@@ -1307,7 +1304,7 @@ dasd_tasklet(struct dasd_device * device)
1307 /* Now call the callback function of requests with final status */ 1304 /* Now call the callback function of requests with final status */
1308 list_for_each_safe(l, n, &final_queue) { 1305 list_for_each_safe(l, n, &final_queue) {
1309 cqr = list_entry(l, struct dasd_ccw_req, list); 1306 cqr = list_entry(l, struct dasd_ccw_req, list);
1310 list_del(&cqr->list); 1307 list_del_init(&cqr->list);
1311 if (cqr->callback != NULL) 1308 if (cqr->callback != NULL)
1312 (cqr->callback)(cqr, cqr->callback_data); 1309 (cqr->callback)(cqr, cqr->callback_data);
1313 } 1310 }
@@ -1392,7 +1389,9 @@ _wait_for_wakeup(struct dasd_ccw_req *cqr)
1392 1389
1393 device = cqr->device; 1390 device = cqr->device;
1394 spin_lock_irq(get_ccwdev_lock(device->cdev)); 1391 spin_lock_irq(get_ccwdev_lock(device->cdev));
1395 rc = cqr->status == DASD_CQR_DONE || cqr->status == DASD_CQR_FAILED; 1392 rc = ((cqr->status == DASD_CQR_DONE ||
1393 cqr->status == DASD_CQR_FAILED) &&
1394 list_empty(&cqr->list));
1396 spin_unlock_irq(get_ccwdev_lock(device->cdev)); 1395 spin_unlock_irq(get_ccwdev_lock(device->cdev));
1397 return rc; 1396 return rc;
1398} 1397}
@@ -1456,15 +1455,37 @@ dasd_sleep_on_interruptible(struct dasd_ccw_req * cqr)
1456 while (!finished) { 1455 while (!finished) {
1457 rc = wait_event_interruptible(wait_q, _wait_for_wakeup(cqr)); 1456 rc = wait_event_interruptible(wait_q, _wait_for_wakeup(cqr));
1458 if (rc != -ERESTARTSYS) { 1457 if (rc != -ERESTARTSYS) {
1459 /* Request status is either done or failed. */ 1458 /* Request is final (done or failed) */
1460 rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0; 1459 rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
1461 break; 1460 break;
1462 } 1461 }
1463 spin_lock_irq(get_ccwdev_lock(device->cdev)); 1462 spin_lock_irq(get_ccwdev_lock(device->cdev));
1464 if (cqr->status == DASD_CQR_IN_IO && 1463 switch (cqr->status) {
1465 device->discipline->term_IO(cqr) == 0) { 1464 case DASD_CQR_IN_IO:
1466 list_del(&cqr->list); 1465 /* terminate runnig cqr */
1466 if (device->discipline->term_IO) {
1467 cqr->retries = -1;
1468 device->discipline->term_IO(cqr);
1469 /*nished =
1470 * wait (non-interruptible) for final status
1471 * because signal ist still pending
1472 */
1473 spin_unlock_irq(get_ccwdev_lock(device->cdev));
1474 wait_event(wait_q, _wait_for_wakeup(cqr));
1475 spin_lock_irq(get_ccwdev_lock(device->cdev));
1476 rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
1477 finished = 1;
1478 }
1479 break;
1480 case DASD_CQR_QUEUED:
1481 /* request */
1482 list_del_init(&cqr->list);
1483 rc = -EIO;
1467 finished = 1; 1484 finished = 1;
1485 break;
1486 default:
1487 /* cqr with 'non-interruptable' status - just wait */
1488 break;
1468 } 1489 }
1469 spin_unlock_irq(get_ccwdev_lock(device->cdev)); 1490 spin_unlock_irq(get_ccwdev_lock(device->cdev));
1470 } 1491 }