From: Suleiman Souhlal <ssouhlal@freebsd.org>
To: bzolnier@gmail.com
Cc: linux-ide@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH] Correctly prevent IDE timer expiry function to run if request was already handled
Date: Fri, 6 Apr 2007 17:36:03 +0000 [thread overview]
Message-ID: <20070406173603.GA82722@freefall.freebsd.org> (raw)
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>
---
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 @@ #if 1
#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 dat
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 dat
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 @@ #endif /* CONFIG_BLK_DEV_IDEPCI */
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
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 *dr
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;
next reply other threads:[~2007-04-06 17:36 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-04-06 17:36 Suleiman Souhlal [this message]
2007-04-06 19:22 ` [PATCH] Correctly prevent IDE timer expiry function to run if request was already handled Sergei Shtylyov
2007-04-06 20:55 ` Suleiman Souhlal
2007-04-06 21:09 ` Sergei Shtylyov
2007-04-06 21:35 ` Bartlomiej Zolnierkiewicz
2007-04-06 20:51 ` Bartlomiej Zolnierkiewicz
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20070406173603.GA82722@freefall.freebsd.org \
--to=ssouhlal@freebsd.org \
--cc=bzolnier@gmail.com \
--cc=linux-ide@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).