From 6072f7491f5ef391a575e18a1165e72a3eef1601 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 31 Mar 2010 20:11:59 +0000 Subject: [PATCH 1/3] ide: Requeue request after DMA timeout I noticed that my KVM virtual machines were experiencing IDE issues resulting in processes stuck on waiting for buffers to complete. The root cause is of course race conditions in the ancient qemu backend that I'm using. However, the fact that the guest isn't recovering is a bug. I've tracked it down to the change made last year to dequeue requests at the start rather than at the end in the IDE layer. commit 8f6205cd572fece673da0255d74843680f67f879 Author: Tejun Heo Date: Fri May 8 11:53:59 2009 +0900 ide: dequeue in-flight request The problem is that the function ide_dma_timeout_retry does not requeue the current request, causing one request to be lost for each DMA timeout. This patch fixes this by requeueing the request. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- drivers/ide/ide-dma.c | 1 + drivers/ide/ide-io.c | 2 +- include/linux/ide.h | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index ee58c88dee5a..fd40a8116574 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -492,6 +492,7 @@ ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error) if (rq) { hwif->rq = NULL; rq->errors = 0; + ide_requeue_and_plug(drive, rq); } return ret; } diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index db96138fefcd..172ac9218154 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -566,7 +566,7 @@ plug_device_2: blk_plug_device(q); } -static void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq) +void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq) { struct request_queue *q = drive->queue; unsigned long flags; diff --git a/include/linux/ide.h b/include/linux/ide.h index 97e6ab435184..3239d1c10acb 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -1169,6 +1169,7 @@ extern void ide_stall_queue(ide_drive_t *drive, unsigned long timeout); extern void ide_timer_expiry(unsigned long); extern irqreturn_t ide_intr(int irq, void *dev_id); extern void do_ide_request(struct request_queue *); +extern void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq); void ide_init_disk(struct gendisk *, ide_drive_t *); From 1af185034662b75279f90e1c7cb958271d4121e2 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 31 Mar 2010 20:13:39 +0000 Subject: [PATCH 2/3] ide: Must hold queue lock when requeueing ide-atapi requeues requests without holding the queue lock. This patch fixes it by using ide_requeue_and_plug. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- drivers/ide/ide-atapi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c index eb2181a6a11c..9aedb9aa544f 100644 --- a/drivers/ide/ide-atapi.c +++ b/drivers/ide/ide-atapi.c @@ -263,8 +263,8 @@ void ide_retry_pc(ide_drive_t *drive) * of it. The failed command will be retried after sense data * is acquired. */ - blk_requeue_request(failed_rq->q, failed_rq); drive->hwif->rq = NULL; + ide_requeue_and_plug(drive, failed_rq); if (ide_queue_sense_rq(drive, pc)) { blk_start_request(failed_rq); ide_complete_rq(drive, -EIO, blk_rq_bytes(failed_rq)); From 720fc22a7af79d91ec460c80efa92c65c12d105e Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Tue, 6 Apr 2010 16:43:33 -0700 Subject: [PATCH 3/3] ide: Fix IDE taskfile with cfq scheduler When ide taskfile access is being used (for example with hdparm --security commands) and cfq scheduler is selected, the scheduler crashes on BUG in cfq_put_request. The reason is that the cfq scheduler is tracking counts of read and write requests separately; the ide-taskfile subsystem allocates a read request and then flips the flag to make it a write request. The counters in cfq will mismatch. This patch changes ide-taskfile to allocate the READ or WRITE request as required and don't change the flag later. Signed-off-by: Mikulas Patocka Signed-off-by: David S. Miller --- drivers/ide/ide-taskfile.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index cc8633cbe133..67fb73559fd5 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -428,13 +428,11 @@ int ide_raw_taskfile(ide_drive_t *drive, struct ide_cmd *cmd, u8 *buf, { struct request *rq; int error; + int rw = !(cmd->tf_flags & IDE_TFLAG_WRITE) ? READ : WRITE; - rq = blk_get_request(drive->queue, READ, __GFP_WAIT); + rq = blk_get_request(drive->queue, rw, __GFP_WAIT); rq->cmd_type = REQ_TYPE_ATA_TASKFILE; - if (cmd->tf_flags & IDE_TFLAG_WRITE) - rq->cmd_flags |= REQ_RW; - /* * (ks) We transfer currently only whole sectors. * This is suffient for now. But, it would be great,