mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-09-18 22:14:16 +00:00 
			
		
		
		
	ide: fix races in handling of user-space SET XFER commands
* Make cmd->tf_flags field 'u16' and add IDE_TFLAG_SET_XFER taskfile flag. * Update ide_finish_cmd() to set xfer / re-read id if the new flag is set. * Convert set_xfer_rate() (write handler for /proc/ide/hd?/current_speed) and ide_cmd_ioctl() (HDIO_DRIVE_CMD ioctl handler) to use the new flag. * Remove no longer needed disable_irq_nosync() + enable_irq() from ide_config_drive_speed(). Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									fa56d4cb40
								
							
						
					
					
						commit
						665d66e8fa
					
				
					 5 changed files with 14 additions and 26 deletions
				
			
		|  | @ -167,6 +167,8 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg) | |||
| 			err = -EINVAL; | ||||
| 			goto abort; | ||||
| 		} | ||||
| 
 | ||||
| 		cmd.tf_flags |= IDE_TFLAG_SET_XFER; | ||||
| 	} | ||||
| 
 | ||||
| 	err = ide_raw_taskfile(drive, &cmd, buf, args[3]); | ||||
|  | @ -174,12 +176,6 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg) | |||
| 	args[0] = tf->status; | ||||
| 	args[1] = tf->error; | ||||
| 	args[2] = tf->nsect; | ||||
| 
 | ||||
| 	if (!err && xfer_rate) { | ||||
| 		/* active-retuning-calls future */ | ||||
| 		ide_set_xfer_rate(drive, xfer_rate); | ||||
| 		ide_driveid_update(drive); | ||||
| 	} | ||||
| abort: | ||||
| 	if (copy_to_user((void __user *)arg, &args, 4)) | ||||
| 		err = -EFAULT; | ||||
|  |  | |||
|  | @ -363,14 +363,6 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed) | |||
| 	 * this point (lost interrupt). | ||||
| 	 */ | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 *	FIXME: we race against the running IRQ here if | ||||
| 	 *	this is called from non IRQ context. If we use | ||||
| 	 *	disable_irq() we hang on the error path. Work | ||||
| 	 *	is needed. | ||||
| 	 */ | ||||
| 	disable_irq_nosync(hwif->irq); | ||||
| 
 | ||||
| 	udelay(1); | ||||
| 	tp_ops->dev_select(drive); | ||||
| 	SELECT_MASK(drive, 1); | ||||
|  | @ -394,8 +386,6 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed) | |||
| 
 | ||||
| 	SELECT_MASK(drive, 0); | ||||
| 
 | ||||
| 	enable_irq(hwif->irq); | ||||
| 
 | ||||
| 	if (error) { | ||||
| 		(void) ide_dump_status(drive, "set_drive_speed_status", stat); | ||||
| 		return error; | ||||
|  |  | |||
|  | @ -195,7 +195,6 @@ ide_devset_get(xfer_rate, current_speed); | |||
| static int set_xfer_rate (ide_drive_t *drive, int arg) | ||||
| { | ||||
| 	struct ide_cmd cmd; | ||||
| 	int err; | ||||
| 
 | ||||
| 	if (arg < XFER_PIO_0 || arg > XFER_UDMA_6) | ||||
| 		return -EINVAL; | ||||
|  | @ -206,14 +205,9 @@ static int set_xfer_rate (ide_drive_t *drive, int arg) | |||
| 	cmd.tf.nsect   = (u8)arg; | ||||
| 	cmd.valid.out.tf = IDE_VALID_FEATURE | IDE_VALID_NSECT; | ||||
| 	cmd.valid.in.tf  = IDE_VALID_NSECT; | ||||
| 	cmd.tf_flags   = IDE_TFLAG_SET_XFER; | ||||
| 
 | ||||
| 	err = ide_no_data_taskfile(drive, &cmd); | ||||
| 
 | ||||
| 	if (!err) { | ||||
| 		ide_set_xfer_rate(drive, (u8) arg); | ||||
| 		ide_driveid_update(drive); | ||||
| 	} | ||||
| 	return err; | ||||
| 	return ide_no_data_taskfile(drive, &cmd); | ||||
| } | ||||
| 
 | ||||
| ide_devset_rw(current_speed, xfer_rate); | ||||
|  |  | |||
|  | @ -324,10 +324,17 @@ static void ide_error_cmd(ide_drive_t *drive, struct ide_cmd *cmd) | |||
| void ide_finish_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat) | ||||
| { | ||||
| 	struct request *rq = drive->hwif->rq; | ||||
| 	u8 err = ide_read_error(drive); | ||||
| 	u8 err = ide_read_error(drive), nsect = cmd->tf.nsect; | ||||
| 	u8 set_xfer = !!(cmd->tf_flags & IDE_TFLAG_SET_XFER); | ||||
| 
 | ||||
| 	ide_complete_cmd(drive, cmd, stat, err); | ||||
| 	rq->errors = err; | ||||
| 
 | ||||
| 	if (err == 0 && set_xfer) { | ||||
| 		ide_set_xfer_rate(drive, nsect); | ||||
| 		ide_driveid_update(drive); | ||||
| 	} | ||||
| 
 | ||||
| 	ide_complete_rq(drive, err ? -EIO : 0, blk_rq_bytes(rq)); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -258,6 +258,7 @@ enum { | |||
| 	IDE_TFLAG_DYN			= (1 << 5), | ||||
| 	IDE_TFLAG_FS			= (1 << 6), | ||||
| 	IDE_TFLAG_MULTI_PIO		= (1 << 7), | ||||
| 	IDE_TFLAG_SET_XFER		= (1 << 8), | ||||
| }; | ||||
| 
 | ||||
| enum { | ||||
|  | @ -294,7 +295,7 @@ struct ide_cmd { | |||
| 		} out, in; | ||||
| 	} valid; | ||||
| 
 | ||||
| 	u8			tf_flags; | ||||
| 	u16			tf_flags; | ||||
| 	u8			ftf_flags;	/* for TASKFILE ioctl */ | ||||
| 	int			protocol; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Bartlomiej Zolnierkiewicz
						Bartlomiej Zolnierkiewicz