mirror of
https://github.com/adulau/aha.git
synced 2024-12-29 12:16:20 +00:00
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>
This commit is contained in:
parent
f68d9320cd
commit
8799620400
1 changed files with 30 additions and 7 deletions
|
@ -1124,17 +1124,40 @@ static int set_io_32bit(ide_drive_t *drive, int arg)
|
|||
static int set_using_dma (ide_drive_t *drive, int arg)
|
||||
{
|
||||
#ifdef CONFIG_BLK_DEV_IDEDMA
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
int err = -EPERM;
|
||||
|
||||
if (!drive->id || !(drive->id->capability & 1))
|
||||
return -EPERM;
|
||||
if (HWIF(drive)->ide_dma_check == NULL)
|
||||
return -EPERM;
|
||||
goto out;
|
||||
|
||||
if (hwif->ide_dma_check == NULL)
|
||||
goto out;
|
||||
|
||||
err = -EBUSY;
|
||||
if (ide_spin_wait_hwgroup(drive))
|
||||
goto out;
|
||||
/*
|
||||
* set ->busy flag, unlock and let it ride
|
||||
*/
|
||||
hwif->hwgroup->busy = 1;
|
||||
spin_unlock_irq(&ide_lock);
|
||||
|
||||
err = 0;
|
||||
|
||||
if (arg) {
|
||||
if (ide_set_dma(drive))
|
||||
return -EIO;
|
||||
if (HWIF(drive)->ide_dma_on(drive)) return -EIO;
|
||||
if (ide_set_dma(drive) || hwif->ide_dma_on(drive))
|
||||
err = -EIO;
|
||||
} else
|
||||
ide_dma_off(drive);
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* lock, clear ->busy flag and unlock before leaving
|
||||
*/
|
||||
spin_lock_irq(&ide_lock);
|
||||
hwif->hwgroup->busy = 0;
|
||||
spin_unlock_irq(&ide_lock);
|
||||
out:
|
||||
return err;
|
||||
#else
|
||||
return -EPERM;
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue