diff options
author | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2007-03-26 17:03:19 -0400 |
---|---|---|
committer | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2007-03-26 17:03:19 -0400 |
commit | 8799620400b0b1a4729d8be828b5bfb3d2a8db1a (patch) | |
tree | 4c5f3bb3360dddcc9638c4e92ddb7f1f2e0b1578 /drivers/ide | |
parent | f68d9320cd06fdec19735143b42e5197b63165b4 (diff) |
ide: fix locking for manual DMA enable/disable ("hdparm -d")
Since hwif->ide_dma_check and hwif->ide_dma_on never queue any commands
(ide_config_drive_speed() sets transfer mode using polling and has no error
recovery) we are safe with setting hwgroup->busy for the time while DMA
setting for a drive is changed (so it won't race against I/O commands in fly).
I audited briefly all ->ide_dma_check/->ide_dma_on/->tuneproc/->speedproc
implementations and they all look OK wrt to this change.
This patch finally allowed me to close kernel bugzilla bug #8169
(once again thanks to Patrick Horn for reporting the issue & testing patches).
Cc: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Diffstat (limited to 'drivers/ide')
-rw-r--r-- | drivers/ide/ide.c | 37 |
1 files changed, 30 insertions, 7 deletions
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 695610f0e3e4..a6f098fda884 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c | |||
@@ -1124,17 +1124,40 @@ static int set_io_32bit(ide_drive_t *drive, int arg) | |||
1124 | static int set_using_dma (ide_drive_t *drive, int arg) | 1124 | static int set_using_dma (ide_drive_t *drive, int arg) |
1125 | { | 1125 | { |
1126 | #ifdef CONFIG_BLK_DEV_IDEDMA | 1126 | #ifdef CONFIG_BLK_DEV_IDEDMA |
1127 | ide_hwif_t *hwif = drive->hwif; | ||
1128 | int err = -EPERM; | ||
1129 | |||
1127 | if (!drive->id || !(drive->id->capability & 1)) | 1130 | if (!drive->id || !(drive->id->capability & 1)) |
1128 | return -EPERM; | 1131 | goto out; |
1129 | if (HWIF(drive)->ide_dma_check == NULL) | 1132 | |
1130 | return -EPERM; | 1133 | if (hwif->ide_dma_check == NULL) |
1134 | goto out; | ||
1135 | |||
1136 | err = -EBUSY; | ||
1137 | if (ide_spin_wait_hwgroup(drive)) | ||
1138 | goto out; | ||
1139 | /* | ||
1140 | * set ->busy flag, unlock and let it ride | ||
1141 | */ | ||
1142 | hwif->hwgroup->busy = 1; | ||
1143 | spin_unlock_irq(&ide_lock); | ||
1144 | |||
1145 | err = 0; | ||
1146 | |||
1131 | if (arg) { | 1147 | if (arg) { |
1132 | if (ide_set_dma(drive)) | 1148 | if (ide_set_dma(drive) || hwif->ide_dma_on(drive)) |
1133 | return -EIO; | 1149 | err = -EIO; |
1134 | if (HWIF(drive)->ide_dma_on(drive)) return -EIO; | ||
1135 | } else | 1150 | } else |
1136 | ide_dma_off(drive); | 1151 | ide_dma_off(drive); |
1137 | return 0; | 1152 | |
1153 | /* | ||
1154 | * lock, clear ->busy flag and unlock before leaving | ||
1155 | */ | ||
1156 | spin_lock_irq(&ide_lock); | ||
1157 | hwif->hwgroup->busy = 0; | ||
1158 | spin_unlock_irq(&ide_lock); | ||
1159 | out: | ||
1160 | return err; | ||
1138 | #else | 1161 | #else |
1139 | return -EPERM; | 1162 | return -EPERM; |
1140 | #endif | 1163 | #endif |