]> err.no Git - linux-2.6/commitdiff
[PATCH] ide: Fix crash on repeated reset
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Tue, 3 Oct 2006 08:14:33 +0000 (01:14 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Tue, 3 Oct 2006 15:04:08 +0000 (08:04 -0700)
Michal Miroslaw reported a problem (bugzilla #7023) where a user initiated
reset while the IDE layer was already resetting the channel caused a crash,
and provided a rough fix.

This is a slightly cleaner version of the fix which tracks the reset state
and blocks further reset requests while a reset is in progress.

Note this is not a security issue - random end users can't access the
ioctl in question anyway.

Signed-off-by: Alan Cox <alan@redhat.com>
Cc: Michal Miroslaw <mirq-linux@rere.qmqm.pl>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
drivers/ide/ide-iops.c
drivers/ide/ide.c
include/linux/ide.h

index 77703acaec1731164c433d7ce35d2eda0ba15293..badde6331775a12208c375fb68139b0e156d9606 100644 (file)
@@ -998,6 +998,7 @@ static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
        }
        /* done polling */
        hwgroup->polling = 0;
+       hwgroup->resetting = 0;
        return ide_stopped;
 }
 
@@ -1057,6 +1058,7 @@ static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
                }
        }
        hwgroup->polling = 0;   /* done polling */
+       hwgroup->resetting = 0; /* done reset attempt */
        return ide_stopped;
 }
 
@@ -1143,6 +1145,7 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
 
        /* For an ATAPI device, first try an ATAPI SRST. */
        if (drive->media != ide_disk && !do_not_try_atapi) {
+               hwgroup->resetting = 1;
                pre_reset(drive);
                SELECT_DRIVE(drive);
                udelay (20);
@@ -1168,6 +1171,7 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
                return ide_stopped;
        }
 
+       hwgroup->resetting = 1;
        /*
         * Note that we also set nIEN while resetting the device,
         * to mask unwanted interrupts from the interface during the reset.
index 97b162ca988569751afb486ae35dd06987755594..287a66201150a0bd32432817a4357705b767329c 100644 (file)
@@ -1364,6 +1364,11 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
 
                        spin_lock_irqsave(&ide_lock, flags);
 
+                       if (HWGROUP(drive)->resetting) {
+                               spin_unlock_irqrestore(&ide_lock, flags);
+                               return -EBUSY;
+                       }
+
                        ide_abort(drive, "drive reset");
 
                        BUG_ON(HWGROUP(drive)->handler);
index a9a9e33e448f13065c6a6856f5823ad6e67a53e7..07d8d725541fa5c9b26d312671fcd8b974329190 100644 (file)
@@ -825,6 +825,9 @@ typedef struct hwgroup_s {
        unsigned int sleeping   : 1;
                /* BOOL: polling active & poll_timeout field valid */
        unsigned int polling    : 1;
+               /* BOOL: in a polling reset situation. Must not trigger another reset yet */
+       unsigned int resetting  : 1;
+
                /* current drive */
        ide_drive_t *drive;
                /* ptr to current hwif in linked-list */