mg_disk: dequeue and track in-flight request

mg_disk has at most single request in flight per device.  Till now,
whenever it needs to access the in-flight request it called
elv_next_request().  This patch makes mg_disk track the in-flight
request directly using mg_host->req and dequeue it when processing
starts.

q->queuedata is set to mg_host so that mg_host can be determined
without fetching request from the queue.

[ Impact: dequeue in-flight request, one elv_next_request() per request ]

Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: unsik Kim <donari75@gmail.com>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
This commit is contained in:
Tejun Heo 2009-05-08 11:54:01 +09:00 committed by Jens Axboe
parent 9a8d23d885
commit 5b36ad6000

View File

@ -135,6 +135,7 @@ struct mg_host {
struct device *dev; struct device *dev;
struct request_queue *breq; struct request_queue *breq;
struct request *req;
spinlock_t lock; spinlock_t lock;
struct gendisk *gd; struct gendisk *gd;
@ -171,17 +172,27 @@ struct mg_host {
static void mg_request(struct request_queue *); static void mg_request(struct request_queue *);
static bool mg_end_request(struct mg_host *host, int err, unsigned int nr_bytes)
{
if (__blk_end_request(host->req, err, nr_bytes))
return true;
host->req = NULL;
return false;
}
static bool mg_end_request_cur(struct mg_host *host, int err)
{
return mg_end_request(host, err, blk_rq_cur_bytes(host->req));
}
static void mg_dump_status(const char *msg, unsigned int stat, static void mg_dump_status(const char *msg, unsigned int stat,
struct mg_host *host) struct mg_host *host)
{ {
char *name = MG_DISK_NAME; char *name = MG_DISK_NAME;
struct request *req;
if (host->breq) { if (host->req)
req = elv_next_request(host->breq); name = host->req->rq_disk->disk_name;
if (req)
name = req->rq_disk->disk_name;
}
printk(KERN_ERR "%s: %s: status=0x%02x { ", name, msg, stat & 0xff); printk(KERN_ERR "%s: %s: status=0x%02x { ", name, msg, stat & 0xff);
if (stat & ATA_BUSY) if (stat & ATA_BUSY)
@ -217,13 +228,9 @@ static void mg_dump_status(const char *msg, unsigned int stat,
printk("AddrMarkNotFound "); printk("AddrMarkNotFound ");
printk("}"); printk("}");
if (host->error & (ATA_BBK | ATA_UNC | ATA_IDNF | ATA_AMNF)) { if (host->error & (ATA_BBK | ATA_UNC | ATA_IDNF | ATA_AMNF)) {
if (host->breq) { if (host->req)
req = elv_next_request(host->breq); printk(", sector=%u",
if (req) (unsigned int)blk_rq_pos(host->req));
printk(", sector=%u",
(unsigned int)blk_rq_pos(req));
}
} }
printk("\n"); printk("\n");
} }
@ -453,11 +460,10 @@ static int mg_disk_init(struct mg_host *host)
static void mg_bad_rw_intr(struct mg_host *host) static void mg_bad_rw_intr(struct mg_host *host)
{ {
struct request *req = elv_next_request(host->breq); if (host->req)
if (req != NULL) if (++host->req->errors >= MG_MAX_ERRORS ||
if (++req->errors >= MG_MAX_ERRORS || host->error == MG_ERR_TIMEOUT)
host->error == MG_ERR_TIMEOUT) mg_end_request_cur(host, -EIO);
__blk_end_request_cur(req, -EIO);
} }
static unsigned int mg_out(struct mg_host *host, static unsigned int mg_out(struct mg_host *host,
@ -515,7 +521,7 @@ static void mg_read(struct request *req)
outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base + outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base +
MG_REG_COMMAND); MG_REG_COMMAND);
} while (__blk_end_request(req, 0, MG_SECTOR_SIZE)); } while (mg_end_request(host, 0, MG_SECTOR_SIZE));
} }
static void mg_write(struct request *req) static void mg_write(struct request *req)
@ -545,14 +551,14 @@ static void mg_write(struct request *req)
outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base + outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base +
MG_REG_COMMAND); MG_REG_COMMAND);
} while (__blk_end_request(req, 0, MG_SECTOR_SIZE)); } while (mg_end_request(host, 0, MG_SECTOR_SIZE));
} }
static void mg_read_intr(struct mg_host *host) static void mg_read_intr(struct mg_host *host)
{ {
struct request *req = host->req;
u32 i; u32 i;
u16 *buff; u16 *buff;
struct request *req;
/* check status */ /* check status */
do { do {
@ -571,7 +577,6 @@ static void mg_read_intr(struct mg_host *host)
ok_to_read: ok_to_read:
/* get current segment of request */ /* get current segment of request */
req = elv_next_request(host->breq);
buff = (u16 *)req->buffer; buff = (u16 *)req->buffer;
/* read 1 sector */ /* read 1 sector */
@ -585,7 +590,7 @@ ok_to_read:
/* send read confirm */ /* send read confirm */
outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND); outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND);
if (__blk_end_request(req, 0, MG_SECTOR_SIZE)) { if (mg_end_request(host, 0, MG_SECTOR_SIZE)) {
/* set handler if read remains */ /* set handler if read remains */
host->mg_do_intr = mg_read_intr; host->mg_do_intr = mg_read_intr;
mod_timer(&host->timer, jiffies + 3 * HZ); mod_timer(&host->timer, jiffies + 3 * HZ);
@ -595,14 +600,11 @@ ok_to_read:
static void mg_write_intr(struct mg_host *host) static void mg_write_intr(struct mg_host *host)
{ {
struct request *req = host->req;
u32 i, j; u32 i, j;
u16 *buff; u16 *buff;
struct request *req;
bool rem; bool rem;
/* get current segment of request */
req = elv_next_request(host->breq);
/* check status */ /* check status */
do { do {
i = inb((unsigned long)host->dev_base + MG_REG_STATUS); i = inb((unsigned long)host->dev_base + MG_REG_STATUS);
@ -619,7 +621,7 @@ static void mg_write_intr(struct mg_host *host)
return; return;
ok_to_write: ok_to_write:
if ((rem = __blk_end_request(req, 0, MG_SECTOR_SIZE))) { if ((rem = mg_end_request(host, 0, MG_SECTOR_SIZE))) {
/* write 1 sector and set handler if remains */ /* write 1 sector and set handler if remains */
buff = (u16 *)req->buffer; buff = (u16 *)req->buffer;
for (j = 0; j < MG_STORAGE_BUFFER_SIZE >> 1; j++) { for (j = 0; j < MG_STORAGE_BUFFER_SIZE >> 1; j++) {
@ -644,44 +646,47 @@ void mg_times_out(unsigned long data)
{ {
struct mg_host *host = (struct mg_host *)data; struct mg_host *host = (struct mg_host *)data;
char *name; char *name;
struct request *req;
spin_lock_irq(&host->lock); spin_lock_irq(&host->lock);
req = elv_next_request(host->breq); if (!host->req)
if (!req)
goto out_unlock; goto out_unlock;
host->mg_do_intr = NULL; host->mg_do_intr = NULL;
name = req->rq_disk->disk_name; name = host->req->rq_disk->disk_name;
printk(KERN_DEBUG "%s: timeout\n", name); printk(KERN_DEBUG "%s: timeout\n", name);
host->error = MG_ERR_TIMEOUT; host->error = MG_ERR_TIMEOUT;
mg_bad_rw_intr(host); mg_bad_rw_intr(host);
mg_request(host->breq);
out_unlock: out_unlock:
mg_request(host->breq);
spin_unlock_irq(&host->lock); spin_unlock_irq(&host->lock);
} }
static void mg_request_poll(struct request_queue *q) static void mg_request_poll(struct request_queue *q)
{ {
struct request *req; struct mg_host *host = q->queuedata;
struct mg_host *host;
while ((req = elv_next_request(q)) != NULL) { while (1) {
host = req->rq_disk->private_data; if (!host->req) {
host->req = elv_next_request(q);
if (host->req)
blkdev_dequeue_request(host->req);
else
break;
}
if (unlikely(!blk_fs_request(req))) { if (unlikely(!blk_fs_request(host->req))) {
__blk_end_request_cur(req, -EIO); mg_end_request_cur(host, -EIO);
continue; continue;
} }
if (rq_data_dir(req) == READ) if (rq_data_dir(host->req) == READ)
mg_read(req); mg_read(host->req);
else else
mg_write(req); mg_write(host->req);
} }
} }
@ -733,16 +738,19 @@ static unsigned int mg_issue_req(struct request *req,
/* This function also called from IRQ context */ /* This function also called from IRQ context */
static void mg_request(struct request_queue *q) static void mg_request(struct request_queue *q)
{ {
struct mg_host *host = q->queuedata;
struct request *req; struct request *req;
struct mg_host *host;
u32 sect_num, sect_cnt; u32 sect_num, sect_cnt;
while (1) { while (1) {
req = elv_next_request(q); if (!host->req) {
if (!req) host->req = elv_next_request(q);
return; if (host->req)
blkdev_dequeue_request(host->req);
host = req->rq_disk->private_data; else
break;
}
req = host->req;
/* check unwanted request call */ /* check unwanted request call */
if (host->mg_do_intr) if (host->mg_do_intr)
@ -762,12 +770,12 @@ static void mg_request(struct request_queue *q)
"%s: bad access: sector=%d, count=%d\n", "%s: bad access: sector=%d, count=%d\n",
req->rq_disk->disk_name, req->rq_disk->disk_name,
sect_num, sect_cnt); sect_num, sect_cnt);
__blk_end_request_cur(req, -EIO); mg_end_request_cur(host, -EIO);
continue; continue;
} }
if (unlikely(!blk_fs_request(req))) { if (unlikely(!blk_fs_request(req))) {
__blk_end_request_cur(req, -EIO); mg_end_request_cur(host, -EIO);
continue; continue;
} }
@ -981,6 +989,7 @@ static int mg_probe(struct platform_device *plat_dev)
__func__, __LINE__); __func__, __LINE__);
goto probe_err_5; goto probe_err_5;
} }
host->breq->queuedata = host;
/* mflash is random device, thanx for the noop */ /* mflash is random device, thanx for the noop */
elevator_exit(host->breq->elevator); elevator_exit(host->breq->elevator);