diff options
author | Elias Oltmanns <eo@nebensachen.de> | 2008-07-16 14:33:48 -0400 |
---|---|---|
committer | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2008-07-16 14:33:48 -0400 |
commit | 79e36a9f54aaf4a52eb2d9520953aa3960e99294 (patch) | |
tree | 70fae17d64a1facde8541184d7139c4bc12d03bf /drivers/ide/ide.c | |
parent | 72a3d651b2fe341a8ae2ca164c395aa3007350cd (diff) |
IDE: Fix HDIO_DRIVE_RESET handling
Currently, the code path executing an HDIO_DRIVE_RESET ioctl is broken
in various ways. Most importantly, it is treated as an out of band
request in an illegal way which may very likely lead to system lock ups.
Use the drive's request queue to avoid this problem (and fix a locking
issue for free along the way).
Signed-off-by: Elias Oltmanns <eo@nebensachen.de>
Cc: "Alan Cox" <alan@lxorguk.ukuu.org.uk>
Cc: "Randy Dunlap" <randy.dunlap@oracle.com>
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Diffstat (limited to 'drivers/ide/ide.c')
-rw-r--r-- | drivers/ide/ide.c | 41 |
1 files changed, 15 insertions, 26 deletions
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 90ae00d4aaf5..1ec983b00511 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c | |||
@@ -529,6 +529,19 @@ static int generic_ide_resume(struct device *dev) | |||
529 | return err; | 529 | return err; |
530 | } | 530 | } |
531 | 531 | ||
532 | static void generic_drive_reset(ide_drive_t *drive) | ||
533 | { | ||
534 | struct request *rq; | ||
535 | |||
536 | rq = blk_get_request(drive->queue, READ, __GFP_WAIT); | ||
537 | rq->cmd_type = REQ_TYPE_SPECIAL; | ||
538 | rq->cmd_len = 1; | ||
539 | rq->cmd[0] = REQ_DRIVE_RESET; | ||
540 | rq->cmd_flags |= REQ_SOFTBARRIER; | ||
541 | blk_execute_rq(drive->queue, NULL, rq, 1); | ||
542 | blk_put_request(rq); | ||
543 | } | ||
544 | |||
532 | int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device *bdev, | 545 | int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device *bdev, |
533 | unsigned int cmd, unsigned long arg) | 546 | unsigned int cmd, unsigned long arg) |
534 | { | 547 | { |
@@ -603,33 +616,9 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device | |||
603 | if (!capable(CAP_SYS_ADMIN)) | 616 | if (!capable(CAP_SYS_ADMIN)) |
604 | return -EACCES; | 617 | return -EACCES; |
605 | 618 | ||
606 | /* | 619 | generic_drive_reset(drive); |
607 | * Abort the current command on the | ||
608 | * group if there is one, taking | ||
609 | * care not to allow anything else | ||
610 | * to be queued and to die on the | ||
611 | * spot if we miss one somehow | ||
612 | */ | ||
613 | |||
614 | spin_lock_irqsave(&ide_lock, flags); | ||
615 | |||
616 | if (HWGROUP(drive)->resetting) { | ||
617 | spin_unlock_irqrestore(&ide_lock, flags); | ||
618 | return -EBUSY; | ||
619 | } | ||
620 | |||
621 | ide_abort(drive, "drive reset"); | ||
622 | |||
623 | BUG_ON(HWGROUP(drive)->handler); | ||
624 | |||
625 | /* Ensure nothing gets queued after we | ||
626 | drop the lock. Reset will clear the busy */ | ||
627 | |||
628 | HWGROUP(drive)->busy = 1; | ||
629 | spin_unlock_irqrestore(&ide_lock, flags); | ||
630 | (void) ide_do_reset(drive); | ||
631 | |||
632 | return 0; | 620 | return 0; |
621 | |||
633 | case HDIO_GET_BUSSTATE: | 622 | case HDIO_GET_BUSSTATE: |
634 | if (!capable(CAP_SYS_ADMIN)) | 623 | if (!capable(CAP_SYS_ADMIN)) |
635 | return -EACCES; | 624 | return -EACCES; |