aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ide/ide-io.c
diff options
context:
space:
mode:
authorSuleiman Souhlal <suleiman@google.com>2007-04-10 16:38:37 -0400
committerBartlomiej Zolnierkiewicz <bzolnier@gmail.com>2007-04-10 16:38:37 -0400
commit23450319e2890986c247ec0aa1442f060e657e6d (patch)
treec30fc173d8b97343f8ae7b1b1ed511366af256ab /drivers/ide/ide-io.c
parent90f30eccf41302a2542f5d374af243061902bd98 (diff)
ide: correctly prevent IDE timer expiry function to run if request was already handled
It is possible for the timer expiry function to run even though the request has already been handled: ide_timer_expiry() only checks that the handler is not NULL, but it is possible that we have handled a request (thus clearing the handler) and then started a new request (thus starting the timer again, and setting a handler). A simple way to exhibit this is to set the DMA timeout to 1 jiffy and run dd: The kernel will panic after a few minutes because ide_timer_expiry() tries to add a timer when it's already active. To fix this, we simply add a request generation count that gets incremented at every interrupt, and check in ide_timer_expiry() that we have not already handled a new interrupt before running the expiry function. Signed-off-by: Suleiman Souhlal <suleiman@google.com> Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Diffstat (limited to 'drivers/ide/ide-io.c')
-rw-r--r--drivers/ide/ide-io.c6
1 files changed, 5 insertions, 1 deletions
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 0e0280076fcd..8670112f1d39 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -1226,6 +1226,7 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
1226#endif 1226#endif
1227 /* so that ide_timer_expiry knows what to do */ 1227 /* so that ide_timer_expiry knows what to do */
1228 hwgroup->sleeping = 1; 1228 hwgroup->sleeping = 1;
1229 hwgroup->req_gen_timer = hwgroup->req_gen;
1229 mod_timer(&hwgroup->timer, sleep); 1230 mod_timer(&hwgroup->timer, sleep);
1230 /* we purposely leave hwgroup->busy==1 1231 /* we purposely leave hwgroup->busy==1
1231 * while sleeping */ 1232 * while sleeping */
@@ -1411,7 +1412,8 @@ void ide_timer_expiry (unsigned long data)
1411 1412
1412 spin_lock_irqsave(&ide_lock, flags); 1413 spin_lock_irqsave(&ide_lock, flags);
1413 1414
1414 if ((handler = hwgroup->handler) == NULL) { 1415 if (((handler = hwgroup->handler) == NULL) ||
1416 (hwgroup->req_gen != hwgroup->req_gen_timer)) {
1415 /* 1417 /*
1416 * Either a marginal timeout occurred 1418 * Either a marginal timeout occurred
1417 * (got the interrupt just as timer expired), 1419 * (got the interrupt just as timer expired),
@@ -1439,6 +1441,7 @@ void ide_timer_expiry (unsigned long data)
1439 if ((wait = expiry(drive)) > 0) { 1441 if ((wait = expiry(drive)) > 0) {
1440 /* reset timer */ 1442 /* reset timer */
1441 hwgroup->timer.expires = jiffies + wait; 1443 hwgroup->timer.expires = jiffies + wait;
1444 hwgroup->req_gen_timer = hwgroup->req_gen;
1442 add_timer(&hwgroup->timer); 1445 add_timer(&hwgroup->timer);
1443 spin_unlock_irqrestore(&ide_lock, flags); 1446 spin_unlock_irqrestore(&ide_lock, flags);
1444 return; 1447 return;
@@ -1653,6 +1656,7 @@ irqreturn_t ide_intr (int irq, void *dev_id)
1653 printk(KERN_ERR "%s: ide_intr: hwgroup->busy was 0 ??\n", drive->name); 1656 printk(KERN_ERR "%s: ide_intr: hwgroup->busy was 0 ??\n", drive->name);
1654 } 1657 }
1655 hwgroup->handler = NULL; 1658 hwgroup->handler = NULL;
1659 hwgroup->req_gen++;
1656 del_timer(&hwgroup->timer); 1660 del_timer(&hwgroup->timer);
1657 spin_unlock(&ide_lock); 1661 spin_unlock(&ide_lock);
1658 1662