Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 35cf2b94 authored by Tejun Heo's avatar Tejun Heo Committed by Bartlomiej Zolnierkiewicz
Browse files

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: default avatarTejun Heo <htejun@gmail.com>
Signed-off-by: default avatarBartlomiej Zolnierkiewicz <bzolnier@gmail.com>
parent 63c44678
Loading
Loading
Loading
Loading
+12 −5
Original line number Diff line number Diff line
@@ -346,9 +346,18 @@ static void ide_pio_multi(ide_drive_t *drive, unsigned int write)
static 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_t *drive, struct request *rq,
		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 *drive, unsigned int cmd, unsigned long arg)
	unsigned 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 *drive, unsigned int cmd, unsigned long arg)

	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 *drive, unsigned int cmd, unsigned long arg)
	if (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 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)

//	printk("IDE Taskfile ioctl ended. rc = %i\n", err);

	drive->io_32bit = io_32bit;

	return err;
}
#endif
+2 −0
Original line number Diff line number Diff line
@@ -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 {