Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

IDE: fix termination of non-fs requests

ide-disk calls

ide_end_request(drive, 0, 0);

to finish an unknown request, but this doesn't work so well for non-fs
requests, since ide_end_request() internally looks at ->hard_cur_sectors
to see how much data to end. Only file system requests store a transfer
value in there, pc requests fill out ->data_len as a byte based transfer
value instead.

Since we ask to end 0 bytes of that request, it will never be terminated
and ide-disk gets stuck in a loop "handling" that same request over and
over.

Switch __ide_end_request() to take a byte based transfer count, and
adjust ide_end_request() to look at the right field to determine how
much IO to end when it's being passed in 0.

Acked-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Tested-By: Giacomo Catenazzi <cate@debian.org>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Jens Axboe and committed by
Linus Torvalds
41e9d344 275afcac

+11 -6
+11 -6
drivers/ide/ide-io.c
··· 55 55 #include <asm/bitops.h> 56 56 57 57 static int __ide_end_request(ide_drive_t *drive, struct request *rq, 58 - int uptodate, int nr_sectors) 58 + int uptodate, unsigned int nr_bytes) 59 59 { 60 60 int ret = 1; 61 61 ··· 64 64 * complete the whole request right now 65 65 */ 66 66 if (blk_noretry_request(rq) && end_io_error(uptodate)) 67 - nr_sectors = rq->hard_nr_sectors; 67 + nr_bytes = rq->hard_nr_sectors << 9; 68 68 69 69 if (!blk_fs_request(rq) && end_io_error(uptodate) && !rq->errors) 70 70 rq->errors = -EIO; ··· 78 78 HWGROUP(drive)->hwif->ide_dma_on(drive); 79 79 } 80 80 81 - if (!end_that_request_first(rq, uptodate, nr_sectors)) { 81 + if (!end_that_request_chunk(rq, uptodate, nr_bytes)) { 82 82 add_disk_randomness(rq->rq_disk); 83 83 if (!list_empty(&rq->queuelist)) 84 84 blkdev_dequeue_request(rq); ··· 103 103 104 104 int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors) 105 105 { 106 + unsigned int nr_bytes = nr_sectors << 9; 106 107 struct request *rq; 107 108 unsigned long flags; 108 109 int ret = 1; ··· 115 114 spin_lock_irqsave(&ide_lock, flags); 116 115 rq = HWGROUP(drive)->rq; 117 116 118 - if (!nr_sectors) 119 - nr_sectors = rq->hard_cur_sectors; 117 + if (!nr_bytes) { 118 + if (blk_pc_request(rq)) 119 + nr_bytes = rq->data_len; 120 + else 121 + nr_bytes = rq->hard_cur_sectors << 9; 122 + } 120 123 121 - ret = __ide_end_request(drive, rq, uptodate, nr_sectors); 124 + ret = __ide_end_request(drive, rq, uptodate, nr_bytes); 122 125 123 126 spin_unlock_irqrestore(&ide_lock, flags); 124 127 return ret;