aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBartlomiej Zolnierkiewicz <bzolnier@gmail.com>2009-06-23 07:35:51 -0400
committerDavid S. Miller <davem@davemloft.net>2009-08-07 13:43:00 -0400
commit665d66e8fad60a5a162c4615f27f916ad1a6d567 (patch)
tree2e4f699f4fec1ca4010a39b9dd787fbd5f03b44d
parentfa56d4cb4022c8b313c3b99236e1b87effc3655b (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.c8
-rw-r--r--drivers/ide/ide-iops.c10
-rw-r--r--drivers/ide/ide-proc.c10
-rw-r--r--drivers/ide/ide-taskfile.c9
-rw-r--r--include/linux/ide.h3
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 }
183abort: 179abort:
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);
195static int set_xfer_rate (ide_drive_t *drive, int arg) 195static 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
219ide_devset_rw(current_speed, xfer_rate); 213ide_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)
324void ide_finish_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat) 324void 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
263enum { 264enum {
@@ -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