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>
        }
        /* done polling */
        hwgroup->polling = 0;
+       hwgroup->resetting = 0;
        return ide_stopped;
 }
 
                }
        }
        hwgroup->polling = 0;   /* done polling */
+       hwgroup->resetting = 0; /* done reset attempt */
        return ide_stopped;
 }
 
 
        /* 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);
                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.
 
 
                        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);
 
        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 */