diff options
| author | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2009-06-23 07:35:51 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2009-08-07 13:43:00 -0400 |
| commit | 665d66e8fad60a5a162c4615f27f916ad1a6d567 (patch) | |
| tree | 2e4f699f4fec1ca4010a39b9dd787fbd5f03b44d | |
| parent | fa56d4cb4022c8b313c3b99236e1b87effc3655b (diff) | |
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>
| -rw-r--r-- | drivers/ide/ide-ioctls.c | 8 | ||||
| -rw-r--r-- | drivers/ide/ide-iops.c | 10 | ||||
| -rw-r--r-- | drivers/ide/ide-proc.c | 10 | ||||
| -rw-r--r-- | drivers/ide/ide-taskfile.c | 9 | ||||
| -rw-r--r-- | include/linux/ide.h | 3 |
5 files changed, 14 insertions, 26 deletions
diff --git a/drivers/ide/ide-ioctls.c b/drivers/ide/ide-ioctls.c index e246d3d3fbcc..d3440b5010a5 100644 --- a/drivers/ide/ide-ioctls.c +++ b/drivers/ide/ide-ioctls.c | |||
| @@ -167,6 +167,8 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg) | |||
| 167 | err = -EINVAL; | 167 | err = -EINVAL; |
| 168 | goto abort; | 168 | goto abort; |
| 169 | } | 169 | } |
| 170 | |||
| 171 | cmd.tf_flags |= IDE_TFLAG_SET_XFER; | ||
| 170 | } | 172 | } |
| 171 | 173 | ||
| 172 | err = ide_raw_taskfile(drive, &cmd, buf, args[3]); | 174 | 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 | args[0] = tf->status; | 176 | args[0] = tf->status; |
| 175 | args[1] = tf->error; | 177 | args[1] = tf->error; |
| 176 | args[2] = tf->nsect; | 178 | args[2] = tf->nsect; |
| 177 | |||
| 178 | if (!err && xfer_rate) { | ||
| 179 | /* active-retuning-calls future */ | ||
| 180 | ide_set_xfer_rate(drive, xfer_rate); | ||
| 181 | ide_driveid_update(drive); | ||
| 182 | } | ||
| 183 | abort: | 179 | abort: |
| 184 | if (copy_to_user((void __user *)arg, &args, 4)) | 180 | if (copy_to_user((void __user *)arg, &args, 4)) |
| 185 | err = -EFAULT; | 181 | err = -EFAULT; |
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index b99873845d21..b14fa9a87c49 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c | |||
| @@ -363,14 +363,6 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed) | |||
| 363 | * this point (lost interrupt). | 363 | * this point (lost interrupt). |
| 364 | */ | 364 | */ |
| 365 | 365 | ||
| 366 | /* | ||
| 367 | * FIXME: we race against the running IRQ here if | ||
| 368 | * this is called from non IRQ context. If we use | ||
| 369 | * disable_irq() we hang on the error path. Work | ||
| 370 | * is needed. | ||
| 371 | */ | ||
| 372 | disable_irq_nosync(hwif->irq); | ||
| 373 | |||
| 374 | udelay(1); | 366 | udelay(1); |
| 375 | tp_ops->dev_select(drive); | 367 | tp_ops->dev_select(drive); |
| 376 | SELECT_MASK(drive, 1); | 368 | SELECT_MASK(drive, 1); |
| @@ -394,8 +386,6 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed) | |||
| 394 | 386 | ||
| 395 | SELECT_MASK(drive, 0); | 387 | SELECT_MASK(drive, 0); |
| 396 | 388 | ||
| 397 | enable_irq(hwif->irq); | ||
| 398 | |||
| 399 | if (error) { | 389 | if (error) { |
| 400 | (void) ide_dump_status(drive, "set_drive_speed_status", stat); | 390 | (void) ide_dump_status(drive, "set_drive_speed_status", stat); |
| 401 | return error; | 391 | return error; |
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c index 3242698832a4..021de41655e6 100644 --- a/drivers/ide/ide-proc.c +++ b/drivers/ide/ide-proc.c | |||
| @@ -195,7 +195,6 @@ ide_devset_get(xfer_rate, current_speed); | |||
| 195 | static int set_xfer_rate (ide_drive_t *drive, int arg) | 195 | static int set_xfer_rate (ide_drive_t *drive, int arg) |
| 196 | { | 196 | { |
| 197 | struct ide_cmd cmd; | 197 | struct ide_cmd cmd; |
| 198 | int err; | ||
| 199 | 198 | ||
| 200 | if (arg < XFER_PIO_0 || arg > XFER_UDMA_6) | 199 | if (arg < XFER_PIO_0 || arg > XFER_UDMA_6) |
| 201 | return -EINVAL; | 200 | return -EINVAL; |
| @@ -206,14 +205,9 @@ static int set_xfer_rate (ide_drive_t *drive, int arg) | |||
| 206 | cmd.tf.nsect = (u8)arg; | 205 | cmd.tf.nsect = (u8)arg; |
| 207 | cmd.valid.out.tf = IDE_VALID_FEATURE | IDE_VALID_NSECT; | 206 | cmd.valid.out.tf = IDE_VALID_FEATURE | IDE_VALID_NSECT; |
| 208 | cmd.valid.in.tf = IDE_VALID_NSECT; | 207 | cmd.valid.in.tf = IDE_VALID_NSECT; |
| 208 | cmd.tf_flags = IDE_TFLAG_SET_XFER; | ||
| 209 | 209 | ||
| 210 | err = ide_no_data_taskfile(drive, &cmd); | 210 | return ide_no_data_taskfile(drive, &cmd); |
| 211 | |||
| 212 | if (!err) { | ||
| 213 | ide_set_xfer_rate(drive, (u8) arg); | ||
| 214 | ide_driveid_update(drive); | ||
| 215 | } | ||
| 216 | return err; | ||
| 217 | } | 211 | } |
| 218 | 212 | ||
| 219 | ide_devset_rw(current_speed, xfer_rate); | 213 | ide_devset_rw(current_speed, xfer_rate); |
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 50336d51eebc..cc8633cbe133 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c | |||
| @@ -324,10 +324,17 @@ static void ide_error_cmd(ide_drive_t *drive, struct ide_cmd *cmd) | |||
| 324 | void ide_finish_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat) | 324 | void ide_finish_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat) |
| 325 | { | 325 | { |
| 326 | struct request *rq = drive->hwif->rq; | 326 | struct request *rq = drive->hwif->rq; |
| 327 | u8 err = ide_read_error(drive); | 327 | u8 err = ide_read_error(drive), nsect = cmd->tf.nsect; |
| 328 | u8 set_xfer = !!(cmd->tf_flags & IDE_TFLAG_SET_XFER); | ||
| 328 | 329 | ||
| 329 | ide_complete_cmd(drive, cmd, stat, err); | 330 | ide_complete_cmd(drive, cmd, stat, err); |
| 330 | rq->errors = err; | 331 | rq->errors = err; |
| 332 | |||
| 333 | if (err == 0 && set_xfer) { | ||
| 334 | ide_set_xfer_rate(drive, nsect); | ||
| 335 | ide_driveid_update(drive); | ||
| 336 | } | ||
| 337 | |||
| 331 | ide_complete_rq(drive, err ? -EIO : 0, blk_rq_bytes(rq)); | 338 | ide_complete_rq(drive, err ? -EIO : 0, blk_rq_bytes(rq)); |
| 332 | } | 339 | } |
| 333 | 340 | ||
diff --git a/include/linux/ide.h b/include/linux/ide.h index cb6cd0459a5e..803c1ae31237 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h | |||
| @@ -258,6 +258,7 @@ enum { | |||
| 258 | IDE_TFLAG_DYN = (1 << 5), | 258 | IDE_TFLAG_DYN = (1 << 5), |
| 259 | IDE_TFLAG_FS = (1 << 6), | 259 | IDE_TFLAG_FS = (1 << 6), |
| 260 | IDE_TFLAG_MULTI_PIO = (1 << 7), | 260 | IDE_TFLAG_MULTI_PIO = (1 << 7), |
| 261 | IDE_TFLAG_SET_XFER = (1 << 8), | ||
| 261 | }; | 262 | }; |
| 262 | 263 | ||
| 263 | enum { | 264 | enum { |
| @@ -294,7 +295,7 @@ struct ide_cmd { | |||
| 294 | } out, in; | 295 | } out, in; |
| 295 | } valid; | 296 | } valid; |
| 296 | 297 | ||
| 297 | u8 tf_flags; | 298 | u16 tf_flags; |
| 298 | u8 ftf_flags; /* for TASKFILE ioctl */ | 299 | u8 ftf_flags; /* for TASKFILE ioctl */ |
| 299 | int protocol; | 300 | int protocol; |
| 300 | 301 | ||
