Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=23450319e2890986c247ec0aa1442f060e657e6d
Commit:     23450319e2890986c247ec0aa1442f060e657e6d
Parent:     90f30eccf41302a2542f5d374af243061902bd98
Author:     Suleiman Souhlal <[EMAIL PROTECTED]>
AuthorDate: Tue Apr 10 22:38:37 2007 +0200
Committer:  Bartlomiej Zolnierkiewicz <[EMAIL PROTECTED]>
CommitDate: Tue Apr 10 22:38:37 2007 +0200

    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 <[EMAIL PROTECTED]>
    Signed-off-by: Bartlomiej Zolnierkiewicz <[EMAIL PROTECTED]>
---
 drivers/ide/ide-io.c   |    6 +++++-
 drivers/ide/ide-iops.c |    2 ++
 include/linux/ide.h    |    2 ++
 3 files changed, 9 insertions(+), 1 deletions(-)

diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 0e02800..8670112 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)
 #endif
                                /* so that ide_timer_expiry knows what to do */
                                hwgroup->sleeping = 1;
+                               hwgroup->req_gen_timer = hwgroup->req_gen;
                                mod_timer(&hwgroup->timer, sleep);
                                /* we purposely leave hwgroup->busy==1
                                 * while sleeping */
@@ -1411,7 +1412,8 @@ void ide_timer_expiry (unsigned long data)
 
        spin_lock_irqsave(&ide_lock, flags);
 
-       if ((handler = hwgroup->handler) == NULL) {
+       if (((handler = hwgroup->handler) == NULL) ||
+           (hwgroup->req_gen != hwgroup->req_gen_timer)) {
                /*
                 * Either a marginal timeout occurred
                 * (got the interrupt just as timer expired),
@@ -1439,6 +1441,7 @@ void ide_timer_expiry (unsigned long data)
                                if ((wait = expiry(drive)) > 0) {
                                        /* reset timer */
                                        hwgroup->timer.expires  = jiffies + 
wait;
+                                       hwgroup->req_gen_timer = 
hwgroup->req_gen;
                                        add_timer(&hwgroup->timer);
                                        spin_unlock_irqrestore(&ide_lock, 
flags);
                                        return;
@@ -1653,6 +1656,7 @@ irqreturn_t ide_intr (int irq, void *dev_id)
                printk(KERN_ERR "%s: ide_intr: hwgroup->busy was 0 ??\n", 
drive->name);
        }
        hwgroup->handler = NULL;
+       hwgroup->req_gen++;
        del_timer(&hwgroup->timer);
        spin_unlock(&ide_lock);
 
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index 1ee53a5..3caa176 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -889,6 +889,7 @@ static void __ide_set_handler (ide_drive_t *drive, 
ide_handler_t *handler,
        hwgroup->handler        = handler;
        hwgroup->expiry         = expiry;
        hwgroup->timer.expires  = jiffies + timeout;
+       hwgroup->req_gen_timer = hwgroup->req_gen;
        add_timer(&hwgroup->timer);
 }
 
@@ -929,6 +930,7 @@ void ide_execute_command(ide_drive_t *drive, task_ioreg_t 
cmd, ide_handler_t *ha
        hwgroup->handler        = handler;
        hwgroup->expiry         = expiry;
        hwgroup->timer.expires  = jiffies + timeout;
+       hwgroup->req_gen_timer = hwgroup->req_gen;
        add_timer(&hwgroup->timer);
        hwif->OUTBSYNC(drive, cmd, IDE_COMMAND_REG);
        /* Drive takes 400nS to respond, we must avoid the IRQ being
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 58564a1..d3bbc71 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -861,6 +861,8 @@ typedef struct hwgroup_s {
        int (*expiry)(ide_drive_t *);
                /* ide_system_bus_speed */
        int pio_clock;
+       int req_gen;
+       int req_gen_timer;
 
        unsigned char cmd_buf[4];
 } ide_hwgroup_t;
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to