Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] ide: Fix crash on repeated reset

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>

authored by

Alan Cox and committed by
Linus Torvalds
913759ac b86cc29d

+12
+4
drivers/ide/ide-iops.c
··· 998 998 } 999 999 /* done polling */ 1000 1000 hwgroup->polling = 0; 1001 + hwgroup->resetting = 0; 1001 1002 return ide_stopped; 1002 1003 } 1003 1004 ··· 1058 1057 } 1059 1058 } 1060 1059 hwgroup->polling = 0; /* done polling */ 1060 + hwgroup->resetting = 0; /* done reset attempt */ 1061 1061 return ide_stopped; 1062 1062 } 1063 1063 ··· 1145 1143 1146 1144 /* For an ATAPI device, first try an ATAPI SRST. */ 1147 1145 if (drive->media != ide_disk && !do_not_try_atapi) { 1146 + hwgroup->resetting = 1; 1148 1147 pre_reset(drive); 1149 1148 SELECT_DRIVE(drive); 1150 1149 udelay (20); ··· 1171 1168 return ide_stopped; 1172 1169 } 1173 1170 1171 + hwgroup->resetting = 1; 1174 1172 /* 1175 1173 * Note that we also set nIEN while resetting the device, 1176 1174 * to mask unwanted interrupts from the interface during the reset.
+5
drivers/ide/ide.c
··· 1364 1364 1365 1365 spin_lock_irqsave(&ide_lock, flags); 1366 1366 1367 + if (HWGROUP(drive)->resetting) { 1368 + spin_unlock_irqrestore(&ide_lock, flags); 1369 + return -EBUSY; 1370 + } 1371 + 1367 1372 ide_abort(drive, "drive reset"); 1368 1373 1369 1374 BUG_ON(HWGROUP(drive)->handler);
+3
include/linux/ide.h
··· 825 825 unsigned int sleeping : 1; 826 826 /* BOOL: polling active & poll_timeout field valid */ 827 827 unsigned int polling : 1; 828 + /* BOOL: in a polling reset situation. Must not trigger another reset yet */ 829 + unsigned int resetting : 1; 830 + 828 831 /* current drive */ 829 832 ide_drive_t *drive; 830 833 /* ptr to current hwif in linked-list */