ide: fix ->io_32bit race in ide_taskfile_ioctl()
PATCH 2/20 ide: fix ->io_32bit race in ide_taskfile_ioctl()
In ide_taskfile_ioctl(), there was a race condition involving drive->io_32bit. It was cleared and restored during ioctl requests but there was no synchronization with other requests. So, other requests could execute with the altered ->io_32bit setting or updated drive->io_32bit could be overwritten by ide_taskfile_ioctl().
This patch adds IDE_TFLAG_IO_16BIT flag to indicate to ide_pio_datablock() that 16-bit I/O is needed regardless of drive->io_32bit settting.
Bart:
- ported it over recent IDE changes
Signed-off-by Tejun Heo <[email protected]>
Signed-off-by Bartlomiej Zolnierkiewicz <[email protected]>
--- drivers/ide/ide-taskfile.c | 17 ++++++++++++----- include/linux/ide.h | 2 ++ 2 files changed, 14 insertions(+), 5 deletions(-)
drivers/ide/ide-taskfile.c +12 -5
@@ -346,9 +346,18 @@ static void ide_pio_multi(ide_drive_t *dstatic void ide_pio_datablock (ide_drive_t *drive,struct request *rq,unsigned int write) { +u8 saved_io_32bit = drive->io_32bit; +if (rq->bio)/* fs request */ rq->errors =0 ; +if (rq->cmd_type ==REQ_TYPE_ATA_TASKFILE ) { +ide_task_t *task = rq->special; + +if (task->tf_flags &IDE_TFLAG_IO_16BIT ) + drive->io_32bit =0 ; + } +touch_softlockup_watchdog ();switch (drive->hwif->data_phase) {
@@ -360,6 +369,8 @@ static void ide_pio_datablock(ide_drive_ide_pio_sector (drive, write);break ; } + + drive->io_32bit = saved_io_32bit; } static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq,
@@ -555,7 +566,6 @@ int ide_taskfile_ioctl (ide_drive_t *driunsigned int taskin =0 ;unsigned int taskout =0 ;u16 nsect =0 ; -u8 io_32bit = drive->io_32bit;char __user *buf = (char __user *)arg;// printk("IDE Taskfile ...\n");
@@ -608,7 +618,7 @@ int ide_taskfile_ioctl (ide_drive_t *dri args.data_phase = req_task->data_phase; - args.tf_flags =IDE_TFLAG_OUT_DEVICE ; + args.tf_flags =IDE_TFLAG_IO_16BIT |IDE_TFLAG_OUT_DEVICE ;if (drive->addressing ==1 ) args.tf_flags |=IDE_TFLAG_LBA48 ;
@@ -646,7 +656,6 @@ int ide_taskfile_ioctl (ide_drive_t *driif (req_task->in_flags.b.data) args.tf_flags |=IDE_TFLAG_IN_DATA ; - drive->io_32bit =0 ;switch (req_task->data_phase) {case TASKFILE_MULTI_OUT :if (!drive->mult_count) {
@@ -742,8 +751,6 @@ abort:// printk("IDE Taskfile ioctl ended. rc = %i\n", err); - drive->io_32bit = io_32bit; - return err; }#endif
include/linux/ide.h +2 -0
@@ -931,6 +931,8 @@ enum {IDE_TFLAG_IN_TF =IDE_TFLAG_IN_NSECT |IDE_TFLAG_IN_LBA ,IDE_TFLAG_IN_DEVICE = (1 <<29 ), +/* force 16-bit I/O operations */ + IDE_TFLAG_IO_16BIT = (1 << 30), }; struct ide_taskfile {