提交 665d66e8 编写于 作者: B Bartlomiej Zolnierkiewicz 提交者: David S. Miller

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: NBartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 fa56d4cb
...@@ -167,6 +167,8 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg) ...@@ -167,6 +167,8 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg)
err = -EINVAL; err = -EINVAL;
goto abort; goto abort;
} }
cmd.tf_flags |= IDE_TFLAG_SET_XFER;
} }
err = ide_raw_taskfile(drive, &cmd, buf, args[3]); 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) ...@@ -174,12 +176,6 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg)
args[0] = tf->status; args[0] = tf->status;
args[1] = tf->error; args[1] = tf->error;
args[2] = tf->nsect; args[2] = tf->nsect;
if (!err && xfer_rate) {
/* active-retuning-calls future */
ide_set_xfer_rate(drive, xfer_rate);
ide_driveid_update(drive);
}
abort: abort:
if (copy_to_user((void __user *)arg, &args, 4)) if (copy_to_user((void __user *)arg, &args, 4))
err = -EFAULT; err = -EFAULT;
......
...@@ -363,14 +363,6 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed) ...@@ -363,14 +363,6 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
* this point (lost interrupt). * 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); udelay(1);
tp_ops->dev_select(drive); tp_ops->dev_select(drive);
SELECT_MASK(drive, 1); SELECT_MASK(drive, 1);
...@@ -394,8 +386,6 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed) ...@@ -394,8 +386,6 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
SELECT_MASK(drive, 0); SELECT_MASK(drive, 0);
enable_irq(hwif->irq);
if (error) { if (error) {
(void) ide_dump_status(drive, "set_drive_speed_status", stat); (void) ide_dump_status(drive, "set_drive_speed_status", stat);
return error; return error;
......
...@@ -195,7 +195,6 @@ ide_devset_get(xfer_rate, current_speed); ...@@ -195,7 +195,6 @@ ide_devset_get(xfer_rate, current_speed);
static int set_xfer_rate (ide_drive_t *drive, int arg) static int set_xfer_rate (ide_drive_t *drive, int arg)
{ {
struct ide_cmd cmd; struct ide_cmd cmd;
int err;
if (arg < XFER_PIO_0 || arg > XFER_UDMA_6) if (arg < XFER_PIO_0 || arg > XFER_UDMA_6)
return -EINVAL; return -EINVAL;
...@@ -206,14 +205,9 @@ static int set_xfer_rate (ide_drive_t *drive, int arg) ...@@ -206,14 +205,9 @@ static int set_xfer_rate (ide_drive_t *drive, int arg)
cmd.tf.nsect = (u8)arg; cmd.tf.nsect = (u8)arg;
cmd.valid.out.tf = IDE_VALID_FEATURE | IDE_VALID_NSECT; cmd.valid.out.tf = IDE_VALID_FEATURE | IDE_VALID_NSECT;
cmd.valid.in.tf = IDE_VALID_NSECT; cmd.valid.in.tf = IDE_VALID_NSECT;
cmd.tf_flags = IDE_TFLAG_SET_XFER;
err = ide_no_data_taskfile(drive, &cmd); return ide_no_data_taskfile(drive, &cmd);
if (!err) {
ide_set_xfer_rate(drive, (u8) arg);
ide_driveid_update(drive);
}
return err;
} }
ide_devset_rw(current_speed, xfer_rate); ide_devset_rw(current_speed, xfer_rate);
......
...@@ -324,10 +324,17 @@ static void ide_error_cmd(ide_drive_t *drive, struct ide_cmd *cmd) ...@@ -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) void ide_finish_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat)
{ {
struct request *rq = drive->hwif->rq; 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); ide_complete_cmd(drive, cmd, stat, err);
rq->errors = 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)); ide_complete_rq(drive, err ? -EIO : 0, blk_rq_bytes(rq));
} }
......
...@@ -258,6 +258,7 @@ enum { ...@@ -258,6 +258,7 @@ enum {
IDE_TFLAG_DYN = (1 << 5), IDE_TFLAG_DYN = (1 << 5),
IDE_TFLAG_FS = (1 << 6), IDE_TFLAG_FS = (1 << 6),
IDE_TFLAG_MULTI_PIO = (1 << 7), IDE_TFLAG_MULTI_PIO = (1 << 7),
IDE_TFLAG_SET_XFER = (1 << 8),
}; };
enum { enum {
...@@ -294,7 +295,7 @@ struct ide_cmd { ...@@ -294,7 +295,7 @@ struct ide_cmd {
} out, in; } out, in;
} valid; } valid;
u8 tf_flags; u16 tf_flags;
u8 ftf_flags; /* for TASKFILE ioctl */ u8 ftf_flags; /* for TASKFILE ioctl */
int protocol; int protocol;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册