From ac2ff946a53e7bd0ae98f4e5d1d6c1b1dced82e5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 28 Apr 2009 12:38:32 +0900 Subject: mg_disk: fix locking IRQ and timeout handlers call functions which expect locked queue lock without locking it. Fix it. While at it, convert 0s used as null pointer constant to NULLs. [ Impact: fix locking, cleanup ] Signed-off-by: Tejun Heo Cc: unsik Kim diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index fb39d9a..d3e72ad 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c @@ -160,11 +160,16 @@ static irqreturn_t mg_irq(int irq, void *dev_id) struct mg_host *host = dev_id; void (*handler)(struct mg_host *) = host->mg_do_intr; - host->mg_do_intr = 0; + spin_lock(&host->lock); + + host->mg_do_intr = NULL; del_timer(&host->timer); if (!handler) handler = mg_unexpected_intr; handler(host); + + spin_unlock(&host->lock); + return IRQ_HANDLED; } @@ -319,7 +324,7 @@ static void mg_read(struct request *req) remains = req->nr_sectors; - if (mg_out(host, req->sector, req->nr_sectors, MG_CMD_RD, 0) != + if (mg_out(host, req->sector, req->nr_sectors, MG_CMD_RD, NULL) != MG_ERR_NONE) mg_bad_rw_intr(host); @@ -363,7 +368,7 @@ static void mg_write(struct request *req) remains = req->nr_sectors; - if (mg_out(host, req->sector, req->nr_sectors, MG_CMD_WR, 0) != + if (mg_out(host, req->sector, req->nr_sectors, MG_CMD_WR, NULL) != MG_ERR_NONE) { mg_bad_rw_intr(host); return; @@ -521,9 +526,11 @@ void mg_times_out(unsigned long data) char *name; struct request *req; + spin_lock_irq(&host->lock); + req = elv_next_request(host->breq); if (!req) - return; + goto out_unlock; host->mg_do_intr = NULL; @@ -534,6 +541,8 @@ void mg_times_out(unsigned long data) mg_bad_rw_intr(host); mg_request(host->breq); +out_unlock: + spin_unlock_irq(&host->lock); } static void mg_request_poll(struct request_queue *q) -- cgit v0.10.2 From 7090a0a97f55cbf47547a140fcc5a349f32c598c Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 28 Apr 2009 12:38:33 +0900 Subject: mg_disk: fix CONFIG_LBD=y warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/block/mg_disk.c: In function ‘mg_dump_status’: drivers/block/mg_disk.c:265: warning: format ‘%ld’ expects type ‘long int’, but argument 2 has type ‘sector_t’ [ Impact: kill build warning ] Cc: unsik Kim Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Tejun Heo diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index d3e72ad..f389835 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c @@ -79,7 +79,7 @@ static void mg_dump_status(const char *msg, unsigned int stat, if (host->breq) { req = elv_next_request(host->breq); if (req) - printk(", sector=%ld", req->sector); + printk(", sector=%u", (u32)req->sector); } } -- cgit v0.10.2 From e93b9fb7d85da4fd9d5171649e5ddcac1dd572bf Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 28 Apr 2009 12:38:33 +0900 Subject: hd: fix locking hd dance around local irq and HD_IRQ enable without achieving much. It ends up transferring data from irq handler with both local irq and HD_IRQ disabled. The only place it actually does something is while transferring the first block of a request which it does with HD_IRQ disabled but local irq enabled. Unfortunately, the dancing is horribly broken from locking POV. IRQ and timeout handlers access block queue without grabbing the queue lock and running the driver in SMP configuration crashes the whole machine pretty quickly. Remove meaningless irq enable/disable dancing and add proper locking in issue, irq and timeout paths. Signed-off-by: Tejun Heo diff --git a/drivers/block/hd.c b/drivers/block/hd.c index 3c11f06..baaa9e4 100644 --- a/drivers/block/hd.c +++ b/drivers/block/hd.c @@ -509,7 +509,6 @@ ok_to_write: if (i > 0) { SET_HANDLER(&write_intr); outsw(HD_DATA, req->buffer, 256); - local_irq_enable(); } else { #if (HD_DELAY > 0) last_req = read_timer(); @@ -541,8 +540,7 @@ static void hd_times_out(unsigned long dummy) if (!CURRENT) return; - disable_irq(HD_IRQ); - local_irq_enable(); + spin_lock_irq(hd_queue->queue_lock); reset = 1; name = CURRENT->rq_disk->disk_name; printk("%s: timeout\n", name); @@ -552,9 +550,8 @@ static void hd_times_out(unsigned long dummy) #endif end_request(CURRENT, 0); } - local_irq_disable(); hd_request(); - enable_irq(HD_IRQ); + spin_unlock_irq(hd_queue->queue_lock); } static int do_special_op(struct hd_i_struct *disk, struct request *req) @@ -592,7 +589,6 @@ static void hd_request(void) return; repeat: del_timer(&device_timer); - local_irq_enable(); req = CURRENT; if (!req) { @@ -601,7 +597,6 @@ repeat: } if (reset) { - local_irq_disable(); reset_hd(); return; } @@ -660,9 +655,7 @@ repeat: static void do_hd_request(struct request_queue *q) { - disable_irq(HD_IRQ); hd_request(); - enable_irq(HD_IRQ); } static int hd_getgeo(struct block_device *bdev, struct hd_geometry *geo) @@ -684,12 +677,16 @@ static irqreturn_t hd_interrupt(int irq, void *dev_id) { void (*handler)(void) = do_hd; + spin_lock(hd_queue->queue_lock); + do_hd = NULL; del_timer(&device_timer); if (!handler) handler = unexpected_hd_interrupt; handler(); - local_irq_enable(); + + spin_unlock(hd_queue->queue_lock); + return IRQ_HANDLED; } -- cgit v0.10.2 From e686307fdc84f249490e6c9da92fcb2424491f14 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Fri, 17 Apr 2009 08:41:21 +0200 Subject: loop: use BIO list management functions Now that the bio list management stuff is generic, convert loop to use bio lists instead of its own private bio list implementation. Cc: Jens Axboe Cc: Christoph Hellwig Signed-off-by: Akinobu Mita Signed-off-by: Jens Axboe diff --git a/drivers/block/loop.c b/drivers/block/loop.c index ddae808..9ca4bb0 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -511,11 +511,7 @@ out: */ static void loop_add_bio(struct loop_device *lo, struct bio *bio) { - if (lo->lo_biotail) { - lo->lo_biotail->bi_next = bio; - lo->lo_biotail = bio; - } else - lo->lo_bio = lo->lo_biotail = bio; + bio_list_add(&lo->lo_bio_list, bio); } /* @@ -523,16 +519,7 @@ static void loop_add_bio(struct loop_device *lo, struct bio *bio) */ static struct bio *loop_get_bio(struct loop_device *lo) { - struct bio *bio; - - if ((bio = lo->lo_bio)) { - if (bio == lo->lo_biotail) - lo->lo_biotail = NULL; - lo->lo_bio = bio->bi_next; - bio->bi_next = NULL; - } - - return bio; + return bio_list_pop(&lo->lo_bio_list); } static int loop_make_request(struct request_queue *q, struct bio *old_bio) @@ -609,12 +596,13 @@ static int loop_thread(void *data) set_user_nice(current, -20); - while (!kthread_should_stop() || lo->lo_bio) { + while (!kthread_should_stop() || !bio_list_empty(&lo->lo_bio_list)) { wait_event_interruptible(lo->lo_event, - lo->lo_bio || kthread_should_stop()); + !bio_list_empty(&lo->lo_bio_list) || + kthread_should_stop()); - if (!lo->lo_bio) + if (bio_list_empty(&lo->lo_bio_list)) continue; spin_lock_irq(&lo->lo_lock); bio = loop_get_bio(lo); @@ -841,7 +829,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, lo->old_gfp_mask = mapping_gfp_mask(mapping); mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS)); - lo->lo_bio = lo->lo_biotail = NULL; + bio_list_init(&lo->lo_bio_list); /* * set queue make_request_fn, and add limits based on lower level diff --git a/include/linux/bio.h b/include/linux/bio.h index 7b214fd..f37ca8c 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -506,7 +506,7 @@ static inline int bio_has_data(struct bio *bio) } /* - * BIO list managment for use by remapping drivers (e.g. DM or MD). + * BIO list management for use by remapping drivers (e.g. DM or MD) and loop. * * A bio_list anchors a singly-linked list of bios chained through the bi_next * member of the bio. The bio_list also caches the last list member to allow diff --git a/include/linux/loop.h b/include/linux/loop.h index 4072544..66c194e 100644 --- a/include/linux/loop.h +++ b/include/linux/loop.h @@ -56,8 +56,7 @@ struct loop_device { gfp_t old_gfp_mask; spinlock_t lo_lock; - struct bio *lo_bio; - struct bio *lo_biotail; + struct bio_list lo_bio_list; int lo_state; struct mutex lo_ctl_mutex; struct task_struct *lo_thread; -- cgit v0.10.2 From 924cec7789f65ab7f022256f6533ecba0747b5f3 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 19 Apr 2009 07:00:41 +0900 Subject: block: clear req->errors on bio completion only for fs requests Impact: subtle behavior change For fs requests, rq is only carrier of bios and rq error status as a whole doesn't mean much. This is the reason why rq->errors is being cleared on each partial completion of a request as on each partial completion the error status is transferred to the respective bios. For pc requests, rq->errors is used to carry error status to the issuer and thus __end_that_request_first() doesn't clear it on such cases. The condition was fine till now as only fs and pc requests have used bio and thus the bio completion path. However, future changes will unify data accesses to bio and all non fs users care about rq error status. Clear rq->errors on bio completion only for fs requests. In general, the implicit clearing is a bit too subtle especially as the meaning of rq->errors is completely dependent on low level drivers. Unifying / cleaning up rq->errors usage and letting llds manage it would be better. TODO comment added. Signed-off-by: Tejun Heo Acked-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index 2998fe3..41bc0ff 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1741,10 +1741,14 @@ static int __end_that_request_first(struct request *req, int error, trace_block_rq_complete(req->q, req); /* - * for a REQ_TYPE_BLOCK_PC request, we want to carry any eventual - * sense key with us all the way through + * For fs requests, rq is just carrier of independent bio's + * and each partial completion should be handled separately. + * Reset per-request error on each partial completion. + * + * TODO: tj: This is too subtle. It would be better to let + * low level drivers do what they see fit. */ - if (!blk_pc_request(req)) + if (blk_fs_request(req)) req->errors = 0; if (error && (blk_fs_request(req) && !(req->cmd_flags & REQ_QUIET))) { -- cgit v0.10.2 From 0de57fb93b1daaeaecb658a98b3299ae460c02e9 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 19 Apr 2009 07:00:41 +0900 Subject: ide-tape: remove back-to-back REQUEST_SENSE detection Impact: fix an oops which always triggers ide_tape_issue_pc() assumed drive->pc isn't NULL on invocation when checking for back-to-back request sense issues but drive->pc can be NULL and even when it's not NULL, it's not safe to dereference it once the previous command is complete because pc could have been freed or was on stack. Kill back-to-back REQUEST_SENSE detection. Signed-off-by: Tejun Heo diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index cb942a9..3a53e08 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -614,12 +614,6 @@ static ide_startstop_t ide_tape_issue_pc(ide_drive_t *drive, { idetape_tape_t *tape = drive->driver_data; - if (drive->pc->c[0] == REQUEST_SENSE && - pc->c[0] == REQUEST_SENSE) { - printk(KERN_ERR "ide-tape: possible ide-tape.c bug - " - "Two request sense in serial were issued\n"); - } - if (drive->failed_pc == NULL && pc->c[0] != REQUEST_SENSE) drive->failed_pc = pc; -- cgit v0.10.2 From 220d06b5531e7b8a6226b2fdfb21198c3ccc4f76 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 19 Apr 2009 07:00:41 +0900 Subject: ide: use blk_run_queue() instead of blk_start_queueing() blk_start_queueing() is being phased out in favor of [__]blk_run_queue(). Switch. Signed-off-by: Tejun Heo diff --git a/drivers/ide/ide-park.c b/drivers/ide/ide-park.c index 310d03f..a914023 100644 --- a/drivers/ide/ide-park.c +++ b/drivers/ide/ide-park.c @@ -24,11 +24,8 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout) start_queue = 1; spin_unlock_irq(&hwif->lock); - if (start_queue) { - spin_lock_irq(q->queue_lock); - blk_start_queueing(q); - spin_unlock_irq(q->queue_lock); - } + if (start_queue) + blk_run_queue(q); return; } spin_unlock_irq(&hwif->lock); -- cgit v0.10.2 From b2963ac1738542d30305d7e12c8c078a383a425c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 19 Apr 2009 07:00:41 +0900 Subject: ide: don't set REQ_SOFTBARRIER ide doesn't have to worry about REQ_SOFTBARRIER. Don't set it. Signed-off-by: Tejun Heo diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index a9fbe2c..c243880 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -411,7 +411,6 @@ static void idedisk_prepare_flush(struct request_queue *q, struct request *rq) cmd->protocol = ATA_PROT_NODATA; rq->cmd_type = REQ_TYPE_ATA_TASKFILE; - rq->cmd_flags |= REQ_SOFTBARRIER; rq->special = cmd; } diff --git a/drivers/ide/ide-ioctls.c b/drivers/ide/ide-ioctls.c index c1c25eb..5991b23 100644 --- a/drivers/ide/ide-ioctls.c +++ b/drivers/ide/ide-ioctls.c @@ -231,7 +231,6 @@ static int generic_drive_reset(ide_drive_t *drive) rq->cmd_type = REQ_TYPE_SPECIAL; rq->cmd_len = 1; rq->cmd[0] = REQ_DRIVE_RESET; - rq->cmd_flags |= REQ_SOFTBARRIER; if (blk_execute_rq(drive->queue, NULL, rq, 1)) ret = rq->errors; blk_put_request(rq); -- cgit v0.10.2 From 214ae19104141404f18ad6651752eb38e3dd584e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 19 Apr 2009 07:00:41 +0900 Subject: ide kill unused ide_cmd->special Impact: removal of unused field No one uses ide_cmd->special anymore. Kill it. Signed-off-by: Tejun Heo diff --git a/include/linux/ide.h b/include/linux/ide.h index ff65fff..846a1e1 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -324,7 +324,6 @@ struct ide_cmd { unsigned int cursg_ofs; struct request *rq; /* copy of request */ - void *special; /* valid_t generally */ }; /* ATAPI packet command flags */ -- cgit v0.10.2 From 59a4f6f355fc718581ddcf1bb45a469d4756c035 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 19 Apr 2009 07:00:41 +0900 Subject: ide-cd: clear sense buffer before issuing request sense Impact: code simplification ide_cd_request_sense_fixup() clears the tail of the sense buffer if the device didn't completely fill it. This patch makes cdrom_queue_request_sense() clear the sense buffer before issuing the command instead of clearing it afterwards. This simplifies code and eases future changes. Signed-off-by: Tejun Heo diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 3d4e099..b6a0d12 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -217,6 +217,8 @@ static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense, if (sense == NULL) sense = &info->sense_data; + memset(sense, 0, 18); + /* stuff the sense request in front of our current request */ blk_rq_init(NULL, rq); rq->cmd_type = REQ_TYPE_ATA_PC; @@ -504,14 +506,8 @@ static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct ide_cmd *cmd) * and some drives don't send them. Sigh. */ if (rq->cmd[0] == GPCMD_REQUEST_SENSE && - cmd->nleft > 0 && cmd->nleft <= 5) { - unsigned int ofs = cmd->nbytes - cmd->nleft; - - while (cmd->nleft > 0) { - *((u8 *)rq->data + ofs++) = 0; - cmd->nleft--; - } - } + cmd->nleft > 0 && cmd->nleft <= 5) + cmd->nleft = 0; } int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd, -- cgit v0.10.2 From 8968932e54db35cf9d69cfbbd50c26dfaaa586c7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 19 Apr 2009 07:00:42 +0900 Subject: ide-floppy: block pc always uses bio Impact: remove unnecessary code path Block pc requests always use bio and rq->data is always NULL. No need to worry about !rq->bio cases in idefloppy_block_pc_cmd(). Note that ide-atapi uses ide_pio_bytes() for bio PIO transfer which handle sg fine. Signed-off-by: Tejun Heo Cc: Jens Axboe diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 2b4868d..3b22e06 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -216,15 +216,13 @@ static void idefloppy_blockpc_cmd(struct ide_disk_obj *floppy, ide_init_pc(pc); memcpy(pc->c, rq->cmd, sizeof(pc->c)); pc->rq = rq; - if (rq->data_len && rq_data_dir(rq) == WRITE) - pc->flags |= PC_FLAG_WRITING; - pc->buf = rq->data; - if (rq->bio) + if (rq->data_len) { pc->flags |= PC_FLAG_DMA_OK; - /* - * possibly problematic, doesn't look like ide-floppy correctly - * handled scattered requests if dma fails... - */ + if (rq_data_dir(rq) == WRITE) + pc->flags |= PC_FLAG_WRITING; + } + /* pio will be performed by ide_pio_bytes() which handles sg fine */ + pc->buf = NULL; pc->req_xfer = pc->buf_size = rq->data_len; } -- cgit v0.10.2 From d868ca24302e99a0e8a86071ca2c66273edf97d9 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 19 Apr 2009 07:00:42 +0900 Subject: ide-taskfile: don't abuse rq->buffer Impact: rq->buffer usage cleanup ide_raw_taskfile() directly uses rq->buffer to carry pointer to the data buffer. This complicates both block interface and ide backend request handling. Use blk_rq_map_kern() instead and drop special handling for REQ_TYPE_ATA_TASKFILE from ide_map_sg(). Note that REQ_RW setting is moved upwards as blk_rq_map_kern() uses it to initialize bio rw flag. Signed-off-by: Tejun Heo Cc: Jens Axboe diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 35dc38d..9b9e8b1 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -248,10 +248,7 @@ void ide_map_sg(ide_drive_t *drive, struct ide_cmd *cmd) struct scatterlist *sg = hwif->sg_table; struct request *rq = cmd->rq; - if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { - sg_init_one(sg, rq->buffer, rq->nr_sectors * SECTOR_SIZE); - cmd->sg_nents = 1; - } else if (!rq->bio) { + if (!rq->bio) { sg_init_one(sg, rq->data, rq->data_len); cmd->sg_nents = 1; } else diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 4aa6223..f400eb4 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -424,7 +424,9 @@ int ide_raw_taskfile(ide_drive_t *drive, struct ide_cmd *cmd, u8 *buf, rq = blk_get_request(drive->queue, READ, __GFP_WAIT); rq->cmd_type = REQ_TYPE_ATA_TASKFILE; - rq->buffer = buf; + + if (cmd->tf_flags & IDE_TFLAG_WRITE) + rq->cmd_flags |= REQ_RW; /* * (ks) We transfer currently only whole sectors. @@ -432,18 +434,20 @@ int ide_raw_taskfile(ide_drive_t *drive, struct ide_cmd *cmd, u8 *buf, * if we would find a solution to transfer any size. * To support special commands like READ LONG. */ - rq->hard_nr_sectors = rq->nr_sectors = nsect; - rq->hard_cur_sectors = rq->current_nr_sectors = nsect; - - if (cmd->tf_flags & IDE_TFLAG_WRITE) - rq->cmd_flags |= REQ_RW; + if (nsect) { + error = blk_rq_map_kern(drive->queue, rq, buf, + nsect * SECTOR_SIZE, __GFP_WAIT); + if (error) + goto put_req; + } rq->special = cmd; cmd->rq = rq; error = blk_execute_rq(drive->queue, NULL, rq, 0); - blk_put_request(rq); +put_req: + blk_put_request(rq); return error; } -- cgit v0.10.2 From ac0b0113ddbab3ed2388132d368c97292f9f3c84 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 19 Apr 2009 07:00:42 +0900 Subject: ide-atapi: don't abuse rq->buffer Impact: rq->buffer usage cleanup ide-atapi uses rq->buffer as private opaque value for internal special requests. rq->special isn't used for these cases (the only case where rq->special is used is for ide-tape rw requests). Use rq->special instead. Signed-off-by: Tejun Heo Cc: Jens Axboe diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c index 7201b17..2894577 100644 --- a/drivers/ide/ide-atapi.c +++ b/drivers/ide/ide-atapi.c @@ -90,7 +90,7 @@ static void ide_queue_pc_head(ide_drive_t *drive, struct gendisk *disk, blk_rq_init(NULL, rq); rq->cmd_type = REQ_TYPE_SPECIAL; rq->cmd_flags |= REQ_PREEMPT; - rq->buffer = (char *)pc; + rq->special = (char *)pc; rq->rq_disk = disk; if (pc->req_xfer) { @@ -119,7 +119,7 @@ int ide_queue_pc_tail(ide_drive_t *drive, struct gendisk *disk, rq = blk_get_request(drive->queue, READ, __GFP_WAIT); rq->cmd_type = REQ_TYPE_SPECIAL; - rq->buffer = (char *)pc; + rq->special = (char *)pc; if (pc->req_xfer) { rq->data = pc->buf; diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 3b22e06..9460033 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -264,7 +264,7 @@ static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive, pc = &floppy->queued_pc; idefloppy_create_rw_cmd(drive, pc, rq, (unsigned long)block); } else if (blk_special_request(rq)) { - pc = (struct ide_atapi_pc *) rq->buffer; + pc = (struct ide_atapi_pc *)rq->special; } else if (blk_pc_request(rq)) { pc = &floppy->queued_pc; idefloppy_blockpc_cmd(floppy, pc, rq); diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 3a53e08..aadf53c 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -828,7 +828,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, goto out; } if (rq->cmd[13] & REQ_IDETAPE_PC1) { - pc = (struct ide_atapi_pc *) rq->buffer; + pc = (struct ide_atapi_pc *)rq->special; rq->cmd[13] &= ~(REQ_IDETAPE_PC1); rq->cmd[13] |= REQ_IDETAPE_PC2; goto out; -- cgit v0.10.2 From 1f181d2b1569dfb88a584a6e1847e9e1c7645951 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 19 Apr 2009 07:00:42 +0900 Subject: ide-cd: don't abuse rq->buffer Impact: rq->buffer usage cleanup ide-cd uses rq->buffer to carry pointer to the original request when issuing REQUEST_SENSE. Use rq->special instead. Signed-off-by: Tejun Heo Cc: Jens Axboe diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index b6a0d12..bb77c79 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -232,8 +232,8 @@ static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense, rq->cmd_type = REQ_TYPE_SENSE; rq->cmd_flags |= REQ_PREEMPT; - /* NOTE! Save the failed command in "rq->buffer" */ - rq->buffer = (void *) failed_command; + /* NOTE! Save the failed command in "rq->special" */ + rq->special = (void *)failed_command; if (failed_command) ide_debug_log(IDE_DBG_SENSE, "failed_cmd: 0x%x", @@ -247,10 +247,10 @@ static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense, static void ide_cd_complete_failed_rq(ide_drive_t *drive, struct request *rq) { /* - * For REQ_TYPE_SENSE, "rq->buffer" points to the original + * For REQ_TYPE_SENSE, "rq->special" points to the original * failed request */ - struct request *failed = (struct request *)rq->buffer; + struct request *failed = (struct request *)rq->special; struct cdrom_info *info = drive->driver_data; void *sense = &info->sense_data; -- cgit v0.10.2 From e69d800f7e8797a8e3423380ee9d8ca1cb90c388 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Sun, 19 Apr 2009 07:00:42 +0900 Subject: ide: add helpers for preparing sense requests This is in preparation of removing the queueing of a sense request out of the IRQ handler path. Use struct request_sense as a general sense buffer for all ATAPI devices ide-{floppy,tape,cd}. tj: * blk_get_request(__GFP_WAIT) can't be called from do_request() as it can cause deadlock. Converted to use inline struct request and blk_rq_init(). * Added xfer / cdb len selection depending on device type. * All sense prep logics folded into ide_prep_sense() which never fails. * hwif->rq clearing and sense_rq used handling moved into ide_queue_sense_rq(). * blk_rq_map_kern() conversion is moved to later patch. CC: Bartlomiej Zolnierkiewicz CC: FUJITA Tomonori Signed-off-by: Borislav Petkov Signed-off-by: Tejun Heo diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c index 2894577..c6e0348 100644 --- a/drivers/ide/ide-atapi.c +++ b/drivers/ide/ide-atapi.c @@ -191,6 +191,67 @@ void ide_create_request_sense_cmd(ide_drive_t *drive, struct ide_atapi_pc *pc) } EXPORT_SYMBOL_GPL(ide_create_request_sense_cmd); +void ide_prep_sense(ide_drive_t *drive, struct request *rq) +{ + struct request_sense *sense = &drive->sense_data; + struct request *sense_rq = &drive->sense_rq; + unsigned int cmd_len, sense_len; + + debug_log("%s: enter\n", __func__); + + switch (drive->media) { + case ide_floppy: + cmd_len = 255; + sense_len = 18; + break; + case ide_tape: + cmd_len = 20; + sense_len = 20; + break; + default: + cmd_len = 18; + sense_len = 18; + } + + BUG_ON(sense_len > sizeof(*sense)); + + if (blk_sense_request(rq) || drive->sense_rq_armed) + return; + + memset(sense, 0, sizeof(*sense)); + + blk_rq_init(rq->q, sense_rq); + sense_rq->rq_disk = rq->rq_disk; + + sense_rq->data = sense; + sense_rq->cmd[0] = GPCMD_REQUEST_SENSE; + sense_rq->cmd[4] = cmd_len; + sense_rq->data_len = sense_len; + + sense_rq->cmd_type = REQ_TYPE_SENSE; + sense_rq->cmd_flags |= REQ_PREEMPT; + + if (drive->media == ide_tape) + sense_rq->cmd[13] = REQ_IDETAPE_PC1; + + drive->sense_rq_armed = true; +} +EXPORT_SYMBOL_GPL(ide_prep_sense); + +void ide_queue_sense_rq(ide_drive_t *drive, void *special) +{ + BUG_ON(!drive->sense_rq_armed); + + drive->sense_rq.special = special; + drive->sense_rq_armed = false; + + drive->hwif->rq = NULL; + + elv_add_request(drive->queue, &drive->sense_rq, + ELEVATOR_INSERT_FRONT, 0); +} +EXPORT_SYMBOL_GPL(ide_queue_sense_rq); + /* * Called when an error was detected during the last packet command. * We queue a request sense packet command in the head of the request list. diff --git a/include/linux/ide.h b/include/linux/ide.h index 846a1e1..a69ccac 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -26,6 +26,9 @@ #include #include +/* for request_sense */ +#include + #if defined(CONFIG_CRIS) || defined(CONFIG_FRV) || defined(CONFIG_MN10300) # define SUPPORT_VLB_SYNC 0 #else @@ -602,6 +605,11 @@ struct ide_drive_s { struct ide_atapi_pc request_sense_pc; struct request request_sense_rq; + + /* current sense rq and buffer */ + bool sense_rq_armed; + struct request sense_rq; + struct request_sense sense_data; }; typedef struct ide_drive_s ide_drive_t; @@ -1175,6 +1183,9 @@ int ide_set_media_lock(ide_drive_t *, struct gendisk *, int); void ide_create_request_sense_cmd(ide_drive_t *, struct ide_atapi_pc *); void ide_retry_pc(ide_drive_t *, struct gendisk *); +void ide_prep_sense(ide_drive_t *drive, struct request *rq); +void ide_queue_sense_rq(ide_drive_t *drive, void *special); + int ide_cd_expiry(ide_drive_t *); int ide_cd_get_xferlen(struct request *); -- cgit v0.10.2 From c457ce874a0f3dfa3d5e9f2309789f6f34e24325 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Sun, 19 Apr 2009 07:00:42 +0900 Subject: ide-cd: convert to using generic sense request Preallocate a sense request in the ->do_request method and reinitialize it only on demand, in case it's been consumed in the IRQ handler path. The reason for this is that we don't want to be mapping rq to bio in the IRQ path and introduce all kinds of unnecessary hacks to the block layer. tj: * Both user and kernel PC requests expect sense data to be stored in separate storage other than drive->sense_data. Copy sense data to rq->sense on completion if rq->sense is not NULL. This fixes bogus sense data on PC requests. As a result, remove cdrom_queue_request_sense. CC: Bartlomiej Zolnierkiewicz CC: FUJITA Tomonori Signed-off-by: Borislav Petkov Signed-off-by: Tejun Heo diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index bb77c79..061d7bb 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -206,44 +206,6 @@ static void cdrom_analyze_sense_data(ide_drive_t *drive, ide_cd_log_error(drive->name, failed_command, sense); } -static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense, - struct request *failed_command) -{ - struct cdrom_info *info = drive->driver_data; - struct request *rq = &drive->request_sense_rq; - - ide_debug_log(IDE_DBG_SENSE, "enter"); - - if (sense == NULL) - sense = &info->sense_data; - - memset(sense, 0, 18); - - /* stuff the sense request in front of our current request */ - blk_rq_init(NULL, rq); - rq->cmd_type = REQ_TYPE_ATA_PC; - rq->rq_disk = info->disk; - - rq->data = sense; - rq->cmd[0] = GPCMD_REQUEST_SENSE; - rq->cmd[4] = 18; - rq->data_len = 18; - - rq->cmd_type = REQ_TYPE_SENSE; - rq->cmd_flags |= REQ_PREEMPT; - - /* NOTE! Save the failed command in "rq->special" */ - rq->special = (void *)failed_command; - - if (failed_command) - ide_debug_log(IDE_DBG_SENSE, "failed_cmd: 0x%x", - failed_command->cmd[0]); - - drive->hwif->rq = NULL; - - elv_add_request(drive->queue, rq, ELEVATOR_INSERT_FRONT, 0); -} - static void ide_cd_complete_failed_rq(ide_drive_t *drive, struct request *rq) { /* @@ -251,11 +213,16 @@ static void ide_cd_complete_failed_rq(ide_drive_t *drive, struct request *rq) * failed request */ struct request *failed = (struct request *)rq->special; - struct cdrom_info *info = drive->driver_data; - void *sense = &info->sense_data; + struct request_sense *sense = &drive->sense_data; if (failed) { if (failed->sense) { + /* + * Sense is always read into drive->sense_data. + * Copy back if the failed request has its + * sense pointer set. + */ + memcpy(failed->sense, sense, 18); sense = failed->sense; failed->sense_len = rq->sense_len; } @@ -431,7 +398,7 @@ static int cdrom_decode_status(ide_drive_t *drive, u8 stat) /* if we got a CHECK_CONDITION status, queue a request sense command */ if (stat & ATA_ERR) - cdrom_queue_request_sense(drive, NULL, NULL); + ide_queue_sense_rq(drive, NULL); return 1; end_request: @@ -445,7 +412,7 @@ end_request: hwif->rq = NULL; - cdrom_queue_request_sense(drive, rq->sense, rq); + ide_queue_sense_rq(drive, rq); return 1; } else return 2; @@ -893,6 +860,9 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq, goto out_end; } + /* prepare sense request for this command */ + ide_prep_sense(drive, rq); + memset(&cmd, 0, sizeof(cmd)); if (rq_data_dir(rq)) diff --git a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h index 1d97101..93a3cf1b 100644 --- a/drivers/ide/ide-cd.h +++ b/drivers/ide/ide-cd.h @@ -87,10 +87,6 @@ struct cdrom_info { struct atapi_toc *toc; - /* The result of the last successful request sense command - on this device. */ - struct request_sense sense_data; - u8 max_speed; /* Max speed of the drive. */ u8 current_speed; /* Current speed of the drive. */ -- cgit v0.10.2 From 068753203e6cd085664a62e0fc0636e19b148a12 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Sun, 19 Apr 2009 07:00:42 +0900 Subject: ide-atapi: convert ide-{floppy,tape} to using preallocated sense buffer Since we're issuing REQ_TYPE_SENSE now we need to allow those types of rqs in the ->do_request callbacks. As a future improvement, sense_len assignment might be unified across all ATAPI devices. Borislav to check with specs and test. As a result, get rid of ide_queue_pc_head() and drive->request_sense_rq. tj: * Init request sense ide_atapi_pc from sense request. In the longer timer, it would probably better to fold ide_create_request_sense_cmd() into its only current user - ide_floppy_get_format_progress(). * ide_retry_pc() no longer takes @disk. CC: Bartlomiej Zolnierkiewicz CC: FUJITA Tomonori Signed-off-by: Borislav Petkov Signed-off-by: Tejun Heo diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c index c6e0348..972c522 100644 --- a/drivers/ide/ide-atapi.c +++ b/drivers/ide/ide-atapi.c @@ -80,34 +80,6 @@ void ide_init_pc(struct ide_atapi_pc *pc) EXPORT_SYMBOL_GPL(ide_init_pc); /* - * Generate a new packet command request in front of the request queue, before - * the current request, so that it will be processed immediately, on the next - * pass through the driver. - */ -static void ide_queue_pc_head(ide_drive_t *drive, struct gendisk *disk, - struct ide_atapi_pc *pc, struct request *rq) -{ - blk_rq_init(NULL, rq); - rq->cmd_type = REQ_TYPE_SPECIAL; - rq->cmd_flags |= REQ_PREEMPT; - rq->special = (char *)pc; - rq->rq_disk = disk; - - if (pc->req_xfer) { - rq->data = pc->buf; - rq->data_len = pc->req_xfer; - } - - memcpy(rq->cmd, pc->c, 12); - if (drive->media == ide_tape) - rq->cmd[13] = REQ_IDETAPE_PC1; - - drive->hwif->rq = NULL; - - elv_add_request(drive->queue, rq, ELEVATOR_INSERT_FRONT, 0); -} - -/* * Add a special packet command request to the tail of the request queue, * and wait for it to be serviced. */ @@ -254,18 +226,26 @@ EXPORT_SYMBOL_GPL(ide_queue_sense_rq); /* * Called when an error was detected during the last packet command. - * We queue a request sense packet command in the head of the request list. + * We queue a request sense packet command at the head of the request + * queue. */ -void ide_retry_pc(ide_drive_t *drive, struct gendisk *disk) +void ide_retry_pc(ide_drive_t *drive) { - struct request *rq = &drive->request_sense_rq; + struct request *sense_rq = &drive->sense_rq; struct ide_atapi_pc *pc = &drive->request_sense_pc; (void)ide_read_error(drive); - ide_create_request_sense_cmd(drive, pc); + + /* init pc from sense_rq */ + ide_init_pc(pc); + memcpy(pc->c, sense_rq->cmd, 12); + pc->buf = sense_rq->data; + pc->req_xfer = sense_rq->data_len; + if (drive->media == ide_tape) set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags); - ide_queue_pc_head(drive, disk, pc, rq); + + ide_queue_sense_rq(drive, pc); } EXPORT_SYMBOL_GPL(ide_retry_pc); @@ -404,7 +384,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) debug_log("[cmd %x]: check condition\n", rq->cmd[0]); /* Retry operation */ - ide_retry_pc(drive, rq->rq_disk); + ide_retry_pc(drive); /* queued, but not started */ return ide_stopped; diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 9460033..d3302cc 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -263,7 +263,7 @@ static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive, } pc = &floppy->queued_pc; idefloppy_create_rw_cmd(drive, pc, rq, (unsigned long)block); - } else if (blk_special_request(rq)) { + } else if (blk_special_request(rq) || blk_sense_request(rq)) { pc = (struct ide_atapi_pc *)rq->special; } else if (blk_pc_request(rq)) { pc = &floppy->queued_pc; @@ -273,6 +273,8 @@ static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive, goto out_end; } + ide_prep_sense(drive, rq); + memset(&cmd, 0, sizeof(cmd)); if (rq_data_dir(rq)) diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index aadf53c..8324dfa 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -695,7 +695,7 @@ static ide_startstop_t idetape_media_access_finished(ide_drive_t *drive) printk(KERN_ERR "ide-tape: %s: I/O error, ", tape->name); /* Retry operation */ - ide_retry_pc(drive, tape->disk); + ide_retry_pc(drive); return ide_stopped; } pc->error = 0; @@ -752,7 +752,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, (unsigned long long)rq->sector, rq->nr_sectors, rq->current_nr_sectors); - if (!blk_special_request(rq)) { + if (!(blk_special_request(rq) || blk_sense_request(rq))) { /* We do not support buffer cache originated requests. */ printk(KERN_NOTICE "ide-tape: %s: Unsupported request in " "request queue (%d)\n", drive->name, rq->cmd_type); @@ -840,6 +840,9 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, BUG(); out: + /* prepare sense request for this command */ + ide_prep_sense(drive, rq); + memset(&cmd, 0, sizeof(cmd)); if (rq_data_dir(rq)) diff --git a/include/linux/ide.h b/include/linux/ide.h index a69ccac..9e67cca 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -604,7 +604,6 @@ struct ide_drive_s { unsigned long atapi_flags; struct ide_atapi_pc request_sense_pc; - struct request request_sense_rq; /* current sense rq and buffer */ bool sense_rq_armed; @@ -1181,7 +1180,7 @@ int ide_do_test_unit_ready(ide_drive_t *, struct gendisk *); int ide_do_start_stop(ide_drive_t *, struct gendisk *, int); int ide_set_media_lock(ide_drive_t *, struct gendisk *, int); void ide_create_request_sense_cmd(ide_drive_t *, struct ide_atapi_pc *); -void ide_retry_pc(ide_drive_t *, struct gendisk *); +void ide_retry_pc(ide_drive_t *drive); void ide_prep_sense(ide_drive_t *drive, struct request *rq); void ide_queue_sense_rq(ide_drive_t *drive, void *special); -- cgit v0.10.2 From 02e7cf8f848841ca21864ccd019e480b73c323b7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 19 Apr 2009 07:00:42 +0900 Subject: ide-cd,atapi: use bio for internal commands Impact: unify request data buffer handling rq->data is used mostly to pass kernel buffer through request queue without using bio. There are only a couple of places which still do this in kernel and converting to bio isn't difficult. This patch converts ide-cd and atapi to use bio instead of rq->data for request sense and internal pc commands. With previous change to unify sense request handling, this is relatively easily achieved by adding blk_rq_map_kern() during sense_rq prep and PC issue. If blk_rq_map_kern() fails for sense, the error is deferred till sense issue and aborts the failed command which triggered the sense. Note that this is a slim possibility as sense prep is done on each command issue, so for the above condition to actually trigger, all preps since the last sense issue till the issue of the request which would require a sense should fail. * do_request functions might sleep now. This should be okay as ide request_fn - do_ide_request() - is invoked only from make_request and plug work. Make sure this is the case by adding might_sleep() to do_ide_request(). * Functions which access the read sense data before the sense request is complete now should access bio_data(sense_rq->bio) as the sense buffer might have been copied during blk_rq_map_kern(). * ide-tape updated to map sg. * cdrom_do_block_pc() now doesn't have to deal with REQ_TYPE_ATA_PC special case. Simplified. * tp_ops->output/input_data path dropped from ide_pc_intr(). Signed-off-by: Tejun Heo diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c index 972c522..5cefe12 100644 --- a/drivers/ide/ide-atapi.c +++ b/drivers/ide/ide-atapi.c @@ -94,16 +94,18 @@ int ide_queue_pc_tail(ide_drive_t *drive, struct gendisk *disk, rq->special = (char *)pc; if (pc->req_xfer) { - rq->data = pc->buf; - rq->data_len = pc->req_xfer; + error = blk_rq_map_kern(drive->queue, rq, pc->buf, pc->req_xfer, + GFP_NOIO); + if (error) + goto put_req; } memcpy(rq->cmd, pc->c, 12); if (drive->media == ide_tape) rq->cmd[13] = REQ_IDETAPE_PC1; error = blk_execute_rq(drive->queue, disk, rq, 0); +put_req: blk_put_request(rq); - return error; } EXPORT_SYMBOL_GPL(ide_queue_pc_tail); @@ -168,6 +170,7 @@ void ide_prep_sense(ide_drive_t *drive, struct request *rq) struct request_sense *sense = &drive->sense_data; struct request *sense_rq = &drive->sense_rq; unsigned int cmd_len, sense_len; + int err; debug_log("%s: enter\n", __func__); @@ -193,13 +196,19 @@ void ide_prep_sense(ide_drive_t *drive, struct request *rq) memset(sense, 0, sizeof(*sense)); blk_rq_init(rq->q, sense_rq); - sense_rq->rq_disk = rq->rq_disk; - sense_rq->data = sense; + err = blk_rq_map_kern(drive->queue, sense_rq, sense, sense_len, + GFP_NOIO); + if (unlikely(err)) { + if (printk_ratelimit()) + printk(KERN_WARNING "%s: failed to map sense buffer\n", + drive->name); + return; + } + + sense_rq->rq_disk = rq->rq_disk; sense_rq->cmd[0] = GPCMD_REQUEST_SENSE; sense_rq->cmd[4] = cmd_len; - sense_rq->data_len = sense_len; - sense_rq->cmd_type = REQ_TYPE_SENSE; sense_rq->cmd_flags |= REQ_PREEMPT; @@ -210,9 +219,14 @@ void ide_prep_sense(ide_drive_t *drive, struct request *rq) } EXPORT_SYMBOL_GPL(ide_prep_sense); -void ide_queue_sense_rq(ide_drive_t *drive, void *special) +int ide_queue_sense_rq(ide_drive_t *drive, void *special) { - BUG_ON(!drive->sense_rq_armed); + /* deferred failure from ide_prep_sense() */ + if (!drive->sense_rq_armed) { + printk(KERN_WARNING "%s: failed queue sense request\n", + drive->name); + return -ENOMEM; + } drive->sense_rq.special = special; drive->sense_rq_armed = false; @@ -221,6 +235,7 @@ void ide_queue_sense_rq(ide_drive_t *drive, void *special) elv_add_request(drive->queue, &drive->sense_rq, ELEVATOR_INSERT_FRONT, 0); + return 0; } EXPORT_SYMBOL_GPL(ide_queue_sense_rq); @@ -239,13 +254,14 @@ void ide_retry_pc(ide_drive_t *drive) /* init pc from sense_rq */ ide_init_pc(pc); memcpy(pc->c, sense_rq->cmd, 12); - pc->buf = sense_rq->data; + pc->buf = bio_data(sense_rq->bio); /* pointer to mapped address */ pc->req_xfer = sense_rq->data_len; if (drive->media == ide_tape) set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags); - ide_queue_sense_rq(drive, pc); + if (ide_queue_sense_rq(drive, pc)) + ide_complete_rq(drive, -EIO, blk_rq_bytes(drive->hwif->rq)); } EXPORT_SYMBOL_GPL(ide_retry_pc); @@ -317,7 +333,6 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) struct ide_cmd *cmd = &hwif->cmd; struct request *rq = hwif->rq; const struct ide_tp_ops *tp_ops = hwif->tp_ops; - xfer_func_t *xferfunc; unsigned int timeout, done; u16 bcount; u8 stat, ireason, dsc = 0; @@ -411,7 +426,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) rq->errors = -EIO; } - if (drive->media == ide_tape) + if (drive->media == ide_tape && !rq->bio) done = ide_rq_bytes(rq); /* FIXME */ else done = blk_rq_bytes(rq); @@ -448,16 +463,11 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) return ide_do_reset(drive); } - xferfunc = write ? tp_ops->output_data : tp_ops->input_data; - - if (drive->media == ide_floppy && pc->buf == NULL) { + if (drive->media == ide_tape && pc->bh) + done = drive->pc_io_buffers(drive, pc, bcount, write); + else { done = min_t(unsigned int, bcount, cmd->nleft); ide_pio_bytes(drive, cmd, write, done); - } else if (drive->media == ide_tape && pc->bh) { - done = drive->pc_io_buffers(drive, pc, bcount, write); - } else { - done = min_t(unsigned int, bcount, pc->req_xfer - pc->xferred); - xferfunc(drive, NULL, pc->cur_pos, done); } /* Update the current position */ diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 061d7bb..6736287 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -210,10 +210,12 @@ static void ide_cd_complete_failed_rq(ide_drive_t *drive, struct request *rq) { /* * For REQ_TYPE_SENSE, "rq->special" points to the original - * failed request + * failed request. Also, the sense data should be read + * directly from rq which might be different from the original + * sense buffer if it got copied during mapping. */ struct request *failed = (struct request *)rq->special; - struct request_sense *sense = &drive->sense_data; + void *sense = bio_data(rq->bio); if (failed) { if (failed->sense) { @@ -398,7 +400,7 @@ static int cdrom_decode_status(ide_drive_t *drive, u8 stat) /* if we got a CHECK_CONDITION status, queue a request sense command */ if (stat & ATA_ERR) - ide_queue_sense_rq(drive, NULL); + return ide_queue_sense_rq(drive, NULL) ? 2 : 1; return 1; end_request: @@ -412,8 +414,7 @@ end_request: hwif->rq = NULL; - ide_queue_sense_rq(drive, rq); - return 1; + return ide_queue_sense_rq(drive, rq) ? 2 : 1; } else return 2; } @@ -507,8 +508,12 @@ int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd, rq->cmd_flags |= cmd_flags; rq->timeout = timeout; if (buffer) { - rq->data = buffer; - rq->data_len = *bufflen; + error = blk_rq_map_kern(drive->queue, rq, buffer, + *bufflen, GFP_NOIO); + if (error) { + blk_put_request(rq); + return error; + } } error = blk_execute_rq(drive->queue, info->disk, rq, 0); @@ -802,15 +807,10 @@ static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq) drive->dma = 0; /* sg request */ - if (rq->bio || ((rq->cmd_type == REQ_TYPE_ATA_PC) && rq->data_len)) { + if (rq->bio) { struct request_queue *q = drive->queue; + char *buf = bio_data(rq->bio); unsigned int alignment; - char *buf; - - if (rq->bio) - buf = bio_data(rq->bio); - else - buf = rq->data; drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA); diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 9b9e8b1..3245c2d 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -481,6 +481,9 @@ void do_ide_request(struct request_queue *q) spin_unlock_irq(q->queue_lock); + /* HLD do_request() callback might sleep, make sure it's okay */ + might_sleep(); + if (ide_lock_host(host, hwif)) goto plug_device_2; diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 8324dfa..9b762a2 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -850,6 +850,9 @@ out: cmd.rq = rq; + ide_init_sg_cmd(&cmd, pc->req_xfer); + ide_map_sg(drive, &cmd); + return ide_tape_issue_pc(drive, &cmd, pc); } diff --git a/include/linux/ide.h b/include/linux/ide.h index 9e67cca..1957461 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -1183,7 +1183,7 @@ void ide_create_request_sense_cmd(ide_drive_t *, struct ide_atapi_pc *); void ide_retry_pc(ide_drive_t *drive); void ide_prep_sense(ide_drive_t *drive, struct request *rq); -void ide_queue_sense_rq(ide_drive_t *drive, void *special); +int ide_queue_sense_rq(ide_drive_t *drive, void *special); int ide_cd_expiry(ide_drive_t *); -- cgit v0.10.2 From 765139ef5f1a4b1d5cb1f1a7a12de7ee61f6500f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 19 Apr 2009 07:00:43 +0900 Subject: ide-pm: don't abuse rq->data Impact: cleanup rq->data usage ide-pm uses rq->data to carry pointer to struct request_pm_state through request queue and rq->special is used to carray pointer to local struct ide_cmd, which isn't necessary. Use rq->special for request_pm_state instead and use local ide_cmd in ide_start_power_step(). Signed-off-by: Tejun Heo Cc: Jens Axboe diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 3245c2d..6e3094e 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -368,7 +368,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) return execute_drive_cmd(drive, rq); else if (blk_pm_request(rq)) { - struct request_pm_state *pm = rq->data; + struct request_pm_state *pm = rq->special; #ifdef DEBUG_PM printk("%s: start_power_step(step: %d)\n", drive->name, pm->pm_step); diff --git a/drivers/ide/ide-pm.c b/drivers/ide/ide-pm.c index 0d8a151..ba1488b 100644 --- a/drivers/ide/ide-pm.c +++ b/drivers/ide/ide-pm.c @@ -7,7 +7,6 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg) ide_hwif_t *hwif = drive->hwif; struct request *rq; struct request_pm_state rqpm; - struct ide_cmd cmd; int ret; /* call ACPI _GTM only once */ @@ -15,11 +14,9 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg) ide_acpi_get_timing(hwif); memset(&rqpm, 0, sizeof(rqpm)); - memset(&cmd, 0, sizeof(cmd)); rq = blk_get_request(drive->queue, READ, __GFP_WAIT); rq->cmd_type = REQ_TYPE_PM_SUSPEND; - rq->special = &cmd; - rq->data = &rqpm; + rq->special = &rqpm; rqpm.pm_step = IDE_PM_START_SUSPEND; if (mesg.event == PM_EVENT_PRETHAW) mesg.event = PM_EVENT_FREEZE; @@ -41,7 +38,6 @@ int generic_ide_resume(struct device *dev) ide_hwif_t *hwif = drive->hwif; struct request *rq; struct request_pm_state rqpm; - struct ide_cmd cmd; int err; /* call ACPI _PS0 / _STM only once */ @@ -53,12 +49,10 @@ int generic_ide_resume(struct device *dev) ide_acpi_exec_tfs(drive); memset(&rqpm, 0, sizeof(rqpm)); - memset(&cmd, 0, sizeof(cmd)); rq = blk_get_request(drive->queue, READ, __GFP_WAIT); rq->cmd_type = REQ_TYPE_PM_RESUME; rq->cmd_flags |= REQ_PREEMPT; - rq->special = &cmd; - rq->data = &rqpm; + rq->special = &rqpm; rqpm.pm_step = IDE_PM_START_RESUME; rqpm.pm_state = PM_EVENT_ON; @@ -77,7 +71,7 @@ int generic_ide_resume(struct device *dev) void ide_complete_power_step(ide_drive_t *drive, struct request *rq) { - struct request_pm_state *pm = rq->data; + struct request_pm_state *pm = rq->special; #ifdef DEBUG_PM printk(KERN_INFO "%s: complete_power_step(step: %d)\n", @@ -107,10 +101,8 @@ void ide_complete_power_step(ide_drive_t *drive, struct request *rq) ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq) { - struct request_pm_state *pm = rq->data; - struct ide_cmd *cmd = rq->special; - - memset(cmd, 0, sizeof(*cmd)); + struct request_pm_state *pm = rq->special; + struct ide_cmd cmd = { }; switch (pm->pm_step) { case IDE_PM_FLUSH_CACHE: /* Suspend step 1 (flush cache) */ @@ -123,12 +115,12 @@ ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq) return ide_stopped; } if (ata_id_flush_ext_enabled(drive->id)) - cmd->tf.command = ATA_CMD_FLUSH_EXT; + cmd.tf.command = ATA_CMD_FLUSH_EXT; else - cmd->tf.command = ATA_CMD_FLUSH; + cmd.tf.command = ATA_CMD_FLUSH; goto out_do_tf; case IDE_PM_STANDBY: /* Suspend step 2 (standby) */ - cmd->tf.command = ATA_CMD_STANDBYNOW1; + cmd.tf.command = ATA_CMD_STANDBYNOW1; goto out_do_tf; case IDE_PM_RESTORE_PIO: /* Resume step 1 (restore PIO) */ ide_set_max_pio(drive); @@ -141,7 +133,7 @@ ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq) ide_complete_power_step(drive, rq); return ide_stopped; case IDE_PM_IDLE: /* Resume step 2 (idle) */ - cmd->tf.command = ATA_CMD_IDLEIMMEDIATE; + cmd.tf.command = ATA_CMD_IDLEIMMEDIATE; goto out_do_tf; case IDE_PM_RESTORE_DMA: /* Resume step 3 (restore DMA) */ /* @@ -163,11 +155,11 @@ ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq) return ide_stopped; out_do_tf: - cmd->valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; - cmd->valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; - cmd->protocol = ATA_PROT_NODATA; + cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; + cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; + cmd.protocol = ATA_PROT_NODATA; - return do_rw_taskfile(drive, cmd); + return do_rw_taskfile(drive, &cmd); } /** @@ -181,7 +173,7 @@ out_do_tf: void ide_complete_pm_rq(ide_drive_t *drive, struct request *rq) { struct request_queue *q = drive->queue; - struct request_pm_state *pm = rq->data; + struct request_pm_state *pm = rq->special; unsigned long flags; ide_complete_power_step(drive, rq); @@ -207,7 +199,7 @@ void ide_complete_pm_rq(ide_drive_t *drive, struct request *rq) void ide_check_pm_state(ide_drive_t *drive, struct request *rq) { - struct request_pm_state *pm = rq->data; + struct request_pm_state *pm = rq->special; if (blk_pm_suspend_request(rq) && pm->pm_step == IDE_PM_START_SUSPEND) -- cgit v0.10.2 From 08f370f0a2fb223bf48d0bfa2a173be0393c19dc Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 19 Apr 2009 08:46:02 +0900 Subject: ide-tape,floppy: fix failed command completion after request sense Impact: fix infinite retry loop After a command failed, ide-tape and floppy inserts REQUEST_SENSE in front of the failed command and according to the result, sets pc->retries, flags and errors. After REQUEST_SENSE is complete, the failed command is again at the front of the queue and if the verdict was to terminate the request, the issue functions tries to complete it directly by calling drive->pc_callback() and returning ide_stopped. However, drive->pc_callback() doesn't complete a request. It only prepares for completion of the request. As a result, this creates an infinite loop where the failed request is retried perpetually. Fix it by actually ending the request by calling ide_complete_rq(). Signed-off-by: Tejun Heo diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index d3302cc..d20704a 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -141,6 +141,7 @@ static ide_startstop_t ide_floppy_issue_pc(ide_drive_t *drive, drive->failed_pc = NULL; drive->pc_callback(drive, 0); + ide_complete_rq(drive, -EIO, blk_rq_bytes(drive->hwif->rq)); return ide_stopped; } diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 9b762a2..2b9a136 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -643,6 +643,7 @@ static ide_startstop_t ide_tape_issue_pc(ide_drive_t *drive, } drive->failed_pc = NULL; drive->pc_callback(drive, 0); + ide_complete_rq(drive, -EIO, blk_rq_bytes(drive->hwif->rq)); return ide_stopped; } debug_log(DBG_SENSE, "Retry #%d, cmd = %02X\n", pc->retries, pc->c[0]); -- cgit v0.10.2 From eb6a61bb9543aa54d62595e27206b3d3c0293bcc Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 19 Apr 2009 08:46:02 +0900 Subject: ide-atapi,tape,floppy: allow ->pc_callback() to change rq->data_len Impact: allow residual count implementation in ->pc_callback() rq->data_len has two duties - carrying the number of input bytes on issue and carrying residual count back to the issuer on completion. ide-atapi completion callback ->pc_callback() is the right place to do this but currently ide-atapi depends on rq->data_len carrying the original request size after calling ->pc_callback() to complete the pc request. This patch makes ide_pc_intr(), ide_tape_issue_pc() and ide_floppy_issue_pc() cache length to complete before calling ->pc_callback() so that it can modify rq->data_len as necessary. Note: As using rq->data_len for two purposes can make cases like this incorrect in subtle ways, future changes will introduce separate field for residual count. Signed-off-by: Tejun Heo Cc: Jens Axboe diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c index 5cefe12..3df5442 100644 --- a/drivers/ide/ide-atapi.c +++ b/drivers/ide/ide-atapi.c @@ -409,6 +409,16 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) if ((pc->flags & PC_FLAG_WAIT_FOR_DSC) && (stat & ATA_DSC) == 0) dsc = 1; + /* + * ->pc_callback() might change rq->data_len for + * residual count, cache total length. + */ + if (!blk_special_request(rq) && + (drive->media == ide_tape && !rq->bio)) + done = ide_rq_bytes(rq); /* FIXME */ + else + done = blk_rq_bytes(rq); + /* Command finished - Call the callback function */ uptodate = drive->pc_callback(drive, dsc); @@ -417,7 +427,6 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) if (blk_special_request(rq)) { rq->errors = 0; - done = blk_rq_bytes(rq); error = 0; } else { @@ -426,11 +435,6 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) rq->errors = -EIO; } - if (drive->media == ide_tape && !rq->bio) - done = ide_rq_bytes(rq); /* FIXME */ - else - done = blk_rq_bytes(rq); - error = uptodate ? 0 : -EIO; } diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index d20704a..537b7c5 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -134,14 +134,17 @@ static ide_startstop_t ide_floppy_issue_pc(ide_drive_t *drive, drive->pc = pc; if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES) { + unsigned int done = blk_rq_bytes(drive->hwif->rq); + if (!(pc->flags & PC_FLAG_SUPPRESS_ERROR)) ide_floppy_report_error(floppy, pc); + /* Giving up */ pc->error = IDE_DRV_ERROR_GENERAL; drive->failed_pc = NULL; drive->pc_callback(drive, 0); - ide_complete_rq(drive, -EIO, blk_rq_bytes(drive->hwif->rq)); + ide_complete_rq(drive, -EIO, done); return ide_stopped; } diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 2b9a136..8226d52 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -622,6 +622,8 @@ static ide_startstop_t ide_tape_issue_pc(ide_drive_t *drive, if (pc->retries > IDETAPE_MAX_PC_RETRIES || (pc->flags & PC_FLAG_ABORT)) { + unsigned int done = blk_rq_bytes(drive->hwif->rq); + /* * We will "abort" retrying a packet command in case legitimate * error code was received (crossing a filemark, or end of the @@ -641,9 +643,10 @@ static ide_startstop_t ide_tape_issue_pc(ide_drive_t *drive, /* Giving up */ pc->error = IDE_DRV_ERROR_GENERAL; } + drive->failed_pc = NULL; drive->pc_callback(drive, 0); - ide_complete_rq(drive, -EIO, blk_rq_bytes(drive->hwif->rq)); + ide_complete_rq(drive, -EIO, done); return ide_stopped; } debug_log(DBG_SENSE, "Retry #%d, cmd = %02X\n", pc->retries, pc->c[0]); -- cgit v0.10.2 From 7b13354eeaabaf6283b8c669a7d67d104ce7c638 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 19 Apr 2009 08:46:02 +0900 Subject: ide-tape: use single continuous buffer Impact: simpler buffer allocation and handling, kills OOM, fix DMA transfers ide-tape has its own multiple buffer mechanism using struct idetape_bh. It allocates buffer with decreasing order-of-two allocations so that it results in minimum number of segments. However, the implementation is quite complex and works in a way that no other block or ide driver works necessitating a lot of special case handling. The benefit this complex allocation scheme brings is questionable as PIO or DMA the number of segments (16 maximum) doesn't make any noticeable difference and it also doesn't negate the need for multiple order allocation which can fail under memory pressure or high fragmentation although it does lower the highest order necessary by one when the buffer size isn't power of two. As the first step to remove the custom buffer management, this patch makes ide-tape allocate single continous buffer. The maximum order is four. I doubt the change would cause any trouble but if it ever matters, it should be converted to regular sg mechanism like everyone else and even in that case dropping custom buffer handling and moving to standard mechanism first make sense as an intermediate step. This patch makes the first bh to contain the whole buffer and drops multi bh handling code. Following patches will make further changes. This patch has the side effect of killing OOM triggered by allocation path and fixing DMA transfers. Previously, bug in alloc path triggered OOM on command issue and commands were passed to DMA engine without DMA-mapping all the segments. Signed-off-by: Tejun Heo diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 8226d52..b2afbc7 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -134,7 +134,6 @@ enum { struct idetape_bh { u32 b_size; atomic_t b_count; - struct idetape_bh *b_reqnext; char *b_data; }; @@ -228,10 +227,6 @@ typedef struct ide_tape_obj { char *b_data; int b_count; - int pages_per_buffer; - /* Wasted space in each stage */ - int excess_bh_size; - /* Measures average tape speed */ unsigned long avg_time; int avg_size; @@ -303,9 +298,7 @@ static int idetape_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, struct idetape_bh *bh = pc->bh; int count; - while (bcount) { - if (bh == NULL) - break; + if (bcount && bh) { count = min( (unsigned int)(bh->b_size - atomic_read(&bh->b_count)), bcount); @@ -313,15 +306,10 @@ static int idetape_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, atomic_read(&bh->b_count), count); bcount -= count; atomic_add(count, &bh->b_count); - if (atomic_read(&bh->b_count) == bh->b_size) { - bh = bh->b_reqnext; - if (bh) - atomic_set(&bh->b_count, 0); - } + if (atomic_read(&bh->b_count) == bh->b_size) + pc->bh = NULL; } - pc->bh = bh; - return bcount; } @@ -331,22 +319,14 @@ static int idetape_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, struct idetape_bh *bh = pc->bh; int count; - while (bcount) { - if (bh == NULL) - break; + if (bcount && bh) { count = min((unsigned int)pc->b_count, (unsigned int)bcount); drive->hwif->tp_ops->output_data(drive, NULL, pc->b_data, count); bcount -= count; pc->b_data += count; pc->b_count -= count; - if (!pc->b_count) { - bh = bh->b_reqnext; - pc->bh = bh; - if (bh) { - pc->b_data = bh->b_data; - pc->b_count = atomic_read(&bh->b_count); - } - } + if (!pc->b_count) + pc->bh = NULL; } return bcount; @@ -355,24 +335,20 @@ static int idetape_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, static void idetape_update_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc) { struct idetape_bh *bh = pc->bh; - int count; unsigned int bcount = pc->xferred; if (pc->flags & PC_FLAG_WRITING) return; - while (bcount) { - if (bh == NULL) { + if (bcount) { + if (bh == NULL || bcount > bh->b_size) { printk(KERN_ERR "ide-tape: bh == NULL in %s\n", __func__); return; } - count = min((unsigned int)bh->b_size, (unsigned int)bcount); - atomic_set(&bh->b_count, count); + atomic_set(&bh->b_count, bcount); if (atomic_read(&bh->b_count) == bh->b_size) - bh = bh->b_reqnext; - bcount -= count; + pc->bh = NULL; } - pc->bh = bh; } /* @@ -439,24 +415,10 @@ static void idetape_analyze_error(ide_drive_t *drive, u8 *sense) /* Free data buffers completely. */ static void ide_tape_kfree_buffer(idetape_tape_t *tape) { - struct idetape_bh *prev_bh, *bh = tape->merge_bh; - - while (bh) { - u32 size = bh->b_size; - - while (size) { - unsigned int order = fls(size >> PAGE_SHIFT)-1; - - if (bh->b_data) - free_pages((unsigned long)bh->b_data, order); + struct idetape_bh *bh = tape->merge_bh; - size &= (order-1); - bh->b_data += (1 << order) * PAGE_SIZE; - } - prev_bh = bh; - bh = bh->b_reqnext; - kfree(prev_bh); - } + kfree(bh->b_data); + kfree(bh); } static void ide_tape_handle_dsc(ide_drive_t *); @@ -861,117 +823,50 @@ out: } /* - * The function below uses __get_free_pages to allocate a data buffer of size - * tape->buffer_size (or a bit more). We attempt to combine sequential pages as - * much as possible. - * - * It returns a pointer to the newly allocated buffer, or NULL in case of - * failure. + * It returns a pointer to the newly allocated buffer, or NULL in case + * of failure. */ static struct idetape_bh *ide_tape_kmalloc_buffer(idetape_tape_t *tape, - int full, int clear) -{ - struct idetape_bh *prev_bh, *bh, *merge_bh; - int pages = tape->pages_per_buffer; - unsigned int order, b_allocd; - char *b_data = NULL; - - merge_bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL); - bh = merge_bh; - if (bh == NULL) - goto abort; - - order = fls(pages) - 1; - bh->b_data = (char *) __get_free_pages(GFP_KERNEL, order); - if (!bh->b_data) - goto abort; - b_allocd = (1 << order) * PAGE_SIZE; - pages &= (order-1); - - if (clear) - memset(bh->b_data, 0, b_allocd); - bh->b_reqnext = NULL; - bh->b_size = b_allocd; - atomic_set(&bh->b_count, full ? bh->b_size : 0); + int full) +{ + struct idetape_bh *bh; - while (pages) { - order = fls(pages) - 1; - b_data = (char *) __get_free_pages(GFP_KERNEL, order); - if (!b_data) - goto abort; - b_allocd = (1 << order) * PAGE_SIZE; - - if (clear) - memset(b_data, 0, b_allocd); - - /* newly allocated page frames below buffer header or ...*/ - if (bh->b_data == b_data + b_allocd) { - bh->b_size += b_allocd; - bh->b_data -= b_allocd; - if (full) - atomic_add(b_allocd, &bh->b_count); - continue; - } - /* they are above the header */ - if (b_data == bh->b_data + bh->b_size) { - bh->b_size += b_allocd; - if (full) - atomic_add(b_allocd, &bh->b_count); - continue; - } - prev_bh = bh; - bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL); - if (!bh) { - free_pages((unsigned long) b_data, order); - goto abort; - } - bh->b_reqnext = NULL; - bh->b_data = b_data; - bh->b_size = b_allocd; - atomic_set(&bh->b_count, full ? bh->b_size : 0); - prev_bh->b_reqnext = bh; + bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL); + if (!bh) + return NULL; - pages &= (order-1); + bh->b_data = kmalloc(tape->buffer_size, GFP_KERNEL); + if (!bh->b_data) { + kfree(bh); + return NULL; } - bh->b_size -= tape->excess_bh_size; - if (full) - atomic_sub(tape->excess_bh_size, &bh->b_count); - return merge_bh; -abort: - ide_tape_kfree_buffer(tape); - return NULL; + bh->b_size = tape->buffer_size; + atomic_set(&bh->b_count, full ? bh->b_size : 0); + + return bh; } static int idetape_copy_stage_from_user(idetape_tape_t *tape, const char __user *buf, int n) { struct idetape_bh *bh = tape->bh; - int count; int ret = 0; - while (n) { - if (bh == NULL) { + if (n) { + if (bh == NULL || n > bh->b_size - atomic_read(&bh->b_count)) { printk(KERN_ERR "ide-tape: bh == NULL in %s\n", __func__); return 1; } - count = min((unsigned int) - (bh->b_size - atomic_read(&bh->b_count)), - (unsigned int)n); if (copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf, - count)) + n)) ret = 1; - n -= count; - atomic_add(count, &bh->b_count); - buf += count; - if (atomic_read(&bh->b_count) == bh->b_size) { - bh = bh->b_reqnext; - if (bh) - atomic_set(&bh->b_count, 0); - } + atomic_add(n, &bh->b_count); + if (atomic_read(&bh->b_count) == bh->b_size) + tape->bh = NULL; } - tape->bh = bh; + return ret; } @@ -979,30 +874,20 @@ static int idetape_copy_stage_to_user(idetape_tape_t *tape, char __user *buf, int n) { struct idetape_bh *bh = tape->bh; - int count; int ret = 0; - while (n) { - if (bh == NULL) { + if (n) { + if (bh == NULL || n > tape->b_count) { printk(KERN_ERR "ide-tape: bh == NULL in %s\n", __func__); return 1; } - count = min(tape->b_count, n); - if (copy_to_user(buf, tape->b_data, count)) + if (copy_to_user(buf, tape->b_data, n)) ret = 1; - n -= count; - tape->b_data += count; - tape->b_count -= count; - buf += count; - if (!tape->b_count) { - bh = bh->b_reqnext; - tape->bh = bh; - if (bh) { - tape->b_data = bh->b_data; - tape->b_count = atomic_read(&bh->b_count); - } - } + tape->b_data += n; + tape->b_count -= n; + if (!tape->b_count) + tape->bh = NULL; } return ret; } @@ -1254,7 +1139,7 @@ static int idetape_add_chrdev_write_request(ide_drive_t *drive, int blocks) static void ide_tape_flush_merge_buffer(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; - int blocks, min; + int blocks; struct idetape_bh *bh; if (tape->chrdev_dir != IDETAPE_DIR_WRITE) { @@ -1269,31 +1154,16 @@ static void ide_tape_flush_merge_buffer(ide_drive_t *drive) if (tape->merge_bh_size) { blocks = tape->merge_bh_size / tape->blk_size; if (tape->merge_bh_size % tape->blk_size) { - unsigned int i; - + unsigned int i = tape->blk_size - + tape->merge_bh_size % tape->blk_size; blocks++; - i = tape->blk_size - tape->merge_bh_size % - tape->blk_size; - bh = tape->bh->b_reqnext; - while (bh) { - atomic_set(&bh->b_count, 0); - bh = bh->b_reqnext; - } bh = tape->bh; - while (i) { - if (bh == NULL) { - printk(KERN_INFO "ide-tape: bug," - " bh NULL\n"); - break; - } - min = min(i, (unsigned int)(bh->b_size - - atomic_read(&bh->b_count))); + if (bh) { memset(bh->b_data + atomic_read(&bh->b_count), - 0, min); - atomic_add(min, &bh->b_count); - i -= min; - bh = bh->b_reqnext; - } + 0, i); + atomic_add(i, &bh->b_count); + } else + printk(KERN_INFO "ide-tape: bug, bh NULL\n"); } (void) idetape_add_chrdev_write_request(drive, blocks); tape->merge_bh_size = 0; @@ -1321,7 +1191,7 @@ static int idetape_init_read(ide_drive_t *drive) " 0 now\n"); tape->merge_bh_size = 0; } - tape->merge_bh = ide_tape_kmalloc_buffer(tape, 0, 0); + tape->merge_bh = ide_tape_kmalloc_buffer(tape, 0); if (!tape->merge_bh) return -ENOMEM; tape->chrdev_dir = IDETAPE_DIR_READ; @@ -1368,23 +1238,18 @@ static int idetape_add_chrdev_read_request(ide_drive_t *drive, int blocks) static void idetape_pad_zeros(ide_drive_t *drive, int bcount) { idetape_tape_t *tape = drive->driver_data; - struct idetape_bh *bh; + struct idetape_bh *bh = tape->merge_bh; int blocks; while (bcount) { unsigned int count; - bh = tape->merge_bh; count = min(tape->buffer_size, bcount); bcount -= count; blocks = count / tape->blk_size; - while (count) { - atomic_set(&bh->b_count, - min(count, (unsigned int)bh->b_size)); - memset(bh->b_data, 0, atomic_read(&bh->b_count)); - count -= atomic_read(&bh->b_count); - bh = bh->b_reqnext; - } + atomic_set(&bh->b_count, count); + memset(bh->b_data, 0, atomic_read(&bh->b_count)); + idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, blocks, tape->merge_bh); } @@ -1596,7 +1461,7 @@ static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf, "should be 0 now\n"); tape->merge_bh_size = 0; } - tape->merge_bh = ide_tape_kmalloc_buffer(tape, 0, 0); + tape->merge_bh = ide_tape_kmalloc_buffer(tape, 0); if (!tape->merge_bh) return -ENOMEM; tape->chrdev_dir = IDETAPE_DIR_WRITE; @@ -1970,7 +1835,7 @@ static void idetape_write_release(ide_drive_t *drive, unsigned int minor) idetape_tape_t *tape = drive->driver_data; ide_tape_flush_merge_buffer(drive); - tape->merge_bh = ide_tape_kmalloc_buffer(tape, 1, 0); + tape->merge_bh = ide_tape_kmalloc_buffer(tape, 1); if (tape->merge_bh != NULL) { idetape_pad_zeros(drive, tape->blk_size * (tape->user_bs_factor - 1)); @@ -2201,11 +2066,6 @@ static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor) tape->buffer_size = *ctl * tape->blk_size; } buffer_size = tape->buffer_size; - tape->pages_per_buffer = buffer_size / PAGE_SIZE; - if (buffer_size % PAGE_SIZE) { - tape->pages_per_buffer++; - tape->excess_bh_size = PAGE_SIZE - buffer_size % PAGE_SIZE; - } /* select the "best" DSC read/write polling freq */ speed = max(*(u16 *)&tape->caps[14], *(u16 *)&tape->caps[8]); -- cgit v0.10.2 From e998f30b45efb99a3c3ce7b5483f76317a17abed Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 19 Apr 2009 08:46:02 +0900 Subject: ide-tape: use standard data transfer mechanism Impact: use standard way to transfer data ide-tape uses rq in an interesting way. For r/w requests, rq->special is used to carry a private buffer management structure idetape_bh and rq->nr_sectors and current_nr_sectors are initialized to the number of idetape blocks which isn't necessary 512 bytes. Also, rq->current_nr_sectors is used to report back the residual count in units of idetape blocks. This peculiarity taxes both block layer and ide. ide-atapi has different paths and hooks to accomodate it and what a rq means becomes quite confusing and making changes at the block layer becomes quite difficult and error-prone. This patch makes ide-tape use bio instead. With the previous patch, ide-tape currently is using single contiguos buffer so replacing it isn't difficult. Data buffer is mapped into bio using blk_rq_map_kern() in idetape_queue_rw_tail(). idetape_io_buffers() and idetape_update_buffers() are dropped and pc->bh is set to null to tell ide-atapi to use standard data transfer mechanism and idetape_bh byte counts are updated by the issuer on completion using the residual count. This change also nicely removes the FIXME in ide_pc_intr() where ide-tape rqs need to be completed using ide_rq_bytes() instead of blk_rq_bytes() (although this didn't really matter as the request didn't have bio). Signed-off-by: Tejun Heo Cc: Jens Axboe diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c index 3df5442..b9dd450 100644 --- a/drivers/ide/ide-atapi.c +++ b/drivers/ide/ide-atapi.c @@ -413,11 +413,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) * ->pc_callback() might change rq->data_len for * residual count, cache total length. */ - if (!blk_special_request(rq) && - (drive->media == ide_tape && !rq->bio)) - done = ide_rq_bytes(rq); /* FIXME */ - else - done = blk_rq_bytes(rq); + done = blk_rq_bytes(rq); /* Command finished - Call the callback function */ uptodate = drive->pc_callback(drive, dsc); diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index b2afbc7..b373ac8 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -292,65 +292,6 @@ static struct ide_tape_obj *ide_tape_chrdev_get(unsigned int i) return tape; } -static int idetape_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, - unsigned int bcount) -{ - struct idetape_bh *bh = pc->bh; - int count; - - if (bcount && bh) { - count = min( - (unsigned int)(bh->b_size - atomic_read(&bh->b_count)), - bcount); - drive->hwif->tp_ops->input_data(drive, NULL, bh->b_data + - atomic_read(&bh->b_count), count); - bcount -= count; - atomic_add(count, &bh->b_count); - if (atomic_read(&bh->b_count) == bh->b_size) - pc->bh = NULL; - } - - return bcount; -} - -static int idetape_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, - unsigned int bcount) -{ - struct idetape_bh *bh = pc->bh; - int count; - - if (bcount && bh) { - count = min((unsigned int)pc->b_count, (unsigned int)bcount); - drive->hwif->tp_ops->output_data(drive, NULL, pc->b_data, count); - bcount -= count; - pc->b_data += count; - pc->b_count -= count; - if (!pc->b_count) - pc->bh = NULL; - } - - return bcount; -} - -static void idetape_update_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc) -{ - struct idetape_bh *bh = pc->bh; - unsigned int bcount = pc->xferred; - - if (pc->flags & PC_FLAG_WRITING) - return; - if (bcount) { - if (bh == NULL || bcount > bh->b_size) { - printk(KERN_ERR "ide-tape: bh == NULL in %s\n", - __func__); - return; - } - atomic_set(&bh->b_count, bcount); - if (atomic_read(&bh->b_count) == bh->b_size) - pc->bh = NULL; - } -} - /* * called on each failed packet command retry to analyze the request sense. We * currently do not utilize this information. @@ -368,12 +309,10 @@ static void idetape_analyze_error(ide_drive_t *drive, u8 *sense) pc->c[0], tape->sense_key, tape->asc, tape->ascq); /* Correct pc->xferred by asking the tape. */ - if (pc->flags & PC_FLAG_DMA_ERROR) { + if (pc->flags & PC_FLAG_DMA_ERROR) pc->xferred = pc->req_xfer - tape->blk_size * get_unaligned_be32(&sense[3]); - idetape_update_buffers(drive, pc); - } /* * If error was the result of a zero-length read or write command, @@ -458,7 +397,7 @@ static int ide_tape_callback(ide_drive_t *drive, int dsc) } tape->first_frame += blocks; - rq->current_nr_sectors -= blocks; + rq->data_len -= blocks * tape->blk_size; if (pc->error) { uptodate = 0; @@ -520,19 +459,6 @@ static void ide_tape_handle_dsc(ide_drive_t *drive) idetape_postpone_request(drive); } -static int ide_tape_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, - unsigned int bcount, int write) -{ - unsigned int bleft; - - if (write) - bleft = idetape_output_buffers(drive, pc, bcount); - else - bleft = idetape_input_buffers(drive, pc, bcount); - - return bcount - bleft; -} - /* * Packet Command Interface * @@ -683,7 +609,7 @@ static void ide_tape_create_rw_cmd(idetape_tape_t *tape, ide_init_pc(pc); put_unaligned(cpu_to_be32(length), (unsigned int *) &pc->c[1]); pc->c[1] = 1; - pc->bh = bh; + pc->bh = NULL; pc->buf = NULL; pc->buf_size = length * tape->blk_size; pc->req_xfer = pc->buf_size; @@ -1063,10 +989,12 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks, struct idetape_bh *bh) { idetape_tape_t *tape = drive->driver_data; + size_t size = blocks * tape->blk_size; struct request *rq; - int ret, errors; + int ret; debug_log(DBG_SENSE, "%s: cmd=%d\n", __func__, cmd); + BUG_ON(cmd != REQ_IDETAPE_READ && cmd != REQ_IDETAPE_WRITE); rq = blk_get_request(drive->queue, READ, __GFP_WAIT); rq->cmd_type = REQ_TYPE_SPECIAL; @@ -1074,21 +1002,29 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks, rq->rq_disk = tape->disk; rq->special = (void *)bh; rq->sector = tape->first_frame; - rq->nr_sectors = blocks; - rq->current_nr_sectors = blocks; + + if (size) { + ret = blk_rq_map_kern(drive->queue, rq, bh->b_data, size, + __GFP_WAIT); + if (ret) + goto out_put; + } + blk_execute_rq(drive->queue, tape->disk, rq, 0); - errors = rq->errors; - ret = tape->blk_size * (blocks - rq->current_nr_sectors); - blk_put_request(rq); + /* calculate the number of transferred bytes and update bh */ + size -= rq->data_len; + if (cmd == REQ_IDETAPE_READ) + atomic_add(size, &bh->b_count); - if ((cmd & (REQ_IDETAPE_READ | REQ_IDETAPE_WRITE)) == 0) - return 0; + ret = size; + if (rq->errors == IDE_DRV_ERROR_GENERAL) + ret = -EIO; if (tape->merge_bh) idetape_init_merge_buffer(tape); - if (errors == IDE_DRV_ERROR_GENERAL) - return -EIO; +out_put: + blk_put_request(rq); return ret; } @@ -2034,8 +1970,6 @@ static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor) u16 *ctl = (u16 *)&tape->caps[12]; drive->pc_callback = ide_tape_callback; - drive->pc_update_buffers = idetape_update_buffers; - drive->pc_io_buffers = ide_tape_io_buffers; drive->dev_flags |= IDE_DFLAG_DSC_OVERLAP; -- cgit v0.10.2 From 6cf3d545f7d71b183e5b89960d4cc850a42c410d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 19 Apr 2009 08:46:02 +0900 Subject: ide-tape: kill idetape_bh Impact: kill now unnecessary idetape_bh With everything using standard mechanisms, there is no need for idetape_bh anymore. Kill it and use tape->buf, cur and valid to describe data buffer instead. Changes worth mentioning are... * idetape_queue_rq_tail() now always queue tape->buf and and adjusts buffer state properly before completion. * idetape_pad_zeros() clears the buffer only once. Signed-off-by: Tejun Heo diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index b373ac8..d2e9c09 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -131,12 +131,6 @@ enum { IDETAPE_DIR_WRITE = (1 << 2), }; -struct idetape_bh { - u32 b_size; - atomic_t b_count; - char *b_data; -}; - /* Tape door status */ #define DOOR_UNLOCKED 0 #define DOOR_LOCKED 1 @@ -218,14 +212,12 @@ typedef struct ide_tape_obj { /* Data buffer size chosen based on the tape's recommendation */ int buffer_size; - /* merge buffer */ - struct idetape_bh *merge_bh; - /* size of the merge buffer */ - int merge_bh_size; - /* pointer to current buffer head within the merge buffer */ - struct idetape_bh *bh; - char *b_data; - int b_count; + /* Staging buffer of buffer_size bytes */ + void *buf; + /* The read/write cursor */ + void *cur; + /* The number of valid bytes in buf */ + size_t valid; /* Measures average tape speed */ unsigned long avg_time; @@ -351,15 +343,6 @@ static void idetape_analyze_error(ide_drive_t *drive, u8 *sense) } } -/* Free data buffers completely. */ -static void ide_tape_kfree_buffer(idetape_tape_t *tape) -{ - struct idetape_bh *bh = tape->merge_bh; - - kfree(bh->b_data); - kfree(bh); -} - static void ide_tape_handle_dsc(ide_drive_t *); static int ide_tape_callback(ide_drive_t *drive, int dsc) @@ -603,8 +586,7 @@ static void ide_tape_create_rw_cmd(idetape_tape_t *tape, struct ide_atapi_pc *pc, struct request *rq, u8 opcode) { - struct idetape_bh *bh = (struct idetape_bh *)rq->special; - unsigned int length = rq->current_nr_sectors; + unsigned int length = rq->nr_sectors; ide_init_pc(pc); put_unaligned(cpu_to_be32(length), (unsigned int *) &pc->c[1]); @@ -616,14 +598,11 @@ static void ide_tape_create_rw_cmd(idetape_tape_t *tape, if (pc->req_xfer == tape->buffer_size) pc->flags |= PC_FLAG_DMA_OK; - if (opcode == READ_6) { + if (opcode == READ_6) pc->c[0] = READ_6; - atomic_set(&bh->b_count, 0); - } else if (opcode == WRITE_6) { + else if (opcode == WRITE_6) { pc->c[0] = WRITE_6; pc->flags |= PC_FLAG_WRITING; - pc->b_data = bh->b_data; - pc->b_count = atomic_read(&bh->b_count); } memcpy(rq->cmd, pc->c, 12); @@ -639,10 +618,8 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, struct ide_cmd cmd; u8 stat; - debug_log(DBG_SENSE, "sector: %llu, nr_sectors: %lu," - " current_nr_sectors: %u\n", - (unsigned long long)rq->sector, rq->nr_sectors, - rq->current_nr_sectors); + debug_log(DBG_SENSE, "sector: %llu, nr_sectors: %lu\n" + (unsigned long long)rq->sector, rq->nr_sectors); if (!(blk_special_request(rq) || blk_sense_request(rq))) { /* We do not support buffer cache originated requests. */ @@ -749,89 +726,6 @@ out: } /* - * It returns a pointer to the newly allocated buffer, or NULL in case - * of failure. - */ -static struct idetape_bh *ide_tape_kmalloc_buffer(idetape_tape_t *tape, - int full) -{ - struct idetape_bh *bh; - - bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL); - if (!bh) - return NULL; - - bh->b_data = kmalloc(tape->buffer_size, GFP_KERNEL); - if (!bh->b_data) { - kfree(bh); - return NULL; - } - - bh->b_size = tape->buffer_size; - atomic_set(&bh->b_count, full ? bh->b_size : 0); - - return bh; -} - -static int idetape_copy_stage_from_user(idetape_tape_t *tape, - const char __user *buf, int n) -{ - struct idetape_bh *bh = tape->bh; - int ret = 0; - - if (n) { - if (bh == NULL || n > bh->b_size - atomic_read(&bh->b_count)) { - printk(KERN_ERR "ide-tape: bh == NULL in %s\n", - __func__); - return 1; - } - if (copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf, - n)) - ret = 1; - atomic_add(n, &bh->b_count); - if (atomic_read(&bh->b_count) == bh->b_size) - tape->bh = NULL; - } - - return ret; -} - -static int idetape_copy_stage_to_user(idetape_tape_t *tape, char __user *buf, - int n) -{ - struct idetape_bh *bh = tape->bh; - int ret = 0; - - if (n) { - if (bh == NULL || n > tape->b_count) { - printk(KERN_ERR "ide-tape: bh == NULL in %s\n", - __func__); - return 1; - } - if (copy_to_user(buf, tape->b_data, n)) - ret = 1; - tape->b_data += n; - tape->b_count -= n; - if (!tape->b_count) - tape->bh = NULL; - } - return ret; -} - -static void idetape_init_merge_buffer(idetape_tape_t *tape) -{ - struct idetape_bh *bh = tape->merge_bh; - tape->bh = tape->merge_bh; - - if (tape->chrdev_dir == IDETAPE_DIR_WRITE) - atomic_set(&bh->b_count, 0); - else { - tape->b_data = bh->b_data; - tape->b_count = atomic_read(&bh->b_count); - } -} - -/* * Write a filemark if write_filemark=1. Flush the device buffers without * writing a filemark otherwise. */ @@ -928,10 +822,10 @@ static void __ide_tape_discard_merge_buffer(ide_drive_t *drive) return; clear_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags); - tape->merge_bh_size = 0; - if (tape->merge_bh != NULL) { - ide_tape_kfree_buffer(tape); - tape->merge_bh = NULL; + tape->valid = 0; + if (tape->buf != NULL) { + kfree(tape->buf); + tape->buf = NULL; } tape->chrdev_dir = IDETAPE_DIR_NONE; @@ -985,8 +879,7 @@ static void ide_tape_discard_merge_buffer(ide_drive_t *drive, * Generate a read/write request for the block device interface and wait for it * to be serviced. */ -static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks, - struct idetape_bh *bh) +static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks) { idetape_tape_t *tape = drive->driver_data; size_t size = blocks * tape->blk_size; @@ -1000,11 +893,10 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks, rq->cmd_type = REQ_TYPE_SPECIAL; rq->cmd[13] = cmd; rq->rq_disk = tape->disk; - rq->special = (void *)bh; rq->sector = tape->first_frame; if (size) { - ret = blk_rq_map_kern(drive->queue, rq, bh->b_data, size, + ret = blk_rq_map_kern(drive->queue, rq, tape->buf, size, __GFP_WAIT); if (ret) goto out_put; @@ -1012,17 +904,17 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks, blk_execute_rq(drive->queue, tape->disk, rq, 0); - /* calculate the number of transferred bytes and update bh */ + /* calculate the number of transferred bytes and update buffer state */ size -= rq->data_len; + tape->cur = tape->buf; if (cmd == REQ_IDETAPE_READ) - atomic_add(size, &bh->b_count); + tape->valid = size; + else + tape->valid = 0; ret = size; if (rq->errors == IDE_DRV_ERROR_GENERAL) ret = -EIO; - - if (tape->merge_bh) - idetape_init_merge_buffer(tape); out_put: blk_put_request(rq); return ret; @@ -1064,49 +956,33 @@ static void idetape_create_space_cmd(struct ide_atapi_pc *pc, int count, u8 cmd) /* Queue up a character device originated write request. */ static int idetape_add_chrdev_write_request(ide_drive_t *drive, int blocks) { - idetape_tape_t *tape = drive->driver_data; - debug_log(DBG_CHRDEV, "Enter %s\n", __func__); - return idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, - blocks, tape->merge_bh); + return idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, blocks); } static void ide_tape_flush_merge_buffer(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; int blocks; - struct idetape_bh *bh; if (tape->chrdev_dir != IDETAPE_DIR_WRITE) { printk(KERN_ERR "ide-tape: bug: Trying to empty merge buffer" " but we are not writing.\n"); return; } - if (tape->merge_bh_size > tape->buffer_size) { - printk(KERN_ERR "ide-tape: bug: merge_buffer too big\n"); - tape->merge_bh_size = tape->buffer_size; - } - if (tape->merge_bh_size) { - blocks = tape->merge_bh_size / tape->blk_size; - if (tape->merge_bh_size % tape->blk_size) { - unsigned int i = tape->blk_size - - tape->merge_bh_size % tape->blk_size; + if (tape->buf) { + blocks = tape->valid / tape->blk_size; + if (tape->valid % tape->blk_size) { blocks++; - bh = tape->bh; - if (bh) { - memset(bh->b_data + atomic_read(&bh->b_count), - 0, i); - atomic_add(i, &bh->b_count); - } else - printk(KERN_INFO "ide-tape: bug, bh NULL\n"); + memset(tape->buf + tape->valid, 0, + tape->blk_size - tape->valid % tape->blk_size); } (void) idetape_add_chrdev_write_request(drive, blocks); - tape->merge_bh_size = 0; } - if (tape->merge_bh != NULL) { - ide_tape_kfree_buffer(tape); - tape->merge_bh = NULL; + if (tape->buf != NULL) { + kfree(tape->buf); + tape->buf = NULL; } tape->chrdev_dir = IDETAPE_DIR_NONE; } @@ -1122,15 +998,15 @@ static int idetape_init_read(ide_drive_t *drive) ide_tape_flush_merge_buffer(drive); idetape_flush_tape_buffers(drive); } - if (tape->merge_bh || tape->merge_bh_size) { - printk(KERN_ERR "ide-tape: merge_bh_size should be" - " 0 now\n"); - tape->merge_bh_size = 0; + if (tape->buf || tape->valid) { + printk(KERN_ERR "ide-tape: valid should be 0 now\n"); + tape->valid = 0; } - tape->merge_bh = ide_tape_kmalloc_buffer(tape, 0); - if (!tape->merge_bh) + tape->buf = kmalloc(tape->buffer_size, GFP_KERNEL); + if (!tape->buf) return -ENOMEM; tape->chrdev_dir = IDETAPE_DIR_READ; + tape->cur = tape->buf; /* * Issue a read 0 command to ensure that DSC handshake is @@ -1140,11 +1016,10 @@ static int idetape_init_read(ide_drive_t *drive) */ if (drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) { bytes_read = idetape_queue_rw_tail(drive, - REQ_IDETAPE_READ, 0, - tape->merge_bh); + REQ_IDETAPE_READ, 0); if (bytes_read < 0) { - ide_tape_kfree_buffer(tape); - tape->merge_bh = NULL; + kfree(tape->buf); + tape->buf = NULL; tape->chrdev_dir = IDETAPE_DIR_NONE; return bytes_read; } @@ -1157,8 +1032,6 @@ static int idetape_init_read(ide_drive_t *drive) /* called from idetape_chrdev_read() to service a chrdev read request. */ static int idetape_add_chrdev_read_request(ide_drive_t *drive, int blocks) { - idetape_tape_t *tape = drive->driver_data; - debug_log(DBG_PROCS, "Enter %s, %d blocks\n", __func__, blocks); /* If we are at a filemark, return a read length of 0 */ @@ -1167,27 +1040,21 @@ static int idetape_add_chrdev_read_request(ide_drive_t *drive, int blocks) idetape_init_read(drive); - return idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, blocks, - tape->merge_bh); + return idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, blocks); } static void idetape_pad_zeros(ide_drive_t *drive, int bcount) { idetape_tape_t *tape = drive->driver_data; - struct idetape_bh *bh = tape->merge_bh; - int blocks; + + memset(tape->buf, 0, tape->buffer_size); while (bcount) { - unsigned int count; + unsigned int count = min(tape->buffer_size, bcount); - count = min(tape->buffer_size, bcount); + idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, + count / tape->blk_size); bcount -= count; - blocks = count / tape->blk_size; - atomic_set(&bh->b_count, count); - memset(bh->b_data, 0, atomic_read(&bh->b_count)); - - idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, blocks, - tape->merge_bh); } } @@ -1267,7 +1134,7 @@ static int idetape_space_over_filemarks(ide_drive_t *drive, short mt_op, } if (tape->chrdev_dir == IDETAPE_DIR_READ) { - tape->merge_bh_size = 0; + tape->valid = 0; if (test_and_clear_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags)) ++count; ide_tape_discard_merge_buffer(drive, 0); @@ -1333,20 +1200,20 @@ static ssize_t idetape_chrdev_read(struct file *file, char __user *buf, return rc; if (count == 0) return (0); - if (tape->merge_bh_size) { - actually_read = min((unsigned int)(tape->merge_bh_size), - (unsigned int)count); - if (idetape_copy_stage_to_user(tape, buf, actually_read)) + if (tape->valid) { + actually_read = min_t(unsigned int, tape->valid, count); + if (copy_to_user(buf, tape->cur, actually_read)) ret = -EFAULT; buf += actually_read; - tape->merge_bh_size -= actually_read; count -= actually_read; + tape->cur += actually_read; + tape->valid -= actually_read; } while (count >= tape->buffer_size) { bytes_read = idetape_add_chrdev_read_request(drive, ctl); if (bytes_read <= 0) goto finish; - if (idetape_copy_stage_to_user(tape, buf, bytes_read)) + if (copy_to_user(buf, tape->cur, bytes_read)) ret = -EFAULT; buf += bytes_read; count -= bytes_read; @@ -1357,10 +1224,11 @@ static ssize_t idetape_chrdev_read(struct file *file, char __user *buf, if (bytes_read <= 0) goto finish; temp = min((unsigned long)count, (unsigned long)bytes_read); - if (idetape_copy_stage_to_user(tape, buf, temp)) + if (copy_to_user(buf, tape->cur, temp)) ret = -EFAULT; actually_read += temp; - tape->merge_bh_size = bytes_read-temp; + tape->cur += temp; + tape->valid -= temp; } finish: if (!actually_read && test_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags)) { @@ -1392,16 +1260,15 @@ static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf, if (tape->chrdev_dir != IDETAPE_DIR_WRITE) { if (tape->chrdev_dir == IDETAPE_DIR_READ) ide_tape_discard_merge_buffer(drive, 1); - if (tape->merge_bh || tape->merge_bh_size) { - printk(KERN_ERR "ide-tape: merge_bh_size " - "should be 0 now\n"); - tape->merge_bh_size = 0; + if (tape->buf || tape->valid) { + printk(KERN_ERR "ide-tape: valid should be 0 now\n"); + tape->valid = 0; } - tape->merge_bh = ide_tape_kmalloc_buffer(tape, 0); - if (!tape->merge_bh) + tape->buf = kmalloc(tape->buffer_size, GFP_KERNEL); + if (!tape->buf) return -ENOMEM; tape->chrdev_dir = IDETAPE_DIR_WRITE; - idetape_init_merge_buffer(tape); + tape->cur = tape->buf; /* * Issue a write 0 command to ensure that DSC handshake is @@ -1411,11 +1278,10 @@ static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf, */ if (drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) { ssize_t retval = idetape_queue_rw_tail(drive, - REQ_IDETAPE_WRITE, 0, - tape->merge_bh); + REQ_IDETAPE_WRITE, 0); if (retval < 0) { - ide_tape_kfree_buffer(tape); - tape->merge_bh = NULL; + kfree(tape->buf); + tape->buf = NULL; tape->chrdev_dir = IDETAPE_DIR_NONE; return retval; } @@ -1423,23 +1289,19 @@ static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf, } if (count == 0) return (0); - if (tape->merge_bh_size) { - if (tape->merge_bh_size >= tape->buffer_size) { - printk(KERN_ERR "ide-tape: bug: merge buf too big\n"); - tape->merge_bh_size = 0; - } - actually_written = min((unsigned int) - (tape->buffer_size - tape->merge_bh_size), - (unsigned int)count); - if (idetape_copy_stage_from_user(tape, buf, actually_written)) - ret = -EFAULT; + if (tape->valid < tape->buffer_size) { + actually_written = min_t(unsigned int, + tape->buffer_size - tape->valid, + count); + if (copy_from_user(tape->cur, buf, actually_written)) + ret = -EFAULT; buf += actually_written; - tape->merge_bh_size += actually_written; count -= actually_written; + tape->cur += actually_written; + tape->valid += actually_written; - if (tape->merge_bh_size == tape->buffer_size) { + if (tape->valid == tape->buffer_size) { ssize_t retval; - tape->merge_bh_size = 0; retval = idetape_add_chrdev_write_request(drive, ctl); if (retval <= 0) return (retval); @@ -1447,7 +1309,7 @@ static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf, } while (count >= tape->buffer_size) { ssize_t retval; - if (idetape_copy_stage_from_user(tape, buf, tape->buffer_size)) + if (copy_from_user(tape->cur, buf, tape->buffer_size)) ret = -EFAULT; buf += tape->buffer_size; count -= tape->buffer_size; @@ -1458,9 +1320,10 @@ static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf, } if (count) { actually_written += count; - if (idetape_copy_stage_from_user(tape, buf, count)) + if (copy_from_user(tape->cur, buf, count)) ret = -EFAULT; - tape->merge_bh_size += count; + tape->cur += count; + tape->valid += count; } return ret ? ret : actually_written; } @@ -1623,7 +1486,7 @@ static int idetape_chrdev_ioctl(struct inode *inode, struct file *file, idetape_flush_tape_buffers(drive); } if (cmd == MTIOCGET || cmd == MTIOCPOS) { - block_offset = tape->merge_bh_size / + block_offset = tape->valid / (tape->blk_size * tape->user_bs_factor); position = idetape_read_position(drive); if (position < 0) @@ -1771,12 +1634,12 @@ static void idetape_write_release(ide_drive_t *drive, unsigned int minor) idetape_tape_t *tape = drive->driver_data; ide_tape_flush_merge_buffer(drive); - tape->merge_bh = ide_tape_kmalloc_buffer(tape, 1); - if (tape->merge_bh != NULL) { + tape->buf = kmalloc(tape->buffer_size, GFP_KERNEL); + if (tape->buf != NULL) { idetape_pad_zeros(drive, tape->blk_size * (tape->user_bs_factor - 1)); - ide_tape_kfree_buffer(tape); - tape->merge_bh = NULL; + kfree(tape->buf); + tape->buf = NULL; } idetape_write_filemark(drive); idetape_flush_tape_buffers(drive); @@ -2042,7 +1905,7 @@ static void ide_tape_release(struct device *dev) ide_drive_t *drive = tape->drive; struct gendisk *g = tape->disk; - BUG_ON(tape->merge_bh_size); + BUG_ON(tape->valid); drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP; drive->driver_data = NULL; -- cgit v0.10.2 From 3596b66452491a3cff26256a5e6e6061a66c4142 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 19 Apr 2009 08:46:02 +0900 Subject: ide-tape: unify r/w init paths Impact: cleanup Read and write init paths are almost identical. Unify them into idetape_init_rw(). Signed-off-by: Tejun Heo diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index d2e9c09..4da7fa9 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -987,42 +987,50 @@ static void ide_tape_flush_merge_buffer(ide_drive_t *drive) tape->chrdev_dir = IDETAPE_DIR_NONE; } -static int idetape_init_read(ide_drive_t *drive) +static int idetape_init_rw(ide_drive_t *drive, int dir) { idetape_tape_t *tape = drive->driver_data; - int bytes_read; + int rc; - /* Initialize read operation */ - if (tape->chrdev_dir != IDETAPE_DIR_READ) { - if (tape->chrdev_dir == IDETAPE_DIR_WRITE) { - ide_tape_flush_merge_buffer(drive); - idetape_flush_tape_buffers(drive); - } - if (tape->buf || tape->valid) { - printk(KERN_ERR "ide-tape: valid should be 0 now\n"); - tape->valid = 0; - } - tape->buf = kmalloc(tape->buffer_size, GFP_KERNEL); - if (!tape->buf) - return -ENOMEM; - tape->chrdev_dir = IDETAPE_DIR_READ; - tape->cur = tape->buf; + BUG_ON(dir != IDETAPE_DIR_READ && dir != IDETAPE_DIR_WRITE); - /* - * Issue a read 0 command to ensure that DSC handshake is - * switched from completion mode to buffer available mode. - * No point in issuing this if DSC overlap isn't supported, some - * drives (Seagate STT3401A) will return an error. - */ - if (drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) { - bytes_read = idetape_queue_rw_tail(drive, - REQ_IDETAPE_READ, 0); - if (bytes_read < 0) { - kfree(tape->buf); - tape->buf = NULL; - tape->chrdev_dir = IDETAPE_DIR_NONE; - return bytes_read; - } + if (tape->chrdev_dir == dir) + return 0; + + if (tape->chrdev_dir == IDETAPE_DIR_READ) + ide_tape_discard_merge_buffer(drive, 1); + else if (tape->chrdev_dir == IDETAPE_DIR_WRITE) { + ide_tape_flush_merge_buffer(drive); + idetape_flush_tape_buffers(drive); + } + + if (tape->buf || tape->valid) { + printk(KERN_ERR "ide-tape: valid should be 0 now\n"); + tape->valid = 0; + } + + tape->buf = kmalloc(tape->buffer_size, GFP_KERNEL); + if (!tape->buf) + return -ENOMEM; + tape->chrdev_dir = dir; + tape->cur = tape->buf; + + /* + * Issue a 0 rw command to ensure that DSC handshake is + * switched from completion mode to buffer available mode. No + * point in issuing this if DSC overlap isn't supported, some + * drives (Seagate STT3401A) will return an error. + */ + if (drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) { + int cmd = dir == IDETAPE_DIR_READ ? REQ_IDETAPE_READ + : REQ_IDETAPE_WRITE; + + rc = idetape_queue_rw_tail(drive, cmd, 0); + if (rc < 0) { + kfree(tape->buf); + tape->buf = NULL; + tape->chrdev_dir = IDETAPE_DIR_NONE; + return rc; } } @@ -1038,7 +1046,7 @@ static int idetape_add_chrdev_read_request(ide_drive_t *drive, int blocks) if (test_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags)) return 0; - idetape_init_read(drive); + idetape_init_rw(drive, IDETAPE_DIR_READ); return idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, blocks); } @@ -1195,7 +1203,7 @@ static ssize_t idetape_chrdev_read(struct file *file, char __user *buf, (count % tape->blk_size) == 0) tape->user_bs_factor = count / tape->blk_size; } - rc = idetape_init_read(drive); + rc = idetape_init_rw(drive, IDETAPE_DIR_READ); if (rc < 0) return rc; if (count == 0) @@ -1249,6 +1257,7 @@ static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf, ssize_t actually_written = 0; ssize_t ret = 0; u16 ctl = *(u16 *)&tape->caps[12]; + int rc; /* The drive is write protected. */ if (tape->write_prot) @@ -1257,36 +1266,9 @@ static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf, debug_log(DBG_CHRDEV, "Enter %s, count %Zd\n", __func__, count); /* Initialize write operation */ - if (tape->chrdev_dir != IDETAPE_DIR_WRITE) { - if (tape->chrdev_dir == IDETAPE_DIR_READ) - ide_tape_discard_merge_buffer(drive, 1); - if (tape->buf || tape->valid) { - printk(KERN_ERR "ide-tape: valid should be 0 now\n"); - tape->valid = 0; - } - tape->buf = kmalloc(tape->buffer_size, GFP_KERNEL); - if (!tape->buf) - return -ENOMEM; - tape->chrdev_dir = IDETAPE_DIR_WRITE; - tape->cur = tape->buf; - - /* - * Issue a write 0 command to ensure that DSC handshake is - * switched from completion mode to buffer available mode. No - * point in issuing this if DSC overlap isn't supported, some - * drives (Seagate STT3401A) will return an error. - */ - if (drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) { - ssize_t retval = idetape_queue_rw_tail(drive, - REQ_IDETAPE_WRITE, 0); - if (retval < 0) { - kfree(tape->buf); - tape->buf = NULL; - tape->chrdev_dir = IDETAPE_DIR_NONE; - return retval; - } - } - } + rc = idetape_init_rw(drive, IDETAPE_DIR_WRITE); + if (rc < 0) + return rc; if (count == 0) return (0); if (tape->valid < tape->buffer_size) { -- cgit v0.10.2 From 71294cf93d22ceaa75448cc6ebee2c65897be8c2 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 19 Apr 2009 08:46:03 +0900 Subject: ide-tape: use byte size instead of sectors on rw issue functions Impact: cleanup Byte size is what most issue functions deal with, make idetape_queue_rw_tail() and its wrappers take byte size instead of sector counts. idetape_chrdev_read() and write() functions are converted to use tape->buffer_size instead of ctl from tape->cap. This cleans up code a little bit and will ease the next r/w reimplementation. Signed-off-by: Tejun Heo diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 4da7fa9..d5e9bb2 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -879,15 +879,15 @@ static void ide_tape_discard_merge_buffer(ide_drive_t *drive, * Generate a read/write request for the block device interface and wait for it * to be serviced. */ -static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks) +static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int size) { idetape_tape_t *tape = drive->driver_data; - size_t size = blocks * tape->blk_size; struct request *rq; int ret; debug_log(DBG_SENSE, "%s: cmd=%d\n", __func__, cmd); BUG_ON(cmd != REQ_IDETAPE_READ && cmd != REQ_IDETAPE_WRITE); + BUG_ON(size < 0 || size % tape->blk_size); rq = blk_get_request(drive->queue, READ, __GFP_WAIT); rq->cmd_type = REQ_TYPE_SPECIAL; @@ -954,17 +954,16 @@ static void idetape_create_space_cmd(struct ide_atapi_pc *pc, int count, u8 cmd) } /* Queue up a character device originated write request. */ -static int idetape_add_chrdev_write_request(ide_drive_t *drive, int blocks) +static int idetape_add_chrdev_write_request(ide_drive_t *drive, int size) { debug_log(DBG_CHRDEV, "Enter %s\n", __func__); - return idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, blocks); + return idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, size); } static void ide_tape_flush_merge_buffer(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; - int blocks; if (tape->chrdev_dir != IDETAPE_DIR_WRITE) { printk(KERN_ERR "ide-tape: bug: Trying to empty merge buffer" @@ -972,15 +971,10 @@ static void ide_tape_flush_merge_buffer(ide_drive_t *drive) return; } if (tape->buf) { - blocks = tape->valid / tape->blk_size; - if (tape->valid % tape->blk_size) { - blocks++; - memset(tape->buf + tape->valid, 0, - tape->blk_size - tape->valid % tape->blk_size); - } - (void) idetape_add_chrdev_write_request(drive, blocks); - } - if (tape->buf != NULL) { + size_t aligned = roundup(tape->valid, tape->blk_size); + + memset(tape->cur, 0, aligned - tape->valid); + idetape_add_chrdev_write_request(drive, aligned); kfree(tape->buf); tape->buf = NULL; } @@ -1038,9 +1032,9 @@ static int idetape_init_rw(ide_drive_t *drive, int dir) } /* called from idetape_chrdev_read() to service a chrdev read request. */ -static int idetape_add_chrdev_read_request(ide_drive_t *drive, int blocks) +static int idetape_add_chrdev_read_request(ide_drive_t *drive, int size) { - debug_log(DBG_PROCS, "Enter %s, %d blocks\n", __func__, blocks); + debug_log(DBG_PROCS, "Enter %s, %d bytes\n", __func__, size); /* If we are at a filemark, return a read length of 0 */ if (test_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags)) @@ -1048,7 +1042,7 @@ static int idetape_add_chrdev_read_request(ide_drive_t *drive, int blocks) idetape_init_rw(drive, IDETAPE_DIR_READ); - return idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, blocks); + return idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, size); } static void idetape_pad_zeros(ide_drive_t *drive, int bcount) @@ -1060,8 +1054,7 @@ static void idetape_pad_zeros(ide_drive_t *drive, int bcount) while (bcount) { unsigned int count = min(tape->buffer_size, bcount); - idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, - count / tape->blk_size); + idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, count); bcount -= count; } } @@ -1193,7 +1186,6 @@ static ssize_t idetape_chrdev_read(struct file *file, char __user *buf, ide_drive_t *drive = tape->drive; ssize_t bytes_read, temp, actually_read = 0, rc; ssize_t ret = 0; - u16 ctl = *(u16 *)&tape->caps[12]; debug_log(DBG_CHRDEV, "Enter %s, count %Zd\n", __func__, count); @@ -1218,7 +1210,8 @@ static ssize_t idetape_chrdev_read(struct file *file, char __user *buf, tape->valid -= actually_read; } while (count >= tape->buffer_size) { - bytes_read = idetape_add_chrdev_read_request(drive, ctl); + bytes_read = idetape_add_chrdev_read_request(drive, + tape->buffer_size); if (bytes_read <= 0) goto finish; if (copy_to_user(buf, tape->cur, bytes_read)) @@ -1228,7 +1221,8 @@ static ssize_t idetape_chrdev_read(struct file *file, char __user *buf, actually_read += bytes_read; } if (count) { - bytes_read = idetape_add_chrdev_read_request(drive, ctl); + bytes_read = idetape_add_chrdev_read_request(drive, + tape->buffer_size); if (bytes_read <= 0) goto finish; temp = min((unsigned long)count, (unsigned long)bytes_read); @@ -1256,7 +1250,6 @@ static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf, ide_drive_t *drive = tape->drive; ssize_t actually_written = 0; ssize_t ret = 0; - u16 ctl = *(u16 *)&tape->caps[12]; int rc; /* The drive is write protected. */ @@ -1284,7 +1277,8 @@ static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf, if (tape->valid == tape->buffer_size) { ssize_t retval; - retval = idetape_add_chrdev_write_request(drive, ctl); + retval = idetape_add_chrdev_write_request(drive, + tape->buffer_size); if (retval <= 0) return (retval); } @@ -1295,7 +1289,8 @@ static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf, ret = -EFAULT; buf += tape->buffer_size; count -= tape->buffer_size; - retval = idetape_add_chrdev_write_request(drive, ctl); + retval = idetape_add_chrdev_write_request(drive, + tape->buffer_size); actually_written += tape->buffer_size; if (retval <= 0) return (retval); -- cgit v0.10.2 From 4344d07fb8dbf0cbfec1f7d7c1afeccaceaaa120 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 19 Apr 2009 08:46:03 +0900 Subject: ide-tape: simplify read/write functions Impact: cleanup idetape_chrdev_read/write() functions are unnecessarily complex when everything can be handled in a single loop. Collapse idetape_add_chrdev_read/write_request() into the rw functions and simplify the implementation. Signed-off-by: Tejun Heo diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index d5e9bb2..2599579 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -953,14 +953,6 @@ static void idetape_create_space_cmd(struct ide_atapi_pc *pc, int count, u8 cmd) pc->flags |= PC_FLAG_WAIT_FOR_DSC; } -/* Queue up a character device originated write request. */ -static int idetape_add_chrdev_write_request(ide_drive_t *drive, int size) -{ - debug_log(DBG_CHRDEV, "Enter %s\n", __func__); - - return idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, size); -} - static void ide_tape_flush_merge_buffer(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; @@ -974,7 +966,7 @@ static void ide_tape_flush_merge_buffer(ide_drive_t *drive) size_t aligned = roundup(tape->valid, tape->blk_size); memset(tape->cur, 0, aligned - tape->valid); - idetape_add_chrdev_write_request(drive, aligned); + idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, aligned); kfree(tape->buf); tape->buf = NULL; } @@ -1031,20 +1023,6 @@ static int idetape_init_rw(ide_drive_t *drive, int dir) return 0; } -/* called from idetape_chrdev_read() to service a chrdev read request. */ -static int idetape_add_chrdev_read_request(ide_drive_t *drive, int size) -{ - debug_log(DBG_PROCS, "Enter %s, %d bytes\n", __func__, size); - - /* If we are at a filemark, return a read length of 0 */ - if (test_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags)) - return 0; - - idetape_init_rw(drive, IDETAPE_DIR_READ); - - return idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, size); -} - static void idetape_pad_zeros(ide_drive_t *drive, int bcount) { idetape_tape_t *tape = drive->driver_data; @@ -1184,8 +1162,9 @@ static ssize_t idetape_chrdev_read(struct file *file, char __user *buf, { struct ide_tape_obj *tape = file->private_data; ide_drive_t *drive = tape->drive; - ssize_t bytes_read, temp, actually_read = 0, rc; + size_t done = 0; ssize_t ret = 0; + int rc; debug_log(DBG_CHRDEV, "Enter %s, count %Zd\n", __func__, count); @@ -1195,52 +1174,43 @@ static ssize_t idetape_chrdev_read(struct file *file, char __user *buf, (count % tape->blk_size) == 0) tape->user_bs_factor = count / tape->blk_size; } + rc = idetape_init_rw(drive, IDETAPE_DIR_READ); if (rc < 0) return rc; - if (count == 0) - return (0); - if (tape->valid) { - actually_read = min_t(unsigned int, tape->valid, count); - if (copy_to_user(buf, tape->cur, actually_read)) - ret = -EFAULT; - buf += actually_read; - count -= actually_read; - tape->cur += actually_read; - tape->valid -= actually_read; - } - while (count >= tape->buffer_size) { - bytes_read = idetape_add_chrdev_read_request(drive, - tape->buffer_size); - if (bytes_read <= 0) - goto finish; - if (copy_to_user(buf, tape->cur, bytes_read)) - ret = -EFAULT; - buf += bytes_read; - count -= bytes_read; - actually_read += bytes_read; - } - if (count) { - bytes_read = idetape_add_chrdev_read_request(drive, - tape->buffer_size); - if (bytes_read <= 0) - goto finish; - temp = min((unsigned long)count, (unsigned long)bytes_read); - if (copy_to_user(buf, tape->cur, temp)) + + while (done < count) { + size_t todo; + + /* refill if staging buffer is empty */ + if (!tape->valid) { + /* If we are at a filemark, nothing more to read */ + if (test_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags)) + break; + /* read */ + if (idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, + tape->buffer_size) <= 0) + break; + } + + /* copy out */ + todo = min_t(size_t, count - done, tape->valid); + if (copy_to_user(buf + done, tape->cur, todo)) ret = -EFAULT; - actually_read += temp; - tape->cur += temp; - tape->valid -= temp; + + tape->cur += todo; + tape->valid -= todo; + done += todo; } -finish: - if (!actually_read && test_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags)) { + + if (!done && test_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags)) { debug_log(DBG_SENSE, "%s: spacing over filemark\n", tape->name); idetape_space_over_filemarks(drive, MTFSF, 1); return 0; } - return ret ? ret : actually_read; + return ret ? ret : done; } static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf, @@ -1248,7 +1218,7 @@ static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf, { struct ide_tape_obj *tape = file->private_data; ide_drive_t *drive = tape->drive; - ssize_t actually_written = 0; + size_t done = 0; ssize_t ret = 0; int rc; @@ -1262,47 +1232,28 @@ static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf, rc = idetape_init_rw(drive, IDETAPE_DIR_WRITE); if (rc < 0) return rc; - if (count == 0) - return (0); - if (tape->valid < tape->buffer_size) { - actually_written = min_t(unsigned int, - tape->buffer_size - tape->valid, - count); - if (copy_from_user(tape->cur, buf, actually_written)) - ret = -EFAULT; - buf += actually_written; - count -= actually_written; - tape->cur += actually_written; - tape->valid += actually_written; - - if (tape->valid == tape->buffer_size) { - ssize_t retval; - retval = idetape_add_chrdev_write_request(drive, - tape->buffer_size); - if (retval <= 0) - return (retval); - } - } - while (count >= tape->buffer_size) { - ssize_t retval; - if (copy_from_user(tape->cur, buf, tape->buffer_size)) - ret = -EFAULT; - buf += tape->buffer_size; - count -= tape->buffer_size; - retval = idetape_add_chrdev_write_request(drive, - tape->buffer_size); - actually_written += tape->buffer_size; - if (retval <= 0) - return (retval); - } - if (count) { - actually_written += count; - if (copy_from_user(tape->cur, buf, count)) + + while (done < count) { + size_t todo; + + /* flush if staging buffer is full */ + if (tape->valid == tape->buffer_size && + idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, + tape->buffer_size) <= 0) + return rc; + + /* copy in */ + todo = min_t(size_t, count - done, + tape->buffer_size - tape->valid); + if (copy_from_user(tape->cur, buf + done, todo)) ret = -EFAULT; - tape->cur += count; - tape->valid += count; + + tape->cur += todo; + tape->valid += todo; + done += todo; } - return ret ? ret : actually_written; + + return ret ? ret : done; } static int idetape_write_filemark(ide_drive_t *drive) -- cgit v0.10.2 From 29d1a4371035e01b0d079bc5aa88b50f5af7a566 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 19 Apr 2009 08:46:03 +0900 Subject: ide-atapi: kill unused fields and callbacks Impact: remove fields and code paths which are no longer necessary Now that ide-tape uses standard mechanisms to transfer data, special case handling for bh handling can be dropped from ide-atapi. Drop the followings. * pc->cur_pos, b_count, bh and b_data * drive->pc_update_buffers() and pc_io_buffers(). Signed-off-by: Tejun Heo diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c index b9dd450..afe5a43 100644 --- a/drivers/ide/ide-atapi.c +++ b/drivers/ide/ide-atapi.c @@ -359,11 +359,8 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) drive->name, rq_data_dir(pc->rq) ? "write" : "read"); pc->flags |= PC_FLAG_DMA_ERROR; - } else { + } else pc->xferred = pc->req_xfer; - if (drive->pc_update_buffers) - drive->pc_update_buffers(drive, pc); - } debug_log("%s: DMA finished\n", drive->name); } @@ -463,16 +460,11 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) return ide_do_reset(drive); } - if (drive->media == ide_tape && pc->bh) - done = drive->pc_io_buffers(drive, pc, bcount, write); - else { - done = min_t(unsigned int, bcount, cmd->nleft); - ide_pio_bytes(drive, cmd, write, done); - } + done = min_t(unsigned int, bcount, cmd->nleft); + ide_pio_bytes(drive, cmd, write, done); - /* Update the current position */ + /* Update transferred byte count */ pc->xferred += done; - pc->cur_pos += done; bcount -= done; @@ -650,7 +642,6 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd) /* We haven't transferred any data yet */ pc->xferred = 0; - pc->cur_pos = pc->buf; valid_tf = IDE_VALID_DEVICE; bcount = ((drive->media == ide_tape) ? diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 2599579..8dfc688 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -591,7 +591,6 @@ static void ide_tape_create_rw_cmd(idetape_tape_t *tape, ide_init_pc(pc); put_unaligned(cpu_to_be32(length), (unsigned int *) &pc->c[1]); pc->c[1] = 1; - pc->bh = NULL; pc->buf = NULL; pc->buf_size = length * tape->blk_size; pc->req_xfer = pc->buf_size; diff --git a/include/linux/ide.h b/include/linux/ide.h index 1957461..34c128f 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -362,11 +362,7 @@ struct ide_atapi_pc { /* data buffer */ u8 *buf; - /* current buffer position */ - u8 *cur_pos; int buf_size; - /* missing/available data on the current buffer */ - int b_count; /* the corresponding request */ struct request *rq; @@ -379,10 +375,6 @@ struct ide_atapi_pc { */ u8 pc_buf[IDE_PC_BUFFER_SIZE]; - /* idetape only */ - struct idetape_bh *bh; - char *b_data; - unsigned long timeout; }; @@ -595,10 +587,6 @@ struct ide_drive_s { /* callback for packet commands */ int (*pc_callback)(struct ide_drive_s *, int); - void (*pc_update_buffers)(struct ide_drive_s *, struct ide_atapi_pc *); - int (*pc_io_buffers)(struct ide_drive_s *, struct ide_atapi_pc *, - unsigned int, int); - ide_startstop_t (*irq_handler)(struct ide_drive_s *); unsigned long atapi_flags; -- cgit v0.10.2 From 5ad960fe8d0e4f99fe2b8dded45e8251137293c9 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 19 Apr 2009 08:46:03 +0900 Subject: ide: drop rq->data handling from ide_map_sg() Impact: remove code path which is no longer necessary All IDE data transfers now use rq->bio. Simplify ide_map_sg() accordingly. Signed-off-by: Tejun Heo Cc: Jens Axboe diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 6e3094e..a0309ea 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -248,11 +248,7 @@ void ide_map_sg(ide_drive_t *drive, struct ide_cmd *cmd) struct scatterlist *sg = hwif->sg_table; struct request *rq = cmd->rq; - if (!rq->bio) { - sg_init_one(sg, rq->data, rq->data_len); - cmd->sg_nents = 1; - } else - cmd->sg_nents = blk_rq_map_sg(drive->queue, rq, sg); + cmd->sg_nents = blk_rq_map_sg(drive->queue, rq, sg); } EXPORT_SYMBOL_GPL(ide_map_sg); -- cgit v0.10.2 From 586cf2681f527ce8b85b9bd57c8b9f7945fbe051 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 21 Apr 2009 12:16:56 +0900 Subject: ide-dma: don't reset request fields on dma_timeout_retry() Impact: drop unnecessary code Now that everything uses bio and block operations, there is no need to reset request fields manually when retrying a request. Every field is guaranteed to be always valid. Drop unnecessary request field resetting from ide_dma_timeout_retry(). Signed-off-by: Tejun Heo diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index a0b8cab1..d9123ec 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -510,23 +510,11 @@ ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error) /* * un-busy drive etc and make sure request is sane */ - rq = hwif->rq; - if (!rq) - goto out; - - hwif->rq = NULL; - - rq->errors = 0; - - if (!rq->bio) - goto out; - - rq->sector = rq->bio->bi_sector; - rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9; - rq->hard_cur_sectors = rq->current_nr_sectors; - rq->buffer = bio_data(rq->bio); -out: + if (rq) { + hwif->rq = NULL; + rq->errors = 0; + } return ret; } -- cgit v0.10.2 From db29a6b49674085f136331014ba0eee249c16a2c Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 21 Apr 2009 09:27:03 +0200 Subject: block: enable by default support for large devices and files on 32-bit archs Enable by default support for large devices and files (CONFIG_LBD): - With 1TB disks being a commodity hardware it is quite easy to hit 2TB limitation while building RAIDs etc. and many distros have been using CONFIG_LBD=y by default already (at least Fedora 10 and openSUSE 11.1). - This should also prevent a subtle ext4 filesystem compatibility issue: mke2fs.ext4 defaults to creating filesystems with huge_files feature enabled and such filesystems cannot be later mounted read-write on machines with CONFIG_LBD=n (it should be quite easy to hit this issue when trying to use filesystem created using distro kernel on system running the self-build kernel, think about USB disk enclosures & co.). While at it: - Clarify config option help text w.r.t. mounting ext4 filesystems (they can be mounted with CONFIG_LBD=n but in the read-only mode). Cc: "Theodore Ts'o" Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Jens Axboe diff --git a/block/Kconfig b/block/Kconfig index e7d1278..2c39527 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -26,6 +26,7 @@ if BLOCK config LBD bool "Support for large block devices and files" depends on !64BIT + default y help Enable block devices or files of size 2TB and larger. @@ -38,11 +39,13 @@ config LBD The ext4 filesystem requires that this feature be enabled in order to support filesystems that have the huge_file feature - enabled. Otherwise, it will refuse to mount any filesystems - that use the huge_file feature, which is enabled by default - by mke2fs.ext4. The GFS2 filesystem also requires this feature. + enabled. Otherwise, it will refuse to mount in the read-write + mode any filesystems that use the huge_file feature, which is + enabled by default by mke2fs.ext4. - If unsure, say N. + The GFS2 filesystem also requires this feature. + + If unsure, say Y. config BLK_DEV_BSG bool "Block layer SG support v4 (EXPERIMENTAL)" -- cgit v0.10.2 From db2dbb12dc47a50c7a4c5678f526014063e486f6 Mon Sep 17 00:00:00 2001 From: Jeff Moyer Date: Wed, 22 Apr 2009 14:08:13 +0200 Subject: block: implement blkdev_readpages Doing a proper block dev ->readpages() speeds up the crazy dump(8) approach of using interleaved process IO. Signed-off-by: Jeff Moyer Signed-off-by: Jens Axboe diff --git a/fs/block_dev.c b/fs/block_dev.c index f45dbc1..a85fe31 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -331,6 +331,12 @@ static int blkdev_readpage(struct file * file, struct page * page) return block_read_full_page(page, blkdev_get_block); } +static int blkdev_readpages(struct file *file, struct address_space *mapping, + struct list_head *pages, unsigned nr_pages) +{ + return mpage_readpages(mapping, pages, nr_pages, blkdev_get_block); +} + static int blkdev_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata) @@ -1399,6 +1405,7 @@ static int blkdev_releasepage(struct page *page, gfp_t wait) static const struct address_space_operations def_blk_aops = { .readpage = blkdev_readpage, + .readpages = blkdev_readpages, .writepage = blkdev_writepage, .sync_page = block_sync_page, .write_begin = blkdev_write_begin, -- cgit v0.10.2 From a538cd03be6f363d039daa94199c28cfbd508455 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 23 Apr 2009 11:05:17 +0900 Subject: block: merge blk_invoke_request_fn() into __blk_run_queue() __blk_run_queue wraps blk_invoke_request_fn() such that it additionally removes plug and bails out early if the queue is empty. Both extra operations have their own pending mechanisms and don't cause any harm correctness-wise when they are done superflously. The only user of blk_invoke_request_fn() being blk_start_queue(), there isn't much reason to keep both functions around. Merge blk_invoke_request_fn() into __blk_run_queue() and make blk_start_queue() use __blk_run_queue() instead. [ Impact: merge two subtly different internal functions ] Signed-off-by: Tejun Heo diff --git a/block/blk-core.c b/block/blk-core.c index 41bc0ff..02f53bc 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -333,24 +333,6 @@ void blk_unplug(struct request_queue *q) } EXPORT_SYMBOL(blk_unplug); -static void blk_invoke_request_fn(struct request_queue *q) -{ - if (unlikely(blk_queue_stopped(q))) - return; - - /* - * one level of recursion is ok and is much faster than kicking - * the unplug handling - */ - if (!queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) { - q->request_fn(q); - queue_flag_clear(QUEUE_FLAG_REENTER, q); - } else { - queue_flag_set(QUEUE_FLAG_PLUGGED, q); - kblockd_schedule_work(q, &q->unplug_work); - } -} - /** * blk_start_queue - restart a previously stopped queue * @q: The &struct request_queue in question @@ -365,7 +347,7 @@ void blk_start_queue(struct request_queue *q) WARN_ON(!irqs_disabled()); queue_flag_clear(QUEUE_FLAG_STOPPED, q); - blk_invoke_request_fn(q); + __blk_run_queue(q); } EXPORT_SYMBOL(blk_start_queue); @@ -425,12 +407,23 @@ void __blk_run_queue(struct request_queue *q) { blk_remove_plug(q); + if (unlikely(blk_queue_stopped(q))) + return; + + if (elv_queue_empty(q)) + return; + /* * Only recurse once to avoid overrunning the stack, let the unplug * handling reinvoke the handler shortly if we already got there. */ - if (!elv_queue_empty(q)) - blk_invoke_request_fn(q); + if (!queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) { + q->request_fn(q); + queue_flag_clear(QUEUE_FLAG_REENTER, q); + } else { + queue_flag_set(QUEUE_FLAG_PLUGGED, q); + kblockd_schedule_work(q, &q->unplug_work); + } } EXPORT_SYMBOL(__blk_run_queue); -- cgit v0.10.2 From a7f557923441186a3cdbabc54f1bcacf42b63bf5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 23 Apr 2009 11:05:17 +0900 Subject: block: kill blk_start_queueing() blk_start_queueing() is identical to __blk_run_queue() except that it doesn't check for recursion. None of the current users depends on blk_start_queueing() running request_fn directly. Replace usages of blk_start_queueing() with [__]blk_run_queue() and kill it. [ Impact: removal of mostly duplicate interface function ] Signed-off-by: Tejun Heo diff --git a/block/as-iosched.c b/block/as-iosched.c index c48fa67..45bd070 100644 --- a/block/as-iosched.c +++ b/block/as-iosched.c @@ -1312,12 +1312,8 @@ static void as_merged_requests(struct request_queue *q, struct request *req, static void as_work_handler(struct work_struct *work) { struct as_data *ad = container_of(work, struct as_data, antic_work); - struct request_queue *q = ad->q; - unsigned long flags; - spin_lock_irqsave(q->queue_lock, flags); - blk_start_queueing(q); - spin_unlock_irqrestore(q->queue_lock, flags); + blk_run_queue(ad->q); } static int as_may_queue(struct request_queue *q, int rw) diff --git a/block/blk-core.c b/block/blk-core.c index 02f53bc..8b4a0af 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -433,9 +433,7 @@ EXPORT_SYMBOL(__blk_run_queue); * * Description: * Invoke request handling on this queue, if it has pending work to do. - * May be used to restart queueing when a request has completed. Also - * See @blk_start_queueing. - * + * May be used to restart queueing when a request has completed. */ void blk_run_queue(struct request_queue *q) { @@ -895,28 +893,6 @@ struct request *blk_get_request(struct request_queue *q, int rw, gfp_t gfp_mask) EXPORT_SYMBOL(blk_get_request); /** - * blk_start_queueing - initiate dispatch of requests to device - * @q: request queue to kick into gear - * - * This is basically a helper to remove the need to know whether a queue - * is plugged or not if someone just wants to initiate dispatch of requests - * for this queue. Should be used to start queueing on a device outside - * of ->request_fn() context. Also see @blk_run_queue. - * - * The queue lock must be held with interrupts disabled. - */ -void blk_start_queueing(struct request_queue *q) -{ - if (!blk_queue_plugged(q)) { - if (unlikely(blk_queue_stopped(q))) - return; - q->request_fn(q); - } else - __generic_unplug_device(q); -} -EXPORT_SYMBOL(blk_start_queueing); - -/** * blk_requeue_request - put a request back on queue * @q: request queue where request should be inserted * @rq: request to be inserted @@ -984,7 +960,7 @@ void blk_insert_request(struct request_queue *q, struct request *rq, drive_stat_acct(rq, 1); __elv_add_request(q, rq, where, 0); - blk_start_queueing(q); + __blk_run_queue(q); spin_unlock_irqrestore(q->queue_lock, flags); } EXPORT_SYMBOL(blk_insert_request); diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index a55a9bd..def0c69 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -2088,7 +2088,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, if (blk_rq_bytes(rq) > PAGE_CACHE_SIZE || cfqd->busy_queues > 1) { del_timer(&cfqd->idle_slice_timer); - blk_start_queueing(cfqd->queue); + __blk_run_queue(cfqd->queue); } cfq_mark_cfqq_must_dispatch(cfqq); } @@ -2100,7 +2100,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, * this new queue is RT and the current one is BE */ cfq_preempt_queue(cfqd, cfqq); - blk_start_queueing(cfqd->queue); + __blk_run_queue(cfqd->queue); } } @@ -2345,7 +2345,7 @@ static void cfq_kick_queue(struct work_struct *work) struct request_queue *q = cfqd->queue; spin_lock_irq(q->queue_lock); - blk_start_queueing(q); + __blk_run_queue(cfqd->queue); spin_unlock_irq(q->queue_lock); } diff --git a/block/elevator.c b/block/elevator.c index 7073a90..2e0fb21 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -599,7 +599,7 @@ void elv_quiesce_start(struct request_queue *q) */ elv_drain_elevator(q); while (q->rq.elvpriv) { - blk_start_queueing(q); + __blk_run_queue(q); spin_unlock_irq(q->queue_lock); msleep(10); spin_lock_irq(q->queue_lock); @@ -643,8 +643,7 @@ void elv_insert(struct request_queue *q, struct request *rq, int where) * with anything. There's no point in delaying queue * processing. */ - blk_remove_plug(q); - blk_start_queueing(q); + __blk_run_queue(q); break; case ELEVATOR_INSERT_SORT: @@ -971,7 +970,7 @@ void elv_completed_request(struct request_queue *q, struct request *rq) blk_ordered_cur_seq(q) == QUEUE_ORDSEQ_DRAIN && (!next || blk_ordered_req_seq(next) > QUEUE_ORDSEQ_DRAIN)) { blk_ordered_complete_seq(q, QUEUE_ORDSEQ_DRAIN, 0); - blk_start_queueing(q); + __blk_run_queue(q); } } } diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 2755d5c..12e20de 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -797,7 +797,6 @@ extern void blk_sync_queue(struct request_queue *q); extern void __blk_stop_queue(struct request_queue *q); extern void __blk_run_queue(struct request_queue *); extern void blk_run_queue(struct request_queue *); -extern void blk_start_queueing(struct request_queue *); extern int blk_rq_map_user(struct request_queue *, struct request *, struct rq_map_data *, void __user *, unsigned long, gfp_t); -- cgit v0.10.2 From e4025f6c21f1389696c069be2dc647f364925c45 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 23 Apr 2009 11:05:17 +0900 Subject: block: don't set REQ_NOMERGE unnecessarily RQ_NOMERGE_FLAGS already clears defines which REQ flags aren't mergeable. There is no reason to specify it superflously. It only adds to confusion. Don't set REQ_NOMERGE for barriers and requests with specific queueing directive. REQ_NOMERGE is now exclusively used by the merging code. [ Impact: cleanup ] Signed-off-by: Tejun Heo diff --git a/block/blk-core.c b/block/blk-core.c index 8b4a0af..7e0fab5 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1082,16 +1082,13 @@ void init_request_from_bio(struct request *req, struct bio *bio) if (bio_failfast_driver(bio)) req->cmd_flags |= REQ_FAILFAST_DRIVER; - /* - * REQ_BARRIER implies no merging, but lets make it explicit - */ if (unlikely(bio_discard(bio))) { req->cmd_flags |= REQ_DISCARD; if (bio_barrier(bio)) req->cmd_flags |= REQ_SOFTBARRIER; req->q->prepare_discard_fn(req->q, req); } else if (unlikely(bio_barrier(bio))) - req->cmd_flags |= (REQ_HARDBARRIER | REQ_NOMERGE); + req->cmd_flags |= REQ_HARDBARRIER; if (bio_sync(bio)) req->cmd_flags |= REQ_RW_SYNC; diff --git a/block/blk-exec.c b/block/blk-exec.c index 6af716d..49557e9 100644 --- a/block/blk-exec.c +++ b/block/blk-exec.c @@ -51,7 +51,6 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk, int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK; rq->rq_disk = bd_disk; - rq->cmd_flags |= REQ_NOMERGE; rq->end_io = done; WARN_ON(irqs_disabled()); spin_lock_irq(q->queue_lock); -- cgit v0.10.2 From 10732f5661fb7adf62e20733b0030fc0fc93b0c4 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 23 Apr 2009 11:05:18 +0900 Subject: block: cleanup REQ_SOFTBARRIER usages blk_insert_request() doesn't need to worry about REQ_SOFTBARRIER. Don't set it. Combined with recent ide updates, REQ_SOFTBARRIER is now only used in elevator proper and for discard requests. [ Impact: cleanup ] Signed-off-by: Tejun Heo diff --git a/block/blk-core.c b/block/blk-core.c index 7e0fab5..cf10dfc 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -946,7 +946,6 @@ void blk_insert_request(struct request_queue *q, struct request *rq, * barrier */ rq->cmd_type = REQ_TYPE_SPECIAL; - rq->cmd_flags |= REQ_SOFTBARRIER; rq->special = data; -- cgit v0.10.2 From 2eef33e439ba9ae387cdc3f1abcef2f3f6c4e7a8 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 23 Apr 2009 11:05:18 +0900 Subject: block: clean up misc stuff after block layer timeout conversion * In blk_rq_timed_out_timer(), else { if } to else if * In blk_add_timer(), simplify if/else block [ Impact: cleanup ] Signed-off-by: Tejun Heo diff --git a/block/blk-timeout.c b/block/blk-timeout.c index 1ec0d50..1ba7e0a 100644 --- a/block/blk-timeout.c +++ b/block/blk-timeout.c @@ -122,10 +122,8 @@ void blk_rq_timed_out_timer(unsigned long data) if (blk_mark_rq_complete(rq)) continue; blk_rq_timed_out(rq); - } else { - if (!next || time_after(next, rq->deadline)) - next = rq->deadline; - } + } else if (!next || time_after(next, rq->deadline)) + next = rq->deadline; } /* @@ -176,16 +174,14 @@ void blk_add_timer(struct request *req) BUG_ON(!list_empty(&req->timeout_list)); BUG_ON(test_bit(REQ_ATOM_COMPLETE, &req->atomic_flags)); - if (req->timeout) - req->deadline = jiffies + req->timeout; - else { - req->deadline = jiffies + q->rq_timeout; - /* - * Some LLDs, like scsi, peek at the timeout to prevent - * a command from being retried forever. - */ + /* + * Some LLDs, like scsi, peek at the timeout to prevent a + * command from being retried forever. + */ + if (!req->timeout) req->timeout = q->rq_timeout; - } + + req->deadline = jiffies + req->timeout; list_add_tail(&req->timeout_list, &q->timeout_list); /* -- cgit v0.10.2 From 5efccd17ceb0fc43837a331297c2c407969d7201 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 23 Apr 2009 11:05:18 +0900 Subject: block: reorder request completion functions Reorder request completion functions such that * All request completion functions are located together. * Functions which are used by only one caller is put right above the caller. * end_request() is put after other completion functions but before blk_update_request(). This change is for completion function cleanup which will follow. [ Impact: cleanup, code reorganization ] Signed-off-by: Tejun Heo diff --git a/block/blk-core.c b/block/blk-core.c index cf10dfc..406a93e 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1684,6 +1684,35 @@ static void blk_account_io_done(struct request *req) } /** + * blk_rq_bytes - Returns bytes left to complete in the entire request + * @rq: the request being processed + **/ +unsigned int blk_rq_bytes(struct request *rq) +{ + if (blk_fs_request(rq)) + return rq->hard_nr_sectors << 9; + + return rq->data_len; +} +EXPORT_SYMBOL_GPL(blk_rq_bytes); + +/** + * blk_rq_cur_bytes - Returns bytes left to complete in the current segment + * @rq: the request being processed + **/ +unsigned int blk_rq_cur_bytes(struct request *rq) +{ + if (blk_fs_request(rq)) + return rq->current_nr_sectors << 9; + + if (rq->bio) + return rq->bio->bi_size; + + return rq->data_len; +} +EXPORT_SYMBOL_GPL(blk_rq_cur_bytes); + +/** * __end_that_request_first - end I/O on a request * @req: the request being processed * @error: %0 for success, < %0 for error @@ -1797,6 +1826,22 @@ static int __end_that_request_first(struct request *req, int error, return 1; } +static int end_that_request_data(struct request *rq, int error, + unsigned int nr_bytes, unsigned int bidi_bytes) +{ + if (rq->bio) { + if (__end_that_request_first(rq, error, nr_bytes)) + return 1; + + /* Bidi request must be completed as a whole */ + if (blk_bidi_rq(rq) && + __end_that_request_first(rq->next_rq, error, bidi_bytes)) + return 1; + } + + return 0; +} + /* * queue lock must be held */ @@ -1826,78 +1871,6 @@ static void end_that_request_last(struct request *req, int error) } /** - * blk_rq_bytes - Returns bytes left to complete in the entire request - * @rq: the request being processed - **/ -unsigned int blk_rq_bytes(struct request *rq) -{ - if (blk_fs_request(rq)) - return rq->hard_nr_sectors << 9; - - return rq->data_len; -} -EXPORT_SYMBOL_GPL(blk_rq_bytes); - -/** - * blk_rq_cur_bytes - Returns bytes left to complete in the current segment - * @rq: the request being processed - **/ -unsigned int blk_rq_cur_bytes(struct request *rq) -{ - if (blk_fs_request(rq)) - return rq->current_nr_sectors << 9; - - if (rq->bio) - return rq->bio->bi_size; - - return rq->data_len; -} -EXPORT_SYMBOL_GPL(blk_rq_cur_bytes); - -/** - * end_request - end I/O on the current segment of the request - * @req: the request being processed - * @uptodate: error value or %0/%1 uptodate flag - * - * Description: - * Ends I/O on the current segment of a request. If that is the only - * remaining segment, the request is also completed and freed. - * - * This is a remnant of how older block drivers handled I/O completions. - * Modern drivers typically end I/O on the full request in one go, unless - * they have a residual value to account for. For that case this function - * isn't really useful, unless the residual just happens to be the - * full current segment. In other words, don't use this function in new - * code. Use blk_end_request() or __blk_end_request() to end a request. - **/ -void end_request(struct request *req, int uptodate) -{ - int error = 0; - - if (uptodate <= 0) - error = uptodate ? uptodate : -EIO; - - __blk_end_request(req, error, req->hard_cur_sectors << 9); -} -EXPORT_SYMBOL(end_request); - -static int end_that_request_data(struct request *rq, int error, - unsigned int nr_bytes, unsigned int bidi_bytes) -{ - if (rq->bio) { - if (__end_that_request_first(rq, error, nr_bytes)) - return 1; - - /* Bidi request must be completed as a whole */ - if (blk_bidi_rq(rq) && - __end_that_request_first(rq->next_rq, error, bidi_bytes)) - return 1; - } - - return 0; -} - -/** * blk_end_io - Generic end_io function to complete a request. * @rq: the request being processed * @error: %0 for success, < %0 for error @@ -2007,6 +1980,33 @@ int blk_end_bidi_request(struct request *rq, int error, unsigned int nr_bytes, EXPORT_SYMBOL_GPL(blk_end_bidi_request); /** + * end_request - end I/O on the current segment of the request + * @req: the request being processed + * @uptodate: error value or %0/%1 uptodate flag + * + * Description: + * Ends I/O on the current segment of a request. If that is the only + * remaining segment, the request is also completed and freed. + * + * This is a remnant of how older block drivers handled I/O completions. + * Modern drivers typically end I/O on the full request in one go, unless + * they have a residual value to account for. For that case this function + * isn't really useful, unless the residual just happens to be the + * full current segment. In other words, don't use this function in new + * code. Use blk_end_request() or __blk_end_request() to end a request. + **/ +void end_request(struct request *req, int uptodate) +{ + int error = 0; + + if (uptodate <= 0) + error = uptodate ? uptodate : -EIO; + + __blk_end_request(req, error, req->hard_cur_sectors << 9); +} +EXPORT_SYMBOL(end_request); + +/** * blk_update_request - Special helper function for request stacking drivers * @rq: the request being processed * @error: %0 for success, < %0 for error diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 12e20de..156ffd9 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -832,6 +832,14 @@ static inline void blk_run_address_space(struct address_space *mapping) extern void blkdev_dequeue_request(struct request *req); /* + * blk_end_request() takes bytes instead of sectors as a complete size. + * blk_rq_bytes() returns bytes left to complete in the entire request. + * blk_rq_cur_bytes() returns bytes left to complete in the current segment. + */ +extern unsigned int blk_rq_bytes(struct request *rq); +extern unsigned int blk_rq_cur_bytes(struct request *rq); + +/* * blk_end_request() and friends. * __blk_end_request() and end_request() must be called with * the request queue spinlock acquired. @@ -858,14 +866,6 @@ extern void blk_update_request(struct request *rq, int error, unsigned int nr_bytes); /* - * blk_end_request() takes bytes instead of sectors as a complete size. - * blk_rq_bytes() returns bytes left to complete in the entire request. - * blk_rq_cur_bytes() returns bytes left to complete in the current segment. - */ -extern unsigned int blk_rq_bytes(struct request *rq); -extern unsigned int blk_rq_cur_bytes(struct request *rq); - -/* * Access functions for manipulating queue properties */ extern struct request_queue *blk_init_queue_node(request_fn_proc *rfn, -- cgit v0.10.2 From 158dbda0068e63c7cce7bd47c123bd1dfa5a902c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 23 Apr 2009 11:05:18 +0900 Subject: block: reorganize request fetching functions Impact: code reorganization elv_next_request() and elv_dequeue_request() are public block layer interface than actual elevator implementation. They mostly deal with how requests interact with block layer and low level drivers at the beginning of rqeuest processing whereas __elv_next_request() is the actual eleveator request fetching interface. Move the two functions to blk-core.c. This prepares for further interface cleanup. Signed-off-by: Tejun Heo diff --git a/block/blk-core.c b/block/blk-core.c index 406a93e..678ede2 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1712,6 +1712,101 @@ unsigned int blk_rq_cur_bytes(struct request *rq) } EXPORT_SYMBOL_GPL(blk_rq_cur_bytes); +struct request *elv_next_request(struct request_queue *q) +{ + struct request *rq; + int ret; + + while ((rq = __elv_next_request(q)) != NULL) { + if (!(rq->cmd_flags & REQ_STARTED)) { + /* + * This is the first time the device driver + * sees this request (possibly after + * requeueing). Notify IO scheduler. + */ + if (blk_sorted_rq(rq)) + elv_activate_rq(q, rq); + + /* + * just mark as started even if we don't start + * it, a request that has been delayed should + * not be passed by new incoming requests + */ + rq->cmd_flags |= REQ_STARTED; + trace_block_rq_issue(q, rq); + } + + if (!q->boundary_rq || q->boundary_rq == rq) { + q->end_sector = rq_end_sector(rq); + q->boundary_rq = NULL; + } + + if (rq->cmd_flags & REQ_DONTPREP) + break; + + if (q->dma_drain_size && rq->data_len) { + /* + * make sure space for the drain appears we + * know we can do this because max_hw_segments + * has been adjusted to be one fewer than the + * device can handle + */ + rq->nr_phys_segments++; + } + + if (!q->prep_rq_fn) + break; + + ret = q->prep_rq_fn(q, rq); + if (ret == BLKPREP_OK) { + break; + } else if (ret == BLKPREP_DEFER) { + /* + * the request may have been (partially) prepped. + * we need to keep this request in the front to + * avoid resource deadlock. REQ_STARTED will + * prevent other fs requests from passing this one. + */ + if (q->dma_drain_size && rq->data_len && + !(rq->cmd_flags & REQ_DONTPREP)) { + /* + * remove the space for the drain we added + * so that we don't add it again + */ + --rq->nr_phys_segments; + } + + rq = NULL; + break; + } else if (ret == BLKPREP_KILL) { + rq->cmd_flags |= REQ_QUIET; + __blk_end_request(rq, -EIO, blk_rq_bytes(rq)); + } else { + printk(KERN_ERR "%s: bad return=%d\n", __func__, ret); + break; + } + } + + return rq; +} +EXPORT_SYMBOL(elv_next_request); + +void elv_dequeue_request(struct request_queue *q, struct request *rq) +{ + BUG_ON(list_empty(&rq->queuelist)); + BUG_ON(ELV_ON_HASH(rq)); + + list_del_init(&rq->queuelist); + + /* + * the time frame between a request being removed from the lists + * and to it is freed is accounted as io that is in progress at + * the driver side. + */ + if (blk_account_rq(rq)) + q->in_flight++; +} + /** * __end_that_request_first - end I/O on a request * @req: the request being processed diff --git a/block/blk.h b/block/blk.h index 79c85f7..9b2c324 100644 --- a/block/blk.h +++ b/block/blk.h @@ -43,6 +43,43 @@ static inline void blk_clear_rq_complete(struct request *rq) clear_bit(REQ_ATOM_COMPLETE, &rq->atomic_flags); } +/* + * Internal elevator interface + */ +#define ELV_ON_HASH(rq) (!hlist_unhashed(&(rq)->hash)) + +static inline struct request *__elv_next_request(struct request_queue *q) +{ + struct request *rq; + + while (1) { + while (!list_empty(&q->queue_head)) { + rq = list_entry_rq(q->queue_head.next); + if (blk_do_ordered(q, &rq)) + return rq; + } + + if (!q->elevator->ops->elevator_dispatch_fn(q, 0)) + return NULL; + } +} + +static inline void elv_activate_rq(struct request_queue *q, struct request *rq) +{ + struct elevator_queue *e = q->elevator; + + if (e->ops->elevator_activate_req_fn) + e->ops->elevator_activate_req_fn(q, rq); +} + +static inline void elv_deactivate_rq(struct request_queue *q, struct request *rq) +{ + struct elevator_queue *e = q->elevator; + + if (e->ops->elevator_deactivate_req_fn) + e->ops->elevator_deactivate_req_fn(q, rq); +} + #ifdef CONFIG_FAIL_IO_TIMEOUT int blk_should_fake_timeout(struct request_queue *); ssize_t part_timeout_show(struct device *, struct device_attribute *, char *); diff --git a/block/elevator.c b/block/elevator.c index 2e0fb21..b03b875 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -53,7 +53,6 @@ static const int elv_hash_shift = 6; (hash_long(ELV_HASH_BLOCK((sec)), elv_hash_shift)) #define ELV_HASH_ENTRIES (1 << elv_hash_shift) #define rq_hash_key(rq) ((rq)->sector + (rq)->nr_sectors) -#define ELV_ON_HASH(rq) (!hlist_unhashed(&(rq)->hash)) DEFINE_TRACE(block_rq_insert); DEFINE_TRACE(block_rq_issue); @@ -310,22 +309,6 @@ void elevator_exit(struct elevator_queue *e) } EXPORT_SYMBOL(elevator_exit); -static void elv_activate_rq(struct request_queue *q, struct request *rq) -{ - struct elevator_queue *e = q->elevator; - - if (e->ops->elevator_activate_req_fn) - e->ops->elevator_activate_req_fn(q, rq); -} - -static void elv_deactivate_rq(struct request_queue *q, struct request *rq) -{ - struct elevator_queue *e = q->elevator; - - if (e->ops->elevator_deactivate_req_fn) - e->ops->elevator_deactivate_req_fn(q, rq); -} - static inline void __elv_rqhash_del(struct request *rq) { hlist_del_init(&rq->hash); @@ -758,117 +741,6 @@ void elv_add_request(struct request_queue *q, struct request *rq, int where, } EXPORT_SYMBOL(elv_add_request); -static inline struct request *__elv_next_request(struct request_queue *q) -{ - struct request *rq; - - while (1) { - while (!list_empty(&q->queue_head)) { - rq = list_entry_rq(q->queue_head.next); - if (blk_do_ordered(q, &rq)) - return rq; - } - - if (!q->elevator->ops->elevator_dispatch_fn(q, 0)) - return NULL; - } -} - -struct request *elv_next_request(struct request_queue *q) -{ - struct request *rq; - int ret; - - while ((rq = __elv_next_request(q)) != NULL) { - if (!(rq->cmd_flags & REQ_STARTED)) { - /* - * This is the first time the device driver - * sees this request (possibly after - * requeueing). Notify IO scheduler. - */ - if (blk_sorted_rq(rq)) - elv_activate_rq(q, rq); - - /* - * just mark as started even if we don't start - * it, a request that has been delayed should - * not be passed by new incoming requests - */ - rq->cmd_flags |= REQ_STARTED; - trace_block_rq_issue(q, rq); - } - - if (!q->boundary_rq || q->boundary_rq == rq) { - q->end_sector = rq_end_sector(rq); - q->boundary_rq = NULL; - } - - if (rq->cmd_flags & REQ_DONTPREP) - break; - - if (q->dma_drain_size && rq->data_len) { - /* - * make sure space for the drain appears we - * know we can do this because max_hw_segments - * has been adjusted to be one fewer than the - * device can handle - */ - rq->nr_phys_segments++; - } - - if (!q->prep_rq_fn) - break; - - ret = q->prep_rq_fn(q, rq); - if (ret == BLKPREP_OK) { - break; - } else if (ret == BLKPREP_DEFER) { - /* - * the request may have been (partially) prepped. - * we need to keep this request in the front to - * avoid resource deadlock. REQ_STARTED will - * prevent other fs requests from passing this one. - */ - if (q->dma_drain_size && rq->data_len && - !(rq->cmd_flags & REQ_DONTPREP)) { - /* - * remove the space for the drain we added - * so that we don't add it again - */ - --rq->nr_phys_segments; - } - - rq = NULL; - break; - } else if (ret == BLKPREP_KILL) { - rq->cmd_flags |= REQ_QUIET; - __blk_end_request(rq, -EIO, blk_rq_bytes(rq)); - } else { - printk(KERN_ERR "%s: bad return=%d\n", __func__, ret); - break; - } - } - - return rq; -} -EXPORT_SYMBOL(elv_next_request); - -void elv_dequeue_request(struct request_queue *q, struct request *rq) -{ - BUG_ON(list_empty(&rq->queuelist)); - BUG_ON(ELV_ON_HASH(rq)); - - list_del_init(&rq->queuelist); - - /* - * the time frame between a request being removed from the lists - * and to it is freed is accounted as io that is in progress at - * the driver side. - */ - if (blk_account_rq(rq)) - q->in_flight++; -} - int elv_queue_empty(struct request_queue *q) { struct elevator_queue *e = q->elevator; -- cgit v0.10.2 From 0b302d5aa7975006fa2ec3d66386610b9b36c669 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 23 Apr 2009 11:05:18 +0900 Subject: block: kill blk_end_request_callback() With recent IDE updates, blk_end_request_callback() doesn't have any user now. Kill it. [ Impact: removal of unused convoluted interface ] Signed-off-by: Tejun Heo diff --git a/block/blk-core.c b/block/blk-core.c index 678ede2..2f277ea 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1971,10 +1971,6 @@ static void end_that_request_last(struct request *req, int error) * @error: %0 for success, < %0 for error * @nr_bytes: number of bytes to complete @rq * @bidi_bytes: number of bytes to complete @rq->next_rq - * @drv_callback: function called between completion of bios in the request - * and completion of the request. - * If the callback returns non %0, this helper returns without - * completion of the request. * * Description: * Ends I/O on a number of bytes attached to @rq and @rq->next_rq. @@ -1985,8 +1981,7 @@ static void end_that_request_last(struct request *req, int error) * %1 - this request is not freed yet, it still has pending buffers. **/ static int blk_end_io(struct request *rq, int error, unsigned int nr_bytes, - unsigned int bidi_bytes, - int (drv_callback)(struct request *)) + unsigned int bidi_bytes) { struct request_queue *q = rq->q; unsigned long flags = 0UL; @@ -1994,10 +1989,6 @@ static int blk_end_io(struct request *rq, int error, unsigned int nr_bytes, if (end_that_request_data(rq, error, nr_bytes, bidi_bytes)) return 1; - /* Special feature for tricky drivers */ - if (drv_callback && drv_callback(rq)) - return 1; - add_disk_randomness(rq->rq_disk); spin_lock_irqsave(q->queue_lock, flags); @@ -2023,7 +2014,7 @@ static int blk_end_io(struct request *rq, int error, unsigned int nr_bytes, **/ int blk_end_request(struct request *rq, int error, unsigned int nr_bytes) { - return blk_end_io(rq, error, nr_bytes, 0, NULL); + return blk_end_io(rq, error, nr_bytes, 0); } EXPORT_SYMBOL_GPL(blk_end_request); @@ -2070,7 +2061,7 @@ EXPORT_SYMBOL_GPL(__blk_end_request); int blk_end_bidi_request(struct request *rq, int error, unsigned int nr_bytes, unsigned int bidi_bytes) { - return blk_end_io(rq, error, nr_bytes, bidi_bytes, NULL); + return blk_end_io(rq, error, nr_bytes, bidi_bytes); } EXPORT_SYMBOL_GPL(blk_end_bidi_request); @@ -2131,39 +2122,6 @@ void blk_update_request(struct request *rq, int error, unsigned int nr_bytes) } EXPORT_SYMBOL_GPL(blk_update_request); -/** - * blk_end_request_callback - Special helper function for tricky drivers - * @rq: the request being processed - * @error: %0 for success, < %0 for error - * @nr_bytes: number of bytes to complete - * @drv_callback: function called between completion of bios in the request - * and completion of the request. - * If the callback returns non %0, this helper returns without - * completion of the request. - * - * Description: - * Ends I/O on a number of bytes attached to @rq. - * If @rq has leftover, sets it up for the next range of segments. - * - * This special helper function is used only for existing tricky drivers. - * (e.g. cdrom_newpc_intr() of ide-cd) - * This interface will be removed when such drivers are rewritten. - * Don't use this interface in other places anymore. - * - * Return: - * %0 - we are done with this request - * %1 - this request is not freed yet. - * this request still has pending buffers or - * the driver doesn't want to finish this request yet. - **/ -int blk_end_request_callback(struct request *rq, int error, - unsigned int nr_bytes, - int (drv_callback)(struct request *)) -{ - return blk_end_io(rq, error, nr_bytes, 0, drv_callback); -} -EXPORT_SYMBOL_GPL(blk_end_request_callback); - void blk_rq_bio_prep(struct request_queue *q, struct request *rq, struct bio *bio) { diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 156ffd9..1fa9dcf 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -855,9 +855,6 @@ extern int __blk_end_request(struct request *rq, int error, extern int blk_end_bidi_request(struct request *rq, int error, unsigned int nr_bytes, unsigned int bidi_bytes); extern void end_request(struct request *, int); -extern int blk_end_request_callback(struct request *rq, int error, - unsigned int nr_bytes, - int (drv_callback)(struct request *)); extern void blk_complete_request(struct request *); extern void __blk_complete_request(struct request *); extern void blk_abort_request(struct request *); -- cgit v0.10.2 From 2e60e02297cf54e367567f2d85b2ca56b1c4a906 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 23 Apr 2009 11:05:18 +0900 Subject: block: clean up request completion API Request completion has gone through several changes and became a bit messy over the time. Clean it up. 1. end_that_request_data() is a thin wrapper around end_that_request_data_first() which checks whether bio is NULL before doing anything and handles bidi completion. blk_update_request() is a thin wrapper around end_that_request_data() which clears nr_sectors on the last iteration but doesn't use the bidi completion. Clean it up by moving the initial bio NULL check and nr_sectors clearing on the last iteration into end_that_request_data() and renaming it to blk_update_request(), which makes blk_end_io() the only user of end_that_request_data(). Collapse end_that_request_data() into blk_end_io(). 2. There are four visible completion variants - blk_end_request(), __blk_end_request(), blk_end_bidi_request() and end_request(). blk_end_request() and blk_end_bidi_request() uses blk_end_request() as the backend but __blk_end_request() and end_request() use separate implementation in __blk_end_request() due to different locking rules. blk_end_bidi_request() is identical to blk_end_io(). Collapse blk_end_io() into blk_end_bidi_request(), separate out request update into internal helper blk_update_bidi_request() and add __blk_end_bidi_request(). Redefine [__]blk_end_request() as thin inline wrappers around [__]blk_end_bidi_request(). 3. As the whole request issue/completion usages are about to be modified and audited, it's a good chance to convert completion functions return bool which better indicates the intended meaning of return values. 4. The function name end_that_request_last() is from the days when it was a public interface and slighly confusing. Give it a proper internal name - blk_finish_request(). 5. Add description explaning that blk_end_bidi_request() can be safely used for uni requests as suggested by Boaz Harrosh. The only visible behavior change is from #1. nr_sectors counts are cleared after the final iteration no matter which function is used to complete the request. I couldn't find any place where the code assumes those nr_sectors counters contain the values for the last segment and this change is good as it makes the API much more consistent as the end result is now same whether a request is completed using [__]blk_end_request() alone or in combination with blk_update_request(). API further cleaned up per Christoph's suggestion. [ Impact: cleanup, rq->*nr_sectors always updated after req completion ] Signed-off-by: Tejun Heo Reviewed-by: Boaz Harrosh Cc: Christoph Hellwig diff --git a/block/blk-core.c b/block/blk-core.c index 2f277ea..89cc05d 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1808,25 +1808,35 @@ void elv_dequeue_request(struct request_queue *q, struct request *rq) } /** - * __end_that_request_first - end I/O on a request - * @req: the request being processed + * blk_update_request - Special helper function for request stacking drivers + * @rq: the request being processed * @error: %0 for success, < %0 for error - * @nr_bytes: number of bytes to complete + * @nr_bytes: number of bytes to complete @rq * * Description: - * Ends I/O on a number of bytes attached to @req, and sets it up - * for the next range of segments (if any) in the cluster. + * Ends I/O on a number of bytes attached to @rq, but doesn't complete + * the request structure even if @rq doesn't have leftover. + * If @rq has leftover, sets it up for the next range of segments. + * + * This special helper function is only for request stacking drivers + * (e.g. request-based dm) so that they can handle partial completion. + * Actual device drivers should use blk_end_request instead. + * + * Passing the result of blk_rq_bytes() as @nr_bytes guarantees + * %false return from this function. * * Return: - * %0 - we are done with this request, call end_that_request_last() - * %1 - still buffers pending for this request + * %false - this request doesn't have any more data + * %true - this request has more data **/ -static int __end_that_request_first(struct request *req, int error, - int nr_bytes) +bool blk_update_request(struct request *req, int error, unsigned int nr_bytes) { int total_bytes, bio_nbytes, next_idx = 0; struct bio *bio; + if (!req->bio) + return false; + trace_block_rq_complete(req->q, req); /* @@ -1903,8 +1913,16 @@ static int __end_that_request_first(struct request *req, int error, /* * completely done */ - if (!req->bio) - return 0; + if (!req->bio) { + /* + * Reset counters so that the request stacking driver + * can find how many bytes remain in the request + * later. + */ + req->nr_sectors = req->hard_nr_sectors = 0; + req->current_nr_sectors = req->hard_cur_sectors = 0; + return false; + } /* * if the request wasn't completed, update state @@ -1918,29 +1936,31 @@ static int __end_that_request_first(struct request *req, int error, blk_recalc_rq_sectors(req, total_bytes >> 9); blk_recalc_rq_segments(req); - return 1; + return true; } +EXPORT_SYMBOL_GPL(blk_update_request); -static int end_that_request_data(struct request *rq, int error, - unsigned int nr_bytes, unsigned int bidi_bytes) +static bool blk_update_bidi_request(struct request *rq, int error, + unsigned int nr_bytes, + unsigned int bidi_bytes) { - if (rq->bio) { - if (__end_that_request_first(rq, error, nr_bytes)) - return 1; + if (blk_update_request(rq, error, nr_bytes)) + return true; - /* Bidi request must be completed as a whole */ - if (blk_bidi_rq(rq) && - __end_that_request_first(rq->next_rq, error, bidi_bytes)) - return 1; - } + /* Bidi request must be completed as a whole */ + if (unlikely(blk_bidi_rq(rq)) && + blk_update_request(rq->next_rq, error, bidi_bytes)) + return true; - return 0; + add_disk_randomness(rq->rq_disk); + + return false; } /* * queue lock must be held */ -static void end_that_request_last(struct request *req, int error) +static void blk_finish_request(struct request *req, int error) { if (blk_rq_tagged(req)) blk_queue_end_tag(req->q, req); @@ -1966,161 +1986,65 @@ static void end_that_request_last(struct request *req, int error) } /** - * blk_end_io - Generic end_io function to complete a request. - * @rq: the request being processed - * @error: %0 for success, < %0 for error - * @nr_bytes: number of bytes to complete @rq - * @bidi_bytes: number of bytes to complete @rq->next_rq + * blk_end_bidi_request - Complete a bidi request + * @rq: the request to complete + * @error: %0 for success, < %0 for error + * @nr_bytes: number of bytes to complete @rq + * @bidi_bytes: number of bytes to complete @rq->next_rq * * Description: * Ends I/O on a number of bytes attached to @rq and @rq->next_rq. - * If @rq has leftover, sets it up for the next range of segments. + * Drivers that supports bidi can safely call this member for any + * type of request, bidi or uni. In the later case @bidi_bytes is + * just ignored. * * Return: - * %0 - we are done with this request - * %1 - this request is not freed yet, it still has pending buffers. + * %false - we are done with this request + * %true - still buffers pending for this request **/ -static int blk_end_io(struct request *rq, int error, unsigned int nr_bytes, - unsigned int bidi_bytes) +bool blk_end_bidi_request(struct request *rq, int error, + unsigned int nr_bytes, unsigned int bidi_bytes) { struct request_queue *q = rq->q; - unsigned long flags = 0UL; - - if (end_that_request_data(rq, error, nr_bytes, bidi_bytes)) - return 1; + unsigned long flags; - add_disk_randomness(rq->rq_disk); + if (blk_update_bidi_request(rq, error, nr_bytes, bidi_bytes)) + return true; spin_lock_irqsave(q->queue_lock, flags); - end_that_request_last(rq, error); + blk_finish_request(rq, error); spin_unlock_irqrestore(q->queue_lock, flags); - return 0; -} - -/** - * blk_end_request - Helper function for drivers to complete the request. - * @rq: the request being processed - * @error: %0 for success, < %0 for error - * @nr_bytes: number of bytes to complete - * - * Description: - * Ends I/O on a number of bytes attached to @rq. - * If @rq has leftover, sets it up for the next range of segments. - * - * Return: - * %0 - we are done with this request - * %1 - still buffers pending for this request - **/ -int blk_end_request(struct request *rq, int error, unsigned int nr_bytes) -{ - return blk_end_io(rq, error, nr_bytes, 0); -} -EXPORT_SYMBOL_GPL(blk_end_request); - -/** - * __blk_end_request - Helper function for drivers to complete the request. - * @rq: the request being processed - * @error: %0 for success, < %0 for error - * @nr_bytes: number of bytes to complete - * - * Description: - * Must be called with queue lock held unlike blk_end_request(). - * - * Return: - * %0 - we are done with this request - * %1 - still buffers pending for this request - **/ -int __blk_end_request(struct request *rq, int error, unsigned int nr_bytes) -{ - if (rq->bio && __end_that_request_first(rq, error, nr_bytes)) - return 1; - - add_disk_randomness(rq->rq_disk); - - end_that_request_last(rq, error); - - return 0; + return false; } -EXPORT_SYMBOL_GPL(__blk_end_request); +EXPORT_SYMBOL_GPL(blk_end_bidi_request); /** - * blk_end_bidi_request - Helper function for drivers to complete bidi request. - * @rq: the bidi request being processed + * __blk_end_bidi_request - Complete a bidi request with queue lock held + * @rq: the request to complete * @error: %0 for success, < %0 for error * @nr_bytes: number of bytes to complete @rq * @bidi_bytes: number of bytes to complete @rq->next_rq * * Description: - * Ends I/O on a number of bytes attached to @rq and @rq->next_rq. + * Identical to blk_end_bidi_request() except that queue lock is + * assumed to be locked on entry and remains so on return. * * Return: - * %0 - we are done with this request - * %1 - still buffers pending for this request - **/ -int blk_end_bidi_request(struct request *rq, int error, unsigned int nr_bytes, - unsigned int bidi_bytes) -{ - return blk_end_io(rq, error, nr_bytes, bidi_bytes); -} -EXPORT_SYMBOL_GPL(blk_end_bidi_request); - -/** - * end_request - end I/O on the current segment of the request - * @req: the request being processed - * @uptodate: error value or %0/%1 uptodate flag - * - * Description: - * Ends I/O on the current segment of a request. If that is the only - * remaining segment, the request is also completed and freed. - * - * This is a remnant of how older block drivers handled I/O completions. - * Modern drivers typically end I/O on the full request in one go, unless - * they have a residual value to account for. For that case this function - * isn't really useful, unless the residual just happens to be the - * full current segment. In other words, don't use this function in new - * code. Use blk_end_request() or __blk_end_request() to end a request. + * %false - we are done with this request + * %true - still buffers pending for this request **/ -void end_request(struct request *req, int uptodate) +bool __blk_end_bidi_request(struct request *rq, int error, + unsigned int nr_bytes, unsigned int bidi_bytes) { - int error = 0; + if (blk_update_bidi_request(rq, error, nr_bytes, bidi_bytes)) + return true; - if (uptodate <= 0) - error = uptodate ? uptodate : -EIO; + blk_finish_request(rq, error); - __blk_end_request(req, error, req->hard_cur_sectors << 9); -} -EXPORT_SYMBOL(end_request); - -/** - * blk_update_request - Special helper function for request stacking drivers - * @rq: the request being processed - * @error: %0 for success, < %0 for error - * @nr_bytes: number of bytes to complete @rq - * - * Description: - * Ends I/O on a number of bytes attached to @rq, but doesn't complete - * the request structure even if @rq doesn't have leftover. - * If @rq has leftover, sets it up for the next range of segments. - * - * This special helper function is only for request stacking drivers - * (e.g. request-based dm) so that they can handle partial completion. - * Actual device drivers should use blk_end_request instead. - */ -void blk_update_request(struct request *rq, int error, unsigned int nr_bytes) -{ - if (!end_that_request_data(rq, error, nr_bytes, 0)) { - /* - * These members are not updated in end_that_request_data() - * when all bios are completed. - * Update them so that the request stacking driver can find - * how many bytes remain in the request later. - */ - rq->nr_sectors = rq->hard_nr_sectors = 0; - rq->current_nr_sectors = rq->hard_cur_sectors = 0; - } + return false; } -EXPORT_SYMBOL_GPL(blk_update_request); +EXPORT_SYMBOL_GPL(__blk_end_bidi_request); void blk_rq_bio_prep(struct request_queue *q, struct request *rq, struct bio *bio) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 1fa9dcf..501f684 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -840,27 +840,97 @@ extern unsigned int blk_rq_bytes(struct request *rq); extern unsigned int blk_rq_cur_bytes(struct request *rq); /* - * blk_end_request() and friends. - * __blk_end_request() and end_request() must be called with - * the request queue spinlock acquired. + * Request completion related functions. + * + * blk_update_request() completes given number of bytes and updates + * the request without completing it. + * + * blk_end_request() and friends. __blk_end_request() and + * end_request() must be called with the request queue spinlock + * acquired. * * Several drivers define their own end_request and call * blk_end_request() for parts of the original function. * This prevents code duplication in drivers. */ -extern int blk_end_request(struct request *rq, int error, - unsigned int nr_bytes); -extern int __blk_end_request(struct request *rq, int error, - unsigned int nr_bytes); -extern int blk_end_bidi_request(struct request *rq, int error, - unsigned int nr_bytes, unsigned int bidi_bytes); -extern void end_request(struct request *, int); +extern bool blk_update_request(struct request *rq, int error, + unsigned int nr_bytes); +extern bool blk_end_bidi_request(struct request *rq, int error, + unsigned int nr_bytes, + unsigned int bidi_bytes); +extern bool __blk_end_bidi_request(struct request *rq, int error, + unsigned int nr_bytes, + unsigned int bidi_bytes); + +/** + * blk_end_request - Helper function for drivers to complete the request. + * @rq: the request being processed + * @error: %0 for success, < %0 for error + * @nr_bytes: number of bytes to complete + * + * Description: + * Ends I/O on a number of bytes attached to @rq. + * If @rq has leftover, sets it up for the next range of segments. + * + * Return: + * %false - we are done with this request + * %true - still buffers pending for this request + **/ +static inline bool blk_end_request(struct request *rq, int error, + unsigned int nr_bytes) +{ + return blk_end_bidi_request(rq, error, nr_bytes, 0); +} + +/** + * __blk_end_request - Helper function for drivers to complete the request. + * @rq: the request being processed + * @error: %0 for success, < %0 for error + * @nr_bytes: number of bytes to complete + * + * Description: + * Must be called with queue lock held unlike blk_end_request(). + * + * Return: + * %false - we are done with this request + * %true - still buffers pending for this request + **/ +static inline bool __blk_end_request(struct request *rq, int error, + unsigned int nr_bytes) +{ + return __blk_end_bidi_request(rq, error, nr_bytes, 0); +} + +/** + * end_request - end I/O on the current segment of the request + * @rq: the request being processed + * @uptodate: error value or %0/%1 uptodate flag + * + * Description: + * Ends I/O on the current segment of a request. If that is the only + * remaining segment, the request is also completed and freed. + * + * This is a remnant of how older block drivers handled I/O completions. + * Modern drivers typically end I/O on the full request in one go, unless + * they have a residual value to account for. For that case this function + * isn't really useful, unless the residual just happens to be the + * full current segment. In other words, don't use this function in new + * code. Use blk_end_request() or __blk_end_request() to end a request. + **/ +static inline void end_request(struct request *rq, int uptodate) +{ + int error = 0; + + if (uptodate <= 0) + error = uptodate ? uptodate : -EIO; + + __blk_end_bidi_request(rq, error, rq->hard_cur_sectors << 9, 0); +} + extern void blk_complete_request(struct request *); extern void __blk_complete_request(struct request *); extern void blk_abort_request(struct request *); extern void blk_abort_queue(struct request_queue *); -extern void blk_update_request(struct request *rq, int error, - unsigned int nr_bytes); /* * Access functions for manipulating queue properties -- cgit v0.10.2 From b243ddcbe9be146172baa544dadecebf156eda0e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 23 Apr 2009 11:05:18 +0900 Subject: block: move rq->start_time initialization to blk_rq_init() rq->start_time was initialized in init_request_from_bio() so special requests didn't have start_time set. This has been okay as start_time has been used only for fs requests; however, there is no indication of this actually is the case or not. Set rq->start_time in blk_rq_init() and guarantee that all initialized rq's have its start_time set. This improves consistency at virtually no cost and future changes will make use of the timestamp for !bio requests. [ Impact: rq->start_time is valid for all requests ] Signed-off-by: Tejun Heo diff --git a/block/blk-core.c b/block/blk-core.c index 89cc05d..b84250d 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -134,6 +134,7 @@ void blk_rq_init(struct request_queue *q, struct request *rq) rq->cmd_len = BLK_MAX_CDB; rq->tag = -1; rq->ref_count = 1; + rq->start_time = jiffies; } EXPORT_SYMBOL(blk_rq_init); @@ -1099,7 +1100,6 @@ void init_request_from_bio(struct request *req, struct bio *bio) req->errors = 0; req->hard_sector = req->sector = bio->bi_sector; req->ioprio = bio_prio(bio); - req->start_time = jiffies; blk_rq_bio_prep(req->q, req, bio); } -- cgit v0.10.2 From 40cbbb781d3eba5d6ac0860db078af490e5c7c6b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 23 Apr 2009 11:05:19 +0900 Subject: block: implement and use [__]blk_end_request_all() There are many [__]blk_end_request() call sites which call it with full request length and expect full completion. Many of them ensure that the request actually completes by doing BUG_ON() the return value, which is awkward and error-prone. This patch adds [__]blk_end_request_all() which takes @rq and @error and fully completes the request. BUG_ON() is added to to ensure that this actually happens. Most conversions are simple but there are a few noteworthy ones. * cdrom/viocd: viocd_end_request() replaced with direct calls to __blk_end_request_all(). * s390/block/dasd: dasd_end_request() replaced with direct calls to __blk_end_request_all(). * s390/char/tape_block: tapeblock_end_request() replaced with direct calls to blk_end_request_all(). [ Impact: cleanup ] Signed-off-by: Tejun Heo Cc: Russell King Cc: Stephen Rothwell Cc: Mike Miller Cc: Martin Schwidefsky Cc: Jeff Garzik Cc: Rusty Russell Cc: Jeremy Fitzhardinge Cc: Alex Dubov Cc: James Bottomley diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c index 0abfbaa..cf81bad 100644 --- a/arch/arm/plat-omap/mailbox.c +++ b/arch/arm/plat-omap/mailbox.c @@ -192,8 +192,7 @@ static void mbox_tx_work(struct work_struct *work) } spin_lock(q->queue_lock); - if (__blk_end_request(rq, 0, 0)) - BUG(); + __blk_end_request_all(rq, 0); spin_unlock(q->queue_lock); } } @@ -224,10 +223,7 @@ static void mbox_rx_work(struct work_struct *work) break; msg = (mbox_msg_t) rq->data; - - if (blk_end_request(rq, 0, 0)) - BUG(); - + blk_end_request_all(rq, 0); mbox->rxq->callback((void *)msg); } } @@ -337,8 +333,7 @@ omap_mbox_read(struct device *dev, struct device_attribute *attr, char *buf) *p = (mbox_msg_t) rq->data; - if (blk_end_request(rq, 0, 0)) - BUG(); + blk_end_request_all(rq, 0); if (unlikely(mbox_seq_test(mbox, *p))) { pr_info("mbox: Illegal seq bit!(%08x) ignored\n", *p); diff --git a/block/blk-barrier.c b/block/blk-barrier.c index 20b4111..c8d0876 100644 --- a/block/blk-barrier.c +++ b/block/blk-barrier.c @@ -106,10 +106,7 @@ bool blk_ordered_complete_seq(struct request_queue *q, unsigned seq, int error) */ q->ordseq = 0; rq = q->orig_bar_rq; - - if (__blk_end_request(rq, q->orderr, blk_rq_bytes(rq))) - BUG(); - + __blk_end_request_all(rq, q->orderr); return true; } @@ -252,9 +249,7 @@ bool blk_do_ordered(struct request_queue *q, struct request **rqp) * with prejudice. */ elv_dequeue_request(q, rq); - if (__blk_end_request(rq, -EOPNOTSUPP, - blk_rq_bytes(rq))) - BUG(); + __blk_end_request_all(rq, -EOPNOTSUPP); *rqp = NULL; return false; } diff --git a/block/blk-core.c b/block/blk-core.c index b84250d..0520cc7 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1780,7 +1780,7 @@ struct request *elv_next_request(struct request_queue *q) break; } else if (ret == BLKPREP_KILL) { rq->cmd_flags |= REQ_QUIET; - __blk_end_request(rq, -EIO, blk_rq_bytes(rq)); + __blk_end_request_all(rq, -EIO); } else { printk(KERN_ERR "%s: bad return=%d\n", __func__, ret); break; diff --git a/block/elevator.c b/block/elevator.c index b03b875..1af5d9f 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -810,7 +810,7 @@ void elv_abort_queue(struct request_queue *q) rq = list_entry_rq(q->queue_head.next); rq->cmd_flags |= REQ_QUIET; trace_block_rq_abort(q, rq); - __blk_end_request(rq, -EIO, blk_rq_bytes(rq)); + __blk_end_request_all(rq, -EIO); } } EXPORT_SYMBOL(elv_abort_queue); diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index ca268ca..488a8f4 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -1024,8 +1024,7 @@ static inline void complete_command(cmdlist_t *cmd, int timeout) cmd->req.sg[i].size, ddir); DBGPX(printk("Done with %p\n", rq);); - if (__blk_end_request(rq, error, blk_rq_bytes(rq))) - BUG(); + __blk_end_request_all(rq, error); } /* diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index ff0448e..60e85bb 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -749,8 +749,7 @@ static inline void carm_end_request_queued(struct carm_host *host, struct request *req = crq->rq; int rc; - rc = __blk_end_request(req, error, blk_rq_bytes(req)); - assert(rc == 0); + __blk_end_request_all(req, error); rc = carm_put_request(host, crq); assert(rc == 0); diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 5d34764..50745e6 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -62,7 +62,7 @@ static void blk_done(struct virtqueue *vq) break; } - __blk_end_request(vbr->req, error, blk_rq_bytes(vbr->req)); + __blk_end_request_all(vbr->req, error); list_del(&vbr->list); mempool_free(vbr, vblk->pool); } diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 8f90508..cd6cfe3 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -551,7 +551,6 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) for (i = info->ring.rsp_cons; i != rp; i++) { unsigned long id; - int ret; bret = RING_GET_RESPONSE(&info->ring, i); id = bret->id; @@ -578,8 +577,7 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) dev_dbg(&info->xbdev->dev, "Bad return from blkdev data " "request: %x\n", bret->status); - ret = __blk_end_request(req, error, blk_rq_bytes(req)); - BUG_ON(ret); + __blk_end_request_all(req, error); break; default: BUG(); diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c index 2eecb77..fee9a9e 100644 --- a/drivers/cdrom/gdrom.c +++ b/drivers/cdrom/gdrom.c @@ -632,7 +632,7 @@ static void gdrom_readdisk_dma(struct work_struct *work) * before handling ending the request */ spin_lock(&gdrom_lock); list_del_init(&req->queuelist); - __blk_end_request(req, err, blk_rq_bytes(req)); + __blk_end_request_all(req, err); } spin_unlock(&gdrom_lock); kfree(read_command); diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index 1392935..cc3efa0 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -291,23 +291,6 @@ static int send_request(struct request *req) return 0; } -static void viocd_end_request(struct request *req, int error) -{ - int nsectors = req->hard_nr_sectors; - - /* - * Make sure it's fully ended, and ensure that we process - * at least one sector. - */ - if (blk_pc_request(req)) - nsectors = (req->data_len + 511) >> 9; - if (!nsectors) - nsectors = 1; - - if (__blk_end_request(req, error, nsectors << 9)) - BUG(); -} - static int rwreq; static void do_viocd_request(struct request_queue *q) @@ -316,11 +299,11 @@ static void do_viocd_request(struct request_queue *q) while ((rwreq == 0) && ((req = elv_next_request(q)) != NULL)) { if (!blk_fs_request(req)) - viocd_end_request(req, -EIO); + __blk_end_request_all(req, -EIO); else if (send_request(req) < 0) { printk(VIOCD_KERN_WARNING "unable to send message to OS/400!"); - viocd_end_request(req, -EIO); + __blk_end_request_all(req, -EIO); } else rwreq++; } @@ -531,9 +514,9 @@ return_complete: "with rc %d:0x%04X: %s\n", req, event->xRc, bevent->sub_result, err->msg); - viocd_end_request(req, -EIO); + __blk_end_request_all(req, -EIO); } else - viocd_end_request(req, 0); + __blk_end_request_all(req, 0); /* restart handling of incoming requests */ spin_unlock_irqrestore(&viocd_reqlock, flags); diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index de143de..a416346 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -826,7 +826,7 @@ static void mspro_block_submit_req(struct request_queue *q) if (msb->eject) { while ((req = elv_next_request(q)) != NULL) - __blk_end_request(req, -ENODEV, blk_rq_bytes(req)); + __blk_end_request_all(req, -ENODEV); return; } diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index d181527..fabec95 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1614,15 +1614,6 @@ void dasd_block_clear_timer(struct dasd_block *block) } /* - * posts the buffer_cache about a finalized request - */ -static inline void dasd_end_request(struct request *req, int error) -{ - if (__blk_end_request(req, error, blk_rq_bytes(req))) - BUG(); -} - -/* * Process finished error recovery ccw. */ static inline void __dasd_block_process_erp(struct dasd_block *block, @@ -1676,7 +1667,7 @@ static void __dasd_process_request_queue(struct dasd_block *block) "Rejecting write request %p", req); blkdev_dequeue_request(req); - dasd_end_request(req, -EIO); + __blk_end_request_all(req, -EIO); continue; } cqr = basedev->discipline->build_cp(basedev, block, req); @@ -1705,7 +1696,7 @@ static void __dasd_process_request_queue(struct dasd_block *block) "on request %p", PTR_ERR(cqr), req); blkdev_dequeue_request(req); - dasd_end_request(req, -EIO); + __blk_end_request_all(req, -EIO); continue; } /* @@ -1731,7 +1722,7 @@ static void __dasd_cleanup_cqr(struct dasd_ccw_req *cqr) status = cqr->block->base->discipline->free_cp(cqr, req); if (status <= 0) error = status ? status : -EIO; - dasd_end_request(req, error); + __blk_end_request_all(req, error); } /* @@ -2040,7 +2031,7 @@ static void dasd_flush_request_queue(struct dasd_block *block) spin_lock_irq(&block->request_queue_lock); while ((req = elv_next_request(block->request_queue))) { blkdev_dequeue_request(req); - dasd_end_request(req, -EIO); + __blk_end_request_all(req, -EIO); } spin_unlock_irq(&block->request_queue_lock); } diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index f32e89e..86596d3 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -74,13 +74,6 @@ tapeblock_trigger_requeue(struct tape_device *device) * Post finished request. */ static void -tapeblock_end_request(struct request *req, int error) -{ - if (blk_end_request(req, error, blk_rq_bytes(req))) - BUG(); -} - -static void __tapeblock_end_request(struct tape_request *ccw_req, void *data) { struct tape_device *device; @@ -90,7 +83,7 @@ __tapeblock_end_request(struct tape_request *ccw_req, void *data) device = ccw_req->device; req = (struct request *) data; - tapeblock_end_request(req, (ccw_req->rc == 0) ? 0 : -EIO); + blk_end_request_all(req, (ccw_req->rc == 0) ? 0 : -EIO); if (ccw_req->rc == 0) /* Update position. */ device->blk_data.block_position = @@ -118,7 +111,7 @@ tapeblock_start_request(struct tape_device *device, struct request *req) ccw_req = device->discipline->bread(device, req); if (IS_ERR(ccw_req)) { DBF_EVENT(1, "TBLOCK: bread failed\n"); - tapeblock_end_request(req, -EIO); + blk_end_request_all(req, -EIO); return PTR_ERR(ccw_req); } ccw_req->callback = __tapeblock_end_request; @@ -131,7 +124,7 @@ tapeblock_start_request(struct tape_device *device, struct request *req) * Start/enqueueing failed. No retries in * this case. */ - tapeblock_end_request(req, -EIO); + blk_end_request_all(req, -EIO); device->discipline->free_bread(ccw_req); } @@ -177,7 +170,7 @@ tapeblock_requeue(struct work_struct *work) { DBF_EVENT(1, "TBLOCK: Rejecting write request\n"); blkdev_dequeue_request(req); spin_unlock_irq(&device->blk_data.request_queue_lock); - tapeblock_end_request(req, -EIO); + blk_end_request_all(req, -EIO); spin_lock_irq(&device->blk_data.request_queue_lock); continue; } diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index d1cb64a..756ac7c 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -922,7 +922,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) if (driver_byte(result) & DRIVER_SENSE) scsi_print_sense("", cmd); } - blk_end_request(req, -EIO, blk_rq_bytes(req)); + blk_end_request_all(req, -EIO); scsi_next_command(cmd); break; case ACTION_REPREP: diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 501f684..e33c835 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -883,6 +883,22 @@ static inline bool blk_end_request(struct request *rq, int error, } /** + * blk_end_request_all - Helper function for drives to finish the request. + * @rq: the request to finish + * @err: %0 for success, < %0 for error + * + * Description: + * Completely finish @rq. + */ +static inline void blk_end_request_all(struct request *rq, int error) +{ + bool pending; + + pending = blk_end_request(rq, error, blk_rq_bytes(rq)); + BUG_ON(pending); +} + +/** * __blk_end_request - Helper function for drivers to complete the request. * @rq: the request being processed * @error: %0 for success, < %0 for error @@ -902,6 +918,22 @@ static inline bool __blk_end_request(struct request *rq, int error, } /** + * __blk_end_request_all - Helper function for drives to finish the request. + * @rq: the request to finish + * @err: %0 for success, < %0 for error + * + * Description: + * Completely finish @rq. Must be called with queue lock held. + */ +static inline void __blk_end_request_all(struct request *rq, int error) +{ + bool pending; + + pending = __blk_end_request(rq, error, blk_rq_bytes(rq)); + BUG_ON(pending); +} + +/** * end_request - end I/O on the current segment of the request * @rq: the request being processed * @uptodate: error value or %0/%1 uptodate flag -- cgit v0.10.2 From f06d9a2b52e246a66b606130cea3f0d7b7be17a7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 23 Apr 2009 11:05:19 +0900 Subject: block: replace end_request() with [__]blk_end_request_cur() end_request() has been kept around for backward compatibility; however, it's about time for it to go away. * There aren't too many users left. * Its use of @updtodate is pretty confusing. * In some cases, newer code ends up using mixture of end_request() and [__]blk_end_request[_all](), which is way too confusing. So, add [__]blk_end_request_cur() and replace end_request() with it. Most conversions are straightforward. Noteworthy ones are... * paride/pcd: next_request() updated to take 0/-errno instead of 1/0. * paride/pf: pf_end_request() and next_request() updated to take 0/-errno instead of 1/0. * xd: xd_readwrite() updated to return 0/-errno instead of 1/0. * mtd/mtd_blkdevs: blktrans_discard_request() updated to return 0/-errno instead of 1/0. Unnecessary local variable res initialization removed from mtd_blktrans_thread(). [ Impact: cleanup ] Signed-off-by: Tejun Heo Acked-by: Joerg Dorchain Acked-by: Geert Uytterhoeven Acked-by: Grant Likely Acked-by: Laurent Vivier Cc: Tim Waugh Cc: Stephen Rothwell Cc: Paul Mackerras Cc: Jeremy Fitzhardinge Cc: Markus Lidel Cc: David Woodhouse Cc: Pete Zaitcev Cc: unsik Kim diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 8df436f..b99a2a6 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -1359,7 +1359,7 @@ static void redo_fd_request(void) #endif block = CURRENT->sector + cnt; if ((int)block > floppy->blocks) { - end_request(CURRENT, 0); + __blk_end_request_cur(CURRENT, -EIO); goto repeat; } @@ -1373,11 +1373,11 @@ static void redo_fd_request(void) if ((rq_data_dir(CURRENT) != READ) && (rq_data_dir(CURRENT) != WRITE)) { printk(KERN_WARNING "do_fd_request: unknown command\n"); - end_request(CURRENT, 0); + __blk_end_request_cur(CURRENT, -EIO); goto repeat; } if (get_track(drive, track) == -1) { - end_request(CURRENT, 0); + __blk_end_request_cur(CURRENT, -EIO); goto repeat; } @@ -1391,7 +1391,7 @@ static void redo_fd_request(void) /* keep the drive spinning while writes are scheduled */ if (!fd_motor_on(drive)) { - end_request(CURRENT, 0); + __blk_end_request_cur(CURRENT, -EIO); goto repeat; } /* @@ -1410,7 +1410,7 @@ static void redo_fd_request(void) CURRENT->nr_sectors -= CURRENT->current_nr_sectors; CURRENT->sector += CURRENT->current_nr_sectors; - end_request(CURRENT, 1); + __blk_end_request_cur(CURRENT, 0); goto repeat; } diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index 4234c11..44a8702 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -612,7 +612,7 @@ static void fd_error( void ) CURRENT->errors++; if (CURRENT->errors >= MAX_ERRORS) { printk(KERN_ERR "fd%d: too many errors.\n", SelectedDrive ); - end_request(CURRENT, 0); + __blk_end_request_cur(CURRENT, -EIO); } else if (CURRENT->errors == RECALIBRATE_ERRORS) { printk(KERN_WARNING "fd%d: recalibrating\n", SelectedDrive ); @@ -734,7 +734,7 @@ static void do_fd_action( int drive ) /* all sectors finished */ CURRENT->nr_sectors -= CURRENT->current_nr_sectors; CURRENT->sector += CURRENT->current_nr_sectors; - end_request(CURRENT, 1); + __blk_end_request_cur(CURRENT, 0); redo_fd_request(); return; } @@ -1141,7 +1141,7 @@ static void fd_rwsec_done1(int status) /* all sectors finished */ CURRENT->nr_sectors -= CURRENT->current_nr_sectors; CURRENT->sector += CURRENT->current_nr_sectors; - end_request(CURRENT, 1); + __blk_end_request_cur(CURRENT, 0); redo_fd_request(); } return; @@ -1414,7 +1414,7 @@ repeat: if (!UD.connected) { /* drive not connected */ printk(KERN_ERR "Unknown Device: fd%d\n", drive ); - end_request(CURRENT, 0); + __blk_end_request_cur(CURRENT, -EIO); goto repeat; } @@ -1430,12 +1430,12 @@ repeat: /* user supplied disk type */ if (--type >= NUM_DISK_MINORS) { printk(KERN_WARNING "fd%d: invalid disk format", drive ); - end_request(CURRENT, 0); + __blk_end_request_cur(CURRENT, -EIO); goto repeat; } if (minor2disktype[type].drive_types > DriveType) { printk(KERN_WARNING "fd%d: unsupported disk format", drive ); - end_request(CURRENT, 0); + __blk_end_request_cur(CURRENT, -EIO); goto repeat; } type = minor2disktype[type].index; @@ -1445,7 +1445,7 @@ repeat: } if (CURRENT->sector + 1 > UDT->blocks) { - end_request(CURRENT, 0); + __blk_end_request_cur(CURRENT, -EIO); goto repeat; } diff --git a/drivers/block/hd.c b/drivers/block/hd.c index baaa9e4..5cb300b 100644 --- a/drivers/block/hd.c +++ b/drivers/block/hd.c @@ -410,7 +410,7 @@ static void bad_rw_intr(void) if (req != NULL) { struct hd_i_struct *disk = req->rq_disk->private_data; if (++req->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) { - end_request(req, 0); + __blk_end_request_cur(req, -EIO); disk->special_op = disk->recalibrate = 1; } else if (req->errors % RESET_FREQ == 0) reset = 1; @@ -466,7 +466,7 @@ ok_to_read: req->buffer+512); #endif if (req->current_nr_sectors <= 0) - end_request(req, 1); + __blk_end_request_cur(req, 0); if (i > 0) { SET_HANDLER(&read_intr); return; @@ -505,7 +505,7 @@ ok_to_write: --req->current_nr_sectors; req->buffer += 512; if (!i || (req->bio && req->current_nr_sectors <= 0)) - end_request(req, 1); + __blk_end_request_cur(req, 0); if (i > 0) { SET_HANDLER(&write_intr); outsw(HD_DATA, req->buffer, 256); @@ -548,7 +548,7 @@ static void hd_times_out(unsigned long dummy) #ifdef DEBUG printk("%s: too many errors\n", name); #endif - end_request(CURRENT, 0); + __blk_end_request_cur(CURRENT, -EIO); } hd_request(); spin_unlock_irq(hd_queue->queue_lock); @@ -563,7 +563,7 @@ static int do_special_op(struct hd_i_struct *disk, struct request *req) } if (disk->head > 16) { printk("%s: cannot handle device with more than 16 heads - giving up\n", req->rq_disk->disk_name); - end_request(req, 0); + __blk_end_request_cur(req, -EIO); } disk->special_op = 0; return 1; @@ -607,7 +607,7 @@ repeat: ((block+nsect) > get_capacity(req->rq_disk))) { printk("%s: bad access: block=%d, count=%d\n", req->rq_disk->disk_name, block, nsect); - end_request(req, 0); + __blk_end_request_cur(req, -EIO); goto repeat; } @@ -647,7 +647,7 @@ repeat: break; default: printk("unknown hd-command\n"); - end_request(req, 0); + __blk_end_request_cur(req, -EIO); break; } } diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index f389835..408c2bd 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c @@ -285,7 +285,7 @@ static void mg_bad_rw_intr(struct mg_host *host) if (req != NULL) if (++req->errors >= MG_MAX_ERRORS || host->error == MG_ERR_TIMEOUT) - end_request(req, 0); + __blk_end_request_cur(req, -EIO); } static unsigned int mg_out(struct mg_host *host, @@ -351,7 +351,7 @@ static void mg_read(struct request *req) if (req->current_nr_sectors <= 0) { MG_DBG("remain : %d sects\n", remains); - end_request(req, 1); + __blk_end_request_cur(req, 0); if (remains > 0) req = elv_next_request(host->breq); } @@ -395,7 +395,7 @@ static void mg_write(struct request *req) if (req->current_nr_sectors <= 0) { MG_DBG("remain : %d sects\n", remains); - end_request(req, 1); + __blk_end_request_cur(req, 0); if (remains > 0) req = elv_next_request(host->breq); } @@ -448,7 +448,7 @@ ok_to_read: /* let know if current segment done */ if (req->current_nr_sectors <= 0) - end_request(req, 1); + __blk_end_request_cur(req, 0); /* set handler if read remains */ if (i > 0) { @@ -497,7 +497,7 @@ ok_to_write: /* let know if current segment or all done */ if (!i || (req->bio && req->current_nr_sectors <= 0)) - end_request(req, 1); + __blk_end_request_cur(req, 0); /* write 1 sector and set handler if remains */ if (i > 0) { @@ -563,7 +563,7 @@ static void mg_request_poll(struct request_queue *q) default: printk(KERN_WARNING "%s:%d unknown command\n", __func__, __LINE__); - end_request(req, 0); + __blk_end_request_cur(req, -EIO); break; } } @@ -617,7 +617,7 @@ static unsigned int mg_issue_req(struct request *req, default: printk(KERN_WARNING "%s:%d unknown command\n", __func__, __LINE__); - end_request(req, 0); + __blk_end_request_cur(req, -EIO); break; } return MG_ERR_NONE; @@ -655,7 +655,7 @@ static void mg_request(struct request_queue *q) "%s: bad access: sector=%d, count=%d\n", req->rq_disk->disk_name, sect_num, sect_cnt); - end_request(req, 0); + __blk_end_request_cur(req, -EIO); continue; } diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c index e91d4b4..9fd57c2 100644 --- a/drivers/block/paride/pcd.c +++ b/drivers/block/paride/pcd.c @@ -735,16 +735,16 @@ static void do_pcd_request(struct request_queue * q) ps_set_intr(do_pcd_read, NULL, 0, nice); return; } else - end_request(pcd_req, 0); + __blk_end_request_cur(pcd_req, -EIO); } } -static inline void next_request(int success) +static inline void next_request(int err) { unsigned long saved_flags; spin_lock_irqsave(&pcd_lock, saved_flags); - end_request(pcd_req, success); + __blk_end_request_cur(pcd_req, err); pcd_busy = 0; do_pcd_request(pcd_queue); spin_unlock_irqrestore(&pcd_lock, saved_flags); @@ -781,7 +781,7 @@ static void pcd_start(void) if (pcd_command(pcd_current, rd_cmd, 2048, "read block")) { pcd_bufblk = -1; - next_request(0); + next_request(-EIO); return; } @@ -796,7 +796,7 @@ static void do_pcd_read(void) pcd_retries = 0; pcd_transfer(); if (!pcd_count) { - next_request(1); + next_request(0); return; } @@ -815,7 +815,7 @@ static void do_pcd_read_drq(void) return; } pcd_bufblk = -1; - next_request(0); + next_request(-EIO); return; } diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 9299455..0732df4 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -410,7 +410,8 @@ static void run_fsm(void) pd_claimed = 0; phase = NULL; spin_lock_irqsave(&pd_lock, saved_flags); - end_request(pd_req, res); + __blk_end_request_cur(pd_req, + res == Ok ? 0 : -EIO); pd_req = elv_next_request(pd_queue); if (!pd_req) stop = 1; @@ -477,7 +478,7 @@ static int pd_next_buf(void) if (pd_count) return 0; spin_lock_irqsave(&pd_lock, saved_flags); - end_request(pd_req, 1); + __blk_end_request_cur(pd_req, 0); pd_count = pd_req->current_nr_sectors; pd_buf = pd_req->buffer; spin_unlock_irqrestore(&pd_lock, saved_flags); diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index bef3b99..3871e35 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -750,10 +750,10 @@ static int pf_ready(void) static struct request_queue *pf_queue; -static void pf_end_request(int uptodate) +static void pf_end_request(int err) { if (pf_req) { - end_request(pf_req, uptodate); + __blk_end_request_cur(pf_req, err); pf_req = NULL; } } @@ -773,7 +773,7 @@ repeat: pf_count = pf_req->current_nr_sectors; if (pf_block + pf_count > get_capacity(pf_req->rq_disk)) { - pf_end_request(0); + pf_end_request(-EIO); goto repeat; } @@ -788,7 +788,7 @@ repeat: pi_do_claimed(pf_current->pi, do_pf_write); else { pf_busy = 0; - pf_end_request(0); + pf_end_request(-EIO); goto repeat; } } @@ -805,7 +805,7 @@ static int pf_next_buf(void) return 1; if (!pf_count) { spin_lock_irqsave(&pf_spin_lock, saved_flags); - pf_end_request(1); + pf_end_request(0); pf_req = elv_next_request(pf_queue); spin_unlock_irqrestore(&pf_spin_lock, saved_flags); if (!pf_req) @@ -816,12 +816,12 @@ static int pf_next_buf(void) return 0; } -static inline void next_request(int success) +static inline void next_request(int err) { unsigned long saved_flags; spin_lock_irqsave(&pf_spin_lock, saved_flags); - pf_end_request(success); + pf_end_request(err); pf_busy = 0; do_pf_request(pf_queue); spin_unlock_irqrestore(&pf_spin_lock, saved_flags); @@ -844,7 +844,7 @@ static void do_pf_read_start(void) pi_do_claimed(pf_current->pi, do_pf_read_start); return; } - next_request(0); + next_request(-EIO); return; } pf_mask = STAT_DRQ; @@ -863,7 +863,7 @@ static void do_pf_read_drq(void) pi_do_claimed(pf_current->pi, do_pf_read_start); return; } - next_request(0); + next_request(-EIO); return; } pi_read_block(pf_current->pi, pf_buf, 512); @@ -871,7 +871,7 @@ static void do_pf_read_drq(void) break; } pi_disconnect(pf_current->pi); - next_request(1); + next_request(0); } static void do_pf_write(void) @@ -890,7 +890,7 @@ static void do_pf_write_start(void) pi_do_claimed(pf_current->pi, do_pf_write_start); return; } - next_request(0); + next_request(-EIO); return; } @@ -903,7 +903,7 @@ static void do_pf_write_start(void) pi_do_claimed(pf_current->pi, do_pf_write_start); return; } - next_request(0); + next_request(-EIO); return; } pi_write_block(pf_current->pi, pf_buf, 512); @@ -923,11 +923,11 @@ static void do_pf_write_done(void) pi_do_claimed(pf_current->pi, do_pf_write_start); return; } - next_request(0); + next_request(-EIO); return; } pi_disconnect(pf_current->pi); - next_request(1); + next_request(0); } static int __init pf_init(void) diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index bccc42b..d23b54b 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -158,7 +158,7 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev, if (res) { dev_err(&dev->sbd.core, "%s:%u: %s failed %d\n", __func__, __LINE__, op, res); - end_request(req, 0); + __blk_end_request_cur(req, -EIO); return 0; } @@ -180,7 +180,7 @@ static int ps3disk_submit_flush_request(struct ps3_storage_device *dev, if (res) { dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%llx\n", __func__, __LINE__, res); - end_request(req, 0); + __blk_end_request_cur(req, -EIO); return 0; } @@ -205,7 +205,7 @@ static void ps3disk_do_request(struct ps3_storage_device *dev, break; } else { blk_dump_rq_flags(req, DEVICE_NAME " bad request"); - end_request(req, 0); + __blk_end_request_cur(req, -EIO); continue; } } diff --git a/drivers/block/swim.c b/drivers/block/swim.c index d22cc38..6544a7b 100644 --- a/drivers/block/swim.c +++ b/drivers/block/swim.c @@ -532,39 +532,39 @@ static void redo_fd_request(struct request_queue *q) fs = req->rq_disk->private_data; if (req->sector < 0 || req->sector >= fs->total_secs) { - end_request(req, 0); + __blk_end_request_cur(req, -EIO); continue; } if (req->current_nr_sectors == 0) { - end_request(req, 1); + __blk_end_request_cur(req, 0); continue; } if (!fs->disk_in) { - end_request(req, 0); + __blk_end_request_cur(req, -EIO); continue; } if (rq_data_dir(req) == WRITE) { if (fs->write_protected) { - end_request(req, 0); + __blk_end_request_cur(req, -EIO); continue; } } switch (rq_data_dir(req)) { case WRITE: /* NOT IMPLEMENTED */ - end_request(req, 0); + __blk_end_request_cur(req, -EIO); break; case READ: if (floppy_read_sectors(fs, req->sector, req->current_nr_sectors, req->buffer)) { - end_request(req, 0); + __blk_end_request_cur(req, -EIO); continue; } req->nr_sectors -= req->current_nr_sectors; req->sector += req->current_nr_sectors; req->buffer += req->current_nr_sectors * 512; - end_request(req, 1); + __blk_end_request_cur(req, 0); break; } } diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index 61296530..5904f7b 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -320,15 +320,15 @@ static void start_request(struct floppy_state *fs) #endif if (req->sector < 0 || req->sector >= fs->total_secs) { - end_request(req, 0); + __blk_end_request_cur(req, -EIO); continue; } if (req->current_nr_sectors == 0) { - end_request(req, 1); + __blk_end_request_cur(req, 0); continue; } if (fs->ejected) { - end_request(req, 0); + __blk_end_request_cur(req, -EIO); continue; } @@ -336,7 +336,7 @@ static void start_request(struct floppy_state *fs) if (fs->write_prot < 0) fs->write_prot = swim3_readbit(fs, WRITE_PROT); if (fs->write_prot) { - end_request(req, 0); + __blk_end_request_cur(req, -EIO); continue; } } @@ -508,7 +508,7 @@ static void act(struct floppy_state *fs) case do_transfer: if (fs->cur_cyl != fs->req_cyl) { if (fs->retries > 5) { - end_request(fd_req, 0); + __blk_end_request_cur(fd_req, -EIO); fs->state = idle; return; } @@ -540,7 +540,7 @@ static void scan_timeout(unsigned long data) out_8(&sw->intr_enable, 0); fs->cur_cyl = -1; if (fs->retries > 5) { - end_request(fd_req, 0); + __blk_end_request_cur(fd_req, -EIO); fs->state = idle; start_request(fs); } else { @@ -559,7 +559,7 @@ static void seek_timeout(unsigned long data) out_8(&sw->select, RELAX); out_8(&sw->intr_enable, 0); printk(KERN_ERR "swim3: seek timeout\n"); - end_request(fd_req, 0); + __blk_end_request_cur(fd_req, -EIO); fs->state = idle; start_request(fs); } @@ -583,7 +583,7 @@ static void settle_timeout(unsigned long data) return; } printk(KERN_ERR "swim3: seek settle timeout\n"); - end_request(fd_req, 0); + __blk_end_request_cur(fd_req, -EIO); fs->state = idle; start_request(fs); } @@ -615,7 +615,7 @@ static void xfer_timeout(unsigned long data) fd_req->current_nr_sectors -= s; printk(KERN_ERR "swim3: timeout %sing sector %ld\n", (rq_data_dir(fd_req)==WRITE? "writ": "read"), (long)fd_req->sector); - end_request(fd_req, 0); + __blk_end_request_cur(fd_req, -EIO); fs->state = idle; start_request(fs); } @@ -646,7 +646,7 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id) printk(KERN_ERR "swim3: seen sector but cyl=ff?\n"); fs->cur_cyl = -1; if (fs->retries > 5) { - end_request(fd_req, 0); + __blk_end_request_cur(fd_req, -EIO); fs->state = idle; start_request(fs); } else { @@ -731,7 +731,7 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id) printk("swim3: error %sing block %ld (err=%x)\n", rq_data_dir(fd_req) == WRITE? "writ": "read", (long)fd_req->sector, err); - end_request(fd_req, 0); + __blk_end_request_cur(fd_req, -EIO); fs->state = idle; } } else { @@ -740,7 +740,7 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id) printk(KERN_ERR "swim3: fd dma: stat=%x resid=%d\n", stat, resid); printk(KERN_ERR " state=%d, dir=%x, intr=%x, err=%x\n", fs->state, rq_data_dir(fd_req), intr, err); - end_request(fd_req, 0); + __blk_end_request_cur(fd_req, -EIO); fs->state = idle; start_request(fs); break; @@ -749,7 +749,7 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id) fd_req->current_nr_sectors -= fs->scount; fd_req->buffer += fs->scount * 512; if (fd_req->current_nr_sectors <= 0) { - end_request(fd_req, 1); + __blk_end_request_cur(fd_req, 0); fs->state = idle; } else { fs->req_sector += fs->scount; diff --git a/drivers/block/xd.c b/drivers/block/xd.c index 64b496f..6f6ad82 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -314,21 +314,22 @@ static void do_xd_request (struct request_queue * q) int retry; if (!blk_fs_request(req)) { - end_request(req, 0); + __blk_end_request_cur(req, -EIO); continue; } if (block + count > get_capacity(req->rq_disk)) { - end_request(req, 0); + __blk_end_request_cur(req, -EIO); continue; } if (rw != READ && rw != WRITE) { printk("do_xd_request: unknown request\n"); - end_request(req, 0); + __blk_end_request_cur(req, -EIO); continue; } for (retry = 0; (retry < XD_RETRIES) && !res; retry++) res = xd_readwrite(rw, disk, req->buffer, block, count); - end_request(req, res); /* wrap up, 0 = fail, 1 = success */ + /* wrap up, 0 = success, -errno = fail */ + __blk_end_request_cur(req, res); } } @@ -418,7 +419,7 @@ static int xd_readwrite (u_char operation,XD_INFO *p,char *buffer,u_int block,u_ printk("xd%c: %s timeout, recalibrating drive\n",'a'+drive,(operation == READ ? "read" : "write")); xd_recalibrate(drive); spin_lock_irq(&xd_lock); - return (0); + return -EIO; case 2: if (sense[0] & 0x30) { printk("xd%c: %s - ",'a'+drive,(operation == READ ? "reading" : "writing")); @@ -439,7 +440,7 @@ static int xd_readwrite (u_char operation,XD_INFO *p,char *buffer,u_int block,u_ else printk(" - no valid disk address\n"); spin_lock_irq(&xd_lock); - return (0); + return -EIO; } if (xd_dma_buffer) for (i=0; i < (temp * 0x200); i++) @@ -448,7 +449,7 @@ static int xd_readwrite (u_char operation,XD_INFO *p,char *buffer,u_int block,u_ count -= temp, buffer += temp * 0x200, block += temp; } spin_lock_irq(&xd_lock); - return (1); + return 0; } /* xd_recalibrate: recalibrate a given drive and reset controller if necessary */ diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index cd6cfe3..b456447 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -302,7 +302,7 @@ static void do_blkif_request(struct request_queue *rq) while ((req = elv_next_request(rq)) != NULL) { info = req->rq_disk->private_data; if (!blk_fs_request(req)) { - end_request(req, 0); + __blk_end_request_cur(req, -EIO); continue; } diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 4aecf5d..b1e1d7e 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -466,7 +466,7 @@ struct request *ace_get_next_request(struct request_queue * q) while ((req = elv_next_request(q)) != NULL) { if (blk_fs_request(req)) break; - end_request(req, 0); + __blk_end_request_cur(req, -EIO); } return req; } @@ -494,7 +494,7 @@ static void ace_fsm_dostate(struct ace_device *ace) /* Drop all pending requests */ while ((req = elv_next_request(ace->queue)) != NULL) - end_request(req, 0); + __blk_end_request_cur(req, -EIO); /* Drop back to IDLE state and notify waiters */ ace->fsm_state = ACE_FSM_STATE_IDLE; diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c index 80754cd..b66ad58 100644 --- a/drivers/block/z2ram.c +++ b/drivers/block/z2ram.c @@ -77,7 +77,7 @@ static void do_z2_request(struct request_queue *q) if (start + len > z2ram_size) { printk( KERN_ERR DEVICE_NAME ": bad access: block=%lu, count=%u\n", req->sector, req->current_nr_sectors); - end_request(req, 0); + __blk_end_request_cur(req, -EIO); continue; } while (len) { @@ -93,7 +93,7 @@ static void do_z2_request(struct request_queue *q) start += size; len -= size; } - end_request(req, 1); + __blk_end_request_cur(req, 0); } } diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c index fee9a9e..cab2b1f 100644 --- a/drivers/cdrom/gdrom.c +++ b/drivers/cdrom/gdrom.c @@ -654,17 +654,17 @@ static void gdrom_request(struct request_queue *rq) while ((req = elv_next_request(rq)) != NULL) { if (!blk_fs_request(req)) { printk(KERN_DEBUG "GDROM: Non-fs request ignored\n"); - end_request(req, 0); + __blk_end_request_cur(req, -EIO); } if (rq_data_dir(req) != READ) { printk(KERN_NOTICE "GDROM: Read only device -"); printk(" write request ignored\n"); - end_request(req, 0); + __blk_end_request_cur(req, -EIO); } if (req->nr_sectors) gdrom_request_handler_dma(req); else - end_request(req, 0); + __blk_end_request_cur(req, -EIO); } } diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index a443e13..221317e 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -923,7 +923,7 @@ static void i2o_block_request_fn(struct request_queue *q) break; } } else - end_request(req, 0); + __blk_end_request_cur(req, -EIO); } }; diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index a49a9c8..76c4c8d 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -54,33 +54,33 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr, if (req->cmd_type == REQ_TYPE_LINUX_BLOCK && req->cmd[0] == REQ_LB_OP_DISCARD) - return !tr->discard(dev, block, nsect); + return tr->discard(dev, block, nsect); if (!blk_fs_request(req)) - return 0; + return -EIO; if (req->sector + req->current_nr_sectors > get_capacity(req->rq_disk)) - return 0; + return -EIO; switch(rq_data_dir(req)) { case READ: for (; nsect > 0; nsect--, block++, buf += tr->blksize) if (tr->readsect(dev, block, buf)) - return 0; - return 1; + return -EIO; + return 0; case WRITE: if (!tr->writesect) - return 0; + return -EIO; for (; nsect > 0; nsect--, block++, buf += tr->blksize) if (tr->writesect(dev, block, buf)) - return 0; - return 1; + return -EIO; + return 0; default: printk(KERN_NOTICE "Unknown request %u\n", rq_data_dir(req)); - return 0; + return -EIO; } } @@ -96,7 +96,7 @@ static int mtd_blktrans_thread(void *arg) while (!kthread_should_stop()) { struct request *req; struct mtd_blktrans_dev *dev; - int res = 0; + int res; req = elv_next_request(rq); @@ -119,7 +119,7 @@ static int mtd_blktrans_thread(void *arg) spin_lock_irq(rq->queue_lock); - end_request(req, res); + __blk_end_request_cur(req, res); } spin_unlock_irq(rq->queue_lock); diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c index a85ad05..0961788 100644 --- a/drivers/sbus/char/jsflash.c +++ b/drivers/sbus/char/jsflash.c @@ -192,25 +192,25 @@ static void jsfd_do_request(struct request_queue *q) size_t len = req->current_nr_sectors << 9; if ((offset + len) > jdp->dsize) { - end_request(req, 0); + __blk_end_request_cur(req, -EIO); continue; } if (rq_data_dir(req) != READ) { printk(KERN_ERR "jsfd: write\n"); - end_request(req, 0); + __blk_end_request_cur(req, -EIO); continue; } if ((jdp->dbase & 0xff000000) != 0x20000000) { printk(KERN_ERR "jsfd: bad base %x\n", (int)jdp->dbase); - end_request(req, 0); + __blk_end_request_cur(req, -EIO); continue; } jsfd_read(req->buffer, jdp->dbase + offset, len); - end_request(req, 1); + __blk_end_request_cur(req, 0); } } diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index e33c835..cfeb3c2 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -845,9 +845,8 @@ extern unsigned int blk_rq_cur_bytes(struct request *rq); * blk_update_request() completes given number of bytes and updates * the request without completing it. * - * blk_end_request() and friends. __blk_end_request() and - * end_request() must be called with the request queue spinlock - * acquired. + * blk_end_request() and friends. __blk_end_request() must be called + * with the request queue spinlock acquired. * * Several drivers define their own end_request and call * blk_end_request() for parts of the original function. @@ -899,6 +898,19 @@ static inline void blk_end_request_all(struct request *rq, int error) } /** + * blk_end_request_cur - Helper function to finish the current request chunk. + * @rq: the request to finish the current chunk for + * @err: %0 for success, < %0 for error + * + * Description: + * Complete the current consecutively mapped chunk from @rq. + */ +static inline void blk_end_request_cur(struct request *rq, int error) +{ + blk_end_request(rq, error, rq->hard_cur_sectors << 9); +} + +/** * __blk_end_request - Helper function for drivers to complete the request. * @rq: the request being processed * @error: %0 for success, < %0 for error @@ -934,29 +946,17 @@ static inline void __blk_end_request_all(struct request *rq, int error) } /** - * end_request - end I/O on the current segment of the request - * @rq: the request being processed - * @uptodate: error value or %0/%1 uptodate flag + * __blk_end_request_cur - Helper function to finish the current request chunk. + * @rq: the request to finish the current chunk for + * @err: %0 for success, < %0 for error * * Description: - * Ends I/O on the current segment of a request. If that is the only - * remaining segment, the request is also completed and freed. - * - * This is a remnant of how older block drivers handled I/O completions. - * Modern drivers typically end I/O on the full request in one go, unless - * they have a residual value to account for. For that case this function - * isn't really useful, unless the residual just happens to be the - * full current segment. In other words, don't use this function in new - * code. Use blk_end_request() or __blk_end_request() to end a request. - **/ -static inline void end_request(struct request *rq, int uptodate) + * Complete the current consecutively mapped chunk from @rq. Must + * be called with queue lock held. + */ +static inline void __blk_end_request_cur(struct request *rq, int error) { - int error = 0; - - if (uptodate <= 0) - error = uptodate ? uptodate : -EIO; - - __blk_end_bidi_request(rq, error, rq->hard_cur_sectors << 9, 0); + __blk_end_request(rq, error, rq->hard_cur_sectors << 9); } extern void blk_complete_request(struct request *); -- cgit v0.10.2 From ec24751a6b57e1373a12361e581b2458bc9bb791 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 23 Apr 2009 11:05:20 +0900 Subject: arm-omap: don't abuse rq->data omap mailbox uses rq->data as the second opaque pointer to carry mbox_msg_t and rq->special message argument which is needed only for tx. Add and use omap_msg_tx_data struct for tx and use rq->special for mbox_msg_t for rx such that only rq->special is used as opaque pointer. [ Impact: cleanup rq->data usage, extra kmalloc in msg_send ] Signed-off-by: Tejun Heo Cc: Russell King diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c index cf81bad..538ba75 100644 --- a/arch/arm/plat-omap/mailbox.c +++ b/arch/arm/plat-omap/mailbox.c @@ -147,24 +147,40 @@ static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void *arg) return ret; } +struct omap_msg_tx_data { + mbox_msg_t msg; + void *arg; +}; + +static void omap_msg_tx_end_io(struct request *rq, int error) +{ + kfree(rq->special); + __blk_put_request(rq->q, rq); +} + int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void* arg) { + struct omap_msg_tx_data *tx_data; struct request *rq; struct request_queue *q = mbox->txq->queue; - int ret = 0; + + tx_data = kmalloc(sizeof(*tx_data), GFP_ATOMIC); + if (unlikely(!tx_data)) + return -ENOMEM; rq = blk_get_request(q, WRITE, GFP_ATOMIC); if (unlikely(!rq)) { - ret = -ENOMEM; - goto fail; + kfree(tx_data); + return -ENOMEM; } - rq->data = (void *)msg; - blk_insert_request(q, rq, 0, arg); + tx_data->msg = msg; + tx_data->arg = arg; + rq->end_io = omap_msg_tx_end_io; + blk_insert_request(q, rq, 0, tx_data); schedule_work(&mbox->txq->work); - fail: - return ret; + return 0; } EXPORT_SYMBOL(omap_mbox_msg_send); @@ -178,6 +194,8 @@ static void mbox_tx_work(struct work_struct *work) struct request_queue *q = mbox->txq->queue; while (1) { + struct omap_msg_tx_data *tx_data; + spin_lock(q->queue_lock); rq = elv_next_request(q); spin_unlock(q->queue_lock); @@ -185,7 +203,9 @@ static void mbox_tx_work(struct work_struct *work) if (!rq) break; - ret = __mbox_msg_send(mbox, (mbox_msg_t) rq->data, rq->special); + tx_data = rq->special; + + ret = __mbox_msg_send(mbox, tx_data->msg, tx_data->arg); if (ret) { enable_mbox_irq(mbox, IRQ_TX); return; @@ -222,7 +242,7 @@ static void mbox_rx_work(struct work_struct *work) if (!rq) break; - msg = (mbox_msg_t) rq->data; + msg = (mbox_msg_t)rq->special; blk_end_request_all(rq, 0); mbox->rxq->callback((void *)msg); } @@ -260,7 +280,6 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox) goto nomem; msg = mbox_fifo_read(mbox); - rq->data = (void *)msg; if (unlikely(mbox_seq_test(mbox, msg))) { pr_info("mbox: Illegal seq bit!(%08x)\n", msg); @@ -268,7 +287,7 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox) mbox->err_notify(); } - blk_insert_request(q, rq, 0, NULL); + blk_insert_request(q, rq, 0, (void *)msg); if (mbox->ops->type == OMAP_MBOX_TYPE1) break; } @@ -331,7 +350,7 @@ omap_mbox_read(struct device *dev, struct device_attribute *attr, char *buf) if (!rq) break; - *p = (mbox_msg_t) rq->data; + *p = (mbox_msg_t)rq->special; blk_end_request_all(rq, 0); -- cgit v0.10.2 From 731ec497e5888c6792ad62613ae9be97eebcd7ca Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 23 Apr 2009 11:05:20 +0900 Subject: block: kill rq->data Now that all block request data transfer is done via bio, rq->data isn't used. Kill it. While at it, make the roles of rq->special and buffer clear. [ Impact: drop now unncessary field from struct request ] Signed-off-by: Tejun Heo Cc: Boaz Harrosh diff --git a/block/blk-core.c b/block/blk-core.c index 0520cc7..6dd180c 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -189,10 +189,9 @@ void blk_dump_rq_flags(struct request *rq, char *msg) (unsigned long long)rq->sector, rq->nr_sectors, rq->current_nr_sectors); - printk(KERN_INFO " bio %p, biotail %p, buffer %p, data %p, len %u\n", + printk(KERN_INFO " bio %p, biotail %p, buffer %p, len %u\n", rq->bio, rq->biotail, - rq->buffer, rq->data, - rq->data_len); + rq->buffer, rq->data_len); if (blk_pc_request(rq)) { printk(KERN_INFO " cdb: "); diff --git a/block/blk-map.c b/block/blk-map.c index f103729..694fefa 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -156,7 +156,7 @@ int blk_rq_map_user(struct request_queue *q, struct request *rq, if (!bio_flagged(bio, BIO_USER_MAPPED)) rq->cmd_flags |= REQ_COPY_USER; - rq->buffer = rq->data = NULL; + rq->buffer = NULL; return 0; unmap_rq: blk_rq_unmap_user(bio); @@ -235,7 +235,7 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq, blk_queue_bounce(q, &bio); bio_get(bio); blk_rq_bio_prep(q, rq, bio); - rq->buffer = rq->data = NULL; + rq->buffer = NULL; return 0; } EXPORT_SYMBOL(blk_rq_map_user_iov); @@ -313,7 +313,7 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf, blk_rq_bio_prep(q, rq, bio); blk_queue_bounce(q, &rq->bio); - rq->buffer = rq->data = NULL; + rq->buffer = NULL; return 0; } EXPORT_SYMBOL(blk_rq_map_kern); diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index 82a0ca2..bb9aa43 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -500,7 +500,6 @@ static int __blk_send_generic(struct request_queue *q, struct gendisk *bd_disk, rq = blk_get_request(q, WRITE, __GFP_WAIT); rq->cmd_type = REQ_TYPE_BLOCK_PC; - rq->data = NULL; rq->data_len = 0; rq->extra_len = 0; rq->timeout = BLK_DEFAULT_SG_TIMEOUT; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 756ac7c..aa9fc57 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1088,7 +1088,6 @@ int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req) return ret; } else { BUG_ON(req->data_len); - BUG_ON(req->data); memset(&cmd->sdb, 0, sizeof(cmd->sdb)); req->buffer = NULL; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index cfeb3c2..12c545e 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -211,8 +211,8 @@ struct request { unsigned short ioprio; - void *special; - char *buffer; + void *special; /* opaque pointer available for LLD use */ + char *buffer; /* kaddr of the current segment if available */ int tag; int errors; @@ -229,7 +229,6 @@ struct request { unsigned int data_len; unsigned int extra_len; /* length of alignment and padding */ unsigned int sense_len; - void *data; void *sense; unsigned long deadline; -- cgit v0.10.2 From c2553b5844b06910435e40cfab9e6f384840cb97 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 24 Apr 2009 08:10:11 +0200 Subject: block: make blk_do_io_stat() do the full "is this rq accountable" checks We currently check for file system requests outside of blk_do_io_stat(rq), but we may as well just include it. Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index 6dd180c..1e3b97f 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -68,7 +68,7 @@ static void drive_stat_acct(struct request *rq, int new_io) int rw = rq_data_dir(rq); int cpu; - if (!blk_fs_request(rq) || !blk_do_io_stat(rq)) + if (!blk_do_io_stat(rq)) return; cpu = part_stat_lock(); @@ -1639,10 +1639,7 @@ EXPORT_SYMBOL(blkdev_dequeue_request); static void blk_account_io_completion(struct request *req, unsigned int bytes) { - if (!blk_do_io_stat(req)) - return; - - if (blk_fs_request(req)) { + if (blk_do_io_stat(req)) { const int rw = rq_data_dir(req); struct hd_struct *part; int cpu; @@ -1656,15 +1653,12 @@ static void blk_account_io_completion(struct request *req, unsigned int bytes) static void blk_account_io_done(struct request *req) { - if (!blk_do_io_stat(req)) - return; - /* * Account IO completion. bar_rq isn't accounted as a normal * IO on queueing nor completion. Accounting the containing * request is enough. */ - if (blk_fs_request(req) && req != &req->q->bar_rq) { + if (blk_do_io_stat(req) && req != &req->q->bar_rq) { unsigned long duration = jiffies - req->start_time; const int rw = rq_data_dir(req); struct hd_struct *part; diff --git a/block/blk.h b/block/blk.h index 9b2c324..404c10b 100644 --- a/block/blk.h +++ b/block/blk.h @@ -149,9 +149,16 @@ static inline int blk_cpu_to_group(int cpu) #endif } +/* + * Contribute to IO statistics IFF: + * + * a) it's attached to a gendisk, and + * b) the queue had IO stats enabled when this request was started, and + * c) it's a file system request + */ static inline int blk_do_io_stat(struct request *rq) { - return rq->rq_disk && blk_rq_io_stat(rq); + return rq->rq_disk && blk_rq_io_stat(rq) && blk_fs_request(rq); } #endif -- cgit v0.10.2 From c69d48540c201394d08cb4d48b905e001313d9b8 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 24 Apr 2009 08:12:19 +0200 Subject: block: include discard requests in IO accounting We currently don't do merging on discard requests, but we potentially could. If we do, then we need to include discard requests in the IO accounting, or merging would end up decrementing in_flight IO counters for an IO which never incremented them. So enable accounting for discard requests. Problem found by Nikanth Karthikesan Signed-off-by: Jens Axboe diff --git a/block/blk.h b/block/blk.h index 404c10b..5111559 100644 --- a/block/blk.h +++ b/block/blk.h @@ -158,7 +158,8 @@ static inline int blk_cpu_to_group(int cpu) */ static inline int blk_do_io_stat(struct request *rq) { - return rq->rq_disk && blk_rq_io_stat(rq) && blk_fs_request(rq); + return rq->rq_disk && blk_rq_io_stat(rq) && blk_fs_request(rq) && + blk_discard_rq(rq); } #endif -- cgit v0.10.2 From 9eb55b030c4b3227334ee4482402096cd1d1a6fe Mon Sep 17 00:00:00 2001 From: Nikanth Karthikesan Date: Mon, 27 Apr 2009 14:53:54 +0200 Subject: block: catch trying to use more bits than request->cmd_flags has Signed-off-by: Nikanth Karthikesan Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index 1e3b97f..394c5bd 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -2097,6 +2097,9 @@ EXPORT_SYMBOL(kblockd_schedule_work); int __init blk_dev_init(void) { + BUILD_BUG_ON(__REQ_NR_BITS > 8 * + sizeof(((struct request *)0)->cmd_flags)); + kblockd_workqueue = create_workqueue("kblockd"); if (!kblockd_workqueue) panic("Failed to create kblockd\n"); -- cgit v0.10.2 From 9fd8d0e1bcb848257968d9a7d73ca4d890ea8bd1 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 28 Apr 2009 13:06:04 +0900 Subject: block: make blk_end_request_cur() return bool In the process of mindlessly copying [__]blk_end_request_all(), [__]blk_end_request_cur() ended up returning void even though they're partial completion functions. Fix it. [ Impact: fix braindead API ] Signed-off-by: Tejun Heo Signed-off-by: Jens Axboe diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 12c545e..3a5b1bd 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -903,10 +903,14 @@ static inline void blk_end_request_all(struct request *rq, int error) * * Description: * Complete the current consecutively mapped chunk from @rq. + * + * Return: + * %false - we are done with this request + * %true - still buffers pending for this request */ -static inline void blk_end_request_cur(struct request *rq, int error) +static inline bool blk_end_request_cur(struct request *rq, int error) { - blk_end_request(rq, error, rq->hard_cur_sectors << 9); + return blk_end_request(rq, error, rq->hard_cur_sectors << 9); } /** @@ -952,10 +956,14 @@ static inline void __blk_end_request_all(struct request *rq, int error) * Description: * Complete the current consecutively mapped chunk from @rq. Must * be called with queue lock held. + * + * Return: + * %false - we are done with this request + * %true - still buffers pending for this request */ -static inline void __blk_end_request_cur(struct request *rq, int error) +static inline bool __blk_end_request_cur(struct request *rq, int error) { - __blk_end_request(rq, error, rq->hard_cur_sectors << 9); + return __blk_end_request(rq, error, rq->hard_cur_sectors << 9); } extern void blk_complete_request(struct request *); -- cgit v0.10.2 From 4c94dece1baf320d925cedb231489c4e0358ac5a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 28 Apr 2009 13:06:05 +0900 Subject: block: don't init rq fields unnecessarily blk_get_request() always returns properly zeroed requests. Don't set fields to zero/NULL unnecessarily. [ Impact: cleanup ] Signed-off-by: Tejun Heo Signed-off-by: Jens Axboe diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index bb9aa43..58cf456 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -500,8 +500,6 @@ static int __blk_send_generic(struct request_queue *q, struct gendisk *bd_disk, rq = blk_get_request(q, WRITE, __GFP_WAIT); rq->cmd_type = REQ_TYPE_BLOCK_PC; - rq->data_len = 0; - rq->extra_len = 0; rq->timeout = BLK_DEFAULT_SG_TIMEOUT; rq->cmd[0] = cmd; rq->cmd[4] = data; -- cgit v0.10.2 From 5b5c5d12b91cb6b2a2967f06aef35d59008dc2e7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 28 Apr 2009 13:06:06 +0900 Subject: amiflop,ataflop,xd,mg_disk: clean up unnecessary stuff from block drivers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rq_data_dir() can only be READ or WRITE and rq->sector and nr_sectors are always automatically updated after partial request completion. Don't worry about rq_data_dir() not being either READ or WRITE or manually update sector and nr_sectors. [ Impact: cleanup ] Signed-off-by: Tejun Heo Cc: Jörg Dorchain Cc: Geert Uytterhoeven Cc: unsik Kim Signed-off-by: Jens Axboe diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index b99a2a6..8ff95f2 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -1371,11 +1371,6 @@ static void redo_fd_request(void) "0x%08lx\n", track, sector, data); #endif - if ((rq_data_dir(CURRENT) != READ) && (rq_data_dir(CURRENT) != WRITE)) { - printk(KERN_WARNING "do_fd_request: unknown command\n"); - __blk_end_request_cur(CURRENT, -EIO); - goto repeat; - } if (get_track(drive, track) == -1) { __blk_end_request_cur(CURRENT, -EIO); goto repeat; @@ -1407,8 +1402,6 @@ static void redo_fd_request(void) break; } } - CURRENT->nr_sectors -= CURRENT->current_nr_sectors; - CURRENT->sector += CURRENT->current_nr_sectors; __blk_end_request_cur(CURRENT, 0); goto repeat; diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index 44a8702..2506728 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -732,8 +732,6 @@ static void do_fd_action( int drive ) } else { /* all sectors finished */ - CURRENT->nr_sectors -= CURRENT->current_nr_sectors; - CURRENT->sector += CURRENT->current_nr_sectors; __blk_end_request_cur(CURRENT, 0); redo_fd_request(); return; @@ -1139,8 +1137,6 @@ static void fd_rwsec_done1(int status) } else { /* all sectors finished */ - CURRENT->nr_sectors -= CURRENT->current_nr_sectors; - CURRENT->sector += CURRENT->current_nr_sectors; __blk_end_request_cur(CURRENT, 0); redo_fd_request(); } diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index 408c2bd..2c00ad9 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c @@ -560,11 +560,6 @@ static void mg_request_poll(struct request_queue *q) case WRITE: mg_write(req); break; - default: - printk(KERN_WARNING "%s:%d unknown command\n", - __func__, __LINE__); - __blk_end_request_cur(req, -EIO); - break; } } } @@ -614,11 +609,6 @@ static unsigned int mg_issue_req(struct request *req, outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND); break; - default: - printk(KERN_WARNING "%s:%d unknown command\n", - __func__, __LINE__); - __blk_end_request_cur(req, -EIO); - break; } return MG_ERR_NONE; } diff --git a/drivers/block/xd.c b/drivers/block/xd.c index 6f6ad82..14be4c1 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -308,7 +308,6 @@ static void do_xd_request (struct request_queue * q) while ((req = elv_next_request(q)) != NULL) { unsigned block = req->sector; unsigned count = req->nr_sectors; - int rw = rq_data_dir(req); XD_INFO *disk = req->rq_disk->private_data; int res = 0; int retry; @@ -321,13 +320,9 @@ static void do_xd_request (struct request_queue * q) __blk_end_request_cur(req, -EIO); continue; } - if (rw != READ && rw != WRITE) { - printk("do_xd_request: unknown request\n"); - __blk_end_request_cur(req, -EIO); - continue; - } for (retry = 0; (retry < XD_RETRIES) && !res; retry++) - res = xd_readwrite(rw, disk, req->buffer, block, count); + res = xd_readwrite(rq_data_dir(req), disk, req->buffer, + block, count); /* wrap up, 0 = success, -errno = fail */ __blk_end_request_cur(req, res); } -- cgit v0.10.2 From cd4c34ebec155e5c10f897d9bebf618248121e70 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 28 Apr 2009 13:06:07 +0900 Subject: ps3disk: simplify request completion ps3disk_interrupt() always completes requests fully but it uses rq->hard_cur_sectors for FLUSH requests for some reason. Drop them and simply use __blk_end_request_all(). [ Impact: cleanup ] Signed-off-by: Tejun Heo Signed-off-by: Jens Axboe diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index d23b54b..f6586e4 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -231,7 +231,6 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data) struct request *req; int res, read, error; u64 tag, status; - unsigned long num_sectors; const char *op; res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status); @@ -261,11 +260,9 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data) if (req->cmd_type == REQ_TYPE_LINUX_BLOCK && req->cmd[0] == REQ_LB_OP_FLUSH) { read = 0; - num_sectors = req->hard_cur_sectors; op = "flush"; } else { read = !rq_data_dir(req); - num_sectors = req->nr_sectors; op = read ? "read" : "write"; } if (status) { @@ -281,7 +278,7 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data) } spin_lock(&priv->lock); - __blk_end_request(req, error, num_sectors << 9); + __blk_end_request_all(req, error); priv->req = NULL; ps3disk_do_request(dev, priv->queue); spin_unlock(&priv->lock); -- cgit v0.10.2 From 044208506d35bd62396c4673176e2c12393905b8 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 28 Apr 2009 13:06:08 +0900 Subject: sunvdc: kill vdc_end_request() vdc_end_request() is a thin silly wrapper on top of __blk_end_request(). Kill it. [ Impact: cleanup ] Signed-off-by: Tejun Heo Acked-by: David S. Miller Signed-off-by: Jens Axboe diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c index 5861e33..f59887c 100644 --- a/drivers/block/sunvdc.c +++ b/drivers/block/sunvdc.c @@ -212,11 +212,6 @@ static void vdc_end_special(struct vdc_port *port, struct vio_disk_desc *desc) vdc_finish(&port->vio, -err, WAITING_FOR_GEN_CMD); } -static void vdc_end_request(struct request *req, int error, int num_sectors) -{ - __blk_end_request(req, error, num_sectors << 9); -} - static void vdc_end_one(struct vdc_port *port, struct vio_dring_state *dr, unsigned int index) { @@ -239,7 +234,7 @@ static void vdc_end_one(struct vdc_port *port, struct vio_dring_state *dr, rqe->req = NULL; - vdc_end_request(req, (desc->status ? -EIO : 0), desc->size >> 9); + __blk_end_request(req, (desc->status ? -EIO : 0), desc->size); if (blk_queue_stopped(port->disk->queue)) blk_start_queue(port->disk->queue); @@ -453,7 +448,7 @@ static void do_vdc_request(struct request_queue *q) blkdev_dequeue_request(req); if (__send_request(req) < 0) - vdc_end_request(req, -EIO, req->hard_nr_sectors); + __blk_end_request_all(req, -EIO); } } -- cgit v0.10.2 From 4d6c84d91d1a539ebc47d1a36a35e9390ba11fdc Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 28 Apr 2009 13:06:09 +0900 Subject: ubd: cleanup completion path ubd had its own block request partial completion mechanism, which is unnecessary as block layer already does it. Kill ubd_end_request() and ubd_finish() and replace them with direct call to blk_end_request(). [ Impact: cleanup ] Signed-off-by: Tejun Heo Cc: Jeff Dike Signed-off-by: Jens Axboe diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index f934225..36ca9fa 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -451,23 +451,6 @@ static void do_ubd_request(struct request_queue * q); /* Only changed by ubd_init, which is an initcall. */ static int thread_fd = -1; - -static void ubd_end_request(struct request *req, int bytes, int error) -{ - blk_end_request(req, error, bytes); -} - -/* Callable only from interrupt context - otherwise you need to do - * spin_lock_irq()/spin_lock_irqsave() */ -static inline void ubd_finish(struct request *req, int bytes) -{ - if(bytes < 0){ - ubd_end_request(req, 0, -EIO); - return; - } - ubd_end_request(req, bytes, 0); -} - static LIST_HEAD(restart); /* XXX - move this inside ubd_intr. */ @@ -475,7 +458,6 @@ static LIST_HEAD(restart); static void ubd_handler(void) { struct io_thread_req *req; - struct request *rq; struct ubd *ubd; struct list_head *list, *next_ele; unsigned long flags; @@ -492,10 +474,7 @@ static void ubd_handler(void) return; } - rq = req->req; - rq->nr_sectors -= req->length >> 9; - if(rq->nr_sectors == 0) - ubd_finish(rq, rq->hard_nr_sectors << 9); + blk_end_request(req->req, 0, req->length); kfree(req); } reactivate_fd(thread_fd, UBD_IRQ); -- cgit v0.10.2 From f81f2f7c9fee307e371f37424577d46f9eaf8692 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 28 Apr 2009 13:06:10 +0900 Subject: ubd: drop unnecessary rq->sector manipulation ubd curiously updates rq->sector while issuing the request in multiple pieces. Don't do it and simply use local copy of sector. [ Impact: cleanup ] Signed-off-by: Tejun Heo Cc: Jeff Dike Signed-off-by: Jens Axboe diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 36ca9fa..4330127 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -1222,7 +1222,8 @@ static void do_ubd_request(struct request_queue *q) { struct io_thread_req *io_req; struct request *req; - int n, last_sectors; + sector_t sector; + int n; while(1){ struct ubd *dev = q->queuedata; @@ -1238,11 +1239,10 @@ static void do_ubd_request(struct request_queue *q) } req = dev->request; - last_sectors = 0; + sector = req->sector; while(dev->start_sg < dev->end_sg){ struct scatterlist *sg = &dev->sg[dev->start_sg]; - req->sector += last_sectors; io_req = kmalloc(sizeof(struct io_thread_req), GFP_ATOMIC); if(io_req == NULL){ @@ -1251,10 +1251,10 @@ static void do_ubd_request(struct request_queue *q) return; } prepare_request(req, io_req, - (unsigned long long) req->sector << 9, + (unsigned long long)sector << 9, sg->offset, sg->length, sg_page(sg)); - last_sectors = sg->length >> 9; + sector += sg->length >> 9; n = os_write_file(thread_fd, &io_req, sizeof(struct io_thread_req *)); if(n != sizeof(struct io_thread_req *)){ -- cgit v0.10.2 From e091eb67af957bac4e4f7410c5d1aa263ee483a4 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 28 Apr 2009 13:06:11 +0900 Subject: hd: clean up request completion paths hd read/write_intr() functions manually manipulate request to incrementally complete it, which block layer already supports. Simply use block layer completion routines instead of manual partial completion. While at it, clear unnecessary elv_next_request() check at the tail of read_intr(). This also makes read and write_intr() more consistent. [ Impact: cleanup ] Signed-off-by: Tejun Heo Signed-off-by: Jens Axboe diff --git a/drivers/block/hd.c b/drivers/block/hd.c index 5cb300b..75b9ca9 100644 --- a/drivers/block/hd.c +++ b/drivers/block/hd.c @@ -452,32 +452,25 @@ static void read_intr(void) bad_rw_intr(); hd_request(); return; + ok_to_read: req = CURRENT; insw(HD_DATA, req->buffer, 256); - req->sector++; - req->buffer += 512; - req->errors = 0; - i = --req->nr_sectors; - --req->current_nr_sectors; #ifdef DEBUG printk("%s: read: sector %ld, remaining = %ld, buffer=%p\n", - req->rq_disk->disk_name, req->sector, req->nr_sectors, + req->rq_disk->disk_name, req->sector + 1, req->nr_sectors - 1, req->buffer+512); #endif - if (req->current_nr_sectors <= 0) - __blk_end_request_cur(req, 0); - if (i > 0) { + if (__blk_end_request(req, 0, 512)) { SET_HANDLER(&read_intr); return; } + (void) inb_p(HD_STATUS); #if (HD_DELAY > 0) last_req = read_timer(); #endif - if (elv_next_request(QUEUE)) - hd_request(); - return; + hd_request(); } static void write_intr(void) @@ -499,23 +492,18 @@ static void write_intr(void) bad_rw_intr(); hd_request(); return; + ok_to_write: - req->sector++; - i = --req->nr_sectors; - --req->current_nr_sectors; - req->buffer += 512; - if (!i || (req->bio && req->current_nr_sectors <= 0)) - __blk_end_request_cur(req, 0); - if (i > 0) { + if (__blk_end_request(req, 0, 512)) { SET_HANDLER(&write_intr); outsw(HD_DATA, req->buffer, 256); - } else { + return; + } + #if (HD_DELAY > 0) - last_req = read_timer(); + last_req = read_timer(); #endif - hd_request(); - } - return; + hd_request(); } static void recal_intr(void) -- cgit v0.10.2 From 467ca759fc83fc35cb7d15aec0d74c62cffc4481 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 28 Apr 2009 13:06:12 +0900 Subject: swim3: clean up request completion paths swim3 curiously tries to update request parameters before calling __blk_end_request() when __blk_end_request() will do it anyway, and it updates request for partial completion manually instead of using blk_update_request(). Also, it does some spurious checks on rq such as testing whether rq->sector is negative or current_nr_sectors is zero right after fetching. Drop unnecessary stuff and use standard block layer mechanisms. [ Impact: cleanup ] Signed-off-by: Tejun Heo Cc: Benjamin Herrenschmidt Signed-off-by: Jens Axboe diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index 5904f7b..4248559 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -319,14 +319,10 @@ static void start_request(struct floppy_state *fs) req->errors, req->current_nr_sectors); #endif - if (req->sector < 0 || req->sector >= fs->total_secs) { + if (req->sector >= fs->total_secs) { __blk_end_request_cur(req, -EIO); continue; } - if (req->current_nr_sectors == 0) { - __blk_end_request_cur(req, 0); - continue; - } if (fs->ejected) { __blk_end_request_cur(req, -EIO); continue; @@ -593,8 +589,6 @@ static void xfer_timeout(unsigned long data) struct floppy_state *fs = (struct floppy_state *) data; struct swim3 __iomem *sw = fs->swim3; struct dbdma_regs __iomem *dr = fs->dma; - struct dbdma_cmd *cp = fs->dma_cmd; - unsigned long s; int n; fs->timeout_pending = 0; @@ -605,14 +599,6 @@ static void xfer_timeout(unsigned long data) out_8(&sw->intr_enable, 0); out_8(&sw->control_bic, WRITE_SECTORS | DO_ACTION); out_8(&sw->select, RELAX); - if (rq_data_dir(fd_req) == WRITE) - ++cp; - if (ld_le16(&cp->xfer_status) != 0) - s = fs->scount - ((ld_le16(&cp->res_count) + 511) >> 9); - else - s = 0; - fd_req->sector += s; - fd_req->current_nr_sectors -= s; printk(KERN_ERR "swim3: timeout %sing sector %ld\n", (rq_data_dir(fd_req)==WRITE? "writ": "read"), (long)fd_req->sector); __blk_end_request_cur(fd_req, -EIO); @@ -719,9 +705,7 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id) if (intr & ERROR_INTR) { n = fs->scount - 1 - resid / 512; if (n > 0) { - fd_req->sector += n; - fd_req->current_nr_sectors -= n; - fd_req->buffer += n * 512; + blk_update_request(fd_req, 0, n << 9); fs->req_sector += n; } if (fs->retries < 5) { @@ -745,13 +729,7 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id) start_request(fs); break; } - fd_req->sector += fs->scount; - fd_req->current_nr_sectors -= fs->scount; - fd_req->buffer += fs->scount * 512; - if (fd_req->current_nr_sectors <= 0) { - __blk_end_request_cur(fd_req, 0); - fs->state = idle; - } else { + if (__blk_end_request(fd_req, 0, fs->scount << 9)) { fs->req_sector += fs->scount; if (fs->req_sector > fs->secpertrack) { fs->req_sector -= fs->secpertrack; @@ -761,7 +739,8 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id) } } act(fs); - } + } else + fs->state = idle; } if (fs->state == idle) start_request(fs); -- cgit v0.10.2 From e138b4e08ef65771000fbe6d93d67e3960ff862b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 28 Apr 2009 13:06:13 +0900 Subject: swim: clean up request completion paths swim curiously tries to update request parameters before calling __blk_end_request() when __blk_end_request() will do it anyway and unnecessarily checks whether current_nr_sectors is zero right after fetching. Drop unnecessary stuff and use standard block layer mechanisms. [ Impact: cleanup ] Signed-off-by: Tejun Heo Cc: Laurent Vivier Signed-off-by: Jens Axboe diff --git a/drivers/block/swim.c b/drivers/block/swim.c index 6544a7b..97ef426 100644 --- a/drivers/block/swim.c +++ b/drivers/block/swim.c @@ -535,10 +535,6 @@ static void redo_fd_request(struct request_queue *q) __blk_end_request_cur(req, -EIO); continue; } - if (req->current_nr_sectors == 0) { - __blk_end_request_cur(req, 0); - continue; - } if (!fs->disk_in) { __blk_end_request_cur(req, -EIO); continue; @@ -561,9 +557,6 @@ static void redo_fd_request(struct request_queue *q) __blk_end_request_cur(req, -EIO); continue; } - req->nr_sectors -= req->current_nr_sectors; - req->sector += req->current_nr_sectors; - req->buffer += req->current_nr_sectors * 512; __blk_end_request_cur(req, 0); break; } -- cgit v0.10.2 From eec9462088a26c046d4db3100796a340a50890b8 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 28 Apr 2009 13:06:14 +0900 Subject: mg_disk: fold mg_disk.h into mg_disk.c include/linux/mg_disk.h is used only by drivers/block/mg_disk.c. No reason to put it in a separate header. Fold it into mg_disk.c. [ Impact: cleanup ] Signed-off-by: Tejun Heo Cc: unsik Kim Signed-off-by: Jens Axboe diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index 2c00ad9..2c6127ee 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c @@ -22,10 +22,194 @@ #include #include #include -#include #define MG_RES_SEC (CONFIG_MG_DISK_RES << 1) +/* name for block device */ +#define MG_DISK_NAME "mgd" +/* name for platform device */ +#define MG_DEV_NAME "mg_disk" + +#define MG_DISK_MAJ 0 +#define MG_DISK_MAX_PART 16 +#define MG_SECTOR_SIZE 512 +#define MG_MAX_SECTS 256 + +/* Register offsets */ +#define MG_BUFF_OFFSET 0x8000 +#define MG_STORAGE_BUFFER_SIZE 0x200 +#define MG_REG_OFFSET 0xC000 +#define MG_REG_FEATURE (MG_REG_OFFSET + 2) /* write case */ +#define MG_REG_ERROR (MG_REG_OFFSET + 2) /* read case */ +#define MG_REG_SECT_CNT (MG_REG_OFFSET + 4) +#define MG_REG_SECT_NUM (MG_REG_OFFSET + 6) +#define MG_REG_CYL_LOW (MG_REG_OFFSET + 8) +#define MG_REG_CYL_HIGH (MG_REG_OFFSET + 0xA) +#define MG_REG_DRV_HEAD (MG_REG_OFFSET + 0xC) +#define MG_REG_COMMAND (MG_REG_OFFSET + 0xE) /* write case */ +#define MG_REG_STATUS (MG_REG_OFFSET + 0xE) /* read case */ +#define MG_REG_DRV_CTRL (MG_REG_OFFSET + 0x10) +#define MG_REG_BURST_CTRL (MG_REG_OFFSET + 0x12) + +/* "Drive Select/Head Register" bit values */ +#define MG_REG_HEAD_MUST_BE_ON 0xA0 /* These 2 bits are always on */ +#define MG_REG_HEAD_DRIVE_MASTER (0x00 | MG_REG_HEAD_MUST_BE_ON) +#define MG_REG_HEAD_DRIVE_SLAVE (0x10 | MG_REG_HEAD_MUST_BE_ON) +#define MG_REG_HEAD_LBA_MODE (0x40 | MG_REG_HEAD_MUST_BE_ON) + + +/* "Device Control Register" bit values */ +#define MG_REG_CTRL_INTR_ENABLE 0x0 +#define MG_REG_CTRL_INTR_DISABLE (0x1<<1) +#define MG_REG_CTRL_RESET (0x1<<2) +#define MG_REG_CTRL_INTR_POLA_ACTIVE_HIGH 0x0 +#define MG_REG_CTRL_INTR_POLA_ACTIVE_LOW (0x1<<4) +#define MG_REG_CTRL_DPD_POLA_ACTIVE_LOW 0x0 +#define MG_REG_CTRL_DPD_POLA_ACTIVE_HIGH (0x1<<5) +#define MG_REG_CTRL_DPD_DISABLE 0x0 +#define MG_REG_CTRL_DPD_ENABLE (0x1<<6) + +/* Status register bit */ +/* error bit in status register */ +#define MG_REG_STATUS_BIT_ERROR 0x01 +/* corrected error in status register */ +#define MG_REG_STATUS_BIT_CORRECTED_ERROR 0x04 +/* data request bit in status register */ +#define MG_REG_STATUS_BIT_DATA_REQ 0x08 +/* DSC - Drive Seek Complete */ +#define MG_REG_STATUS_BIT_SEEK_DONE 0x10 +/* DWF - Drive Write Fault */ +#define MG_REG_STATUS_BIT_WRITE_FAULT 0x20 +#define MG_REG_STATUS_BIT_READY 0x40 +#define MG_REG_STATUS_BIT_BUSY 0x80 + +/* handy status */ +#define MG_STAT_READY (MG_REG_STATUS_BIT_READY | MG_REG_STATUS_BIT_SEEK_DONE) +#define MG_READY_OK(s) (((s) & (MG_STAT_READY | \ + (MG_REG_STATUS_BIT_BUSY | \ + MG_REG_STATUS_BIT_WRITE_FAULT | \ + MG_REG_STATUS_BIT_ERROR))) == MG_STAT_READY) + +/* Error register */ +#define MG_REG_ERR_AMNF 0x01 +#define MG_REG_ERR_ABRT 0x04 +#define MG_REG_ERR_IDNF 0x10 +#define MG_REG_ERR_UNC 0x40 +#define MG_REG_ERR_BBK 0x80 + +/* error code for others */ +#define MG_ERR_NONE 0 +#define MG_ERR_TIMEOUT 0x100 +#define MG_ERR_INIT_STAT 0x101 +#define MG_ERR_TRANSLATION 0x102 +#define MG_ERR_CTRL_RST 0x103 +#define MG_ERR_INV_STAT 0x104 +#define MG_ERR_RSTOUT 0x105 + +#define MG_MAX_ERRORS 6 /* Max read/write errors */ + +/* command */ +#define MG_CMD_RD 0x20 +#define MG_CMD_WR 0x30 +#define MG_CMD_SLEEP 0x99 +#define MG_CMD_WAKEUP 0xC3 +#define MG_CMD_ID 0xEC +#define MG_CMD_WR_CONF 0x3C +#define MG_CMD_RD_CONF 0x40 + +/* operation mode */ +#define MG_OP_CASCADE (1 << 0) +#define MG_OP_CASCADE_SYNC_RD (1 << 1) +#define MG_OP_CASCADE_SYNC_WR (1 << 2) +#define MG_OP_INTERLEAVE (1 << 3) + +/* synchronous */ +#define MG_BURST_LAT_4 (3 << 4) +#define MG_BURST_LAT_5 (4 << 4) +#define MG_BURST_LAT_6 (5 << 4) +#define MG_BURST_LAT_7 (6 << 4) +#define MG_BURST_LAT_8 (7 << 4) +#define MG_BURST_LEN_4 (1 << 1) +#define MG_BURST_LEN_8 (2 << 1) +#define MG_BURST_LEN_16 (3 << 1) +#define MG_BURST_LEN_32 (4 << 1) +#define MG_BURST_LEN_CONT (0 << 1) + +/* timeout value (unit: ms) */ +#define MG_TMAX_CONF_TO_CMD 1 +#define MG_TMAX_WAIT_RD_DRQ 10 +#define MG_TMAX_WAIT_WR_DRQ 500 +#define MG_TMAX_RST_TO_BUSY 10 +#define MG_TMAX_HDRST_TO_RDY 500 +#define MG_TMAX_SWRST_TO_RDY 500 +#define MG_TMAX_RSTOUT 3000 + +/* device attribution */ +/* use mflash as boot device */ +#define MG_BOOT_DEV (1 << 0) +/* use mflash as storage device */ +#define MG_STORAGE_DEV (1 << 1) +/* same as MG_STORAGE_DEV, but bootloader already done reset sequence */ +#define MG_STORAGE_DEV_SKIP_RST (1 << 2) + +#define MG_DEV_MASK (MG_BOOT_DEV | MG_STORAGE_DEV | MG_STORAGE_DEV_SKIP_RST) + +/* names of GPIO resource */ +#define MG_RST_PIN "mg_rst" +/* except MG_BOOT_DEV, reset-out pin should be assigned */ +#define MG_RSTOUT_PIN "mg_rstout" + +/* private driver data */ +struct mg_drv_data { + /* disk resource */ + u32 use_polling; + + /* device attribution */ + u32 dev_attr; + + /* internally used */ + struct mg_host *host; +}; + +/* main structure for mflash driver */ +struct mg_host { + struct device *dev; + + struct request_queue *breq; + spinlock_t lock; + struct gendisk *gd; + + struct timer_list timer; + void (*mg_do_intr) (struct mg_host *); + + u16 id[ATA_ID_WORDS]; + + u16 cyls; + u16 heads; + u16 sectors; + u32 n_sectors; + u32 nres_sectors; + + void __iomem *dev_base; + unsigned int irq; + unsigned int rst; + unsigned int rstout; + + u32 major; + u32 error; +}; + +/* + * Debugging macro and defines + */ +#undef DO_MG_DEBUG +#ifdef DO_MG_DEBUG +# define MG_DBG(fmt, args...) \ + printk(KERN_DEBUG "%s:%d "fmt, __func__, __LINE__, ##args) +#else /* CONFIG_MG_DEBUG */ +# define MG_DBG(fmt, args...) do { } while (0) +#endif /* CONFIG_MG_DEBUG */ + static void mg_request(struct request_queue *); static void mg_dump_status(const char *msg, unsigned int stat, diff --git a/include/linux/mg_disk.h b/include/linux/mg_disk.h deleted file mode 100644 index 1f76b1e..0000000 --- a/include/linux/mg_disk.h +++ /dev/null @@ -1,206 +0,0 @@ -/* - * include/linux/mg_disk.c - * - * Support for the mGine m[g]flash IO mode. - * Based on legacy hd.c - * - * (c) 2008 mGine Co.,LTD - * (c) 2008 unsik Kim - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __MG_DISK_H__ -#define __MG_DISK_H__ - -#include -#include - -/* name for block device */ -#define MG_DISK_NAME "mgd" -/* name for platform device */ -#define MG_DEV_NAME "mg_disk" - -#define MG_DISK_MAJ 0 -#define MG_DISK_MAX_PART 16 -#define MG_SECTOR_SIZE 512 -#define MG_MAX_SECTS 256 - -/* Register offsets */ -#define MG_BUFF_OFFSET 0x8000 -#define MG_STORAGE_BUFFER_SIZE 0x200 -#define MG_REG_OFFSET 0xC000 -#define MG_REG_FEATURE (MG_REG_OFFSET + 2) /* write case */ -#define MG_REG_ERROR (MG_REG_OFFSET + 2) /* read case */ -#define MG_REG_SECT_CNT (MG_REG_OFFSET + 4) -#define MG_REG_SECT_NUM (MG_REG_OFFSET + 6) -#define MG_REG_CYL_LOW (MG_REG_OFFSET + 8) -#define MG_REG_CYL_HIGH (MG_REG_OFFSET + 0xA) -#define MG_REG_DRV_HEAD (MG_REG_OFFSET + 0xC) -#define MG_REG_COMMAND (MG_REG_OFFSET + 0xE) /* write case */ -#define MG_REG_STATUS (MG_REG_OFFSET + 0xE) /* read case */ -#define MG_REG_DRV_CTRL (MG_REG_OFFSET + 0x10) -#define MG_REG_BURST_CTRL (MG_REG_OFFSET + 0x12) - -/* "Drive Select/Head Register" bit values */ -#define MG_REG_HEAD_MUST_BE_ON 0xA0 /* These 2 bits are always on */ -#define MG_REG_HEAD_DRIVE_MASTER (0x00 | MG_REG_HEAD_MUST_BE_ON) -#define MG_REG_HEAD_DRIVE_SLAVE (0x10 | MG_REG_HEAD_MUST_BE_ON) -#define MG_REG_HEAD_LBA_MODE (0x40 | MG_REG_HEAD_MUST_BE_ON) - - -/* "Device Control Register" bit values */ -#define MG_REG_CTRL_INTR_ENABLE 0x0 -#define MG_REG_CTRL_INTR_DISABLE (0x1<<1) -#define MG_REG_CTRL_RESET (0x1<<2) -#define MG_REG_CTRL_INTR_POLA_ACTIVE_HIGH 0x0 -#define MG_REG_CTRL_INTR_POLA_ACTIVE_LOW (0x1<<4) -#define MG_REG_CTRL_DPD_POLA_ACTIVE_LOW 0x0 -#define MG_REG_CTRL_DPD_POLA_ACTIVE_HIGH (0x1<<5) -#define MG_REG_CTRL_DPD_DISABLE 0x0 -#define MG_REG_CTRL_DPD_ENABLE (0x1<<6) - -/* Status register bit */ -/* error bit in status register */ -#define MG_REG_STATUS_BIT_ERROR 0x01 -/* corrected error in status register */ -#define MG_REG_STATUS_BIT_CORRECTED_ERROR 0x04 -/* data request bit in status register */ -#define MG_REG_STATUS_BIT_DATA_REQ 0x08 -/* DSC - Drive Seek Complete */ -#define MG_REG_STATUS_BIT_SEEK_DONE 0x10 -/* DWF - Drive Write Fault */ -#define MG_REG_STATUS_BIT_WRITE_FAULT 0x20 -#define MG_REG_STATUS_BIT_READY 0x40 -#define MG_REG_STATUS_BIT_BUSY 0x80 - -/* handy status */ -#define MG_STAT_READY (MG_REG_STATUS_BIT_READY | MG_REG_STATUS_BIT_SEEK_DONE) -#define MG_READY_OK(s) (((s) & (MG_STAT_READY | \ - (MG_REG_STATUS_BIT_BUSY | \ - MG_REG_STATUS_BIT_WRITE_FAULT | \ - MG_REG_STATUS_BIT_ERROR))) == MG_STAT_READY) - -/* Error register */ -#define MG_REG_ERR_AMNF 0x01 -#define MG_REG_ERR_ABRT 0x04 -#define MG_REG_ERR_IDNF 0x10 -#define MG_REG_ERR_UNC 0x40 -#define MG_REG_ERR_BBK 0x80 - -/* error code for others */ -#define MG_ERR_NONE 0 -#define MG_ERR_TIMEOUT 0x100 -#define MG_ERR_INIT_STAT 0x101 -#define MG_ERR_TRANSLATION 0x102 -#define MG_ERR_CTRL_RST 0x103 -#define MG_ERR_INV_STAT 0x104 -#define MG_ERR_RSTOUT 0x105 - -#define MG_MAX_ERRORS 6 /* Max read/write errors */ - -/* command */ -#define MG_CMD_RD 0x20 -#define MG_CMD_WR 0x30 -#define MG_CMD_SLEEP 0x99 -#define MG_CMD_WAKEUP 0xC3 -#define MG_CMD_ID 0xEC -#define MG_CMD_WR_CONF 0x3C -#define MG_CMD_RD_CONF 0x40 - -/* operation mode */ -#define MG_OP_CASCADE (1 << 0) -#define MG_OP_CASCADE_SYNC_RD (1 << 1) -#define MG_OP_CASCADE_SYNC_WR (1 << 2) -#define MG_OP_INTERLEAVE (1 << 3) - -/* synchronous */ -#define MG_BURST_LAT_4 (3 << 4) -#define MG_BURST_LAT_5 (4 << 4) -#define MG_BURST_LAT_6 (5 << 4) -#define MG_BURST_LAT_7 (6 << 4) -#define MG_BURST_LAT_8 (7 << 4) -#define MG_BURST_LEN_4 (1 << 1) -#define MG_BURST_LEN_8 (2 << 1) -#define MG_BURST_LEN_16 (3 << 1) -#define MG_BURST_LEN_32 (4 << 1) -#define MG_BURST_LEN_CONT (0 << 1) - -/* timeout value (unit: ms) */ -#define MG_TMAX_CONF_TO_CMD 1 -#define MG_TMAX_WAIT_RD_DRQ 10 -#define MG_TMAX_WAIT_WR_DRQ 500 -#define MG_TMAX_RST_TO_BUSY 10 -#define MG_TMAX_HDRST_TO_RDY 500 -#define MG_TMAX_SWRST_TO_RDY 500 -#define MG_TMAX_RSTOUT 3000 - -/* device attribution */ -/* use mflash as boot device */ -#define MG_BOOT_DEV (1 << 0) -/* use mflash as storage device */ -#define MG_STORAGE_DEV (1 << 1) -/* same as MG_STORAGE_DEV, but bootloader already done reset sequence */ -#define MG_STORAGE_DEV_SKIP_RST (1 << 2) - -#define MG_DEV_MASK (MG_BOOT_DEV | MG_STORAGE_DEV | MG_STORAGE_DEV_SKIP_RST) - -/* names of GPIO resource */ -#define MG_RST_PIN "mg_rst" -/* except MG_BOOT_DEV, reset-out pin should be assigned */ -#define MG_RSTOUT_PIN "mg_rstout" - -/* private driver data */ -struct mg_drv_data { - /* disk resource */ - u32 use_polling; - - /* device attribution */ - u32 dev_attr; - - /* internally used */ - struct mg_host *host; -}; - -/* main structure for mflash driver */ -struct mg_host { - struct device *dev; - - struct request_queue *breq; - spinlock_t lock; - struct gendisk *gd; - - struct timer_list timer; - void (*mg_do_intr) (struct mg_host *); - - u16 id[ATA_ID_WORDS]; - - u16 cyls; - u16 heads; - u16 sectors; - u32 n_sectors; - u32 nres_sectors; - - void __iomem *dev_base; - unsigned int irq; - unsigned int rst; - unsigned int rstout; - - u32 major; - u32 error; -}; - -/* - * Debugging macro and defines - */ -#undef DO_MG_DEBUG -#ifdef DO_MG_DEBUG -# define MG_DBG(fmt, args...) \ - printk(KERN_DEBUG "%s:%d "fmt, __func__, __LINE__, ##args) -#else /* CONFIG_MG_DEBUG */ -# define MG_DBG(fmt, args...) do { } while (0) -#endif /* CONFIG_MG_DEBUG */ - -#endif -- cgit v0.10.2 From a03bb5a32fff4aa23f081a3cff7e98d4084104cd Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 28 Apr 2009 13:06:15 +0900 Subject: mg_disk: clean up request completion paths mg_disk implements its own partial completion. Convert to standard block layer partial completion. [ Impact: cleanup ] Signed-off-by: Tejun Heo Cc: unsik Kim Signed-off-by: Jens Axboe diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index 2c6127ee..1a4cc96 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c @@ -503,95 +503,68 @@ static unsigned int mg_out(struct mg_host *host, static void mg_read(struct request *req) { - u32 remains, j; + u32 j; struct mg_host *host = req->rq_disk->private_data; - remains = req->nr_sectors; - if (mg_out(host, req->sector, req->nr_sectors, MG_CMD_RD, NULL) != MG_ERR_NONE) mg_bad_rw_intr(host); MG_DBG("requested %d sects (from %ld), buffer=0x%p\n", - remains, req->sector, req->buffer); + req->nr_sectors, req->sector, req->buffer); + + do { + u16 *buff = (u16 *)req->buffer; - while (remains) { if (mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ, MG_TMAX_WAIT_RD_DRQ) != MG_ERR_NONE) { mg_bad_rw_intr(host); return; } - for (j = 0; j < MG_SECTOR_SIZE >> 1; j++) { - *(u16 *)req->buffer = - inw((unsigned long)host->dev_base + - MG_BUFF_OFFSET + (j << 1)); - req->buffer += 2; - } - - req->sector++; - req->errors = 0; - remains = --req->nr_sectors; - --req->current_nr_sectors; - - if (req->current_nr_sectors <= 0) { - MG_DBG("remain : %d sects\n", remains); - __blk_end_request_cur(req, 0); - if (remains > 0) - req = elv_next_request(host->breq); - } + for (j = 0; j < MG_SECTOR_SIZE >> 1; j++) + *buff++ = inw((unsigned long)host->dev_base + + MG_BUFF_OFFSET + (j << 1)); outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND); - } + } while (__blk_end_request(req, 0, MG_SECTOR_SIZE)); } static void mg_write(struct request *req) { - u32 remains, j; + u32 j; struct mg_host *host = req->rq_disk->private_data; - remains = req->nr_sectors; - if (mg_out(host, req->sector, req->nr_sectors, MG_CMD_WR, NULL) != MG_ERR_NONE) { mg_bad_rw_intr(host); return; } - MG_DBG("requested %d sects (from %ld), buffer=0x%p\n", - remains, req->sector, req->buffer); - while (remains) { + req->nr_sectors, req->sector, req->buffer); + + do { + u16 *buff = (u16 *)req->buffer; + if (mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ, MG_TMAX_WAIT_WR_DRQ) != MG_ERR_NONE) { mg_bad_rw_intr(host); return; } - for (j = 0; j < MG_SECTOR_SIZE >> 1; j++) { - outw(*(u16 *)req->buffer, - (unsigned long)host->dev_base + - MG_BUFF_OFFSET + (j << 1)); - req->buffer += 2; - } - req->sector++; - remains = --req->nr_sectors; - --req->current_nr_sectors; - - if (req->current_nr_sectors <= 0) { - MG_DBG("remain : %d sects\n", remains); - __blk_end_request_cur(req, 0); - if (remains > 0) - req = elv_next_request(host->breq); - } + for (j = 0; j < MG_SECTOR_SIZE >> 1; j++) + outw(*buff++, (unsigned long)host->dev_base + + MG_BUFF_OFFSET + (j << 1)); outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND); - } + } while (__blk_end_request(req, 0, MG_SECTOR_SIZE)); } static void mg_read_intr(struct mg_host *host) { u32 i; + u16 *buff; struct request *req; /* check status */ @@ -612,39 +585,24 @@ static void mg_read_intr(struct mg_host *host) ok_to_read: /* get current segment of request */ req = elv_next_request(host->breq); + buff = (u16 *)req->buffer; /* read 1 sector */ - for (i = 0; i < MG_SECTOR_SIZE >> 1; i++) { - *(u16 *)req->buffer = - inw((unsigned long)host->dev_base + MG_BUFF_OFFSET + - (i << 1)); - req->buffer += 2; - } + for (i = 0; i < MG_SECTOR_SIZE >> 1; i++) + *buff++ = inw((unsigned long)host->dev_base + MG_BUFF_OFFSET + + (i << 1)); - /* manipulate request */ MG_DBG("sector %ld, remaining=%ld, buffer=0x%p\n", req->sector, req->nr_sectors - 1, req->buffer); - req->sector++; - req->errors = 0; - i = --req->nr_sectors; - --req->current_nr_sectors; - - /* let know if current segment done */ - if (req->current_nr_sectors <= 0) - __blk_end_request_cur(req, 0); - - /* set handler if read remains */ - if (i > 0) { - host->mg_do_intr = mg_read_intr; - mod_timer(&host->timer, jiffies + 3 * HZ); - } - /* send read confirm */ outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND); - /* goto next request */ - if (!i) + if (__blk_end_request(req, 0, MG_SECTOR_SIZE)) { + /* set handler if read remains */ + host->mg_do_intr = mg_read_intr; + mod_timer(&host->timer, jiffies + 3 * HZ); + } else /* goto next request */ mg_request(host->breq); } @@ -653,6 +611,7 @@ static void mg_write_intr(struct mg_host *host) u32 i, j; u16 *buff; struct request *req; + bool rem; /* get current segment of request */ req = elv_next_request(host->breq); @@ -673,18 +632,8 @@ static void mg_write_intr(struct mg_host *host) return; ok_to_write: - /* manipulate request */ - req->sector++; - i = --req->nr_sectors; - --req->current_nr_sectors; - req->buffer += MG_SECTOR_SIZE; - - /* let know if current segment or all done */ - if (!i || (req->bio && req->current_nr_sectors <= 0)) - __blk_end_request_cur(req, 0); - - /* write 1 sector and set handler if remains */ - if (i > 0) { + if ((rem = __blk_end_request(req, 0, MG_SECTOR_SIZE))) { + /* write 1 sector and set handler if remains */ buff = (u16 *)req->buffer; for (j = 0; j < MG_STORAGE_BUFFER_SIZE >> 1; j++) { outw(*buff, (unsigned long)host->dev_base + @@ -700,7 +649,7 @@ ok_to_write: /* send write confirm */ outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND); - if (!i) + if (!rem) mg_request(host->breq); } -- cgit v0.10.2 From 8a11a789c39cd6f61de4243234cf44a46c23ffd0 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 28 Apr 2009 13:06:16 +0900 Subject: mg_disk: fix dependency on libata Add local copies of ata_id_string() and ata_id_c_string() to mg_disk so there is no need for the driver to depend on ATA and SCSI. [ Impact: break dependency on libata by copying ata id string functions ] Cc: unsik Kim Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Tejun Heo Signed-off-by: Jens Axboe diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index ddea8e4..f42fa50 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -412,7 +412,7 @@ config ATA_OVER_ETH config MG_DISK tristate "mGine mflash, gflash support" - depends on ARM && ATA && GPIOLIB + depends on ARM && GPIOLIB help mGine mFlash(gFlash) block device driver diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index 1a4cc96..8e53cae 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -357,6 +357,42 @@ static irqreturn_t mg_irq(int irq, void *dev_id) return IRQ_HANDLED; } +/* local copy of ata_id_string() */ +static void mg_id_string(const u16 *id, unsigned char *s, + unsigned int ofs, unsigned int len) +{ + unsigned int c; + + BUG_ON(len & 1); + + while (len > 0) { + c = id[ofs] >> 8; + *s = c; + s++; + + c = id[ofs] & 0xff; + *s = c; + s++; + + ofs++; + len -= 2; + } +} + +/* local copy of ata_id_c_string() */ +static void mg_id_c_string(const u16 *id, unsigned char *s, + unsigned int ofs, unsigned int len) +{ + unsigned char *p; + + mg_id_string(id, s, ofs, len - 1); + + p = s + strnlen(s, len - 1); + while (p > s && p[-1] == ' ') + p--; + *p = '\0'; +} + static int mg_get_disk_id(struct mg_host *host) { u32 i; @@ -403,9 +439,9 @@ static int mg_get_disk_id(struct mg_host *host) host->n_sectors -= host->nres_sectors; } - ata_id_c_string(id, fwrev, ATA_ID_FW_REV, sizeof(fwrev)); - ata_id_c_string(id, model, ATA_ID_PROD, sizeof(model)); - ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); + mg_id_c_string(id, fwrev, ATA_ID_FW_REV, sizeof(fwrev)); + mg_id_c_string(id, model, ATA_ID_PROD, sizeof(model)); + mg_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); printk(KERN_INFO "mg_disk: model: %s\n", model); printk(KERN_INFO "mg_disk: firm: %.8s\n", fwrev); printk(KERN_INFO "mg_disk: serial: %s\n", serial); -- cgit v0.10.2 From f68adec3c7155a8bbf32a90cb4c4d0737df045d9 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 28 Apr 2009 13:06:17 +0900 Subject: mg_disk: use defines from While at it: - remove MG_REG_HEAD_MUST_BE_ON define - remove MG_REG_CTRL_INTR_ENABLE define - remove MG_REG_HEAD_LBA_MODE define - remove unused defines Cc: unsik Kim Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Tejun Heo Signed-off-by: Jens Axboe diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index 8e53cae..71e56cc 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c @@ -51,51 +51,10 @@ #define MG_REG_DRV_CTRL (MG_REG_OFFSET + 0x10) #define MG_REG_BURST_CTRL (MG_REG_OFFSET + 0x12) -/* "Drive Select/Head Register" bit values */ -#define MG_REG_HEAD_MUST_BE_ON 0xA0 /* These 2 bits are always on */ -#define MG_REG_HEAD_DRIVE_MASTER (0x00 | MG_REG_HEAD_MUST_BE_ON) -#define MG_REG_HEAD_DRIVE_SLAVE (0x10 | MG_REG_HEAD_MUST_BE_ON) -#define MG_REG_HEAD_LBA_MODE (0x40 | MG_REG_HEAD_MUST_BE_ON) - - -/* "Device Control Register" bit values */ -#define MG_REG_CTRL_INTR_ENABLE 0x0 -#define MG_REG_CTRL_INTR_DISABLE (0x1<<1) -#define MG_REG_CTRL_RESET (0x1<<2) -#define MG_REG_CTRL_INTR_POLA_ACTIVE_HIGH 0x0 -#define MG_REG_CTRL_INTR_POLA_ACTIVE_LOW (0x1<<4) -#define MG_REG_CTRL_DPD_POLA_ACTIVE_LOW 0x0 -#define MG_REG_CTRL_DPD_POLA_ACTIVE_HIGH (0x1<<5) -#define MG_REG_CTRL_DPD_DISABLE 0x0 -#define MG_REG_CTRL_DPD_ENABLE (0x1<<6) - -/* Status register bit */ -/* error bit in status register */ -#define MG_REG_STATUS_BIT_ERROR 0x01 -/* corrected error in status register */ -#define MG_REG_STATUS_BIT_CORRECTED_ERROR 0x04 -/* data request bit in status register */ -#define MG_REG_STATUS_BIT_DATA_REQ 0x08 -/* DSC - Drive Seek Complete */ -#define MG_REG_STATUS_BIT_SEEK_DONE 0x10 -/* DWF - Drive Write Fault */ -#define MG_REG_STATUS_BIT_WRITE_FAULT 0x20 -#define MG_REG_STATUS_BIT_READY 0x40 -#define MG_REG_STATUS_BIT_BUSY 0x80 - /* handy status */ -#define MG_STAT_READY (MG_REG_STATUS_BIT_READY | MG_REG_STATUS_BIT_SEEK_DONE) -#define MG_READY_OK(s) (((s) & (MG_STAT_READY | \ - (MG_REG_STATUS_BIT_BUSY | \ - MG_REG_STATUS_BIT_WRITE_FAULT | \ - MG_REG_STATUS_BIT_ERROR))) == MG_STAT_READY) - -/* Error register */ -#define MG_REG_ERR_AMNF 0x01 -#define MG_REG_ERR_ABRT 0x04 -#define MG_REG_ERR_IDNF 0x10 -#define MG_REG_ERR_UNC 0x40 -#define MG_REG_ERR_BBK 0x80 +#define MG_STAT_READY (ATA_DRDY | ATA_DSC) +#define MG_READY_OK(s) (((s) & (MG_STAT_READY | (ATA_BUSY | ATA_DF | \ + ATA_ERR))) == MG_STAT_READY) /* error code for others */ #define MG_ERR_NONE 0 @@ -225,41 +184,39 @@ static void mg_dump_status(const char *msg, unsigned int stat, } printk(KERN_ERR "%s: %s: status=0x%02x { ", name, msg, stat & 0xff); - if (stat & MG_REG_STATUS_BIT_BUSY) + if (stat & ATA_BUSY) printk("Busy "); - if (stat & MG_REG_STATUS_BIT_READY) + if (stat & ATA_DRDY) printk("DriveReady "); - if (stat & MG_REG_STATUS_BIT_WRITE_FAULT) + if (stat & ATA_DF) printk("WriteFault "); - if (stat & MG_REG_STATUS_BIT_SEEK_DONE) + if (stat & ATA_DSC) printk("SeekComplete "); - if (stat & MG_REG_STATUS_BIT_DATA_REQ) + if (stat & ATA_DRQ) printk("DataRequest "); - if (stat & MG_REG_STATUS_BIT_CORRECTED_ERROR) + if (stat & ATA_CORR) printk("CorrectedError "); - if (stat & MG_REG_STATUS_BIT_ERROR) + if (stat & ATA_ERR) printk("Error "); printk("}\n"); - if ((stat & MG_REG_STATUS_BIT_ERROR) == 0) { + if ((stat & ATA_ERR) == 0) { host->error = 0; } else { host->error = inb((unsigned long)host->dev_base + MG_REG_ERROR); printk(KERN_ERR "%s: %s: error=0x%02x { ", name, msg, host->error & 0xff); - if (host->error & MG_REG_ERR_BBK) + if (host->error & ATA_BBK) printk("BadSector "); - if (host->error & MG_REG_ERR_UNC) + if (host->error & ATA_UNC) printk("UncorrectableError "); - if (host->error & MG_REG_ERR_IDNF) + if (host->error & ATA_IDNF) printk("SectorIdNotFound "); - if (host->error & MG_REG_ERR_ABRT) + if (host->error & ATA_ABORTED) printk("DriveStatusError "); - if (host->error & MG_REG_ERR_AMNF) + if (host->error & ATA_AMNF) printk("AddrMarkNotFound "); printk("}"); - if (host->error & - (MG_REG_ERR_BBK | MG_REG_ERR_UNC | - MG_REG_ERR_IDNF | MG_REG_ERR_AMNF)) { + if (host->error & (ATA_BBK | ATA_UNC | ATA_IDNF | ATA_AMNF)) { if (host->breq) { req = elv_next_request(host->breq); if (req) @@ -284,12 +241,12 @@ static unsigned int mg_wait(struct mg_host *host, u32 expect, u32 msec) do { cur_jiffies = jiffies; - if (status & MG_REG_STATUS_BIT_BUSY) { - if (expect == MG_REG_STATUS_BIT_BUSY) + if (status & ATA_BUSY) { + if (expect == ATA_BUSY) break; } else { /* Check the error condition! */ - if (status & MG_REG_STATUS_BIT_ERROR) { + if (status & ATA_ERR) { mg_dump_status("mg_wait", status, host); break; } @@ -298,8 +255,8 @@ static unsigned int mg_wait(struct mg_host *host, u32 expect, u32 msec) if (MG_READY_OK(status)) break; - if (expect == MG_REG_STATUS_BIT_DATA_REQ) - if (status & MG_REG_STATUS_BIT_DATA_REQ) + if (expect == ATA_DRQ) + if (status & ATA_DRQ) break; } if (!msec) { @@ -404,12 +361,10 @@ static int mg_get_disk_id(struct mg_host *host) char serial[ATA_ID_SERNO_LEN + 1]; if (!prv_data->use_polling) - outb(MG_REG_CTRL_INTR_DISABLE, - (unsigned long)host->dev_base + - MG_REG_DRV_CTRL); + outb(ATA_NIEN, (unsigned long)host->dev_base + MG_REG_DRV_CTRL); outb(MG_CMD_ID, (unsigned long)host->dev_base + MG_REG_COMMAND); - err = mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ, MG_TMAX_WAIT_RD_DRQ); + err = mg_wait(host, ATA_DRQ, MG_TMAX_WAIT_RD_DRQ); if (err) return err; @@ -449,8 +404,7 @@ static int mg_get_disk_id(struct mg_host *host) host->n_sectors, host->nres_sectors); if (!prv_data->use_polling) - outb(MG_REG_CTRL_INTR_ENABLE, (unsigned long)host->dev_base + - MG_REG_DRV_CTRL); + outb(0, (unsigned long)host->dev_base + MG_REG_DRV_CTRL); return err; } @@ -464,7 +418,7 @@ static int mg_disk_init(struct mg_host *host) /* hdd rst low */ gpio_set_value(host->rst, 0); - err = mg_wait(host, MG_REG_STATUS_BIT_BUSY, MG_TMAX_RST_TO_BUSY); + err = mg_wait(host, ATA_BUSY, MG_TMAX_RST_TO_BUSY); if (err) return err; @@ -475,17 +429,14 @@ static int mg_disk_init(struct mg_host *host) return err; /* soft reset on */ - outb(MG_REG_CTRL_RESET | - (prv_data->use_polling ? MG_REG_CTRL_INTR_DISABLE : - MG_REG_CTRL_INTR_ENABLE), + outb(ATA_SRST | (prv_data->use_polling ? ATA_NIEN : 0), (unsigned long)host->dev_base + MG_REG_DRV_CTRL); - err = mg_wait(host, MG_REG_STATUS_BIT_BUSY, MG_TMAX_RST_TO_BUSY); + err = mg_wait(host, ATA_BUSY, MG_TMAX_RST_TO_BUSY); if (err) return err; /* soft reset off */ - outb(prv_data->use_polling ? MG_REG_CTRL_INTR_DISABLE : - MG_REG_CTRL_INTR_ENABLE, + outb(prv_data->use_polling ? ATA_NIEN : 0, (unsigned long)host->dev_base + MG_REG_DRV_CTRL); err = mg_wait(host, MG_STAT_READY, MG_TMAX_SWRST_TO_RDY); if (err) @@ -531,7 +482,7 @@ static unsigned int mg_out(struct mg_host *host, MG_REG_CYL_LOW); outb((u8)(sect_num >> 16), (unsigned long)host->dev_base + MG_REG_CYL_HIGH); - outb((u8)((sect_num >> 24) | MG_REG_HEAD_LBA_MODE), + outb((u8)((sect_num >> 24) | ATA_LBA | ATA_DEVICE_OBS), (unsigned long)host->dev_base + MG_REG_DRV_HEAD); outb(cmd, (unsigned long)host->dev_base + MG_REG_COMMAND); return MG_ERR_NONE; @@ -552,8 +503,8 @@ static void mg_read(struct request *req) do { u16 *buff = (u16 *)req->buffer; - if (mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ, - MG_TMAX_WAIT_RD_DRQ) != MG_ERR_NONE) { + if (mg_wait(host, ATA_DRQ, + MG_TMAX_WAIT_RD_DRQ) != MG_ERR_NONE) { mg_bad_rw_intr(host); return; } @@ -583,8 +534,7 @@ static void mg_write(struct request *req) do { u16 *buff = (u16 *)req->buffer; - if (mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ, - MG_TMAX_WAIT_WR_DRQ) != MG_ERR_NONE) { + if (mg_wait(host, ATA_DRQ, MG_TMAX_WAIT_WR_DRQ) != MG_ERR_NONE) { mg_bad_rw_intr(host); return; } @@ -606,11 +556,11 @@ static void mg_read_intr(struct mg_host *host) /* check status */ do { i = inb((unsigned long)host->dev_base + MG_REG_STATUS); - if (i & MG_REG_STATUS_BIT_BUSY) + if (i & ATA_BUSY) break; if (!MG_READY_OK(i)) break; - if (i & MG_REG_STATUS_BIT_DATA_REQ) + if (i & ATA_DRQ) goto ok_to_read; } while (0); mg_dump_status("mg_read_intr", i, host); @@ -655,11 +605,11 @@ static void mg_write_intr(struct mg_host *host) /* check status */ do { i = inb((unsigned long)host->dev_base + MG_REG_STATUS); - if (i & MG_REG_STATUS_BIT_BUSY) + if (i & ATA_BUSY) break; if (!MG_READY_OK(i)) break; - if ((req->nr_sectors <= 1) || (i & MG_REG_STATUS_BIT_DATA_REQ)) + if ((req->nr_sectors <= 1) || (i & ATA_DRQ)) goto ok_to_write; } while (0); mg_dump_status("mg_write_intr", i, host); @@ -752,18 +702,15 @@ static unsigned int mg_issue_req(struct request *req, break; case WRITE: /* TODO : handler */ - outb(MG_REG_CTRL_INTR_DISABLE, - (unsigned long)host->dev_base + - MG_REG_DRV_CTRL); + outb(ATA_NIEN, (unsigned long)host->dev_base + MG_REG_DRV_CTRL); if (mg_out(host, sect_num, sect_cnt, MG_CMD_WR, &mg_write_intr) != MG_ERR_NONE) { mg_bad_rw_intr(host); return host->error; } del_timer(&host->timer); - mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ, MG_TMAX_WAIT_WR_DRQ); - outb(MG_REG_CTRL_INTR_ENABLE, (unsigned long)host->dev_base + - MG_REG_DRV_CTRL); + mg_wait(host, ATA_DRQ, MG_TMAX_WAIT_WR_DRQ); + outb(0, (unsigned long)host->dev_base + MG_REG_DRV_CTRL); if (host->error) { mg_bad_rw_intr(host); return host->error; @@ -849,9 +796,7 @@ static int mg_suspend(struct platform_device *plat_dev, pm_message_t state) return -EIO; if (!prv_data->use_polling) - outb(MG_REG_CTRL_INTR_DISABLE, - (unsigned long)host->dev_base + - MG_REG_DRV_CTRL); + outb(ATA_NIEN, (unsigned long)host->dev_base + MG_REG_DRV_CTRL); outb(MG_CMD_SLEEP, (unsigned long)host->dev_base + MG_REG_COMMAND); /* wait until mflash deep sleep */ @@ -859,9 +804,7 @@ static int mg_suspend(struct platform_device *plat_dev, pm_message_t state) if (mg_wait(host, MG_STAT_READY, MG_TMAX_CONF_TO_CMD)) { if (!prv_data->use_polling) - outb(MG_REG_CTRL_INTR_ENABLE, - (unsigned long)host->dev_base + - MG_REG_DRV_CTRL); + outb(0, (unsigned long)host->dev_base + MG_REG_DRV_CTRL); return -EIO; } @@ -884,8 +827,7 @@ static int mg_resume(struct platform_device *plat_dev) return -EIO; if (!prv_data->use_polling) - outb(MG_REG_CTRL_INTR_ENABLE, (unsigned long)host->dev_base + - MG_REG_DRV_CTRL); + outb(0, (unsigned long)host->dev_base + MG_REG_DRV_CTRL); return 0; } -- cgit v0.10.2 From 53d6979ab6747e758207e8ac861b96d0da0d3332 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 7 May 2009 22:24:35 +0900 Subject: nbd: don't clear rq->sector and nr_sectors unnecessarily There's no reason to clear rq->sector and nr_sectors after calling blk_rq_init(). They're guaranteed to be clear. Drop unnecessary clearing. [ Impact: cleanup ] Signed-off-by: Tejun Heo Cc: Paul Clements Signed-off-by: Jens Axboe diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 4d6de4f..a9ab8be 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -580,13 +580,6 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo, blk_rq_init(NULL, &sreq); sreq.cmd_type = REQ_TYPE_SPECIAL; nbd_cmd(&sreq) = NBD_CMD_DISC; - /* - * Set these to sane values in case server implementation - * fails to check the request type first and also to keep - * debugging output cleaner. - */ - sreq.sector = 0; - sreq.nr_sectors = 0; if (!lo->sock) return -EINVAL; nbd_send_req(lo, &sreq); -- cgit v0.10.2 From 9720aef2539c10e3a872e9a92beec225030d99db Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 7 May 2009 22:24:36 +0900 Subject: ide-tape: don't initialize rq->sector for rw requests rq->sector is set to the tape->first_frame but it's never actually used and not even in the correct unit (512 byte sectors). Don't set it. [ Impact: cleanup ] Signed-off-by: Tejun Heo Acked-by: Borislav Petkov Acked-by: Bartlomiej Zolnierkiewicz Signed-off-by: Jens Axboe diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 8dfc688..7149224 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -892,7 +892,6 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int size) rq->cmd_type = REQ_TYPE_SPECIAL; rq->cmd[13] = cmd; rq->rq_disk = tape->disk; - rq->sector = tape->first_frame; if (size) { ret = blk_rq_map_kern(drive->queue, rq, tape->buf, size, -- cgit v0.10.2 From c3a4d78c580de4edc9ef0f7c59812fb02ceb037f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 7 May 2009 22:24:37 +0900 Subject: block: add rq->resid_len rq->data_len served two purposes - the length of data buffer on issue and the residual count on completion. This duality creates some headaches. First of all, block layer and low level drivers can't really determine what rq->data_len contains while a request is executing. It could be the total request length or it coulde be anything else one of the lower layers is using to keep track of residual count. This complicates things because blk_rq_bytes() and thus [__]blk_end_request_all() relies on rq->data_len for PC commands. Drivers which want to report residual count should first cache the total request length, update rq->data_len and then complete the request with the cached data length. Secondly, it makes requests default to reporting full residual count, ie. reporting that no data transfer occurred. The residual count is an exception not the norm; however, the driver should clear rq->data_len to zero to signify the normal cases while leaving it alone means no data transfer occurred at all. This reverse default behavior complicates code unnecessarily and renders block PC on some drivers (ide-tape/floppy) unuseable. This patch adds rq->resid_len which is used only for residual count. While at it, remove now unnecessasry blk_rq_bytes() caching in ide_pc_intr() as rq->data_len is not changed anymore. Boaz : spotted missing conversion in osd Sergei : spotted too early conversion to blk_rq_bytes() in ide-tape [ Impact: cleanup residual count handling, report 0 resid by default ] Signed-off-by: Tejun Heo Cc: James Bottomley Cc: Bartlomiej Zolnierkiewicz Cc: Borislav Petkov Cc: Sergei Shtylyov Cc: Mike Miller Cc: Eric Moore Cc: Alan Stern Cc: FUJITA Tomonori Cc: Doug Gilbert Cc: Mike Miller Cc: Eric Moore Cc: Darrick J. Wong Cc: Pete Zaitcev Cc: Boaz Harrosh Signed-off-by: Jens Axboe diff --git a/block/bsg.c b/block/bsg.c index 206060e..2d746e3 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -445,14 +445,14 @@ static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr, } if (rq->next_rq) { - hdr->dout_resid = rq->data_len; - hdr->din_resid = rq->next_rq->data_len; + hdr->dout_resid = rq->resid_len; + hdr->din_resid = rq->next_rq->resid_len; blk_rq_unmap_user(bidi_bio); blk_put_request(rq->next_rq); } else if (rq_data_dir(rq) == READ) - hdr->din_resid = rq->data_len; + hdr->din_resid = rq->resid_len; else - hdr->dout_resid = rq->data_len; + hdr->dout_resid = rq->resid_len; /* * If the request generated a negative error number, return it diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index 58cf456..a9670dd 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -230,7 +230,7 @@ static int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr, hdr->info = 0; if (hdr->masked_status || hdr->host_status || hdr->driver_status) hdr->info |= SG_INFO_CHECK; - hdr->resid = rq->data_len; + hdr->resid = rq->resid_len; hdr->sb_len_wr = 0; if (rq->sense_len && hdr->sbp) { diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 4d4d5e0..f22d493 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1299,7 +1299,6 @@ static void cciss_softirq_done(struct request *rq) { CommandList_struct *cmd = rq->completion_data; ctlr_info_t *h = hba[cmd->ctlr]; - unsigned int nr_bytes; unsigned long flags; u64bit temp64; int i, ddir; @@ -1321,15 +1320,11 @@ static void cciss_softirq_done(struct request *rq) printk("Done with %p\n", rq); #endif /* CCISS_DEBUG */ - /* - * Store the full size and set the residual count for pc requests - */ - nr_bytes = blk_rq_bytes(rq); + /* set the residual count for pc requests */ if (blk_pc_request(rq)) - rq->data_len = cmd->err_info->ResidualCnt; + rq->resid_len = cmd->err_info->ResidualCnt; - if (blk_end_request(rq, (rq->errors == 0) ? 0 : -EIO, nr_bytes)) - BUG(); + blk_end_request_all(rq, (rq->errors == 0) ? 0 : -EIO); spin_lock_irqsave(&h->lock, flags); cmd_free(h, cmd, 1); @@ -2691,7 +2686,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, printk(KERN_WARNING "cciss: cmd %p has" " completed with data underrun " "reported\n", cmd); - cmd->rq->data_len = cmd->err_info->ResidualCnt; + cmd->rq->resid_len = cmd->err_info->ResidualCnt; } break; case CMD_DATA_OVERRUN: diff --git a/drivers/block/ub.c b/drivers/block/ub.c index 689cd27..8c2cc71 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -783,10 +783,8 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) if (cmd->error == 0) { if (blk_pc_request(rq)) { - if (cmd->act_len >= rq->data_len) - rq->data_len = 0; - else - rq->data_len -= cmd->act_len; + if (cmd->act_len < rq->data_len) + rq->resid_len = rq->data_len - cmd->act_len; scsi_status = 0; } else { if (cmd->act_len != cmd->len) { diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c index afe5a43..e4a02a0 100644 --- a/drivers/ide/ide-atapi.c +++ b/drivers/ide/ide-atapi.c @@ -367,7 +367,6 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) /* No more interrupts */ if ((stat & ATA_DRQ) == 0) { int uptodate, error; - unsigned int done; debug_log("Packet command completed, %d bytes transferred\n", pc->xferred); @@ -406,12 +405,6 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) if ((pc->flags & PC_FLAG_WAIT_FOR_DSC) && (stat & ATA_DSC) == 0) dsc = 1; - /* - * ->pc_callback() might change rq->data_len for - * residual count, cache total length. - */ - done = blk_rq_bytes(rq); - /* Command finished - Call the callback function */ uptodate = drive->pc_callback(drive, dsc); @@ -431,7 +424,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) error = uptodate ? 0 : -EIO; } - ide_complete_rq(drive, error, done); + ide_complete_rq(drive, error, blk_rq_bytes(rq)); return ide_stopped; } diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 6736287..8bbe222 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -519,7 +519,7 @@ int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd, error = blk_execute_rq(drive->queue, info->disk, rq, 0); if (buffer) - *bufflen = rq->data_len; + *bufflen = rq->resid_len; flags = rq->cmd_flags; blk_put_request(rq); @@ -707,11 +707,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) out_end: if (blk_pc_request(rq) && rc == 0) { - unsigned int dlen = rq->data_len; - - rq->data_len = 0; - - if (blk_end_request(rq, 0, dlen)) + if (blk_end_request(rq, 0, rq->data_len)) BUG(); hwif->rq = NULL; @@ -740,9 +736,10 @@ out_end: nsectors = 1; if (blk_fs_request(rq) == 0) { - rq->data_len -= (cmd->nbytes - cmd->nleft); + rq->resid_len = rq->data_len - + (cmd->nbytes - cmd->nleft); if (uptodate == 0 && (cmd->tf_flags & IDE_TFLAG_WRITE)) - rq->data_len += cmd->last_xfer_len; + rq->resid_len += cmd->last_xfer_len; } ide_complete_rq(drive, uptodate ? 0 : -EIO, nsectors << 9); diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 7149224..65c5b70 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -380,7 +380,7 @@ static int ide_tape_callback(ide_drive_t *drive, int dsc) } tape->first_frame += blocks; - rq->data_len -= blocks * tape->blk_size; + rq->resid_len = rq->data_len - blocks * tape->blk_size; if (pc->error) { uptodate = 0; @@ -903,7 +903,7 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int size) blk_execute_rq(drive->queue, tape->disk, rq, 0); /* calculate the number of transferred bytes and update buffer state */ - size -= rq->data_len; + size -= rq->resid_len; tape->cur = tape->buf; if (cmd == REQ_IDETAPE_READ) tape->valid = size; diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index a9019f0..5d5f347 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -1357,8 +1357,7 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; memcpy(req->sense, smprep, sizeof(*smprep)); req->sense_len = sizeof(*smprep); - req->data_len = 0; - rsp->data_len -= smprep->ResponseDataLength; + rsp->resid_len = rsp->data_len - smprep->ResponseDataLength; } else { printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n", ioc->name, __func__); diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 3da02e4..6605ec9 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -1936,12 +1936,8 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, bio_data(rsp->bio), rsp->data_len); if (ret > 0) { /* positive number is the untransferred residual */ - rsp->data_len = ret; - req->data_len = 0; + rsp->resid_len = ret; ret = 0; - } else if (ret == 0) { - rsp->data_len = 0; - req->data_len = 0; } return ret; diff --git a/drivers/scsi/libsas/sas_host_smp.c b/drivers/scsi/libsas/sas_host_smp.c index d110a36..89952ed 100644 --- a/drivers/scsi/libsas/sas_host_smp.c +++ b/drivers/scsi/libsas/sas_host_smp.c @@ -134,7 +134,7 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, { u8 *req_data = NULL, *resp_data = NULL, *buf; struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); - int error = -EINVAL, resp_data_len = rsp->data_len; + int error = -EINVAL; /* eight is the minimum size for request and response frames */ if (req->data_len < 8 || rsp->data_len < 8) @@ -176,17 +176,20 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, resp_data[1] = req_data[1]; resp_data[2] = SMP_RESP_FUNC_UNK; + req->resid_len = req->data_len; + rsp->resid_len = rsp->data_len; + switch (req_data[1]) { case SMP_REPORT_GENERAL: - req->data_len -= 8; - resp_data_len -= 32; + req->resid_len -= 8; + rsp->resid_len -= 32; resp_data[2] = SMP_RESP_FUNC_ACC; resp_data[9] = sas_ha->num_phys; break; case SMP_REPORT_MANUF_INFO: - req->data_len -= 8; - resp_data_len -= 64; + req->resid_len -= 8; + rsp->resid_len -= 64; resp_data[2] = SMP_RESP_FUNC_ACC; memcpy(resp_data + 12, shost->hostt->name, SAS_EXPANDER_VENDOR_ID_LEN); @@ -199,13 +202,13 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, break; case SMP_DISCOVER: - req->data_len -= 16; - if ((int)req->data_len < 0) { - req->data_len = 0; + req->resid_len -= 16; + if ((int)req->resid_len < 0) { + req->resid_len = 0; error = -EINVAL; goto out; } - resp_data_len -= 56; + rsp->resid_len -= 56; sas_host_smp_discover(sas_ha, resp_data, req_data[9]); break; @@ -215,13 +218,13 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, break; case SMP_REPORT_PHY_SATA: - req->data_len -= 16; - if ((int)req->data_len < 0) { - req->data_len = 0; + req->resid_len -= 16; + if ((int)req->resid_len < 0) { + req->resid_len = 0; error = -EINVAL; goto out; } - resp_data_len -= 60; + rsp->resid_len -= 60; sas_report_phy_sata(sas_ha, resp_data, req_data[9]); break; @@ -238,13 +241,13 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, break; case SMP_PHY_CONTROL: - req->data_len -= 44; - if ((int)req->data_len < 0) { - req->data_len = 0; + req->resid_len -= 44; + if ((int)req->resid_len < 0) { + req->resid_len = 0; error = -EINVAL; goto out; } - resp_data_len -= 8; + rsp->resid_len -= 8; sas_phy_control(sas_ha, req_data[9], req_data[10], req_data[32] >> 4, req_data[33] >> 4, resp_data); @@ -265,7 +268,6 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, flush_kernel_dcache_page(bio_page(rsp->bio)); kunmap_atomic(buf - bio_offset(rsp->bio), KM_USER0); local_irq_enable(); - rsp->data_len = resp_data_len; out: kfree(req_data); diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index e03dc0b..53759c5 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c @@ -1170,9 +1170,7 @@ transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, memcpy(req->sense, mpi_reply, sizeof(*mpi_reply)); req->sense_len = sizeof(*mpi_reply); - req->data_len = 0; - rsp->data_len -= mpi_reply->ResponseDataLength; - + rsp->resid_len = rsp->data_len - mpi_reply->ResponseDataLength; } else { dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - no reply\n", ioc->name, __func__)); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index aa9fc57..7d49ef5 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -240,11 +240,11 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, * is invalid. Prevent the garbage from being misinterpreted * and prevent security leaks by zeroing out the excess data. */ - if (unlikely(req->data_len > 0 && req->data_len <= bufflen)) - memset(buffer + (bufflen - req->data_len), 0, req->data_len); + if (unlikely(req->resid_len > 0 && req->resid_len <= bufflen)) + memset(buffer + (bufflen - req->resid_len), 0, req->resid_len); if (resid) - *resid = req->data_len; + *resid = req->resid_len; ret = req->errors; out: blk_put_request(req); @@ -549,7 +549,7 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int error, int leftover = (req->hard_nr_sectors << 9); if (blk_pc_request(req)) - leftover = req->data_len; + leftover = req->resid_len; /* kill remainder if no retrys */ if (error && scsi_noretry_cmd(cmd)) @@ -673,11 +673,11 @@ void scsi_release_buffers(struct scsi_cmnd *cmd) EXPORT_SYMBOL(scsi_release_buffers); /* - * Bidi commands Must be complete as a whole, both sides at once. - * If part of the bytes were written and lld returned - * scsi_in()->resid and/or scsi_out()->resid this information will be left - * in req->data_len and req->next_rq->data_len. The upper-layer driver can - * decide what to do with this information. + * Bidi commands Must be complete as a whole, both sides at once. If + * part of the bytes were written and lld returned scsi_in()->resid + * and/or scsi_out()->resid this information will be left in + * req->resid_len and req->next_rq->resid_len. The upper-layer driver + * can decide what to do with this information. */ static void scsi_end_bidi_request(struct scsi_cmnd *cmd) { @@ -685,8 +685,8 @@ static void scsi_end_bidi_request(struct scsi_cmnd *cmd) unsigned int dlen = req->data_len; unsigned int next_dlen = req->next_rq->data_len; - req->data_len = scsi_out(cmd)->resid; - req->next_rq->data_len = scsi_in(cmd)->resid; + req->resid_len = scsi_out(cmd)->resid; + req->next_rq->resid_len = scsi_in(cmd)->resid; /* The req and req->next_rq have not been completed */ BUG_ON(blk_end_bidi_request(req, 0, dlen, next_dlen)); @@ -778,7 +778,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) scsi_end_bidi_request(cmd); return; } - req->data_len = scsi_get_resid(cmd); + req->resid_len = scsi_get_resid(cmd); } BUG_ON(blk_bidi_rq(req)); /* bidi not support for !blk_pc_request yet */ diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 82312df..dec4c70 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1260,7 +1260,7 @@ static void sg_rq_end_io(struct request *rq, int uptodate) sense = rq->sense; result = rq->errors; - resid = rq->data_len; + resid = rq->resid_len; SCSI_LOG_TIMEOUT(4, printk("sg_cmd_done: %s, pack_id=%d, res=0x%x\n", sdp->disk->disk_name, srp->header.pack_id, result)); diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index eb24efe..8681b7083 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -463,7 +463,7 @@ static void st_scsi_execute_end(struct request *req, int uptodate) struct scsi_tape *STp = SRpnt->stp; STp->buffer->cmdstat.midlevel_result = SRpnt->result = req->errors; - STp->buffer->cmdstat.residual = req->data_len; + STp->buffer->cmdstat.residual = req->resid_len; if (SRpnt->waiting) complete(SRpnt->waiting); diff --git a/fs/exofs/osd.c b/fs/exofs/osd.c index b249ae9..06ca926 100644 --- a/fs/exofs/osd.c +++ b/fs/exofs/osd.c @@ -50,10 +50,10 @@ int exofs_check_ok_resid(struct osd_request *or, u64 *in_resid, u64 *out_resid) /* FIXME: should be include in osd_sense_info */ if (in_resid) - *in_resid = or->in.req ? or->in.req->data_len : 0; + *in_resid = or->in.req ? or->in.req->resid_len : 0; if (out_resid) - *out_resid = or->out.req ? or->out.req->data_len : 0; + *out_resid = or->out.req ? or->out.req->resid_len : 0; return ret; } diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 3a5b1bd..6a967ca 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -229,6 +229,7 @@ struct request { unsigned int data_len; unsigned int extra_len; /* length of alignment and padding */ unsigned int sense_len; + unsigned int resid_len; /* residual count */ void *sense; unsigned long deadline; -- cgit v0.10.2 From 5b93629b4509c03ffa87a9316412fedf6f58cb37 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 7 May 2009 22:24:38 +0900 Subject: block: implement blk_rq_pos/[cur_]sectors() and convert obvious ones Implement accessors - blk_rq_pos(), blk_rq_sectors() and blk_rq_cur_sectors() which return rq->hard_sector, rq->hard_nr_sectors and rq->hard_cur_sectors respectively and convert direct references of the said fields to the accessors. This is in preparation of request data length handling cleanup. Geert : suggested adding const to struct request * parameter to accessors Sergei : spotted error in patch description [ Impact: cleanup ] Signed-off-by: Tejun Heo Acked-by: Geert Uytterhoeven Acked-by: Stephen Rothwell Tested-by: Grant Likely Acked-by: Grant Likely Ackec-by: Sergei Shtylyov Cc: Bartlomiej Zolnierkiewicz Cc: Borislav Petkov Cc: James Bottomley Signed-off-by: Jens Axboe diff --git a/block/blk-barrier.c b/block/blk-barrier.c index c8d0876..c167de5 100644 --- a/block/blk-barrier.c +++ b/block/blk-barrier.c @@ -163,7 +163,7 @@ static inline bool start_ordered(struct request_queue *q, struct request **rqp) * For an empty barrier, there's no actual BAR request, which * in turn makes POSTFLUSH unnecessary. Mask them off. */ - if (!rq->hard_nr_sectors) { + if (!blk_rq_sectors(rq)) { q->ordered &= ~(QUEUE_ORDERED_DO_BAR | QUEUE_ORDERED_DO_POSTFLUSH); /* diff --git a/block/blk-core.c b/block/blk-core.c index 394c5bd..895e55b 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1683,7 +1683,7 @@ static void blk_account_io_done(struct request *req) unsigned int blk_rq_bytes(struct request *rq) { if (blk_fs_request(rq)) - return rq->hard_nr_sectors << 9; + return blk_rq_sectors(rq) << 9; return rq->data_len; } diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index def0c69..575083a 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -760,7 +760,7 @@ static void cfq_activate_request(struct request_queue *q, struct request *rq) cfq_log_cfqq(cfqd, RQ_CFQQ(rq), "activate rq, drv=%d", cfqd->rq_in_driver); - cfqd->last_position = rq->hard_sector + rq->hard_nr_sectors; + cfqd->last_position = blk_rq_pos(rq) + blk_rq_sectors(rq); } static void cfq_deactivate_request(struct request_queue *q, struct request *rq) diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index f6586e4..c238867 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -136,7 +136,7 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev, dev_dbg(&dev->sbd.core, "%s:%u: %s req has %u bvecs for %lu sectors %lu hard sectors\n", __func__, __LINE__, op, n, req->nr_sectors, - req->hard_nr_sectors); + blk_rq_sectors(req)); #endif start_sector = req->sector * priv->blocking_factor; diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index ecccf65..e821eed 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c @@ -368,12 +368,12 @@ static void do_viodasd_request(struct request_queue *q) blkdev_dequeue_request(req); /* check that request contains a valid command */ if (!blk_fs_request(req)) { - viodasd_end_request(req, -EIO, req->hard_nr_sectors); + viodasd_end_request(req, -EIO, blk_rq_sectors(req)); continue; } /* Try sending the request */ if (send_request(req) != 0) - viodasd_end_request(req, -EIO, req->hard_nr_sectors); + viodasd_end_request(req, -EIO, blk_rq_sectors(req)); } } @@ -590,7 +590,7 @@ static int viodasd_handle_read_write(struct vioblocklpevent *bevent) err = vio_lookup_rc(viodasd_err_table, bevent->sub_result); printk(VIOD_KERN_WARNING "read/write error %d:0x%04x (%s)\n", event->xRc, bevent->sub_result, err->msg); - num_sect = req->hard_nr_sectors; + num_sect = blk_rq_sectors(req); } qlock = req->q->queue_lock; spin_lock_irqsave(qlock, irq_flags); diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index b1e1d7e..5722931 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -645,8 +645,8 @@ static void ace_fsm_dostate(struct ace_device *ace) /* Okay, it's a data request, set it up for transfer */ dev_dbg(ace->dev, - "request: sec=%llx hcnt=%lx, ccnt=%x, dir=%i\n", - (unsigned long long) req->sector, req->hard_nr_sectors, + "request: sec=%llx hcnt=%x, ccnt=%x, dir=%i\n", + (unsigned long long) req->sector, blk_rq_sectors(req), req->current_nr_sectors, rq_data_dir(req)); ace->req = req; @@ -654,7 +654,7 @@ static void ace_fsm_dostate(struct ace_device *ace) ace->data_count = req->current_nr_sectors * ACE_BUF_PER_SECTOR; ace_out32(ace, ACE_MPULBA, req->sector & 0x0FFFFFFF); - count = req->hard_nr_sectors; + count = blk_rq_sectors(req); if (rq_data_dir(req)) { /* Kick off write request */ dev_dbg(ace->dev, "write data\n"); @@ -719,8 +719,8 @@ static void ace_fsm_dostate(struct ace_device *ace) /* bio finished; is there another one? */ if (__blk_end_request(ace->req, 0, blk_rq_cur_bytes(ace->req))) { - /* dev_dbg(ace->dev, "next block; h=%li c=%i\n", - * ace->req->hard_nr_sectors, + /* dev_dbg(ace->dev, "next block; h=%u c=%u\n", + * blk_rq_sectors(ace->req), * ace->req->current_nr_sectors); */ ace->data_ptr = ace->req->buffer; diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 8bbe222..182320d 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -730,7 +730,7 @@ out_end: if (blk_pc_request(rq)) nsectors = (rq->data_len + 511) >> 9; else - nsectors = rq->hard_nr_sectors; + nsectors = blk_rq_sectors(rq); if (nsectors == 0) nsectors = 1; @@ -875,7 +875,7 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq, return ide_issue_pc(drive, &cmd); out_end: - nsectors = rq->hard_nr_sectors; + nsectors = blk_rq_sectors(rq); if (nsectors == 0) nsectors = 1; @@ -1359,8 +1359,8 @@ static int ide_cdrom_probe_capabilities(ide_drive_t *drive) static int ide_cdrom_prep_fs(struct request_queue *q, struct request *rq) { int hard_sect = queue_hardsect_size(q); - long block = (long)rq->hard_sector / (hard_sect >> 9); - unsigned long blocks = rq->hard_nr_sectors / (hard_sect >> 9); + long block = (long)blk_rq_pos(rq) / (hard_sect >> 9); + unsigned long blocks = blk_rq_sectors(rq) / (hard_sect >> 9); memset(rq->cmd, 0, BLK_MAX_CDB); diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index a0309ea..df23bcb 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -118,7 +118,7 @@ unsigned int ide_rq_bytes(struct request *rq) if (blk_pc_request(rq)) return rq->data_len; else - return rq->hard_cur_sectors << 9; + return blk_rq_cur_sectors(rq) << 9; } EXPORT_SYMBOL_GPL(ide_rq_bytes); @@ -133,7 +133,7 @@ int ide_complete_rq(ide_drive_t *drive, int error, unsigned int nr_bytes) * and complete the whole request right now */ if (blk_noretry_request(rq) && error <= 0) - nr_bytes = rq->hard_nr_sectors << 9; + nr_bytes = blk_rq_sectors(rq) << 9; rc = ide_end_rq(drive, rq, error, nr_bytes); if (rc == 0) diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index 221317e..56e60f0 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -427,7 +427,7 @@ static void i2o_block_end_request(struct request *req, int error, unsigned long flags; if (blk_end_request(req, error, nr_bytes)) { - int leftover = (req->hard_nr_sectors << KERNEL_SECTOR_SHIFT); + int leftover = (blk_rq_sectors(req) << KERNEL_SECTOR_SHIFT); if (blk_pc_request(req)) leftover = req->data_len; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 7d49ef5..9ff0ca9 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -546,7 +546,7 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int error, * to queue the remainder of them. */ if (blk_end_request(req, error, bytes)) { - int leftover = (req->hard_nr_sectors << 9); + int leftover = blk_rq_sectors(req) << 9; if (blk_pc_request(req)) leftover = req->resid_len; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 6a967ca..4e5f855 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -832,13 +832,30 @@ static inline void blk_run_address_space(struct address_space *mapping) extern void blkdev_dequeue_request(struct request *req); /* - * blk_end_request() takes bytes instead of sectors as a complete size. - * blk_rq_bytes() returns bytes left to complete in the entire request. - * blk_rq_cur_bytes() returns bytes left to complete in the current segment. + * blk_rq_pos() : the current sector + * blk_rq_bytes() : bytes left in the entire request + * blk_rq_cur_bytes() : bytes left in the current segment + * blk_rq_sectors() : sectors left in the entire request + * blk_rq_cur_sectors() : sectors left in the current segment */ +static inline sector_t blk_rq_pos(const struct request *rq) +{ + return rq->hard_sector; +} + extern unsigned int blk_rq_bytes(struct request *rq); extern unsigned int blk_rq_cur_bytes(struct request *rq); +static inline unsigned int blk_rq_sectors(const struct request *rq) +{ + return rq->hard_nr_sectors; +} + +static inline unsigned int blk_rq_cur_sectors(const struct request *rq) +{ + return rq->hard_cur_sectors; +} + /* * Request completion related functions. * diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c index 921ef5d..42f1c11 100644 --- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c @@ -646,7 +646,7 @@ static void blk_add_trace_rq(struct request_queue *q, struct request *rq, rq->cmd_len, rq->cmd); } else { what |= BLK_TC_ACT(BLK_TC_FS); - __blk_add_trace(bt, rq->hard_sector, rq->hard_nr_sectors << 9, + __blk_add_trace(bt, blk_rq_pos(rq), blk_rq_sectors(rq) << 9, rw, what, rq->errors, 0, NULL); } } @@ -857,7 +857,7 @@ void blk_add_driver_data(struct request_queue *q, __blk_add_trace(bt, 0, rq->data_len, 0, BLK_TA_DRV_DATA, rq->errors, len, data); else - __blk_add_trace(bt, rq->hard_sector, rq->hard_nr_sectors << 9, + __blk_add_trace(bt, blk_rq_pos(rq), blk_rq_sectors(rq) << 9, 0, BLK_TA_DRV_DATA, rq->errors, len, data); } EXPORT_SYMBOL_GPL(blk_add_driver_data); -- cgit v0.10.2 From 83096ebf1263b2c1ee5e653ba37d993d02e3eb7b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 7 May 2009 22:24:39 +0900 Subject: block: convert to pos and nr_sectors accessors With recent cleanups, there is no place where low level driver directly manipulates request fields. This means that the 'hard' request fields always equal the !hard fields. Convert all rq->sectors, nr_sectors and current_nr_sectors references to accessors. While at it, drop superflous blk_rq_pos() < 0 test in swim.c. [ Impact: use pos and nr_sectors accessors ] Signed-off-by: Tejun Heo Acked-by: Geert Uytterhoeven Tested-by: Grant Likely Acked-by: Grant Likely Tested-by: Adrian McMenamin Acked-by: Adrian McMenamin Acked-by: Mike Miller Cc: James Bottomley Cc: Bartlomiej Zolnierkiewicz Cc: Borislav Petkov Cc: Sergei Shtylyov Cc: Eric Moore Cc: Alan Stern Cc: FUJITA Tomonori Cc: Pete Zaitcev Cc: Stephen Rothwell Cc: Paul Clements Cc: Tim Waugh Cc: Jeff Garzik Cc: Jeremy Fitzhardinge Cc: Alex Dubov Cc: David Woodhouse Cc: Martin Schwidefsky Cc: Dario Ballabio Cc: David S. Miller Cc: Rusty Russell Cc: unsik Kim Cc: Laurent Vivier Signed-off-by: Jens Axboe diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 4330127..402ba8f 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -1239,7 +1239,7 @@ static void do_ubd_request(struct request_queue *q) } req = dev->request; - sector = req->sector; + sector = blk_rq_pos(req); while(dev->start_sg < dev->end_sg){ struct scatterlist *sg = &dev->sg[dev->start_sg]; diff --git a/block/as-iosched.c b/block/as-iosched.c index 45bd070..7a12cf6 100644 --- a/block/as-iosched.c +++ b/block/as-iosched.c @@ -306,8 +306,8 @@ as_choose_req(struct as_data *ad, struct request *rq1, struct request *rq2) data_dir = rq_is_sync(rq1); last = ad->last_sector[data_dir]; - s1 = rq1->sector; - s2 = rq2->sector; + s1 = blk_rq_pos(rq1); + s2 = blk_rq_pos(rq2); BUG_ON(data_dir != rq_is_sync(rq2)); @@ -566,13 +566,15 @@ static void as_update_iohist(struct as_data *ad, struct as_io_context *aic, as_update_thinktime(ad, aic, thinktime); /* Calculate read -> read seek distance */ - if (aic->last_request_pos < rq->sector) - seek_dist = rq->sector - aic->last_request_pos; + if (aic->last_request_pos < blk_rq_pos(rq)) + seek_dist = blk_rq_pos(rq) - + aic->last_request_pos; else - seek_dist = aic->last_request_pos - rq->sector; + seek_dist = aic->last_request_pos - + blk_rq_pos(rq); as_update_seekdist(ad, aic, seek_dist); } - aic->last_request_pos = rq->sector + rq->nr_sectors; + aic->last_request_pos = blk_rq_pos(rq) + blk_rq_sectors(rq); set_bit(AS_TASK_IOSTARTED, &aic->state); spin_unlock(&aic->lock); } @@ -587,7 +589,7 @@ static int as_close_req(struct as_data *ad, struct as_io_context *aic, { unsigned long delay; /* jiffies */ sector_t last = ad->last_sector[ad->batch_data_dir]; - sector_t next = rq->sector; + sector_t next = blk_rq_pos(rq); sector_t delta; /* acceptable close offset (in sectors) */ sector_t s; @@ -981,7 +983,7 @@ static void as_move_to_dispatch(struct as_data *ad, struct request *rq) * This has to be set in order to be correctly updated by * as_find_next_rq */ - ad->last_sector[data_dir] = rq->sector + rq->nr_sectors; + ad->last_sector[data_dir] = blk_rq_pos(rq) + blk_rq_sectors(rq); if (data_dir == BLK_RW_SYNC) { struct io_context *ioc = RQ_IOC(rq); diff --git a/block/blk-barrier.c b/block/blk-barrier.c index c167de5..8713c2f 100644 --- a/block/blk-barrier.c +++ b/block/blk-barrier.c @@ -324,7 +324,7 @@ int blkdev_issue_flush(struct block_device *bdev, sector_t *error_sector) /* * The driver must store the error location in ->bi_sector, if * it supports it. For non-stacked drivers, this should be copied - * from rq->sector. + * from blk_rq_pos(rq). */ if (error_sector) *error_sector = bio->bi_sector; diff --git a/block/blk-core.c b/block/blk-core.c index 895e55b..82dc206 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -72,7 +72,7 @@ static void drive_stat_acct(struct request *rq, int new_io) return; cpu = part_stat_lock(); - part = disk_map_sector_rcu(rq->rq_disk, rq->sector); + part = disk_map_sector_rcu(rq->rq_disk, blk_rq_pos(rq)); if (!new_io) part_stat_inc(cpu, part, merges[rw]); @@ -185,10 +185,9 @@ void blk_dump_rq_flags(struct request *rq, char *msg) rq->rq_disk ? rq->rq_disk->disk_name : "?", rq->cmd_type, rq->cmd_flags); - printk(KERN_INFO " sector %llu, nr/cnr %lu/%u\n", - (unsigned long long)rq->sector, - rq->nr_sectors, - rq->current_nr_sectors); + printk(KERN_INFO " sector %llu, nr/cnr %u/%u\n", + (unsigned long long)blk_rq_pos(rq), + blk_rq_sectors(rq), blk_rq_cur_sectors(rq)); printk(KERN_INFO " bio %p, biotail %p, buffer %p, len %u\n", rq->bio, rq->biotail, rq->buffer, rq->data_len); @@ -1557,7 +1556,7 @@ EXPORT_SYMBOL(submit_bio); */ int blk_rq_check_limits(struct request_queue *q, struct request *rq) { - if (rq->nr_sectors > q->max_sectors || + if (blk_rq_sectors(rq) > q->max_sectors || rq->data_len > q->max_hw_sectors << 9) { printk(KERN_ERR "%s: over max size limit.\n", __func__); return -EIO; @@ -1645,7 +1644,7 @@ static void blk_account_io_completion(struct request *req, unsigned int bytes) int cpu; cpu = part_stat_lock(); - part = disk_map_sector_rcu(req->rq_disk, req->sector); + part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req)); part_stat_add(cpu, part, sectors[rw], bytes >> 9); part_stat_unlock(); } @@ -1665,7 +1664,7 @@ static void blk_account_io_done(struct request *req) int cpu; cpu = part_stat_lock(); - part = disk_map_sector_rcu(req->rq_disk, req->sector); + part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req)); part_stat_inc(cpu, part, ios[rw]); part_stat_add(cpu, part, ticks[rw], duration); @@ -1846,7 +1845,7 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes) if (error && (blk_fs_request(req) && !(req->cmd_flags & REQ_QUIET))) { printk(KERN_ERR "end_request: I/O error, dev %s, sector %llu\n", req->rq_disk ? req->rq_disk->disk_name : "?", - (unsigned long long)req->sector); + (unsigned long long)blk_rq_pos(req)); } blk_account_io_completion(req, nr_bytes); diff --git a/block/blk-merge.c b/block/blk-merge.c index 23d2a6f..bf62a87 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -259,7 +259,7 @@ int ll_back_merge_fn(struct request_queue *q, struct request *req, else max_sectors = q->max_sectors; - if (req->nr_sectors + bio_sectors(bio) > max_sectors) { + if (blk_rq_sectors(req) + bio_sectors(bio) > max_sectors) { req->cmd_flags |= REQ_NOMERGE; if (req == q->last_merge) q->last_merge = NULL; @@ -284,7 +284,7 @@ int ll_front_merge_fn(struct request_queue *q, struct request *req, max_sectors = q->max_sectors; - if (req->nr_sectors + bio_sectors(bio) > max_sectors) { + if (blk_rq_sectors(req) + bio_sectors(bio) > max_sectors) { req->cmd_flags |= REQ_NOMERGE; if (req == q->last_merge) q->last_merge = NULL; @@ -315,7 +315,7 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req, /* * Will it become too large? */ - if ((req->nr_sectors + next->nr_sectors) > q->max_sectors) + if ((blk_rq_sectors(req) + blk_rq_sectors(next)) > q->max_sectors) return 0; total_phys_segments = req->nr_phys_segments + next->nr_phys_segments; @@ -345,7 +345,7 @@ static void blk_account_io_merge(struct request *req) int cpu; cpu = part_stat_lock(); - part = disk_map_sector_rcu(req->rq_disk, req->sector); + part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req)); part_round_stats(cpu, part); part_dec_in_flight(part); @@ -366,7 +366,7 @@ static int attempt_merge(struct request_queue *q, struct request *req, /* * not contiguous */ - if (req->sector + req->nr_sectors != next->sector) + if (blk_rq_pos(req) + blk_rq_sectors(req) != blk_rq_pos(next)) return 0; if (rq_data_dir(req) != rq_data_dir(next) diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 575083a..db4d990 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -349,8 +349,8 @@ cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2) else if (rq_is_meta(rq2) && !rq_is_meta(rq1)) return rq2; - s1 = rq1->sector; - s2 = rq2->sector; + s1 = blk_rq_pos(rq1); + s2 = blk_rq_pos(rq2); last = cfqd->last_position; @@ -949,10 +949,10 @@ static struct cfq_queue *cfq_set_active_queue(struct cfq_data *cfqd, static inline sector_t cfq_dist_from_last(struct cfq_data *cfqd, struct request *rq) { - if (rq->sector >= cfqd->last_position) - return rq->sector - cfqd->last_position; + if (blk_rq_pos(rq) >= cfqd->last_position) + return blk_rq_pos(rq) - cfqd->last_position; else - return cfqd->last_position - rq->sector; + return cfqd->last_position - blk_rq_pos(rq); } #define CIC_SEEK_THR 8 * 1024 @@ -1918,10 +1918,10 @@ cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_io_context *cic, if (!cic->last_request_pos) sdist = 0; - else if (cic->last_request_pos < rq->sector) - sdist = rq->sector - cic->last_request_pos; + else if (cic->last_request_pos < blk_rq_pos(rq)) + sdist = blk_rq_pos(rq) - cic->last_request_pos; else - sdist = cic->last_request_pos - rq->sector; + sdist = cic->last_request_pos - blk_rq_pos(rq); /* * Don't allow the seek distance to get too large from the @@ -2071,7 +2071,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, cfq_update_io_seektime(cfqd, cic, rq); cfq_update_idle_window(cfqd, cfqq, cic); - cic->last_request_pos = rq->sector + rq->nr_sectors; + cic->last_request_pos = blk_rq_pos(rq) + blk_rq_sectors(rq); if (cfqq == cfqd->active_queue) { /* diff --git a/block/deadline-iosched.c b/block/deadline-iosched.c index c4d991d..b547cbc 100644 --- a/block/deadline-iosched.c +++ b/block/deadline-iosched.c @@ -138,7 +138,7 @@ deadline_merge(struct request_queue *q, struct request **req, struct bio *bio) __rq = elv_rb_find(&dd->sort_list[bio_data_dir(bio)], sector); if (__rq) { - BUG_ON(sector != __rq->sector); + BUG_ON(sector != blk_rq_pos(__rq)); if (elv_rq_merge_ok(__rq, bio)) { ret = ELEVATOR_FRONT_MERGE; diff --git a/block/elevator.c b/block/elevator.c index 1af5d9f..9189200 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -52,7 +52,7 @@ static const int elv_hash_shift = 6; #define ELV_HASH_FN(sec) \ (hash_long(ELV_HASH_BLOCK((sec)), elv_hash_shift)) #define ELV_HASH_ENTRIES (1 << elv_hash_shift) -#define rq_hash_key(rq) ((rq)->sector + (rq)->nr_sectors) +#define rq_hash_key(rq) (blk_rq_pos(rq) + blk_rq_sectors(rq)) DEFINE_TRACE(block_rq_insert); DEFINE_TRACE(block_rq_issue); @@ -119,9 +119,9 @@ static inline int elv_try_merge(struct request *__rq, struct bio *bio) * we can merge and sequence is ok, check if it's possible */ if (elv_rq_merge_ok(__rq, bio)) { - if (__rq->sector + __rq->nr_sectors == bio->bi_sector) + if (blk_rq_pos(__rq) + blk_rq_sectors(__rq) == bio->bi_sector) ret = ELEVATOR_BACK_MERGE; - else if (__rq->sector - bio_sectors(bio) == bio->bi_sector) + else if (blk_rq_pos(__rq) - bio_sectors(bio) == bio->bi_sector) ret = ELEVATOR_FRONT_MERGE; } @@ -370,9 +370,9 @@ struct request *elv_rb_add(struct rb_root *root, struct request *rq) parent = *p; __rq = rb_entry(parent, struct request, rb_node); - if (rq->sector < __rq->sector) + if (blk_rq_pos(rq) < blk_rq_pos(__rq)) p = &(*p)->rb_left; - else if (rq->sector > __rq->sector) + else if (blk_rq_pos(rq) > blk_rq_pos(__rq)) p = &(*p)->rb_right; else return __rq; @@ -400,9 +400,9 @@ struct request *elv_rb_find(struct rb_root *root, sector_t sector) while (n) { rq = rb_entry(n, struct request, rb_node); - if (sector < rq->sector) + if (sector < blk_rq_pos(rq)) n = n->rb_left; - else if (sector > rq->sector) + else if (sector > blk_rq_pos(rq)) n = n->rb_right; else return rq; @@ -441,14 +441,14 @@ void elv_dispatch_sort(struct request_queue *q, struct request *rq) break; if (pos->cmd_flags & stop_flags) break; - if (rq->sector >= boundary) { - if (pos->sector < boundary) + if (blk_rq_pos(rq) >= boundary) { + if (blk_rq_pos(pos) < boundary) continue; } else { - if (pos->sector >= boundary) + if (blk_rq_pos(pos) >= boundary) break; } - if (rq->sector >= pos->sector) + if (blk_rq_pos(rq) >= blk_rq_pos(pos)) break; } diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index f22ed6c..774ab05 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -3338,8 +3338,8 @@ static int DAC960_process_queue(DAC960_Controller_T *Controller, struct request_ } Command->Completion = Request->end_io_data; Command->LogicalDriveNumber = (long)Request->rq_disk->private_data; - Command->BlockNumber = Request->sector; - Command->BlockCount = Request->nr_sectors; + Command->BlockNumber = blk_rq_pos(Request); + Command->BlockCount = blk_rq_sectors(Request); Command->Request = Request; blkdev_dequeue_request(Request); Command->SegmentCount = blk_rq_map_sg(req_q, @@ -3431,7 +3431,7 @@ static void DAC960_queue_partial_rw(DAC960_Command_T *Command) * successfully as possible. */ Command->SegmentCount = 1; - Command->BlockNumber = Request->sector; + Command->BlockNumber = blk_rq_pos(Request); Command->BlockCount = 1; DAC960_QueueReadWriteCommand(Command); return; diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 8ff95f2..e4a14b9 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -1351,13 +1351,13 @@ static void redo_fd_request(void) drive = floppy - unit; /* Here someone could investigate to be more efficient */ - for (cnt = 0; cnt < CURRENT->current_nr_sectors; cnt++) { + for (cnt = 0; cnt < blk_rq_cur_sectors(CURRENT); cnt++) { #ifdef DEBUG printk("fd: sector %ld + %d requested for %s\n", - CURRENT->sector,cnt, + blk_rq_pos(CURRENT), cnt, (rq_data_dir(CURRENT) == READ) ? "read" : "write"); #endif - block = CURRENT->sector + cnt; + block = blk_rq_pos(CURRENT) + cnt; if ((int)block > floppy->blocks) { __blk_end_request_cur(CURRENT, -EIO); goto repeat; diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index 2506728..234024c 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -725,7 +725,7 @@ static void do_fd_action( int drive ) if (IS_BUFFERED( drive, ReqSide, ReqTrack )) { if (ReqCmd == READ) { copy_buffer( SECTOR_BUFFER(ReqSector), ReqData ); - if (++ReqCnt < CURRENT->current_nr_sectors) { + if (++ReqCnt < blk_rq_cur_sectors(CURRENT)) { /* read next sector */ setup_req_params( drive ); goto repeat; @@ -1130,7 +1130,7 @@ static void fd_rwsec_done1(int status) } } - if (++ReqCnt < CURRENT->current_nr_sectors) { + if (++ReqCnt < blk_rq_cur_sectors(CURRENT)) { /* read next sector */ setup_req_params( SelectedDrive ); do_fd_action( SelectedDrive ); @@ -1394,7 +1394,7 @@ static void redo_fd_request(void) DPRINT(("redo_fd_request: CURRENT=%p dev=%s CURRENT->sector=%ld\n", CURRENT, CURRENT ? CURRENT->rq_disk->disk_name : "", - CURRENT ? CURRENT->sector : 0 )); + CURRENT ? blk_rq_pos(CURRENT) : 0 )); IsFormatting = 0; @@ -1440,7 +1440,7 @@ repeat: UD.autoprobe = 0; } - if (CURRENT->sector + 1 > UDT->blocks) { + if (blk_rq_pos(CURRENT) + 1 > UDT->blocks) { __blk_end_request_cur(CURRENT, -EIO); goto repeat; } @@ -1450,7 +1450,7 @@ repeat: ReqCnt = 0; ReqCmd = rq_data_dir(CURRENT); - ReqBlock = CURRENT->sector; + ReqBlock = blk_rq_pos(CURRENT); ReqBuffer = CURRENT->buffer; setup_req_params( drive ); do_fd_action( drive ); diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index f22d493..ab7b04c 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -2835,10 +2835,10 @@ static void do_cciss_request(struct request_queue *q) c->Request.Timeout = 0; // Don't time out c->Request.CDB[0] = (rq_data_dir(creq) == READ) ? h->cciss_read : h->cciss_write; - start_blk = creq->sector; + start_blk = blk_rq_pos(creq); #ifdef CCISS_DEBUG - printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n", (int)creq->sector, - (int)creq->nr_sectors); + printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n", + (int)blk_rq_pos(creq), (int)blk_rq_sectors(creq)); #endif /* CCISS_DEBUG */ sg_init_table(tmp_sg, MAXSGENTRIES); @@ -2864,8 +2864,8 @@ static void do_cciss_request(struct request_queue *q) h->maxSG = seg; #ifdef CCISS_DEBUG - printk(KERN_DEBUG "cciss: Submitting %lu sectors in %d segments\n", - creq->nr_sectors, seg); + printk(KERN_DEBUG "cciss: Submitting %u sectors in %d segments\n", + blk_rq_sectors(creq), seg); #endif /* CCISS_DEBUG */ c->Header.SGList = c->Header.SGTotal = seg; @@ -2877,8 +2877,8 @@ static void do_cciss_request(struct request_queue *q) c->Request.CDB[4] = (start_blk >> 8) & 0xff; c->Request.CDB[5] = start_blk & 0xff; c->Request.CDB[6] = 0; // (sect >> 24) & 0xff; MSB - c->Request.CDB[7] = (creq->nr_sectors >> 8) & 0xff; - c->Request.CDB[8] = creq->nr_sectors & 0xff; + c->Request.CDB[7] = (blk_rq_sectors(creq) >> 8) & 0xff; + c->Request.CDB[8] = blk_rq_sectors(creq) & 0xff; c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0; } else { u32 upper32 = upper_32_bits(start_blk); @@ -2893,10 +2893,10 @@ static void do_cciss_request(struct request_queue *q) c->Request.CDB[7]= (start_blk >> 16) & 0xff; c->Request.CDB[8]= (start_blk >> 8) & 0xff; c->Request.CDB[9]= start_blk & 0xff; - c->Request.CDB[10]= (creq->nr_sectors >> 24) & 0xff; - c->Request.CDB[11]= (creq->nr_sectors >> 16) & 0xff; - c->Request.CDB[12]= (creq->nr_sectors >> 8) & 0xff; - c->Request.CDB[13]= creq->nr_sectors & 0xff; + c->Request.CDB[10]= (blk_rq_sectors(creq) >> 24) & 0xff; + c->Request.CDB[11]= (blk_rq_sectors(creq) >> 16) & 0xff; + c->Request.CDB[12]= (blk_rq_sectors(creq) >> 8) & 0xff; + c->Request.CDB[13]= blk_rq_sectors(creq) & 0xff; c->Request.CDB[14] = c->Request.CDB[15] = 0; } } else if (blk_pc_request(creq)) { diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index 488a8f4..a5caeff 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -919,10 +919,11 @@ queue_next: c->hdr.size = sizeof(rblk_t) >> 2; c->size += sizeof(rblk_t); - c->req.hdr.blk = creq->sector; + c->req.hdr.blk = blk_rq_pos(creq); c->rq = creq; DBGPX( - printk("sector=%d, nr_sectors=%d\n", creq->sector, creq->nr_sectors); + printk("sector=%d, nr_sectors=%u\n", + blk_rq_pos(creq), blk_rq_sectors(creq)); ); sg_init_table(tmp_sg, SG_MAX); seg = blk_rq_map_sg(q, creq, tmp_sg); @@ -940,9 +941,9 @@ DBGPX( tmp_sg[i].offset, tmp_sg[i].length, dir); } -DBGPX( printk("Submitting %d sectors in %d segments\n", creq->nr_sectors, seg); ); +DBGPX( printk("Submitting %u sectors in %d segments\n", blk_rq_sectors(creq), seg); ); c->req.hdr.sg_cnt = seg; - c->req.hdr.blk_cnt = creq->nr_sectors; + c->req.hdr.blk_cnt = blk_rq_sectors(creq); c->req.hdr.cmd = (rq_data_dir(creq) == READ) ? IDA_READ : IDA_WRITE; c->type = CMD_RWREQ; diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 1300df6..4524862 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -2303,7 +2303,7 @@ static void floppy_end_request(struct request *req, int error) /* current_count_sectors can be zero if transfer failed */ if (error) - nr_sectors = req->current_nr_sectors; + nr_sectors = blk_rq_cur_sectors(req); if (__blk_end_request(req, error, nr_sectors << 9)) return; @@ -2332,7 +2332,7 @@ static void request_done(int uptodate) if (uptodate) { /* maintain values for invalidation on geometry * change */ - block = current_count_sectors + req->sector; + block = current_count_sectors + blk_rq_pos(req); INFBOUND(DRS->maxblock, block); if (block > _floppy->sect) DRS->maxtrack = 1; @@ -2346,10 +2346,10 @@ static void request_done(int uptodate) /* record write error information */ DRWE->write_errors++; if (DRWE->write_errors == 1) { - DRWE->first_error_sector = req->sector; + DRWE->first_error_sector = blk_rq_pos(req); DRWE->first_error_generation = DRS->generation; } - DRWE->last_error_sector = req->sector; + DRWE->last_error_sector = blk_rq_pos(req); DRWE->last_error_generation = DRS->generation; } spin_lock_irqsave(q->queue_lock, flags); @@ -2503,24 +2503,24 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2) max_sector = transfer_size(ssize, min(max_sector, max_sector_2), - current_req->nr_sectors); + blk_rq_sectors(current_req)); if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE && - buffer_max > fsector_t + current_req->nr_sectors) + buffer_max > fsector_t + blk_rq_sectors(current_req)) current_count_sectors = min_t(int, buffer_max - fsector_t, - current_req->nr_sectors); + blk_rq_sectors(current_req)); remaining = current_count_sectors << 9; #ifdef FLOPPY_SANITY_CHECK - if ((remaining >> 9) > current_req->nr_sectors && + if ((remaining >> 9) > blk_rq_sectors(current_req) && CT(COMMAND) == FD_WRITE) { DPRINT("in copy buffer\n"); printk("current_count_sectors=%ld\n", current_count_sectors); printk("remaining=%d\n", remaining >> 9); - printk("current_req->nr_sectors=%ld\n", - current_req->nr_sectors); + printk("current_req->nr_sectors=%u\n", + blk_rq_sectors(current_req)); printk("current_req->current_nr_sectors=%u\n", - current_req->current_nr_sectors); + blk_rq_cur_sectors(current_req)); printk("max_sector=%d\n", max_sector); printk("ssize=%d\n", ssize); } @@ -2530,7 +2530,7 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2) dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9); - size = current_req->current_nr_sectors << 9; + size = blk_rq_cur_sectors(current_req) << 9; rq_for_each_segment(bv, current_req, iter) { if (!remaining) @@ -2648,10 +2648,10 @@ static int make_raw_rw_request(void) max_sector = _floppy->sect * _floppy->head; - TRACK = (int)current_req->sector / max_sector; - fsector_t = (int)current_req->sector % max_sector; + TRACK = (int)blk_rq_pos(current_req) / max_sector; + fsector_t = (int)blk_rq_pos(current_req) % max_sector; if (_floppy->track && TRACK >= _floppy->track) { - if (current_req->current_nr_sectors & 1) { + if (blk_rq_cur_sectors(current_req) & 1) { current_count_sectors = 1; return 1; } else @@ -2669,7 +2669,7 @@ static int make_raw_rw_request(void) if (fsector_t >= max_sector) { current_count_sectors = min_t(int, _floppy->sect - fsector_t, - current_req->nr_sectors); + blk_rq_sectors(current_req)); return 1; } SIZECODE = 2; @@ -2720,7 +2720,7 @@ static int make_raw_rw_request(void) in_sector_offset = (fsector_t % _floppy->sect) % ssize; aligned_sector_t = fsector_t - in_sector_offset; - max_size = current_req->nr_sectors; + max_size = blk_rq_sectors(current_req); if ((raw_cmd->track == buffer_track) && (current_drive == buffer_drive) && (fsector_t >= buffer_min) && (fsector_t < buffer_max)) { @@ -2729,10 +2729,10 @@ static int make_raw_rw_request(void) copy_buffer(1, max_sector, buffer_max); return 1; } - } else if (in_sector_offset || current_req->nr_sectors < ssize) { + } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) { if (CT(COMMAND) == FD_WRITE) { - if (fsector_t + current_req->nr_sectors > ssize && - fsector_t + current_req->nr_sectors < ssize + ssize) + if (fsector_t + blk_rq_sectors(current_req) > ssize && + fsector_t + blk_rq_sectors(current_req) < ssize + ssize) max_size = ssize + ssize; else max_size = ssize; @@ -2776,7 +2776,7 @@ static int make_raw_rw_request(void) (indirect * 2 > direct * 3 && *errors < DP->max_errors.read_track && ((!probing || (DP->read_track & (1 << DRS->probed_format)))))) { - max_size = current_req->nr_sectors; + max_size = blk_rq_sectors(current_req); } else { raw_cmd->kernel_data = current_req->buffer; raw_cmd->length = current_count_sectors << 9; @@ -2801,7 +2801,7 @@ static int make_raw_rw_request(void) fsector_t > buffer_max || fsector_t < buffer_min || ((CT(COMMAND) == FD_READ || - (!in_sector_offset && current_req->nr_sectors >= ssize)) && + (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) && max_sector > 2 * max_buffer_sectors + buffer_min && max_size + fsector_t > 2 * max_buffer_sectors + buffer_min) /* not enough space */ @@ -2879,8 +2879,8 @@ static int make_raw_rw_request(void) printk("write\n"); return 0; } - } else if (raw_cmd->length > current_req->nr_sectors << 9 || - current_count_sectors > current_req->nr_sectors) { + } else if (raw_cmd->length > blk_rq_sectors(current_req) << 9 || + current_count_sectors > blk_rq_sectors(current_req)) { DPRINT("buffer overrun in direct transfer\n"); return 0; } else if (raw_cmd->length < current_count_sectors << 9) { @@ -2990,8 +2990,9 @@ static void do_fd_request(struct request_queue * q) if (usage_count == 0) { printk("warning: usage count=0, current_req=%p exiting\n", current_req); - printk("sect=%ld type=%x flags=%x\n", (long)current_req->sector, - current_req->cmd_type, current_req->cmd_flags); + printk("sect=%ld type=%x flags=%x\n", + (long)blk_rq_pos(current_req), current_req->cmd_type, + current_req->cmd_flags); return; } if (test_bit(0, &fdc_busy)) { diff --git a/drivers/block/hd.c b/drivers/block/hd.c index 75b9ca9..a3b3994 100644 --- a/drivers/block/hd.c +++ b/drivers/block/hd.c @@ -228,7 +228,7 @@ static void dump_status(const char *msg, unsigned int stat) printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL), inb(HD_CURRENT) & 0xf, inb(HD_SECTOR)); if (CURRENT) - printk(", sector=%ld", CURRENT->sector); + printk(", sector=%ld", blk_rq_pos(CURRENT)); } printk("\n"); } @@ -457,9 +457,9 @@ ok_to_read: req = CURRENT; insw(HD_DATA, req->buffer, 256); #ifdef DEBUG - printk("%s: read: sector %ld, remaining = %ld, buffer=%p\n", - req->rq_disk->disk_name, req->sector + 1, req->nr_sectors - 1, - req->buffer+512); + printk("%s: read: sector %ld, remaining = %u, buffer=%p\n", + req->rq_disk->disk_name, blk_rq_pos(req) + 1, + blk_rq_sectors(req) - 1, req->buffer+512); #endif if (__blk_end_request(req, 0, 512)) { SET_HANDLER(&read_intr); @@ -485,7 +485,7 @@ static void write_intr(void) continue; if (!OK_STATUS(i)) break; - if ((req->nr_sectors <= 1) || (i & DRQ_STAT)) + if ((blk_rq_sectors(req) <= 1) || (i & DRQ_STAT)) goto ok_to_write; } while (--retries > 0); dump_status("write_intr", i); @@ -589,8 +589,8 @@ repeat: return; } disk = req->rq_disk->private_data; - block = req->sector; - nsect = req->nr_sectors; + block = blk_rq_pos(req); + nsect = blk_rq_sectors(req); if (block >= get_capacity(req->rq_disk) || ((block+nsect) > get_capacity(req->rq_disk))) { printk("%s: bad access: block=%d, count=%d\n", diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index 71e56cc..826c349 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c @@ -220,7 +220,8 @@ static void mg_dump_status(const char *msg, unsigned int stat, if (host->breq) { req = elv_next_request(host->breq); if (req) - printk(", sector=%u", (u32)req->sector); + printk(", sector=%u", + (unsigned int)blk_rq_pos(req)); } } @@ -493,12 +494,12 @@ static void mg_read(struct request *req) u32 j; struct mg_host *host = req->rq_disk->private_data; - if (mg_out(host, req->sector, req->nr_sectors, MG_CMD_RD, NULL) != - MG_ERR_NONE) + if (mg_out(host, blk_rq_pos(req), blk_rq_sectors(req), + MG_CMD_RD, NULL) != MG_ERR_NONE) mg_bad_rw_intr(host); MG_DBG("requested %d sects (from %ld), buffer=0x%p\n", - req->nr_sectors, req->sector, req->buffer); + blk_rq_sectors(req), blk_rq_pos(req), req->buffer); do { u16 *buff = (u16 *)req->buffer; @@ -522,14 +523,14 @@ static void mg_write(struct request *req) u32 j; struct mg_host *host = req->rq_disk->private_data; - if (mg_out(host, req->sector, req->nr_sectors, MG_CMD_WR, NULL) != - MG_ERR_NONE) { + if (mg_out(host, blk_rq_pos(req), blk_rq_sectors(req), + MG_CMD_WR, NULL) != MG_ERR_NONE) { mg_bad_rw_intr(host); return; } MG_DBG("requested %d sects (from %ld), buffer=0x%p\n", - req->nr_sectors, req->sector, req->buffer); + blk_rq_sectors(req), blk_rq_pos(req), req->buffer); do { u16 *buff = (u16 *)req->buffer; @@ -579,7 +580,7 @@ ok_to_read: (i << 1)); MG_DBG("sector %ld, remaining=%ld, buffer=0x%p\n", - req->sector, req->nr_sectors - 1, req->buffer); + blk_rq_pos(req), blk_rq_sectors(req) - 1, req->buffer); /* send read confirm */ outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND); @@ -609,7 +610,7 @@ static void mg_write_intr(struct mg_host *host) break; if (!MG_READY_OK(i)) break; - if ((req->nr_sectors <= 1) || (i & ATA_DRQ)) + if ((blk_rq_sectors(req) <= 1) || (i & ATA_DRQ)) goto ok_to_write; } while (0); mg_dump_status("mg_write_intr", i, host); @@ -627,7 +628,7 @@ ok_to_write: buff++; } MG_DBG("sector %ld, remaining=%ld, buffer=0x%p\n", - req->sector, req->nr_sectors, req->buffer); + blk_rq_pos(req), blk_rq_sectors(req), req->buffer); host->mg_do_intr = mg_write_intr; mod_timer(&host->timer, jiffies + 3 * HZ); } @@ -749,9 +750,9 @@ static void mg_request(struct request_queue *q) del_timer(&host->timer); - sect_num = req->sector; + sect_num = blk_rq_pos(req); /* deal whole segments */ - sect_cnt = req->nr_sectors; + sect_cnt = blk_rq_sectors(req); /* sanity check */ if (sect_num >= get_capacity(req->rq_disk) || diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index a9ab8be..977a573 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -110,7 +110,7 @@ static void nbd_end_request(struct request *req) req, error ? "failed" : "done"); spin_lock_irqsave(q->queue_lock, flags); - __blk_end_request(req, error, req->nr_sectors << 9); + __blk_end_request(req, error, blk_rq_sectors(req) << 9); spin_unlock_irqrestore(q->queue_lock, flags); } @@ -231,19 +231,19 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req) { int result, flags; struct nbd_request request; - unsigned long size = req->nr_sectors << 9; + unsigned long size = blk_rq_sectors(req) << 9; request.magic = htonl(NBD_REQUEST_MAGIC); request.type = htonl(nbd_cmd(req)); - request.from = cpu_to_be64((u64) req->sector << 9); + request.from = cpu_to_be64((u64)blk_rq_pos(req) << 9); request.len = htonl(size); memcpy(request.handle, &req, sizeof(req)); - dprintk(DBG_TX, "%s: request %p: sending control (%s@%llu,%luB)\n", + dprintk(DBG_TX, "%s: request %p: sending control (%s@%llu,%uB)\n", lo->disk->disk_name, req, nbdcmd_to_ascii(nbd_cmd(req)), - (unsigned long long)req->sector << 9, - req->nr_sectors << 9); + (unsigned long long)blk_rq_pos(req) << 9, + blk_rq_sectors(req) << 9); result = sock_xmit(lo, 1, &request, sizeof(request), (nbd_cmd(req) == NBD_CMD_WRITE) ? MSG_MORE : 0); if (result <= 0) { diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c index 9fd57c2..2d5dc0a 100644 --- a/drivers/block/paride/pcd.c +++ b/drivers/block/paride/pcd.c @@ -728,8 +728,8 @@ static void do_pcd_request(struct request_queue * q) if (cd != pcd_current) pcd_bufblk = -1; pcd_current = cd; - pcd_sector = pcd_req->sector; - pcd_count = pcd_req->current_nr_sectors; + pcd_sector = blk_rq_pos(pcd_req); + pcd_count = blk_rq_cur_sectors(pcd_req); pcd_buf = pcd_req->buffer; pcd_busy = 1; ps_set_intr(do_pcd_read, NULL, 0, nice); diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 0732df4..9ec5d4a 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -444,11 +444,11 @@ static enum action do_pd_io_start(void) pd_cmd = rq_data_dir(pd_req); if (pd_cmd == READ || pd_cmd == WRITE) { - pd_block = pd_req->sector; - pd_count = pd_req->current_nr_sectors; + pd_block = blk_rq_pos(pd_req); + pd_count = blk_rq_cur_sectors(pd_req); if (pd_block + pd_count > get_capacity(pd_req->rq_disk)) return Fail; - pd_run = pd_req->nr_sectors; + pd_run = blk_rq_sectors(pd_req); pd_buf = pd_req->buffer; pd_retries = 0; if (pd_cmd == READ) @@ -479,7 +479,7 @@ static int pd_next_buf(void) return 0; spin_lock_irqsave(&pd_lock, saved_flags); __blk_end_request_cur(pd_req, 0); - pd_count = pd_req->current_nr_sectors; + pd_count = blk_rq_cur_sectors(pd_req); pd_buf = pd_req->buffer; spin_unlock_irqrestore(&pd_lock, saved_flags); return 0; diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index 3871e35..e88c889 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -768,9 +768,9 @@ repeat: return; pf_current = pf_req->rq_disk->private_data; - pf_block = pf_req->sector; - pf_run = pf_req->nr_sectors; - pf_count = pf_req->current_nr_sectors; + pf_block = blk_rq_pos(pf_req); + pf_run = blk_rq_sectors(pf_req); + pf_count = blk_rq_cur_sectors(pf_req); if (pf_block + pf_count > get_capacity(pf_req->rq_disk)) { pf_end_request(-EIO); @@ -810,7 +810,7 @@ static int pf_next_buf(void) spin_unlock_irqrestore(&pf_spin_lock, saved_flags); if (!pf_req) return 1; - pf_count = pf_req->current_nr_sectors; + pf_count = blk_rq_cur_sectors(pf_req); pf_buf = pf_req->buffer; } return 0; diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index c238867..8d58308 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -134,13 +134,12 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev, rq_for_each_segment(bv, req, iter) n++; dev_dbg(&dev->sbd.core, - "%s:%u: %s req has %u bvecs for %lu sectors %lu hard sectors\n", - __func__, __LINE__, op, n, req->nr_sectors, - blk_rq_sectors(req)); + "%s:%u: %s req has %u bvecs for %u sectors\n", + __func__, __LINE__, op, n, blk_rq_sectors(req)); #endif - start_sector = req->sector * priv->blocking_factor; - sectors = req->nr_sectors * priv->blocking_factor; + start_sector = blk_rq_pos(req) * priv->blocking_factor; + sectors = blk_rq_sectors(req) * priv->blocking_factor; dev_dbg(&dev->sbd.core, "%s:%u: %s %llu sectors starting at %llu\n", __func__, __LINE__, op, sectors, start_sector); diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c index f59887c..9f351bf 100644 --- a/drivers/block/sunvdc.c +++ b/drivers/block/sunvdc.c @@ -416,7 +416,7 @@ static int __send_request(struct request *req) desc->slice = 0; } desc->status = ~0; - desc->offset = (req->sector << 9) / port->vdisk_block_size; + desc->offset = (blk_rq_pos(req) << 9) / port->vdisk_block_size; desc->size = len; desc->ncookies = err; diff --git a/drivers/block/swim.c b/drivers/block/swim.c index 97ef426..fc6a1c3 100644 --- a/drivers/block/swim.c +++ b/drivers/block/swim.c @@ -531,7 +531,7 @@ static void redo_fd_request(struct request_queue *q) while ((req = elv_next_request(q))) { fs = req->rq_disk->private_data; - if (req->sector < 0 || req->sector >= fs->total_secs) { + if (blk_rq_pos(req) >= fs->total_secs) { __blk_end_request_cur(req, -EIO); continue; } @@ -551,8 +551,8 @@ static void redo_fd_request(struct request_queue *q) __blk_end_request_cur(req, -EIO); break; case READ: - if (floppy_read_sectors(fs, req->sector, - req->current_nr_sectors, + if (floppy_read_sectors(fs, blk_rq_pos(req), + blk_rq_cur_sectors(req), req->buffer)) { __blk_end_request_cur(req, -EIO); continue; diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index 4248559..c1b9a4d 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -312,14 +312,14 @@ static void start_request(struct floppy_state *fs) } while (fs->state == idle && (req = elv_next_request(swim3_queue))) { #if 0 - printk("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%ld buf=%p\n", + printk("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%u buf=%p\n", req->rq_disk->disk_name, req->cmd, - (long)req->sector, req->nr_sectors, req->buffer); - printk(" errors=%d current_nr_sectors=%ld\n", - req->errors, req->current_nr_sectors); + (long)blk_rq_pos(req), blk_rq_sectors(req), req->buffer); + printk(" errors=%d current_nr_sectors=%u\n", + req->errors, blk_rq_cur_sectors(req)); #endif - if (req->sector >= fs->total_secs) { + if (blk_rq_pos(req) >= fs->total_secs) { __blk_end_request_cur(req, -EIO); continue; } @@ -337,13 +337,14 @@ static void start_request(struct floppy_state *fs) } } - /* Do not remove the cast. req->sector is now a sector_t and - * can be 64 bits, but it will never go past 32 bits for this - * driver anyway, so we can safely cast it down and not have - * to do a 64/32 division + /* Do not remove the cast. blk_rq_pos(req) is now a + * sector_t and can be 64 bits, but it will never go + * past 32 bits for this driver anyway, so we can + * safely cast it down and not have to do a 64/32 + * division */ - fs->req_cyl = ((long)req->sector) / fs->secpercyl; - x = ((long)req->sector) % fs->secpercyl; + fs->req_cyl = ((long)blk_rq_pos(req)) / fs->secpercyl; + x = ((long)blk_rq_pos(req)) % fs->secpercyl; fs->head = x / fs->secpertrack; fs->req_sector = x % fs->secpertrack + 1; fd_req = req; @@ -420,7 +421,7 @@ static inline void setup_transfer(struct floppy_state *fs) struct dbdma_cmd *cp = fs->dma_cmd; struct dbdma_regs __iomem *dr = fs->dma; - if (fd_req->current_nr_sectors <= 0) { + if (blk_rq_cur_sectors(fd_req) <= 0) { printk(KERN_ERR "swim3: transfer 0 sectors?\n"); return; } @@ -428,8 +429,8 @@ static inline void setup_transfer(struct floppy_state *fs) n = 1; else { n = fs->secpertrack - fs->req_sector + 1; - if (n > fd_req->current_nr_sectors) - n = fd_req->current_nr_sectors; + if (n > blk_rq_cur_sectors(fd_req)) + n = blk_rq_cur_sectors(fd_req); } fs->scount = n; swim3_select(fs, fs->head? READ_DATA_1: READ_DATA_0); @@ -600,7 +601,8 @@ static void xfer_timeout(unsigned long data) out_8(&sw->control_bic, WRITE_SECTORS | DO_ACTION); out_8(&sw->select, RELAX); printk(KERN_ERR "swim3: timeout %sing sector %ld\n", - (rq_data_dir(fd_req)==WRITE? "writ": "read"), (long)fd_req->sector); + (rq_data_dir(fd_req)==WRITE? "writ": "read"), + (long)blk_rq_pos(fd_req)); __blk_end_request_cur(fd_req, -EIO); fs->state = idle; start_request(fs); @@ -714,7 +716,7 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id) } else { printk("swim3: error %sing block %ld (err=%x)\n", rq_data_dir(fd_req) == WRITE? "writ": "read", - (long)fd_req->sector, err); + (long)blk_rq_pos(fd_req), err); __blk_end_request_cur(fd_req, -EIO); fs->state = idle; } diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index 60e85bb..087c94c 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -903,10 +903,10 @@ queue_one_request: msg->sg_count = n_elem; msg->sg_type = SGT_32BIT; msg->handle = cpu_to_le32(TAG_ENCODE(crq->tag)); - msg->lba = cpu_to_le32(rq->sector & 0xffffffff); - tmp = (rq->sector >> 16) >> 16; + msg->lba = cpu_to_le32(blk_rq_pos(rq) & 0xffffffff); + tmp = (blk_rq_pos(rq) >> 16) >> 16; msg->lba_high = cpu_to_le16( (u16) tmp ); - msg->lba_count = cpu_to_le16(rq->nr_sectors); + msg->lba_count = cpu_to_le16(blk_rq_sectors(rq)); msg_size = sizeof(struct carm_msg_rw) - sizeof(msg->sg); for (i = 0; i < n_elem; i++) { diff --git a/drivers/block/ub.c b/drivers/block/ub.c index 8c2cc71..dc3b899 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -726,8 +726,8 @@ static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun, * The call to blk_queue_hardsect_size() guarantees that request * is aligned, but it is given in terms of 512 byte units, always. */ - block = rq->sector >> lun->capacity.bshift; - nblks = rq->nr_sectors >> lun->capacity.bshift; + block = blk_rq_pos(rq) >> lun->capacity.bshift; + nblks = blk_rq_sectors(rq) >> lun->capacity.bshift; cmd->cdb[0] = (cmd->dir == UB_DIR_READ)? READ_10: WRITE_10; /* 10-byte uses 4 bytes of LBA: 2147483648KB, 2097152MB, 2048GB */ @@ -739,7 +739,7 @@ static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun, cmd->cdb[8] = nblks; cmd->cdb_len = 10; - cmd->len = rq->nr_sectors * 512; + cmd->len = blk_rq_sectors(rq) * 512; } static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun, diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index e821eed..2086cb1 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c @@ -252,7 +252,7 @@ static int send_request(struct request *req) struct viodasd_device *d; unsigned long flags; - start = (u64)req->sector << 9; + start = (u64)blk_rq_pos(req) << 9; if (rq_data_dir(req) == READ) { direction = DMA_FROM_DEVICE; diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 50745e6..1980ab4 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -85,7 +85,7 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk, vbr->req = req; if (blk_fs_request(vbr->req)) { vbr->out_hdr.type = 0; - vbr->out_hdr.sector = vbr->req->sector; + vbr->out_hdr.sector = blk_rq_pos(vbr->req); vbr->out_hdr.ioprio = req_get_ioprio(vbr->req); } else if (blk_pc_request(vbr->req)) { vbr->out_hdr.type = VIRTIO_BLK_T_SCSI_CMD; diff --git a/drivers/block/xd.c b/drivers/block/xd.c index 14be4c1..4ef8801 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -306,8 +306,8 @@ static void do_xd_request (struct request_queue * q) return; while ((req = elv_next_request(q)) != NULL) { - unsigned block = req->sector; - unsigned count = req->nr_sectors; + unsigned block = blk_rq_pos(req); + unsigned count = blk_rq_sectors(req); XD_INFO *disk = req->rq_disk->private_data; int res = 0; int retry; diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index b456447..91fc565 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -231,7 +231,7 @@ static int blkif_queue_request(struct request *req) info->shadow[id].request = (unsigned long)req; ring_req->id = id; - ring_req->sector_number = (blkif_sector_t)req->sector; + ring_req->sector_number = (blkif_sector_t)blk_rq_pos(req); ring_req->handle = info->handle; ring_req->operation = rq_data_dir(req) ? @@ -310,11 +310,10 @@ static void do_blkif_request(struct request_queue *rq) goto wait; pr_debug("do_blk_req %p: cmd %p, sec %lx, " - "(%u/%li) buffer:%p [%s]\n", - req, req->cmd, (unsigned long)req->sector, - req->current_nr_sectors, - req->nr_sectors, req->buffer, - rq_data_dir(req) ? "write" : "read"); + "(%u/%u) buffer:%p [%s]\n", + req, req->cmd, (unsigned long)blk_rq_pos(req), + blk_rq_cur_sectors(req), blk_rq_sectors(req), + req->buffer, rq_data_dir(req) ? "write" : "read"); blkdev_dequeue_request(req); diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 5722931..97c99b43 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -646,13 +646,14 @@ static void ace_fsm_dostate(struct ace_device *ace) /* Okay, it's a data request, set it up for transfer */ dev_dbg(ace->dev, "request: sec=%llx hcnt=%x, ccnt=%x, dir=%i\n", - (unsigned long long) req->sector, blk_rq_sectors(req), - req->current_nr_sectors, rq_data_dir(req)); + (unsigned long long)blk_rq_pos(req), + blk_rq_sectors(req), blk_rq_cur_sectors(req), + rq_data_dir(req)); ace->req = req; ace->data_ptr = req->buffer; - ace->data_count = req->current_nr_sectors * ACE_BUF_PER_SECTOR; - ace_out32(ace, ACE_MPULBA, req->sector & 0x0FFFFFFF); + ace->data_count = blk_rq_cur_sectors(req) * ACE_BUF_PER_SECTOR; + ace_out32(ace, ACE_MPULBA, blk_rq_pos(req) & 0x0FFFFFFF); count = blk_rq_sectors(req); if (rq_data_dir(req)) { @@ -688,7 +689,7 @@ static void ace_fsm_dostate(struct ace_device *ace) dev_dbg(ace->dev, "CFBSY set; t=%i iter=%i c=%i dc=%i irq=%i\n", ace->fsm_task, ace->fsm_iter_num, - ace->req->current_nr_sectors * 16, + blk_rq_cur_sectors(ace->req) * 16, ace->data_count, ace->in_irq); ace_fsm_yield(ace); /* need to poll CFBSY bit */ break; @@ -697,7 +698,7 @@ static void ace_fsm_dostate(struct ace_device *ace) dev_dbg(ace->dev, "DATABUF not set; t=%i iter=%i c=%i dc=%i irq=%i\n", ace->fsm_task, ace->fsm_iter_num, - ace->req->current_nr_sectors * 16, + blk_rq_cur_sectors(ace->req) * 16, ace->data_count, ace->in_irq); ace_fsm_yieldirq(ace); break; @@ -721,10 +722,10 @@ static void ace_fsm_dostate(struct ace_device *ace) blk_rq_cur_bytes(ace->req))) { /* dev_dbg(ace->dev, "next block; h=%u c=%u\n", * blk_rq_sectors(ace->req), - * ace->req->current_nr_sectors); + * blk_rq_cur_sectors(ace->req)); */ ace->data_ptr = ace->req->buffer; - ace->data_count = ace->req->current_nr_sectors * 16; + ace->data_count = blk_rq_cur_sectors(ace->req) * 16; ace_fsm_yieldirq(ace); break; } diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c index b66ad58..d4e6b71 100644 --- a/drivers/block/z2ram.c +++ b/drivers/block/z2ram.c @@ -71,12 +71,12 @@ static void do_z2_request(struct request_queue *q) { struct request *req; while ((req = elv_next_request(q)) != NULL) { - unsigned long start = req->sector << 9; - unsigned long len = req->current_nr_sectors << 9; + unsigned long start = blk_rq_pos(req) << 9; + unsigned long len = blk_rq_cur_sectors(req) << 9; if (start + len > z2ram_size) { printk( KERN_ERR DEVICE_NAME ": bad access: block=%lu, count=%u\n", - req->sector, req->current_nr_sectors); + blk_rq_pos(req), blk_rq_cur_sectors(req)); __blk_end_request_cur(req, -EIO); continue; } diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c index cab2b1f..488423c 100644 --- a/drivers/cdrom/gdrom.c +++ b/drivers/cdrom/gdrom.c @@ -584,8 +584,8 @@ static void gdrom_readdisk_dma(struct work_struct *work) list_for_each_safe(elem, next, &gdrom_deferred) { req = list_entry(elem, struct request, queuelist); spin_unlock(&gdrom_lock); - block = req->sector/GD_TO_BLK + GD_SESSION_OFFSET; - block_cnt = req->nr_sectors/GD_TO_BLK; + block = blk_rq_pos(req)/GD_TO_BLK + GD_SESSION_OFFSET; + block_cnt = blk_rq_sectors(req)/GD_TO_BLK; ctrl_outl(PHYSADDR(req->buffer), GDROM_DMA_STARTADDR_REG); ctrl_outl(block_cnt * GDROM_HARD_SECTOR, GDROM_DMA_LENGTH_REG); ctrl_outl(1, GDROM_DMA_DIRECTION_REG); @@ -661,7 +661,7 @@ static void gdrom_request(struct request_queue *rq) printk(" write request ignored\n"); __blk_end_request_cur(req, -EIO); } - if (req->nr_sectors) + if (blk_rq_sectors(req)) gdrom_request_handler_dma(req); else __blk_end_request_cur(req, -EIO); diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index cc3efa0..6e190a9 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -282,7 +282,7 @@ static int send_request(struct request *req) viopath_targetinst(viopath_hostLp), (u64)req, VIOVERSION << 16, ((u64)DEVICE_NR(diskinfo) << 48) | dmaaddr, - (u64)req->sector * 512, len, 0); + (u64)blk_rq_pos(req) * 512, len, 0); if (hvrc != HvLpEvent_Rc_Good) { printk(VIOCD_KERN_WARNING "hv error on op %d\n", (int)hvrc); return -1; diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index a416346..9e600d2 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -677,10 +677,10 @@ try_again: continue; } - t_sec = msb->block_req->sector << 9; + t_sec = blk_rq_pos(msb->block_req) << 9; sector_div(t_sec, msb->page_size); - count = msb->block_req->nr_sectors << 9; + count = blk_rq_sectors(msb->block_req) << 9; count /= msb->page_size; param.system = msb->system; @@ -745,7 +745,7 @@ static int mspro_block_complete_req(struct memstick_dev *card, int error) t_len *= msb->page_size; } } else - t_len = msb->block_req->nr_sectors << 9; + t_len = blk_rq_sectors(msb->block_req) << 9; dev_dbg(&card->dev, "transferred %x (%d)\n", t_len, error); diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index 56e60f0..510eb47 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -761,7 +761,7 @@ static int i2o_block_transfer(struct request *req) break; case CACHE_SMARTFETCH: - if (req->nr_sectors > 16) + if (blk_rq_sectors(req) > 16) ctl_flags = 0x201F0008; else ctl_flags = 0x001F0000; @@ -781,13 +781,13 @@ static int i2o_block_transfer(struct request *req) ctl_flags = 0x001F0010; break; case CACHE_SMARTBACK: - if (req->nr_sectors > 16) + if (blk_rq_sectors(req) > 16) ctl_flags = 0x001F0004; else ctl_flags = 0x001F0010; break; case CACHE_SMARTTHROUGH: - if (req->nr_sectors > 16) + if (blk_rq_sectors(req) > 16) ctl_flags = 0x001F0004; else ctl_flags = 0x001F0010; @@ -827,22 +827,24 @@ static int i2o_block_transfer(struct request *req) *mptr++ = cpu_to_le32(scsi_flags); - *((u32 *) & cmd[2]) = cpu_to_be32(req->sector * hwsec); - *((u16 *) & cmd[7]) = cpu_to_be16(req->nr_sectors * hwsec); + *((u32 *) & cmd[2]) = cpu_to_be32(blk_rq_pos(req) * hwsec); + *((u16 *) & cmd[7]) = cpu_to_be16(blk_rq_sectors(req) * hwsec); memcpy(mptr, cmd, 10); mptr += 4; - *mptr++ = cpu_to_le32(req->nr_sectors << KERNEL_SECTOR_SHIFT); + *mptr++ = + cpu_to_le32(blk_rq_sectors(req) << KERNEL_SECTOR_SHIFT); } else #endif { msg->u.head[1] = cpu_to_le32(cmd | HOST_TID << 12 | tid); *mptr++ = cpu_to_le32(ctl_flags); - *mptr++ = cpu_to_le32(req->nr_sectors << KERNEL_SECTOR_SHIFT); *mptr++ = - cpu_to_le32((u32) (req->sector << KERNEL_SECTOR_SHIFT)); + cpu_to_le32(blk_rq_sectors(req) << KERNEL_SECTOR_SHIFT); + *mptr++ = + cpu_to_le32((u32) (blk_rq_pos(req) << KERNEL_SECTOR_SHIFT)); *mptr++ = - cpu_to_le32(req->sector >> (32 - KERNEL_SECTOR_SHIFT)); + cpu_to_le32(blk_rq_pos(req) >> (32 - KERNEL_SECTOR_SHIFT)); } if (!i2o_block_sglist_alloc(c, ireq, &mptr)) { diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index fe8041e..949e997 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -243,7 +243,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) brq.mrq.cmd = &brq.cmd; brq.mrq.data = &brq.data; - brq.cmd.arg = req->sector; + brq.cmd.arg = blk_rq_pos(req); if (!mmc_card_blockaddr(card)) brq.cmd.arg <<= 9; brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; @@ -251,7 +251,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) brq.stop.opcode = MMC_STOP_TRANSMISSION; brq.stop.arg = 0; brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; - brq.data.blocks = req->nr_sectors; + brq.data.blocks = blk_rq_sectors(req); /* * After a read error, we redo the request one sector at a time @@ -293,7 +293,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) * Adjust the sg list so it is the same size as the * request. */ - if (brq.data.blocks != req->nr_sectors) { + if (brq.data.blocks != blk_rq_sectors(req)) { int i, data_size = brq.data.blocks << 9; struct scatterlist *sg; @@ -344,8 +344,8 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) printk(KERN_ERR "%s: error %d transferring data," " sector %u, nr %u, card status %#x\n", req->rq_disk->disk_name, brq.data.error, - (unsigned)req->sector, - (unsigned)req->nr_sectors, status); + (unsigned)blk_rq_pos(req), + (unsigned)blk_rq_sectors(req), status); } if (brq.stop.error) { diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 76c4c8d..4ea2e67 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -47,8 +47,8 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr, unsigned long block, nsect; char *buf; - block = req->sector << 9 >> tr->blkshift; - nsect = req->current_nr_sectors << 9 >> tr->blkshift; + block = blk_rq_pos(req) << 9 >> tr->blkshift; + nsect = blk_rq_cur_sectors(req) << 9 >> tr->blkshift; buf = req->buffer; @@ -59,7 +59,8 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr, if (!blk_fs_request(req)) return -EIO; - if (req->sector + req->current_nr_sectors > get_capacity(req->rq_disk)) + if (blk_rq_pos(req) + blk_rq_cur_sectors(req) > + get_capacity(req->rq_disk)) return -EIO; switch(rq_data_dir(req)) { diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index fabec95..7df03c7a 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -603,7 +603,7 @@ static void dasd_profile_end(struct dasd_block *block, if (dasd_profile_level != DASD_PROFILE_ON) return; - sectors = req->nr_sectors; + sectors = blk_rq_sectors(req); if (!cqr->buildclk || !cqr->startclk || !cqr->stopclk || !cqr->endclk || !sectors) diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index b9a7f77..2efaddf 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -505,8 +505,9 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev, return ERR_PTR(-EINVAL); blksize = block->bp_block; /* Calculate record id of first and last block. */ - first_rec = req->sector >> block->s2b_shift; - last_rec = (req->sector + req->nr_sectors - 1) >> block->s2b_shift; + first_rec = blk_rq_pos(req) >> block->s2b_shift; + last_rec = + (blk_rq_pos(req) + blk_rq_sectors(req) - 1) >> block->s2b_shift; /* Check struct bio and count the number of blocks for the request. */ count = 0; rq_for_each_segment(bv, req, iter) { diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index cb52da0..a41c940 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -2354,10 +2354,10 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, blksize = block->bp_block; blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize); /* Calculate record id of first and last block. */ - first_rec = first_trk = req->sector >> block->s2b_shift; + first_rec = first_trk = blk_rq_pos(req) >> block->s2b_shift; first_offs = sector_div(first_trk, blk_per_trk); last_rec = last_trk = - (req->sector + req->nr_sectors - 1) >> block->s2b_shift; + (blk_rq_pos(req) + blk_rq_sectors(req) - 1) >> block->s2b_shift; last_offs = sector_div(last_trk, blk_per_trk); cdlspecial = (private->uses_cdl && first_rec < 2*blk_per_trk); @@ -2420,7 +2420,7 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req) private = (struct dasd_eckd_private *) cqr->block->base->private; blksize = cqr->block->bp_block; blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize); - recid = req->sector >> cqr->block->s2b_shift; + recid = blk_rq_pos(req) >> cqr->block->s2b_shift; ccw = cqr->cpaddr; /* Skip over define extent & locate record. */ ccw++; diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index a3eb6fd..8912358 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -270,8 +270,9 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev, return ERR_PTR(-EINVAL); blksize = block->bp_block; /* Calculate record id of first and last block. */ - first_rec = req->sector >> block->s2b_shift; - last_rec = (req->sector + req->nr_sectors - 1) >> block->s2b_shift; + first_rec = blk_rq_pos(req) >> block->s2b_shift; + last_rec = + (blk_rq_pos(req) + blk_rq_sectors(req) - 1) >> block->s2b_shift; /* Check struct bio and count the number of blocks for the request. */ count = 0; cidaw = 0; @@ -309,7 +310,7 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev, ccw = cqr->cpaddr; /* First ccw is define extent. */ define_extent(ccw++, cqr->data, rq_data_dir(req), - block->bp_block, req->sector, req->nr_sectors); + block->bp_block, blk_rq_pos(req), blk_rq_sectors(req)); /* Build locate_record + read/write ccws. */ idaws = (unsigned long *) (cqr->data + sizeof(struct DE_fba_data)); LO_data = (struct LO_fba_data *) (idaws + cidaw); diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c index 5f8e8ef..2d00a38 100644 --- a/drivers/s390/char/tape_34xx.c +++ b/drivers/s390/char/tape_34xx.c @@ -1134,7 +1134,7 @@ tape_34xx_bread(struct tape_device *device, struct request *req) /* Setup ccws. */ request->op = TO_BLOCK; start_block = (struct tape_34xx_block_id *) request->cpdata; - start_block->block = req->sector >> TAPEBLOCK_HSEC_S2B; + start_block->block = blk_rq_pos(req) >> TAPEBLOCK_HSEC_S2B; DBF_EVENT(6, "start_block = %i\n", start_block->block); ccw = request->cpaddr; diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index 823b05b..c453b2f 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -633,7 +633,7 @@ tape_3590_bread(struct tape_device *device, struct request *req) struct req_iterator iter; DBF_EVENT(6, "xBREDid:"); - start_block = req->sector >> TAPEBLOCK_HSEC_S2B; + start_block = blk_rq_pos(req) >> TAPEBLOCK_HSEC_S2B; DBF_EVENT(6, "start_block = %i\n", start_block); rq_for_each_segment(bv, req, iter) diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index 86596d3..5d035e4 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -87,7 +87,7 @@ __tapeblock_end_request(struct tape_request *ccw_req, void *data) if (ccw_req->rc == 0) /* Update position. */ device->blk_data.block_position = - (req->sector + req->nr_sectors) >> TAPEBLOCK_HSEC_S2B; + (blk_rq_pos(req) + blk_rq_sectors(req)) >> TAPEBLOCK_HSEC_S2B; else /* We lost the position information due to an error. */ device->blk_data.block_position = -1; diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c index 0961788..2132c90 100644 --- a/drivers/sbus/char/jsflash.c +++ b/drivers/sbus/char/jsflash.c @@ -188,8 +188,8 @@ static void jsfd_do_request(struct request_queue *q) while ((req = elv_next_request(q)) != NULL) { struct jsfd_part *jdp = req->rq_disk->private_data; - unsigned long offset = req->sector << 9; - size_t len = req->current_nr_sectors << 9; + unsigned long offset = blk_rq_pos(req) << 9; + size_t len = blk_rq_cur_sectors(req) << 9; if ((offset + len) > jdp->dsize) { __blk_end_request_cur(req, -EIO); diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c index be5099d..c7076ce 100644 --- a/drivers/scsi/eata.c +++ b/drivers/scsi/eata.c @@ -1825,7 +1825,7 @@ static int eata2x_queuecommand(struct scsi_cmnd *SCpnt, if (linked_comm && SCpnt->device->queue_depth > 2 && TLDEV(SCpnt->device->type)) { ha->cp_stat[i] = READY; - flush_dev(SCpnt->device, SCpnt->request->sector, ha, 0); + flush_dev(SCpnt->device, blk_rq_pos(SCpnt->request), ha, 0); return 0; } @@ -2144,13 +2144,13 @@ static int reorder(struct hostdata *ha, unsigned long cursec, if (!cpp->din) input_only = 0; - if (SCpnt->request->sector < minsec) - minsec = SCpnt->request->sector; - if (SCpnt->request->sector > maxsec) - maxsec = SCpnt->request->sector; + if (blk_rq_pos(SCpnt->request) < minsec) + minsec = blk_rq_pos(SCpnt->request); + if (blk_rq_pos(SCpnt->request) > maxsec) + maxsec = blk_rq_pos(SCpnt->request); - sl[n] = SCpnt->request->sector; - ioseek += SCpnt->request->nr_sectors; + sl[n] = blk_rq_pos(SCpnt->request); + ioseek += blk_rq_sectors(SCpnt->request); if (!n) continue; @@ -2190,7 +2190,7 @@ static int reorder(struct hostdata *ha, unsigned long cursec, k = il[n]; cpp = &ha->cp[k]; SCpnt = cpp->SCpnt; - ll[n] = SCpnt->request->nr_sectors; + ll[n] = blk_rq_sectors(SCpnt->request); pl[n] = SCpnt->serial_number; if (!n) @@ -2236,12 +2236,12 @@ static int reorder(struct hostdata *ha, unsigned long cursec, cpp = &ha->cp[k]; SCpnt = cpp->SCpnt; scmd_printk(KERN_INFO, SCpnt, - "%s pid %ld mb %d fc %d nr %d sec %ld ns %ld" + "%s pid %ld mb %d fc %d nr %d sec %ld ns %u" " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n", (ihdlr ? "ihdlr" : "qcomm"), SCpnt->serial_number, k, flushcount, - n_ready, SCpnt->request->sector, - SCpnt->request->nr_sectors, cursec, YESNO(s), + n_ready, blk_rq_pos(SCpnt->request), + blk_rq_sectors(SCpnt->request), cursec, YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only), YESNO(overlap), cpp->din); } @@ -2408,7 +2408,7 @@ static irqreturn_t ihdlr(struct Scsi_Host *shost) if (linked_comm && SCpnt->device->queue_depth > 2 && TLDEV(SCpnt->device->type)) - flush_dev(SCpnt->device, SCpnt->request->sector, ha, 1); + flush_dev(SCpnt->device, blk_rq_pos(SCpnt->request), ha, 1); tstatus = status_byte(spp->target_status); diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 36fd2e7..a8fab39 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1313,10 +1313,10 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd, uint32_t bgstat = bgf->bgstat; uint64_t failing_sector = 0; - printk(KERN_ERR "BG ERROR in cmd 0x%x lba 0x%llx blk cnt 0x%lx " + printk(KERN_ERR "BG ERROR in cmd 0x%x lba 0x%llx blk cnt 0x%x " "bgstat=0x%x bghm=0x%x\n", cmd->cmnd[0], (unsigned long long)scsi_get_lba(cmd), - cmd->request->nr_sectors, bgstat, bghm); + blk_rq_sectors(cmd->request), bgstat, bghm); spin_lock(&_dump_buf_lock); if (!_dump_buf_done) { @@ -2375,15 +2375,15 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) if (cmnd->cmnd[0] == READ_10) lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, "9035 BLKGRD: READ @ sector %llu, " - "count %lu\n", - (unsigned long long)scsi_get_lba(cmnd), - cmnd->request->nr_sectors); + "count %u\n", + (unsigned long long)scsi_get_lba(cmnd), + blk_rq_sectors(cmnd->request)); else if (cmnd->cmnd[0] == WRITE_10) lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, "9036 BLKGRD: WRITE @ sector %llu, " - "count %lu cmd=%p\n", + "count %u cmd=%p\n", (unsigned long long)scsi_get_lba(cmnd), - cmnd->request->nr_sectors, + blk_rq_sectors(cmnd->request), cmnd); err = lpfc_bg_scsi_prep_dma_buf(phba, lpfc_cmd); @@ -2403,15 +2403,15 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) if (cmnd->cmnd[0] == READ_10) lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, "9040 dbg: READ @ sector %llu, " - "count %lu\n", + "count %u\n", (unsigned long long)scsi_get_lba(cmnd), - cmnd->request->nr_sectors); + blk_rq_sectors(cmnd->request)); else if (cmnd->cmnd[0] == WRITE_10) lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, "9041 dbg: WRITE @ sector %llu, " - "count %lu cmd=%p\n", + "count %u cmd=%p\n", (unsigned long long)scsi_get_lba(cmnd), - cmnd->request->nr_sectors, cmnd); + blk_rq_sectors(cmnd->request), cmnd); else lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, "9042 dbg: parser not implemented\n"); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 9ff0ca9..39b3acf 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -787,9 +787,9 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) * Next deal with any sectors which we were able to correctly * handle. */ - SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, " + SCSI_LOG_HLCOMPLETE(1, printk("%u sectors total, " "%d bytes done.\n", - req->nr_sectors, good_bytes)); + blk_rq_sectors(req), good_bytes)); /* * Recovered errors need reporting, but they're always treated @@ -968,7 +968,7 @@ static int scsi_init_sgtable(struct request *req, struct scsi_data_buffer *sdb, if (blk_pc_request(req)) sdb->length = req->data_len; else - sdb->length = req->nr_sectors << 9; + sdb->length = blk_rq_sectors(req) << 9; return BLKPREP_OK; } diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 3fcb64b..70c4dd9 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -383,9 +383,9 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) struct scsi_device *sdp = q->queuedata; struct gendisk *disk = rq->rq_disk; struct scsi_disk *sdkp; - sector_t block = rq->sector; + sector_t block = blk_rq_pos(rq); sector_t threshold; - unsigned int this_count = rq->nr_sectors; + unsigned int this_count = blk_rq_sectors(rq); int ret, host_dif; if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { @@ -412,10 +412,10 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) this_count)); if (!sdp || !scsi_device_online(sdp) || - block + rq->nr_sectors > get_capacity(disk)) { + block + blk_rq_sectors(rq) > get_capacity(disk)) { SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, - "Finishing %ld sectors\n", - rq->nr_sectors)); + "Finishing %u sectors\n", + blk_rq_sectors(rq))); SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "Retry with 0x%p\n", SCpnt)); goto out; @@ -462,7 +462,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) * for this. */ if (sdp->sector_size == 1024) { - if ((block & 1) || (rq->nr_sectors & 1)) { + if ((block & 1) || (blk_rq_sectors(rq) & 1)) { scmd_printk(KERN_ERR, SCpnt, "Bad block number requested\n"); goto out; @@ -472,7 +472,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) } } if (sdp->sector_size == 2048) { - if ((block & 3) || (rq->nr_sectors & 3)) { + if ((block & 3) || (blk_rq_sectors(rq) & 3)) { scmd_printk(KERN_ERR, SCpnt, "Bad block number requested\n"); goto out; @@ -482,7 +482,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) } } if (sdp->sector_size == 4096) { - if ((block & 7) || (rq->nr_sectors & 7)) { + if ((block & 7) || (blk_rq_sectors(rq) & 7)) { scmd_printk(KERN_ERR, SCpnt, "Bad block number requested\n"); goto out; @@ -511,10 +511,10 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) } SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, - "%s %d/%ld 512 byte blocks.\n", + "%s %d/%u 512 byte blocks.\n", (rq_data_dir(rq) == WRITE) ? "writing" : "reading", this_count, - rq->nr_sectors)); + blk_rq_sectors(rq))); /* Set RDPROTECT/WRPROTECT if disk is formatted with DIF */ host_dif = scsi_host_dif_capable(sdp->host, sdkp->protection_type); @@ -970,8 +970,8 @@ static struct block_device_operations sd_fops = { static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd) { - u64 start_lba = scmd->request->sector; - u64 end_lba = scmd->request->sector + (scsi_bufflen(scmd) / 512); + u64 start_lba = blk_rq_pos(scmd->request); + u64 end_lba = blk_rq_pos(scmd->request) + (scsi_bufflen(scmd) / 512); u64 bad_lba; int info_valid; diff --git a/drivers/scsi/sd_dif.c b/drivers/scsi/sd_dif.c index 184dff4..82f14a9 100644 --- a/drivers/scsi/sd_dif.c +++ b/drivers/scsi/sd_dif.c @@ -507,7 +507,7 @@ void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes) sector_sz = scmd->device->sector_size; sectors = good_bytes / sector_sz; - phys = scmd->request->sector & 0xffffffff; + phys = blk_rq_pos(scmd->request) & 0xffffffff; if (sector_sz == 4096) phys >>= 3; diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 0e1a0f2..fddba53 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -292,7 +292,8 @@ static int sr_done(struct scsi_cmnd *SCpnt) if (cd->device->sector_size == 2048) error_sector <<= 2; error_sector &= ~(block_sectors - 1); - good_bytes = (error_sector - SCpnt->request->sector) << 9; + good_bytes = (error_sector - + blk_rq_pos(SCpnt->request)) << 9; if (good_bytes < 0 || good_bytes >= this_count) good_bytes = 0; /* @@ -349,8 +350,8 @@ static int sr_prep_fn(struct request_queue *q, struct request *rq) cd->disk->disk_name, block)); if (!cd->device || !scsi_device_online(cd->device)) { - SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", - rq->nr_sectors)); + SCSI_LOG_HLQUEUE(2, printk("Finishing %u sectors\n", + blk_rq_sectors(rq))); SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt)); goto out; } @@ -413,7 +414,7 @@ static int sr_prep_fn(struct request_queue *q, struct request *rq) /* * request doesn't start on hw block boundary, add scatter pads */ - if (((unsigned int)rq->sector % (s_size >> 9)) || + if (((unsigned int)blk_rq_pos(rq) % (s_size >> 9)) || (scsi_bufflen(SCpnt) % s_size)) { scmd_printk(KERN_NOTICE, SCpnt, "unaligned transfer\n"); goto out; @@ -422,14 +423,14 @@ static int sr_prep_fn(struct request_queue *q, struct request *rq) this_count = (scsi_bufflen(SCpnt) >> 9) / (s_size >> 9); - SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n", + SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%u 512 byte blocks.\n", cd->cdi.name, (rq_data_dir(rq) == WRITE) ? "writing" : "reading", - this_count, rq->nr_sectors)); + this_count, blk_rq_sectors(rq))); SCpnt->cmnd[1] = 0; - block = (unsigned int)rq->sector / (s_size >> 9); + block = (unsigned int)blk_rq_pos(rq) / (s_size >> 9); if (this_count > 0xffff) { this_count = 0xffff; diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c index 601e951..54023d41 100644 --- a/drivers/scsi/u14-34f.c +++ b/drivers/scsi/u14-34f.c @@ -1306,7 +1306,7 @@ static int u14_34f_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scs if (linked_comm && SCpnt->device->queue_depth > 2 && TLDEV(SCpnt->device->type)) { HD(j)->cp_stat[i] = READY; - flush_dev(SCpnt->device, SCpnt->request->sector, j, FALSE); + flush_dev(SCpnt->device, blk_rq_pos(SCpnt->request), j, FALSE); return 0; } @@ -1610,11 +1610,13 @@ static int reorder(unsigned int j, unsigned long cursec, if (!(cpp->xdir == DTD_IN)) input_only = FALSE; - if (SCpnt->request->sector < minsec) minsec = SCpnt->request->sector; - if (SCpnt->request->sector > maxsec) maxsec = SCpnt->request->sector; + if (blk_rq_pos(SCpnt->request) < minsec) + minsec = blk_rq_pos(SCpnt->request); + if (blk_rq_pos(SCpnt->request) > maxsec) + maxsec = blk_rq_pos(SCpnt->request); - sl[n] = SCpnt->request->sector; - ioseek += SCpnt->request->nr_sectors; + sl[n] = blk_rq_pos(SCpnt->request); + ioseek += blk_rq_sectors(SCpnt->request); if (!n) continue; @@ -1642,7 +1644,7 @@ static int reorder(unsigned int j, unsigned long cursec, if (!input_only) for (n = 0; n < n_ready; n++) { k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; - ll[n] = SCpnt->request->nr_sectors; pl[n] = SCpnt->serial_number; + ll[n] = blk_rq_sectors(SCpnt->request); pl[n] = SCpnt->serial_number; if (!n) continue; @@ -1666,12 +1668,12 @@ static int reorder(unsigned int j, unsigned long cursec, if (link_statistics && (overlap || !(flushcount % link_statistics))) for (n = 0; n < n_ready; n++) { k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; - printk("%s %d.%d:%d pid %ld mb %d fc %d nr %d sec %ld ns %ld"\ + printk("%s %d.%d:%d pid %ld mb %d fc %d nr %d sec %ld ns %u"\ " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n", (ihdlr ? "ihdlr" : "qcomm"), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->serial_number, k, flushcount, n_ready, - SCpnt->request->sector, SCpnt->request->nr_sectors, cursec, - YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only), + blk_rq_pos(SCpnt->request), blk_rq_sectors(SCpnt->request), + cursec, YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only), YESNO(overlap), cpp->xdir); } #endif @@ -1799,7 +1801,7 @@ static irqreturn_t ihdlr(unsigned int j) if (linked_comm && SCpnt->device->queue_depth > 2 && TLDEV(SCpnt->device->type)) - flush_dev(SCpnt->device, SCpnt->request->sector, j, TRUE); + flush_dev(SCpnt->device, blk_rq_pos(SCpnt->request), j, TRUE); tstatus = status_byte(spp->target_status); diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index 43b50d3..3878d1d 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h @@ -270,7 +270,7 @@ static inline unsigned char scsi_get_prot_type(struct scsi_cmnd *scmd) static inline sector_t scsi_get_lba(struct scsi_cmnd *scmd) { - return scmd->request->sector; + return blk_rq_pos(scmd->request); } static inline unsigned scsi_prot_sg_count(struct scsi_cmnd *cmd) -- cgit v0.10.2 From 9780e2dd8254351f6cbe11304849126b51dbd561 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 7 May 2009 22:24:40 +0900 Subject: ide: convert to rq pos and nr_sectors accessors ide doesn't manipulate request fields anymore and thus all hard and their soft equivalents are always equal. Convert all references to accessors. [ Impact: use pos and nr_sectors accessors ] Signed-off-by: Tejun Heo Acked-by: Bartlomiej Zolnierkiewicz Cc: Borislav Petkov Cc: Sergei Shtylyov Signed-off-by: Jens Axboe diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 182320d..eb4f3dc 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -775,8 +775,8 @@ static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq) } /* fs requests *must* be hardware frame aligned */ - if ((rq->nr_sectors & (sectors_per_frame - 1)) || - (rq->sector & (sectors_per_frame - 1))) + if ((blk_rq_sectors(rq) & (sectors_per_frame - 1)) || + (blk_rq_pos(rq) & (sectors_per_frame - 1))) return ide_stopped; /* use DMA, if possible */ @@ -868,8 +868,8 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq, cmd.rq = rq; if (blk_fs_request(rq) || rq->data_len) { - ide_init_sg_cmd(&cmd, blk_fs_request(rq) ? (rq->nr_sectors << 9) - : rq->data_len); + ide_init_sg_cmd(&cmd, blk_fs_request(rq) ? + (blk_rq_sectors(rq) << 9) : rq->data_len); ide_map_sg(drive, &cmd); } diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index c243880..ad18e14 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -82,7 +82,7 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq, sector_t block) { ide_hwif_t *hwif = drive->hwif; - u16 nsectors = (u16)rq->nr_sectors; + u16 nsectors = (u16)blk_rq_sectors(rq); u8 lba48 = !!(drive->dev_flags & IDE_DFLAG_LBA48); u8 dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA); struct ide_cmd cmd; @@ -90,7 +90,7 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq, ide_startstop_t rc; if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && lba48 && dma) { - if (block + rq->nr_sectors > 1ULL << 28) + if (block + blk_rq_sectors(rq) > 1ULL << 28) dma = 0; else lba48 = 0; @@ -195,9 +195,9 @@ static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq, ledtrig_ide_activity(); - pr_debug("%s: %sing: block=%llu, sectors=%lu, buffer=0x%08lx\n", + pr_debug("%s: %sing: block=%llu, sectors=%u, buffer=0x%08lx\n", drive->name, rq_data_dir(rq) == READ ? "read" : "writ", - (unsigned long long)block, rq->nr_sectors, + (unsigned long long)block, blk_rq_sectors(rq), (unsigned long)rq->buffer); if (hwif->rw_disk) diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index d9123ec..001f68f 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -103,7 +103,7 @@ ide_startstop_t ide_dma_intr(ide_drive_t *drive) ide_finish_cmd(drive, cmd, stat); else ide_complete_rq(drive, 0, - cmd->rq->nr_sectors << 9); + blk_rq_sectors(cmd->rq) << 9); return ide_stopped; } printk(KERN_ERR "%s: %s: bad DMA status (0x%02x)\n", diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 537b7c5..1c460bd 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -194,7 +194,7 @@ static void idefloppy_create_rw_cmd(ide_drive_t *drive, { struct ide_disk_obj *floppy = drive->driver_data; int block = sector / floppy->bs_factor; - int blocks = rq->nr_sectors / floppy->bs_factor; + int blocks = blk_rq_sectors(rq) / floppy->bs_factor; int cmd = rq_data_dir(rq); ide_debug_log(IDE_DBG_FUNC, "block: %d, blocks: %d", block, blocks); @@ -259,8 +259,8 @@ static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive, goto out_end; } if (blk_fs_request(rq)) { - if (((long)rq->sector % floppy->bs_factor) || - (rq->nr_sectors % floppy->bs_factor)) { + if (((long)blk_rq_pos(rq) % floppy->bs_factor) || + (blk_rq_sectors(rq) % floppy->bs_factor)) { printk(KERN_ERR PFX "%s: unsupported r/w rq size\n", drive->name); goto out_end; diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index df23bcb..59799ca 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -279,7 +279,7 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, if (cmd) { if (cmd->protocol == ATA_PROT_PIO) { - ide_init_sg_cmd(cmd, rq->nr_sectors << 9); + ide_init_sg_cmd(cmd, blk_rq_sectors(rq) << 9); ide_map_sg(drive, cmd); } @@ -387,7 +387,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) drv = *(struct ide_driver **)rq->rq_disk->private_data; - return drv->do_request(drive, rq, rq->sector); + return drv->do_request(drive, rq, blk_rq_pos(rq)); } return do_special(drive); kill_rq: diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 56ff8c4..05b7fbc 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -114,7 +114,7 @@ static void ide_dump_ata_error(ide_drive_t *drive, u8 err) if (rq) printk(KERN_CONT ", sector=%llu", - (unsigned long long)rq->sector); + (unsigned long long)blk_rq_pos(rq)); } printk(KERN_CONT "\n"); } diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 65c5b70..c6cf3a9 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -586,7 +586,7 @@ static void ide_tape_create_rw_cmd(idetape_tape_t *tape, struct ide_atapi_pc *pc, struct request *rq, u8 opcode) { - unsigned int length = rq->nr_sectors; + unsigned int length = blk_rq_sectors(rq); ide_init_pc(pc); put_unaligned(cpu_to_be32(length), (unsigned int *) &pc->c[1]); @@ -617,8 +617,8 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, struct ide_cmd cmd; u8 stat; - debug_log(DBG_SENSE, "sector: %llu, nr_sectors: %lu\n" - (unsigned long long)rq->sector, rq->nr_sectors); + debug_log(DBG_SENSE, "sector: %llu, nr_sectors: %u\n" + (unsigned long long)blk_rq_pos(rq), blk_rq_sectors(rq)); if (!(blk_special_request(rq) || blk_sense_request(rq))) { /* We do not support buffer cache originated requests. */ diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index f400eb4..a0c3e1b 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -385,7 +385,7 @@ out_end: if ((cmd->tf_flags & IDE_TFLAG_FS) == 0) ide_finish_cmd(drive, cmd, stat); else - ide_complete_rq(drive, 0, cmd->rq->nr_sectors << 9); + ide_complete_rq(drive, 0, blk_rq_sectors(cmd->rq) << 9); return ide_stopped; out_err: ide_error_cmd(drive, cmd); diff --git a/drivers/ide/pdc202xx_old.c b/drivers/ide/pdc202xx_old.c index 248a54b..c2a16a8 100644 --- a/drivers/ide/pdc202xx_old.c +++ b/drivers/ide/pdc202xx_old.c @@ -177,7 +177,7 @@ static void pdc202xx_dma_start(ide_drive_t *drive) u8 clock = inb(high_16 + 0x11); outb(clock | (hwif->channel ? 0x08 : 0x02), high_16 + 0x11); - word_count = (rq->nr_sectors << 8); + word_count = (blk_rq_sectors(rq) << 8); word_count = (rq_data_dir(rq) == READ) ? word_count | 0x05000000 : word_count | 0x06000000; diff --git a/drivers/ide/tc86c001.c b/drivers/ide/tc86c001.c index b4cf42d..05a93d6b 100644 --- a/drivers/ide/tc86c001.c +++ b/drivers/ide/tc86c001.c @@ -112,7 +112,7 @@ static void tc86c001_dma_start(ide_drive_t *drive) ide_hwif_t *hwif = drive->hwif; unsigned long sc_base = hwif->config_data; unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04); - unsigned long nsectors = hwif->rq->nr_sectors; + unsigned long nsectors = blk_rq_sectors(hwif->rq); /* * We have to manually load the sector count and size into diff --git a/drivers/ide/tx4939ide.c b/drivers/ide/tx4939ide.c index 564422d..5ca7622 100644 --- a/drivers/ide/tx4939ide.c +++ b/drivers/ide/tx4939ide.c @@ -307,7 +307,7 @@ static int tx4939ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) tx4939ide_writew(SECTOR_SIZE / 2, base, drive->dn ? TX4939IDE_Xfer_Cnt_2 : TX4939IDE_Xfer_Cnt_1); - tx4939ide_writew(cmd->rq->nr_sectors, base, TX4939IDE_Sec_Cnt); + tx4939ide_writew(blk_rq_sectors(cmd->rq), base, TX4939IDE_Sec_Cnt); return 0; } -- cgit v0.10.2 From 2e46e8b27aa57c6bd34b3102b40ee4d0144b4fab Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 7 May 2009 22:24:41 +0900 Subject: block: drop request->hard_* and *nr_sectors struct request has had a few different ways to represent some properties of a request. ->hard_* represent block layer's view of the request progress (completion cursor) and the ones without the prefix are supposed to represent the issue cursor and allowed to be updated as necessary by the low level drivers. The thing is that as block layer supports partial completion, the two cursors really aren't necessary and only cause confusion. In addition, manual management of request detail from low level drivers is cumbersome and error-prone at the very least. Another interesting duplicate fields are rq->[hard_]nr_sectors and rq->{hard_cur|current}_nr_sectors against rq->data_len and rq->bio->bi_size. This is more convoluted than the hard_ case. rq->[hard_]nr_sectors are initialized for requests with bio but blk_rq_bytes() uses it only for !pc requests. rq->data_len is initialized for all request but blk_rq_bytes() uses it only for pc requests. This causes good amount of confusion throughout block layer and its drivers and determining the request length has been a bit of black magic which may or may not work depending on circumstances and what the specific LLD is actually doing. rq->{hard_cur|current}_nr_sectors represent the number of sectors in the contiguous data area at the front. This is mainly used by drivers which transfers data by walking request segment-by-segment. This value always equals rq->bio->bi_size >> 9. However, data length for pc requests may not be multiple of 512 bytes and using this field becomes a bit confusing. In general, having multiple fields to represent the same property leads only to confusion and subtle bugs. With recent block low level driver cleanups, no driver is accessing or manipulating these duplicate fields directly. Drop all the duplicates. Now rq->sector means the current sector, rq->data_len the current total length and rq->bio->bi_size the current segment length. Everything else is defined in terms of these three and available only through accessors. * blk_recalc_rq_sectors() is collapsed into blk_update_request() and now handles pc and fs requests equally other than rq->sector update. This means that now pc requests can use partial completion too (no in-kernel user yet tho). * bio_cur_sectors() is replaced with bio_cur_bytes() as block layer now uses byte count as the primary data length. * blk_rq_pos() is now guranteed to be always correct. In-block users converted. * blk_rq_bytes() is now guaranteed to be always valid as is blk_rq_sectors(). In-block users converted. * blk_rq_sectors() is now guaranteed to equal blk_rq_bytes() >> 9. More convenient one is used. * blk_rq_bytes() and blk_rq_cur_bytes() are now inlined and take const pointer to request. [ Impact: API cleanup, single way to represent one property of a request ] Signed-off-by: Tejun Heo Cc: Boaz Harrosh Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index 82dc206..3596ca7 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -127,7 +127,7 @@ void blk_rq_init(struct request_queue *q, struct request *rq) INIT_LIST_HEAD(&rq->timeout_list); rq->cpu = -1; rq->q = q; - rq->sector = rq->hard_sector = (sector_t) -1; + rq->sector = (sector_t) -1; INIT_HLIST_NODE(&rq->hash); RB_CLEAR_NODE(&rq->rb_node); rq->cmd = rq->__cmd; @@ -189,8 +189,7 @@ void blk_dump_rq_flags(struct request *rq, char *msg) (unsigned long long)blk_rq_pos(rq), blk_rq_sectors(rq), blk_rq_cur_sectors(rq)); printk(KERN_INFO " bio %p, biotail %p, buffer %p, len %u\n", - rq->bio, rq->biotail, - rq->buffer, rq->data_len); + rq->bio, rq->biotail, rq->buffer, blk_rq_bytes(rq)); if (blk_pc_request(rq)) { printk(KERN_INFO " cdb: "); @@ -1096,7 +1095,7 @@ void init_request_from_bio(struct request *req, struct bio *bio) req->cmd_flags |= REQ_NOIDLE; req->errors = 0; - req->hard_sector = req->sector = bio->bi_sector; + req->sector = bio->bi_sector; req->ioprio = bio_prio(bio); blk_rq_bio_prep(req->q, req, bio); } @@ -1113,14 +1112,13 @@ static inline bool queue_should_plug(struct request_queue *q) static int __make_request(struct request_queue *q, struct bio *bio) { struct request *req; - int el_ret, nr_sectors; + int el_ret; + unsigned int bytes = bio->bi_size; const unsigned short prio = bio_prio(bio); const int sync = bio_sync(bio); const int unplug = bio_unplug(bio); int rw_flags; - nr_sectors = bio_sectors(bio); - /* * low level driver can indicate that it wants pages above a * certain limit bounced to low memory (ie for highmem, or even @@ -1145,7 +1143,7 @@ static int __make_request(struct request_queue *q, struct bio *bio) req->biotail->bi_next = bio; req->biotail = bio; - req->nr_sectors = req->hard_nr_sectors += nr_sectors; + req->data_len += bytes; req->ioprio = ioprio_best(req->ioprio, prio); if (!blk_rq_cpu_valid(req)) req->cpu = bio->bi_comp_cpu; @@ -1171,10 +1169,8 @@ static int __make_request(struct request_queue *q, struct bio *bio) * not touch req->buffer either... */ req->buffer = bio_data(bio); - req->current_nr_sectors = bio_cur_sectors(bio); - req->hard_cur_sectors = req->current_nr_sectors; - req->sector = req->hard_sector = bio->bi_sector; - req->nr_sectors = req->hard_nr_sectors += nr_sectors; + req->sector = bio->bi_sector; + req->data_len += bytes; req->ioprio = ioprio_best(req->ioprio, prio); if (!blk_rq_cpu_valid(req)) req->cpu = bio->bi_comp_cpu; @@ -1557,7 +1553,7 @@ EXPORT_SYMBOL(submit_bio); int blk_rq_check_limits(struct request_queue *q, struct request *rq) { if (blk_rq_sectors(rq) > q->max_sectors || - rq->data_len > q->max_hw_sectors << 9) { + blk_rq_bytes(rq) > q->max_hw_sectors << 9) { printk(KERN_ERR "%s: over max size limit.\n", __func__); return -EIO; } @@ -1675,35 +1671,6 @@ static void blk_account_io_done(struct request *req) } } -/** - * blk_rq_bytes - Returns bytes left to complete in the entire request - * @rq: the request being processed - **/ -unsigned int blk_rq_bytes(struct request *rq) -{ - if (blk_fs_request(rq)) - return blk_rq_sectors(rq) << 9; - - return rq->data_len; -} -EXPORT_SYMBOL_GPL(blk_rq_bytes); - -/** - * blk_rq_cur_bytes - Returns bytes left to complete in the current segment - * @rq: the request being processed - **/ -unsigned int blk_rq_cur_bytes(struct request *rq) -{ - if (blk_fs_request(rq)) - return rq->current_nr_sectors << 9; - - if (rq->bio) - return rq->bio->bi_size; - - return rq->data_len; -} -EXPORT_SYMBOL_GPL(blk_rq_cur_bytes); - struct request *elv_next_request(struct request_queue *q) { struct request *rq; @@ -1736,7 +1703,7 @@ struct request *elv_next_request(struct request_queue *q) if (rq->cmd_flags & REQ_DONTPREP) break; - if (q->dma_drain_size && rq->data_len) { + if (q->dma_drain_size && blk_rq_bytes(rq)) { /* * make sure space for the drain appears we * know we can do this because max_hw_segments @@ -1759,7 +1726,7 @@ struct request *elv_next_request(struct request_queue *q) * avoid resource deadlock. REQ_STARTED will * prevent other fs requests from passing this one. */ - if (q->dma_drain_size && rq->data_len && + if (q->dma_drain_size && blk_rq_bytes(rq) && !(rq->cmd_flags & REQ_DONTPREP)) { /* * remove the space for the drain we added @@ -1911,8 +1878,7 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes) * can find how many bytes remain in the request * later. */ - req->nr_sectors = req->hard_nr_sectors = 0; - req->current_nr_sectors = req->hard_cur_sectors = 0; + req->data_len = 0; return false; } @@ -1926,8 +1892,25 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes) bio_iovec(bio)->bv_len -= nr_bytes; } - blk_recalc_rq_sectors(req, total_bytes >> 9); + req->data_len -= total_bytes; + req->buffer = bio_data(req->bio); + + /* update sector only for requests with clear definition of sector */ + if (blk_fs_request(req) || blk_discard_rq(req)) + req->sector += total_bytes >> 9; + + /* + * If total number of sectors is less than the first segment + * size, something has gone terribly wrong. + */ + if (blk_rq_bytes(req) < blk_rq_cur_bytes(req)) { + printk(KERN_ERR "blk: request botched\n"); + req->data_len = blk_rq_cur_bytes(req); + } + + /* recalculate the number of segments */ blk_recalc_rq_segments(req); + return true; } EXPORT_SYMBOL_GPL(blk_update_request); @@ -2049,11 +2032,7 @@ void blk_rq_bio_prep(struct request_queue *q, struct request *rq, rq->nr_phys_segments = bio_phys_segments(q, bio); rq->buffer = bio_data(bio); } - rq->current_nr_sectors = bio_cur_sectors(bio); - rq->hard_cur_sectors = rq->current_nr_sectors; - rq->hard_nr_sectors = rq->nr_sectors = bio_sectors(bio); rq->data_len = bio->bi_size; - rq->bio = rq->biotail = bio; if (bio->bi_bdev) diff --git a/block/blk-merge.c b/block/blk-merge.c index bf62a87..b8df66a 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -9,35 +9,6 @@ #include "blk.h" -void blk_recalc_rq_sectors(struct request *rq, int nsect) -{ - if (blk_fs_request(rq) || blk_discard_rq(rq)) { - rq->hard_sector += nsect; - rq->hard_nr_sectors -= nsect; - - /* - * Move the I/O submission pointers ahead if required. - */ - if ((rq->nr_sectors >= rq->hard_nr_sectors) && - (rq->sector <= rq->hard_sector)) { - rq->sector = rq->hard_sector; - rq->nr_sectors = rq->hard_nr_sectors; - rq->hard_cur_sectors = bio_cur_sectors(rq->bio); - rq->current_nr_sectors = rq->hard_cur_sectors; - rq->buffer = bio_data(rq->bio); - } - - /* - * if total number of sectors is less than the first segment - * size, something has gone terribly wrong - */ - if (rq->nr_sectors < rq->current_nr_sectors) { - printk(KERN_ERR "blk: request botched\n"); - rq->nr_sectors = rq->current_nr_sectors; - } - } -} - static unsigned int __blk_recalc_rq_segments(struct request_queue *q, struct bio *bio) { @@ -199,8 +170,9 @@ new_segment: if (unlikely(rq->cmd_flags & REQ_COPY_USER) && - (rq->data_len & q->dma_pad_mask)) { - unsigned int pad_len = (q->dma_pad_mask & ~rq->data_len) + 1; + (blk_rq_bytes(rq) & q->dma_pad_mask)) { + unsigned int pad_len = + (q->dma_pad_mask & ~blk_rq_bytes(rq)) + 1; sg->length += pad_len; rq->extra_len += pad_len; @@ -398,7 +370,7 @@ static int attempt_merge(struct request_queue *q, struct request *req, req->biotail->bi_next = next->bio; req->biotail = next->biotail; - req->nr_sectors = req->hard_nr_sectors += next->hard_nr_sectors; + req->data_len += blk_rq_bytes(next); elv_merge_requests(q, req, next); diff --git a/block/blk.h b/block/blk.h index 5111559..ab54529 100644 --- a/block/blk.h +++ b/block/blk.h @@ -101,7 +101,6 @@ int ll_front_merge_fn(struct request_queue *q, struct request *req, int attempt_back_merge(struct request_queue *q, struct request *rq); int attempt_front_merge(struct request_queue *q, struct request *rq); void blk_recalc_rq_segments(struct request *rq); -void blk_recalc_rq_sectors(struct request *rq, int nsect); void blk_queue_congestion_threshold(struct request_queue *q); diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index db4d990..99ac430 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -579,9 +579,9 @@ cfq_prio_tree_lookup(struct cfq_data *cfqd, struct rb_root *root, * Sort strictly based on sector. Smallest to the left, * largest to the right. */ - if (sector > cfqq->next_rq->sector) + if (sector > blk_rq_pos(cfqq->next_rq)) n = &(*p)->rb_right; - else if (sector < cfqq->next_rq->sector) + else if (sector < blk_rq_pos(cfqq->next_rq)) n = &(*p)->rb_left; else break; @@ -611,8 +611,8 @@ static void cfq_prio_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq) return; cfqq->p_root = &cfqd->prio_trees[cfqq->org_ioprio]; - __cfqq = cfq_prio_tree_lookup(cfqd, cfqq->p_root, cfqq->next_rq->sector, - &parent, &p); + __cfqq = cfq_prio_tree_lookup(cfqd, cfqq->p_root, + blk_rq_pos(cfqq->next_rq), &parent, &p); if (!__cfqq) { rb_link_node(&cfqq->p_node, parent, p); rb_insert_color(&cfqq->p_node, cfqq->p_root); @@ -996,7 +996,7 @@ static struct cfq_queue *cfqq_close(struct cfq_data *cfqd, if (cfq_rq_close(cfqd, __cfqq->next_rq)) return __cfqq; - if (__cfqq->next_rq->sector < sector) + if (blk_rq_pos(__cfqq->next_rq) < sector) node = rb_next(&__cfqq->p_node); else node = rb_prev(&__cfqq->p_node); diff --git a/include/linux/bio.h b/include/linux/bio.h index f37ca8c..d30ec6f 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -218,12 +218,12 @@ struct bio { #define bio_sectors(bio) ((bio)->bi_size >> 9) #define bio_empty_barrier(bio) (bio_barrier(bio) && !bio_has_data(bio) && !bio_discard(bio)) -static inline unsigned int bio_cur_sectors(struct bio *bio) +static inline unsigned int bio_cur_bytes(struct bio *bio) { if (bio->bi_vcnt) - return bio_iovec(bio)->bv_len >> 9; + return bio_iovec(bio)->bv_len; else /* dataless requests such as discard */ - return bio->bi_size >> 9; + return bio->bi_size; } static inline void *bio_data(struct bio *bio) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 4e5f855..ce2bf5e 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -166,19 +166,8 @@ struct request { enum rq_cmd_type_bits cmd_type; unsigned long atomic_flags; - /* Maintain bio traversal state for part by part I/O submission. - * hard_* are block layer internals, no driver should touch them! - */ - - sector_t sector; /* next sector to submit */ - sector_t hard_sector; /* next sector to complete */ - unsigned long nr_sectors; /* no. of sectors left to submit */ - unsigned long hard_nr_sectors; /* no. of sectors left to complete */ - /* no. of sectors left to submit in the current segment */ - unsigned int current_nr_sectors; - - /* no. of sectors left to complete in the current segment */ - unsigned int hard_cur_sectors; + sector_t sector; /* sector cursor */ + unsigned int data_len; /* total data len, don't access directly */ struct bio *bio; struct bio *biotail; @@ -226,7 +215,6 @@ struct request { unsigned char __cmd[BLK_MAX_CDB]; unsigned char *cmd; - unsigned int data_len; unsigned int extra_len; /* length of alignment and padding */ unsigned int sense_len; unsigned int resid_len; /* residual count */ @@ -840,20 +828,27 @@ extern void blkdev_dequeue_request(struct request *req); */ static inline sector_t blk_rq_pos(const struct request *rq) { - return rq->hard_sector; + return rq->sector; +} + +static inline unsigned int blk_rq_bytes(const struct request *rq) +{ + return rq->data_len; } -extern unsigned int blk_rq_bytes(struct request *rq); -extern unsigned int blk_rq_cur_bytes(struct request *rq); +static inline int blk_rq_cur_bytes(const struct request *rq) +{ + return rq->bio ? bio_cur_bytes(rq->bio) : 0; +} static inline unsigned int blk_rq_sectors(const struct request *rq) { - return rq->hard_nr_sectors; + return blk_rq_bytes(rq) >> 9; } static inline unsigned int blk_rq_cur_sectors(const struct request *rq) { - return rq->hard_cur_sectors; + return blk_rq_cur_bytes(rq) >> 9; } /* @@ -928,7 +923,7 @@ static inline void blk_end_request_all(struct request *rq, int error) */ static inline bool blk_end_request_cur(struct request *rq, int error) { - return blk_end_request(rq, error, rq->hard_cur_sectors << 9); + return blk_end_request(rq, error, blk_rq_cur_bytes(rq)); } /** @@ -981,7 +976,7 @@ static inline void __blk_end_request_all(struct request *rq, int error) */ static inline bool __blk_end_request_cur(struct request *rq, int error) { - return __blk_end_request(rq, error, rq->hard_cur_sectors << 9); + return __blk_end_request(rq, error, blk_rq_cur_bytes(rq)); } extern void blk_complete_request(struct request *); diff --git a/include/linux/elevator.h b/include/linux/elevator.h index c59b769..4e46287 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h @@ -171,7 +171,7 @@ enum { ELV_MQUEUE_MUST, }; -#define rq_end_sector(rq) ((rq)->sector + (rq)->nr_sectors) +#define rq_end_sector(rq) (blk_rq_pos(rq) + blk_rq_sectors(rq)) #define rb_entry_rq(node) rb_entry((node), struct request, rb_node) /* diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c index 42f1c11..5708a14 100644 --- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c @@ -642,12 +642,12 @@ static void blk_add_trace_rq(struct request_queue *q, struct request *rq, if (blk_pc_request(rq)) { what |= BLK_TC_ACT(BLK_TC_PC); - __blk_add_trace(bt, 0, rq->data_len, rw, what, rq->errors, - rq->cmd_len, rq->cmd); + __blk_add_trace(bt, 0, blk_rq_bytes(rq), rw, + what, rq->errors, rq->cmd_len, rq->cmd); } else { what |= BLK_TC_ACT(BLK_TC_FS); - __blk_add_trace(bt, blk_rq_pos(rq), blk_rq_sectors(rq) << 9, - rw, what, rq->errors, 0, NULL); + __blk_add_trace(bt, blk_rq_pos(rq), blk_rq_bytes(rq), rw, + what, rq->errors, 0, NULL); } } @@ -854,11 +854,11 @@ void blk_add_driver_data(struct request_queue *q, return; if (blk_pc_request(rq)) - __blk_add_trace(bt, 0, rq->data_len, 0, BLK_TA_DRV_DATA, - rq->errors, len, data); + __blk_add_trace(bt, 0, blk_rq_bytes(rq), 0, + BLK_TA_DRV_DATA, rq->errors, len, data); else - __blk_add_trace(bt, blk_rq_pos(rq), blk_rq_sectors(rq) << 9, - 0, BLK_TA_DRV_DATA, rq->errors, len, data); + __blk_add_trace(bt, blk_rq_pos(rq), blk_rq_bytes(rq), 0, + BLK_TA_DRV_DATA, rq->errors, len, data); } EXPORT_SYMBOL_GPL(blk_add_driver_data); -- cgit v0.10.2 From b0790410300abaaf4f25f702803beff701baebf1 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 7 May 2009 22:24:42 +0900 Subject: block: cleanup rq->data_len usages With recent unification of fields, it's now guaranteed that rq->data_len always equals blk_rq_bytes(). Convert all non-IDE direct users to accessors. IDE will be converted in a separate patch. Boaz: spotted incorrect data_len/resid_len conversion in osd. [ Impact: convert direct rq->data_len usages to blk_rq_bytes() ] Signed-off-by: Tejun Heo Acked-by: Sergei Shtylyov Cc: Pete Zaitcev Cc: Eric Moore Cc: Markus Lidel Cc: Darrick J. Wong Cc: James Bottomley Cc: Eric Moore Cc: Boaz Harrosh Cc: FUJITA Tomonori Signed-off-by: Jens Axboe diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 2733b0c..6e4c600 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1084,7 +1084,7 @@ static int atapi_drain_needed(struct request *rq) if (likely(!blk_pc_request(rq))) return 0; - if (!rq->data_len || (rq->cmd_flags & REQ_RW)) + if (!blk_rq_bytes(rq) || (rq->cmd_flags & REQ_RW)) return 0; return atapi_cmd_type(rq->cmd[0]) == ATAPI_MISC; diff --git a/drivers/block/ub.c b/drivers/block/ub.c index dc3b899..1591f61 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -747,7 +747,7 @@ static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun, { struct request *rq = urq->rq; - if (rq->data_len == 0) { + if (blk_rq_bytes(rq) == 0) { cmd->dir = UB_DIR_NONE; } else { if (rq_data_dir(rq) == WRITE) @@ -762,7 +762,7 @@ static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun, memcpy(&cmd->cdb, rq->cmd, rq->cmd_len); cmd->cdb_len = rq->cmd_len; - cmd->len = rq->data_len; + cmd->len = blk_rq_bytes(rq); /* * To reapply this to every URB is not as incorrect as it looks. @@ -783,8 +783,8 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) if (cmd->error == 0) { if (blk_pc_request(rq)) { - if (cmd->act_len < rq->data_len) - rq->resid_len = rq->data_len - cmd->act_len; + if (cmd->act_len < blk_rq_bytes(rq)) + rq->resid_len = blk_rq_bytes(rq) - cmd->act_len; scsi_status = 0; } else { if (cmd->act_len != cmd->len) { diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 5d5f347..4e6fcf0 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -1277,8 +1277,8 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, /* do we need to support multiple segments? */ if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) { printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n", - ioc->name, __func__, req->bio->bi_vcnt, req->data_len, - rsp->bio->bi_vcnt, rsp->data_len); + ioc->name, __func__, req->bio->bi_vcnt, blk_rq_bytes(req), + rsp->bio->bi_vcnt, blk_rq_bytes(rsp)); return -EINVAL; } @@ -1295,7 +1295,7 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, smpreq = (SmpPassthroughRequest_t *)mf; memset(smpreq, 0, sizeof(*smpreq)); - smpreq->RequestDataLength = cpu_to_le16(req->data_len - 4); + smpreq->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4); smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH; if (rphy) @@ -1321,10 +1321,10 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, MPI_SGE_FLAGS_END_OF_BUFFER | MPI_SGE_FLAGS_DIRECTION | mpt_addr_size()) << MPI_SGE_FLAGS_SHIFT; - flagsLength |= (req->data_len - 4); + flagsLength |= (blk_rq_bytes(req) - 4); dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio), - req->data_len, PCI_DMA_BIDIRECTIONAL); + blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); if (!dma_addr_out) goto put_mf; mpt_add_sge(psge, flagsLength, dma_addr_out); @@ -1332,9 +1332,9 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, /* response */ flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; - flagsLength |= rsp->data_len + 4; + flagsLength |= blk_rq_bytes(rsp) + 4; dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio), - rsp->data_len, PCI_DMA_BIDIRECTIONAL); + blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); if (!dma_addr_in) goto unmap; mpt_add_sge(psge, flagsLength, dma_addr_in); @@ -1357,7 +1357,7 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; memcpy(req->sense, smprep, sizeof(*smprep)); req->sense_len = sizeof(*smprep); - rsp->resid_len = rsp->data_len - smprep->ResponseDataLength; + rsp->resid_len = blk_rq_bytes(rsp) - smprep->ResponseDataLength; } else { printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n", ioc->name, __func__); @@ -1365,10 +1365,10 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, } unmap: if (dma_addr_out) - pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len, + pci_unmap_single(ioc->pcidev, dma_addr_out, blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); if (dma_addr_in) - pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len, + pci_unmap_single(ioc->pcidev, dma_addr_in, blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); put_mf: if (mf) diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index 510eb47..6b61d28 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -430,7 +430,7 @@ static void i2o_block_end_request(struct request *req, int error, int leftover = (blk_rq_sectors(req) << KERNEL_SECTOR_SHIFT); if (blk_pc_request(req)) - leftover = req->data_len; + leftover = blk_rq_bytes(req); if (error) blk_end_request(req, -EIO, leftover); diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 6605ec9..531af9e 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -1927,13 +1927,13 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, /* do we need to support multiple segments? */ if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) { printk("%s: multiple segments req %u %u, rsp %u %u\n", - __func__, req->bio->bi_vcnt, req->data_len, - rsp->bio->bi_vcnt, rsp->data_len); + __func__, req->bio->bi_vcnt, blk_rq_bytes(req), + rsp->bio->bi_vcnt, blk_rq_bytes(rsp)); return -EINVAL; } - ret = smp_execute_task(dev, bio_data(req->bio), req->data_len, - bio_data(rsp->bio), rsp->data_len); + ret = smp_execute_task(dev, bio_data(req->bio), blk_rq_bytes(req), + bio_data(rsp->bio), blk_rq_bytes(rsp)); if (ret > 0) { /* positive number is the untransferred residual */ rsp->resid_len = ret; diff --git a/drivers/scsi/libsas/sas_host_smp.c b/drivers/scsi/libsas/sas_host_smp.c index 89952ed..be9a951 100644 --- a/drivers/scsi/libsas/sas_host_smp.c +++ b/drivers/scsi/libsas/sas_host_smp.c @@ -137,21 +137,21 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, int error = -EINVAL; /* eight is the minimum size for request and response frames */ - if (req->data_len < 8 || rsp->data_len < 8) + if (blk_rq_bytes(req) < 8 || blk_rq_bytes(rsp) < 8) goto out; - if (bio_offset(req->bio) + req->data_len > PAGE_SIZE || - bio_offset(rsp->bio) + rsp->data_len > PAGE_SIZE) { + if (bio_offset(req->bio) + blk_rq_bytes(req) > PAGE_SIZE || + bio_offset(rsp->bio) + blk_rq_bytes(rsp) > PAGE_SIZE) { shost_printk(KERN_ERR, shost, "SMP request/response frame crosses page boundary"); goto out; } - req_data = kzalloc(req->data_len, GFP_KERNEL); + req_data = kzalloc(blk_rq_bytes(req), GFP_KERNEL); /* make sure frame can always be built ... we copy * back only the requested length */ - resp_data = kzalloc(max(rsp->data_len, 128U), GFP_KERNEL); + resp_data = kzalloc(max(blk_rq_bytes(rsp), 128U), GFP_KERNEL); if (!req_data || !resp_data) { error = -ENOMEM; @@ -160,7 +160,7 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, local_irq_disable(); buf = kmap_atomic(bio_page(req->bio), KM_USER0) + bio_offset(req->bio); - memcpy(req_data, buf, req->data_len); + memcpy(req_data, buf, blk_rq_bytes(req)); kunmap_atomic(buf - bio_offset(req->bio), KM_USER0); local_irq_enable(); @@ -176,8 +176,8 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, resp_data[1] = req_data[1]; resp_data[2] = SMP_RESP_FUNC_UNK; - req->resid_len = req->data_len; - rsp->resid_len = rsp->data_len; + req->resid_len = blk_rq_bytes(req); + rsp->resid_len = blk_rq_bytes(rsp); switch (req_data[1]) { case SMP_REPORT_GENERAL: @@ -264,7 +264,7 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, local_irq_disable(); buf = kmap_atomic(bio_page(rsp->bio), KM_USER0) + bio_offset(rsp->bio); - memcpy(buf, resp_data, rsp->data_len); + memcpy(buf, resp_data, blk_rq_bytes(rsp)); flush_kernel_dcache_page(bio_page(rsp->bio)); kunmap_atomic(buf - bio_offset(rsp->bio), KM_USER0); local_irq_enable(); diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index 53759c5..af95a44 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c @@ -1041,7 +1041,7 @@ transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) { printk(MPT2SAS_ERR_FMT "%s: multiple segments req %u %u, " "rsp %u %u\n", ioc->name, __func__, req->bio->bi_vcnt, - req->data_len, rsp->bio->bi_vcnt, rsp->data_len); + blk_rq_bytes(req), rsp->bio->bi_vcnt, blk_rq_bytes(rsp)); return -EINVAL; } @@ -1104,7 +1104,7 @@ transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, *((u64 *)&mpi_request->SASAddress) = (rphy) ? cpu_to_le64(rphy->identify.sas_address) : cpu_to_le64(ioc->sas_hba.sas_address); - mpi_request->RequestDataLength = cpu_to_le16(req->data_len - 4); + mpi_request->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4); psge = &mpi_request->SGL; /* WRITE sgel first */ @@ -1112,13 +1112,13 @@ transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio), - req->data_len, PCI_DMA_BIDIRECTIONAL); + blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); if (!dma_addr_out) { mpt2sas_base_free_smid(ioc, le16_to_cpu(smid)); goto unmap; } - ioc->base_add_sg_single(psge, sgl_flags | (req->data_len - 4), + ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(req) - 4), dma_addr_out); /* incr sgel */ @@ -1129,14 +1129,14 @@ transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST); sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio), - rsp->data_len, PCI_DMA_BIDIRECTIONAL); + dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio), + blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); if (!dma_addr_in) { mpt2sas_base_free_smid(ioc, le16_to_cpu(smid)); goto unmap; } - ioc->base_add_sg_single(psge, sgl_flags | (rsp->data_len + 4), + ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(rsp) + 4), dma_addr_in); dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - " @@ -1170,7 +1170,8 @@ transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, memcpy(req->sense, mpi_reply, sizeof(*mpi_reply)); req->sense_len = sizeof(*mpi_reply); - rsp->resid_len = rsp->data_len - mpi_reply->ResponseDataLength; + rsp->resid_len = blk_rq_bytes(rsp) - + mpi_reply->ResponseDataLength; } else { dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - no reply\n", ioc->name, __func__)); @@ -1186,10 +1187,10 @@ transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, unmap: if (dma_addr_out) - pci_unmap_single(ioc->pdev, dma_addr_out, req->data_len, + pci_unmap_single(ioc->pdev, dma_addr_out, blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); if (dma_addr_in) - pci_unmap_single(ioc->pdev, dma_addr_in, rsp->data_len, + pci_unmap_single(ioc->pdev, dma_addr_in, blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); out: diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index 2a5f077..d178a8b 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c @@ -1299,7 +1299,7 @@ int osd_finalize_request(struct osd_request *or, return ret; } OSD_DEBUG("out bytes=%llu (bytes_req=%u)\n", - _LLU(or->out.total_bytes), or->out.req->data_len); + _LLU(or->out.total_bytes), blk_rq_bytes(or->out.req)); } if (or->in.bio) { ret = blk_rq_append_bio(or->request->q, or->in.req, or->in.bio); @@ -1308,7 +1308,7 @@ int osd_finalize_request(struct osd_request *or, return ret; } OSD_DEBUG("in bytes=%llu (bytes_req=%u)\n", - _LLU(or->in.total_bytes), or->in.req->data_len); + _LLU(or->in.total_bytes), blk_rq_bytes(or->in.req)); } or->out.pad_buff = sg_out_pad_buffer; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 39b3acf..3d16c70 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -682,14 +682,13 @@ EXPORT_SYMBOL(scsi_release_buffers); static void scsi_end_bidi_request(struct scsi_cmnd *cmd) { struct request *req = cmd->request; - unsigned int dlen = req->data_len; - unsigned int next_dlen = req->next_rq->data_len; req->resid_len = scsi_out(cmd)->resid; req->next_rq->resid_len = scsi_in(cmd)->resid; /* The req and req->next_rq have not been completed */ - BUG_ON(blk_end_bidi_request(req, 0, dlen, next_dlen)); + BUG_ON(blk_end_bidi_request(req, 0, blk_rq_bytes(req), + blk_rq_bytes(req->next_rq))); scsi_release_buffers(cmd); @@ -966,7 +965,7 @@ static int scsi_init_sgtable(struct request *req, struct scsi_data_buffer *sdb, BUG_ON(count > sdb->table.nents); sdb->table.nents = count; if (blk_pc_request(req)) - sdb->length = req->data_len; + sdb->length = blk_rq_bytes(req); else sdb->length = blk_rq_sectors(req) << 9; return BLKPREP_OK; @@ -1087,21 +1086,21 @@ int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req) if (unlikely(ret)) return ret; } else { - BUG_ON(req->data_len); + BUG_ON(blk_rq_bytes(req)); memset(&cmd->sdb, 0, sizeof(cmd->sdb)); req->buffer = NULL; } cmd->cmd_len = req->cmd_len; - if (!req->data_len) + if (!blk_rq_bytes(req)) cmd->sc_data_direction = DMA_NONE; else if (rq_data_dir(req) == WRITE) cmd->sc_data_direction = DMA_TO_DEVICE; else cmd->sc_data_direction = DMA_FROM_DEVICE; - cmd->transfersize = req->data_len; + cmd->transfersize = blk_rq_bytes(req); cmd->allowed = req->retries; return BLKPREP_OK; } diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c index 48ba413..1030327 100644 --- a/drivers/scsi/scsi_tgt_lib.c +++ b/drivers/scsi/scsi_tgt_lib.c @@ -387,7 +387,7 @@ static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd *cmd, * we use REQ_TYPE_BLOCK_PC so scsi_init_io doesn't set the * length for us. */ - cmd->sdb.length = rq->data_len; + cmd->sdb.length = blk_rq_bytes(rq); return 0; -- cgit v0.10.2 From 34b7d2c957199834c474c9d46739265643f4d9c7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 7 May 2009 22:24:43 +0900 Subject: ide: cleanup rq->data_len usages With recent unification of fields, it's now guaranteed that rq->data_len always equals blk_rq_bytes(). Convert all direct users to accessors. [ Impact: convert direct rq->data_len usages to blk_rq_bytes() ] Signed-off-by: Tejun Heo Acked-by: Bartlomiej Zolnierkiewicz Cc: Borislav Petkov Cc: Sergei Shtylyov Signed-off-by: Jens Axboe diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c index e4a02a0..792534d 100644 --- a/drivers/ide/ide-atapi.c +++ b/drivers/ide/ide-atapi.c @@ -255,7 +255,7 @@ void ide_retry_pc(ide_drive_t *drive) ide_init_pc(pc); memcpy(pc->c, sense_rq->cmd, 12); pc->buf = bio_data(sense_rq->bio); /* pointer to mapped address */ - pc->req_xfer = sense_rq->data_len; + pc->req_xfer = blk_rq_bytes(sense_rq); if (drive->media == ide_tape) set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags); @@ -303,7 +303,7 @@ int ide_cd_get_xferlen(struct request *rq) return 32768; else if (blk_sense_request(rq) || blk_pc_request(rq) || rq->cmd_type == REQ_TYPE_ATA_PC) - return rq->data_len; + return blk_rq_bytes(rq); else return 0; } diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index eb4f3dc..2eadc9d 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -577,7 +577,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) struct request *rq = hwif->rq; ide_expiry_t *expiry = NULL; int dma_error = 0, dma, thislen, uptodate = 0; - int write = (rq_data_dir(rq) == WRITE) ? 1 : 0, rc = 0, nsectors; + int write = (rq_data_dir(rq) == WRITE) ? 1 : 0, rc = 0; int sense = blk_sense_request(rq); unsigned int timeout; u16 len; @@ -707,9 +707,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) out_end: if (blk_pc_request(rq) && rc == 0) { - if (blk_end_request(rq, 0, rq->data_len)) - BUG(); - + blk_end_request_all(rq, 0); hwif->rq = NULL; } else { if (sense && uptodate) @@ -727,22 +725,14 @@ out_end: ide_cd_error_cmd(drive, cmd); /* make sure it's fully ended */ - if (blk_pc_request(rq)) - nsectors = (rq->data_len + 511) >> 9; - else - nsectors = blk_rq_sectors(rq); - - if (nsectors == 0) - nsectors = 1; - if (blk_fs_request(rq) == 0) { - rq->resid_len = rq->data_len - + rq->resid_len = blk_rq_bytes(rq) - (cmd->nbytes - cmd->nleft); if (uptodate == 0 && (cmd->tf_flags & IDE_TFLAG_WRITE)) rq->resid_len += cmd->last_xfer_len; } - ide_complete_rq(drive, uptodate ? 0 : -EIO, nsectors << 9); + ide_complete_rq(drive, uptodate ? 0 : -EIO, blk_rq_bytes(rq)); if (sense && rc == 2) ide_error(drive, "request sense failure", stat); @@ -819,7 +809,7 @@ static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq) */ alignment = queue_dma_alignment(q) | q->dma_pad_mask; if ((unsigned long)buf & alignment - || rq->data_len & q->dma_pad_mask + || blk_rq_bytes(rq) & q->dma_pad_mask || object_is_on_stack(buf)) drive->dma = 0; } @@ -867,9 +857,8 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq, cmd.rq = rq; - if (blk_fs_request(rq) || rq->data_len) { - ide_init_sg_cmd(&cmd, blk_fs_request(rq) ? - (blk_rq_sectors(rq) << 9) : rq->data_len); + if (blk_fs_request(rq) || blk_rq_bytes(rq)) { + ide_init_sg_cmd(&cmd, blk_rq_bytes(rq)); ide_map_sg(drive, &cmd); } diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 1c460bd..6509817 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -220,14 +220,14 @@ static void idefloppy_blockpc_cmd(struct ide_disk_obj *floppy, ide_init_pc(pc); memcpy(pc->c, rq->cmd, sizeof(pc->c)); pc->rq = rq; - if (rq->data_len) { + if (blk_rq_bytes(rq)) { pc->flags |= PC_FLAG_DMA_OK; if (rq_data_dir(rq) == WRITE) pc->flags |= PC_FLAG_WRITING; } /* pio will be performed by ide_pio_bytes() which handles sg fine */ pc->buf = NULL; - pc->req_xfer = pc->buf_size = rq->data_len; + pc->req_xfer = pc->buf_size = blk_rq_bytes(rq); } static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive, diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 59799ca..ca2519d 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -116,7 +116,7 @@ void ide_complete_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat, u8 err) unsigned int ide_rq_bytes(struct request *rq) { if (blk_pc_request(rq)) - return rq->data_len; + return blk_rq_bytes(rq); else return blk_rq_cur_sectors(rq) << 9; } diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index c6cf3a9..e166045 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -380,7 +380,7 @@ static int ide_tape_callback(ide_drive_t *drive, int dsc) } tape->first_frame += blocks; - rq->resid_len = rq->data_len - blocks * tape->blk_size; + rq->resid_len = blk_rq_bytes(rq) - blocks * tape->blk_size; if (pc->error) { uptodate = 0; -- cgit v0.10.2 From a2dec7b36364a5cc564c4d76cf16d2e7d33f5c05 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 7 May 2009 22:24:44 +0900 Subject: block: hide request sector and data_len Block low level drivers for some reason have been pretty good at abusing block layer API. Especially struct request's fields tend to get violated in all possible ways. Make it clear that low level drivers MUST NOT access or manipulate rq->sector and rq->data_len directly by prefixing them with double underscores. This change is also necessary to break build of out-of-tree codes which assume the previous block API where internal fields can be manipulated and rq->data_len carries residual count on completion. [ Impact: hide internal fields, block API change ] Signed-off-by: Tejun Heo Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index 3596ca7..6226a38 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -127,7 +127,7 @@ void blk_rq_init(struct request_queue *q, struct request *rq) INIT_LIST_HEAD(&rq->timeout_list); rq->cpu = -1; rq->q = q; - rq->sector = (sector_t) -1; + rq->__sector = (sector_t) -1; INIT_HLIST_NODE(&rq->hash); RB_CLEAR_NODE(&rq->rb_node); rq->cmd = rq->__cmd; @@ -1095,7 +1095,7 @@ void init_request_from_bio(struct request *req, struct bio *bio) req->cmd_flags |= REQ_NOIDLE; req->errors = 0; - req->sector = bio->bi_sector; + req->__sector = bio->bi_sector; req->ioprio = bio_prio(bio); blk_rq_bio_prep(req->q, req, bio); } @@ -1143,7 +1143,7 @@ static int __make_request(struct request_queue *q, struct bio *bio) req->biotail->bi_next = bio; req->biotail = bio; - req->data_len += bytes; + req->__data_len += bytes; req->ioprio = ioprio_best(req->ioprio, prio); if (!blk_rq_cpu_valid(req)) req->cpu = bio->bi_comp_cpu; @@ -1169,8 +1169,8 @@ static int __make_request(struct request_queue *q, struct bio *bio) * not touch req->buffer either... */ req->buffer = bio_data(bio); - req->sector = bio->bi_sector; - req->data_len += bytes; + req->__sector = bio->bi_sector; + req->__data_len += bytes; req->ioprio = ioprio_best(req->ioprio, prio); if (!blk_rq_cpu_valid(req)) req->cpu = bio->bi_comp_cpu; @@ -1878,7 +1878,7 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes) * can find how many bytes remain in the request * later. */ - req->data_len = 0; + req->__data_len = 0; return false; } @@ -1892,12 +1892,12 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes) bio_iovec(bio)->bv_len -= nr_bytes; } - req->data_len -= total_bytes; + req->__data_len -= total_bytes; req->buffer = bio_data(req->bio); /* update sector only for requests with clear definition of sector */ if (blk_fs_request(req) || blk_discard_rq(req)) - req->sector += total_bytes >> 9; + req->__sector += total_bytes >> 9; /* * If total number of sectors is less than the first segment @@ -1905,7 +1905,7 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes) */ if (blk_rq_bytes(req) < blk_rq_cur_bytes(req)) { printk(KERN_ERR "blk: request botched\n"); - req->data_len = blk_rq_cur_bytes(req); + req->__data_len = blk_rq_cur_bytes(req); } /* recalculate the number of segments */ @@ -2032,7 +2032,7 @@ void blk_rq_bio_prep(struct request_queue *q, struct request *rq, rq->nr_phys_segments = bio_phys_segments(q, bio); rq->buffer = bio_data(bio); } - rq->data_len = bio->bi_size; + rq->__data_len = bio->bi_size; rq->bio = rq->biotail = bio; if (bio->bi_bdev) diff --git a/block/blk-map.c b/block/blk-map.c index 694fefa..56082be 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -20,7 +20,7 @@ int blk_rq_append_bio(struct request_queue *q, struct request *rq, rq->biotail->bi_next = bio; rq->biotail = bio; - rq->data_len += bio->bi_size; + rq->__data_len += bio->bi_size; } return 0; } diff --git a/block/blk-merge.c b/block/blk-merge.c index b8df66a..4974dd5 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -370,7 +370,7 @@ static int attempt_merge(struct request_queue *q, struct request *req, req->biotail->bi_next = next->bio; req->biotail = next->biotail; - req->data_len += blk_rq_bytes(next); + req->__data_len += blk_rq_bytes(next); elv_merge_requests(q, req, next); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index ce2bf5e..c755803 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -166,8 +166,9 @@ struct request { enum rq_cmd_type_bits cmd_type; unsigned long atomic_flags; - sector_t sector; /* sector cursor */ - unsigned int data_len; /* total data len, don't access directly */ + /* the following two fields are internal, NEVER access directly */ + sector_t __sector; /* sector cursor */ + unsigned int __data_len; /* total data len */ struct bio *bio; struct bio *biotail; @@ -828,12 +829,12 @@ extern void blkdev_dequeue_request(struct request *req); */ static inline sector_t blk_rq_pos(const struct request *rq) { - return rq->sector; + return rq->__sector; } static inline unsigned int blk_rq_bytes(const struct request *rq) { - return rq->data_len; + return rq->__data_len; } static inline int blk_rq_cur_bytes(const struct request *rq) -- cgit v0.10.2 From 1011c1b9f2e45ce7c6e38888d2b83936aec38771 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 7 May 2009 22:24:45 +0900 Subject: block: blk_rq_[cur_]_{sectors|bytes}() usage cleanup With the previous changes, the followings are now guaranteed for all requests in any valid state. * blk_rq_sectors() == blk_rq_bytes() >> 9 * blk_rq_cur_sectors() == blk_rq_cur_bytes() >> 9 Clean up accessor usages. Notable changes are * nbd,i2o_block: end_all used instead of explicit byte count * scsi_lib: unnecessary conditional on request type removed [ Impact: cleanup ] Signed-off-by: Tejun Heo Cc: Paul Clements Cc: Pete Zaitcev Cc: Alex Dubov Cc: Markus Lidel Cc: David Woodhouse Cc: James Bottomley Cc: Boaz Harrosh Signed-off-by: Jens Axboe diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 4524862..1e27ed9 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -2512,8 +2512,7 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2) remaining = current_count_sectors << 9; #ifdef FLOPPY_SANITY_CHECK - if ((remaining >> 9) > blk_rq_sectors(current_req) && - CT(COMMAND) == FD_WRITE) { + if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) { DPRINT("in copy buffer\n"); printk("current_count_sectors=%ld\n", current_count_sectors); printk("remaining=%d\n", remaining >> 9); @@ -2530,7 +2529,7 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2) dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9); - size = blk_rq_cur_sectors(current_req) << 9; + size = blk_rq_cur_bytes(current_req); rq_for_each_segment(bv, current_req, iter) { if (!remaining) @@ -2879,7 +2878,7 @@ static int make_raw_rw_request(void) printk("write\n"); return 0; } - } else if (raw_cmd->length > blk_rq_sectors(current_req) << 9 || + } else if (raw_cmd->length > blk_rq_bytes(current_req) || current_count_sectors > blk_rq_sectors(current_req)) { DPRINT("buffer overrun in direct transfer\n"); return 0; diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 977a573..fad167de 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -110,7 +110,7 @@ static void nbd_end_request(struct request *req) req, error ? "failed" : "done"); spin_lock_irqsave(q->queue_lock, flags); - __blk_end_request(req, error, blk_rq_sectors(req) << 9); + __blk_end_request_all(req, error); spin_unlock_irqrestore(q->queue_lock, flags); } @@ -231,7 +231,7 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req) { int result, flags; struct nbd_request request; - unsigned long size = blk_rq_sectors(req) << 9; + unsigned long size = blk_rq_bytes(req); request.magic = htonl(NBD_REQUEST_MAGIC); request.type = htonl(nbd_cmd(req)); @@ -243,7 +243,7 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req) lo->disk->disk_name, req, nbdcmd_to_ascii(nbd_cmd(req)), (unsigned long long)blk_rq_pos(req) << 9, - blk_rq_sectors(req) << 9); + blk_rq_bytes(req)); result = sock_xmit(lo, 1, &request, sizeof(request), (nbd_cmd(req) == NBD_CMD_WRITE) ? MSG_MORE : 0); if (result <= 0) { diff --git a/drivers/block/ub.c b/drivers/block/ub.c index 1591f61..40d03cf 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -739,7 +739,7 @@ static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun, cmd->cdb[8] = nblks; cmd->cdb_len = 10; - cmd->len = blk_rq_sectors(rq) * 512; + cmd->len = blk_rq_bytes(rq); } static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun, diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c index d4e6b71..6a13838 100644 --- a/drivers/block/z2ram.c +++ b/drivers/block/z2ram.c @@ -72,7 +72,7 @@ static void do_z2_request(struct request_queue *q) struct request *req; while ((req = elv_next_request(q)) != NULL) { unsigned long start = blk_rq_pos(req) << 9; - unsigned long len = blk_rq_cur_sectors(req) << 9; + unsigned long len = blk_rq_cur_bytes(req); if (start + len > z2ram_size) { printk( KERN_ERR DEVICE_NAME ": bad access: block=%lu, count=%u\n", diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index 9e600d2..93b2c61 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -680,7 +680,7 @@ try_again: t_sec = blk_rq_pos(msb->block_req) << 9; sector_div(t_sec, msb->page_size); - count = blk_rq_sectors(msb->block_req) << 9; + count = blk_rq_bytes(msb->block_req); count /= msb->page_size; param.system = msb->system; @@ -745,7 +745,7 @@ static int mspro_block_complete_req(struct memstick_dev *card, int error) t_len *= msb->page_size; } } else - t_len = blk_rq_sectors(msb->block_req) << 9; + t_len = blk_rq_bytes(msb->block_req); dev_dbg(&card->dev, "transferred %x (%d)\n", t_len, error); diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index 6b61d28..e153f5d 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -426,15 +426,9 @@ static void i2o_block_end_request(struct request *req, int error, struct request_queue *q = req->q; unsigned long flags; - if (blk_end_request(req, error, nr_bytes)) { - int leftover = (blk_rq_sectors(req) << KERNEL_SECTOR_SHIFT); - - if (blk_pc_request(req)) - leftover = blk_rq_bytes(req); - + if (blk_end_request(req, error, nr_bytes)) if (error) - blk_end_request(req, -EIO, leftover); - } + blk_end_request_all(req, -EIO); spin_lock_irqsave(q->queue_lock, flags); @@ -832,15 +826,13 @@ static int i2o_block_transfer(struct request *req) memcpy(mptr, cmd, 10); mptr += 4; - *mptr++ = - cpu_to_le32(blk_rq_sectors(req) << KERNEL_SECTOR_SHIFT); + *mptr++ = cpu_to_le32(blk_rq_bytes(req)); } else #endif { msg->u.head[1] = cpu_to_le32(cmd | HOST_TID << 12 | tid); *mptr++ = cpu_to_le32(ctl_flags); - *mptr++ = - cpu_to_le32(blk_rq_sectors(req) << KERNEL_SECTOR_SHIFT); + *mptr++ = cpu_to_le32(blk_rq_bytes(req)); *mptr++ = cpu_to_le32((u32) (blk_rq_pos(req) << KERNEL_SECTOR_SHIFT)); *mptr++ = diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 4ea2e67..50c76a2 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -48,7 +48,7 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr, char *buf; block = blk_rq_pos(req) << 9 >> tr->blkshift; - nsect = blk_rq_cur_sectors(req) << 9 >> tr->blkshift; + nsect = blk_rq_cur_bytes(req) >> tr->blkshift; buf = req->buffer; diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c index 2132c90..d56ddaa 100644 --- a/drivers/sbus/char/jsflash.c +++ b/drivers/sbus/char/jsflash.c @@ -189,7 +189,7 @@ static void jsfd_do_request(struct request_queue *q) while ((req = elv_next_request(q)) != NULL) { struct jsfd_part *jdp = req->rq_disk->private_data; unsigned long offset = blk_rq_pos(req) << 9; - size_t len = blk_rq_cur_sectors(req) << 9; + size_t len = blk_rq_cur_bytes(req); if ((offset + len) > jdp->dsize) { __blk_end_request_cur(req, -EIO); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 3d16c70..ee308f6 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -546,7 +546,7 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int error, * to queue the remainder of them. */ if (blk_end_request(req, error, bytes)) { - int leftover = blk_rq_sectors(req) << 9; + int leftover = blk_rq_bytes(req); if (blk_pc_request(req)) leftover = req->resid_len; @@ -964,10 +964,7 @@ static int scsi_init_sgtable(struct request *req, struct scsi_data_buffer *sdb, count = blk_rq_map_sg(req->q, req, sdb->table.sgl); BUG_ON(count > sdb->table.nents); sdb->table.nents = count; - if (blk_pc_request(req)) - sdb->length = blk_rq_bytes(req); - else - sdb->length = blk_rq_sectors(req) << 9; + sdb->length = blk_rq_bytes(req); return BLKPREP_OK; } -- cgit v0.10.2 From 8f6205cd572fece673da0255d74843680f67f879 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 8 May 2009 11:53:59 +0900 Subject: ide: dequeue in-flight request ide generally has single request in flight and tracks it using hwif->rq and all state handlers follow the following convention. * ide_started is returned if the request is in flight. * ide_stopped is returned if the queue needs to be restarted. The request might or might not have been processed fully or partially. * hwif->rq is set to NULL, when an issued request completes. So, dequeueing model can be implemented by dequeueing after fetch, requeueing if hwif->rq isn't NULL on ide_stopped return and doing about the same thing on completion / port unlock paths. These changes can be made in ide-io proper. In addition to the above main changes, the following updates are necessary. * ide-cd shouldn't dequeue a request when issuing REQUEST SENSE for it as the request is already dequeued. * ide-atapi uses request queue as stack when issuing REQUEST SENSE to put the REQUEST SENSE in front of the failed request. This now needs to be done using requeueing. [ Impact: dequeue in-flight request ] Signed-off-by: Tejun Heo Cc: Bartlomiej Zolnierkiewicz Cc: Borislav Petkov Cc: Sergei Shtylyov Signed-off-by: Jens Axboe diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c index 792534d..2874c3d 100644 --- a/drivers/ide/ide-atapi.c +++ b/drivers/ide/ide-atapi.c @@ -246,6 +246,7 @@ EXPORT_SYMBOL_GPL(ide_queue_sense_rq); */ void ide_retry_pc(ide_drive_t *drive) { + struct request *failed_rq = drive->hwif->rq; struct request *sense_rq = &drive->sense_rq; struct ide_atapi_pc *pc = &drive->request_sense_pc; @@ -260,8 +261,17 @@ void ide_retry_pc(ide_drive_t *drive) if (drive->media == ide_tape) set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags); - if (ide_queue_sense_rq(drive, pc)) - ide_complete_rq(drive, -EIO, blk_rq_bytes(drive->hwif->rq)); + /* + * Push back the failed request and put request sense on top + * 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; + if (ide_queue_sense_rq(drive, pc)) { + blkdev_dequeue_request(failed_rq); + ide_complete_rq(drive, -EIO, blk_rq_bytes(failed_rq)); + } } EXPORT_SYMBOL_GPL(ide_retry_pc); diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 2eadc9d..4c7792f 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -405,15 +405,7 @@ static int cdrom_decode_status(ide_drive_t *drive, u8 stat) end_request: if (stat & ATA_ERR) { - struct request_queue *q = drive->queue; - unsigned long flags; - - spin_lock_irqsave(q->queue_lock, flags); - blkdev_dequeue_request(rq); - spin_unlock_irqrestore(q->queue_lock, flags); - hwif->rq = NULL; - return ide_queue_sense_rq(drive, rq) ? 2 : 1; } else return 2; diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index ca2519d..abda733 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -487,10 +487,10 @@ void do_ide_request(struct request_queue *q) if (!ide_lock_port(hwif)) { ide_hwif_t *prev_port; + + WARN_ON_ONCE(hwif->rq); repeat: prev_port = hwif->host->cur_port; - hwif->rq = NULL; - if (drive->dev_flags & IDE_DFLAG_SLEEPING && time_after(drive->sleep, jiffies)) { ide_unlock_port(hwif); @@ -519,7 +519,12 @@ repeat: * we know that the queue isn't empty, but this can happen * if the q->prep_rq_fn() decides to kill a request */ - rq = elv_next_request(drive->queue); + if (!rq) { + rq = elv_next_request(drive->queue); + if (rq) + blkdev_dequeue_request(rq); + } + spin_unlock_irq(q->queue_lock); spin_lock_irq(&hwif->lock); @@ -555,8 +560,11 @@ repeat: startstop = start_request(drive, rq); spin_lock_irq(&hwif->lock); - if (startstop == ide_stopped) + if (startstop == ide_stopped) { + rq = hwif->rq; + hwif->rq = NULL; goto repeat; + } } else goto plug_device; out: @@ -572,18 +580,24 @@ plug_device: plug_device_2: spin_lock_irq(q->queue_lock); + if (rq) + blk_requeue_request(q, rq); if (!elv_queue_empty(q)) blk_plug_device(q); } -static void ide_plug_device(ide_drive_t *drive) +static void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq) { struct request_queue *q = drive->queue; unsigned long flags; spin_lock_irqsave(q->queue_lock, flags); + + if (rq) + blk_requeue_request(q, rq); if (!elv_queue_empty(q)) blk_plug_device(q); + spin_unlock_irqrestore(q->queue_lock, flags); } @@ -632,6 +646,7 @@ void ide_timer_expiry (unsigned long data) unsigned long flags; int wait = -1; int plug_device = 0; + struct request *uninitialized_var(rq_in_flight); spin_lock_irqsave(&hwif->lock, flags); @@ -693,6 +708,8 @@ void ide_timer_expiry (unsigned long data) spin_lock_irq(&hwif->lock); enable_irq(hwif->irq); if (startstop == ide_stopped) { + rq_in_flight = hwif->rq; + hwif->rq = NULL; ide_unlock_port(hwif); plug_device = 1; } @@ -701,7 +718,7 @@ void ide_timer_expiry (unsigned long data) if (plug_device) { ide_unlock_host(hwif->host); - ide_plug_device(drive); + ide_requeue_and_plug(drive, rq_in_flight); } } @@ -787,6 +804,7 @@ irqreturn_t ide_intr (int irq, void *dev_id) ide_startstop_t startstop; irqreturn_t irq_ret = IRQ_NONE; int plug_device = 0; + struct request *uninitialized_var(rq_in_flight); if (host->host_flags & IDE_HFLAG_SERIALIZE) { if (hwif != host->cur_port) @@ -866,6 +884,8 @@ irqreturn_t ide_intr (int irq, void *dev_id) */ if (startstop == ide_stopped) { BUG_ON(hwif->handler); + rq_in_flight = hwif->rq; + hwif->rq = NULL; ide_unlock_port(hwif); plug_device = 1; } @@ -875,7 +895,7 @@ out: out_early: if (plug_device) { ide_unlock_host(hwif->host); - ide_plug_device(drive); + ide_requeue_and_plug(drive, rq_in_flight); } return irq_ret; -- cgit v0.10.2 From 9a8d23d8855e554fc5887f14cb008b55c4300ccc Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 8 May 2009 11:54:00 +0900 Subject: mg_disk: fix queue hang / infinite retry on !fs requests Both request functions in mg_disk simply return when they encounter a !fs request, which means the request will never be cleared from the queue causing queue hang and indefinite retry of the request. Fix it. While at it, flatten condition checks and add unlikely to !fs tests. [ Impact: fix possible queue hang / infinite retry of !fs requests ] Signed-off-by: Tejun Heo Cc: unsik Kim Signed-off-by: Jens Axboe diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index 826c349..be32388 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c @@ -672,16 +672,16 @@ static void mg_request_poll(struct request_queue *q) while ((req = elv_next_request(q)) != NULL) { host = req->rq_disk->private_data; - if (blk_fs_request(req)) { - switch (rq_data_dir(req)) { - case READ: - mg_read(req); - break; - case WRITE: - mg_write(req); - break; - } + + if (unlikely(!blk_fs_request(req))) { + __blk_end_request_cur(req, -EIO); + continue; } + + if (rq_data_dir(req) == READ) + mg_read(req); + else + mg_write(req); } } @@ -766,8 +766,10 @@ static void mg_request(struct request_queue *q) continue; } - if (!blk_fs_request(req)) - return; + if (unlikely(!blk_fs_request(req))) { + __blk_end_request_cur(req, -EIO); + continue; + } if (!mg_issue_req(req, host, sect_num, sect_cnt)) return; -- cgit v0.10.2 From 5b36ad6000ddea390aca3c3b67ead7616ace2ffc Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 8 May 2009 11:54:01 +0900 Subject: 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 Cc: unsik Kim Signed-off-by: Jens Axboe diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index be32388..1ca5d14 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c @@ -135,6 +135,7 @@ struct mg_host { struct device *dev; struct request_queue *breq; + struct request *req; spinlock_t lock; struct gendisk *gd; @@ -171,17 +172,27 @@ struct mg_host { 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, struct mg_host *host) { char *name = MG_DISK_NAME; - struct request *req; - if (host->breq) { - req = elv_next_request(host->breq); - if (req) - name = req->rq_disk->disk_name; - } + if (host->req) + name = host->req->rq_disk->disk_name; printk(KERN_ERR "%s: %s: status=0x%02x { ", name, msg, stat & 0xff); if (stat & ATA_BUSY) @@ -217,13 +228,9 @@ static void mg_dump_status(const char *msg, unsigned int stat, printk("AddrMarkNotFound "); printk("}"); if (host->error & (ATA_BBK | ATA_UNC | ATA_IDNF | ATA_AMNF)) { - if (host->breq) { - req = elv_next_request(host->breq); - if (req) - printk(", sector=%u", - (unsigned int)blk_rq_pos(req)); - } - + if (host->req) + printk(", sector=%u", + (unsigned int)blk_rq_pos(host->req)); } 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) { - struct request *req = elv_next_request(host->breq); - if (req != NULL) - if (++req->errors >= MG_MAX_ERRORS || - host->error == MG_ERR_TIMEOUT) - __blk_end_request_cur(req, -EIO); + if (host->req) + if (++host->req->errors >= MG_MAX_ERRORS || + host->error == MG_ERR_TIMEOUT) + mg_end_request_cur(host, -EIO); } 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 + 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) @@ -545,14 +551,14 @@ static void mg_write(struct request *req) outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base + 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) { + struct request *req = host->req; u32 i; u16 *buff; - struct request *req; /* check status */ do { @@ -571,7 +577,6 @@ static void mg_read_intr(struct mg_host *host) ok_to_read: /* get current segment of request */ - req = elv_next_request(host->breq); buff = (u16 *)req->buffer; /* read 1 sector */ @@ -585,7 +590,7 @@ ok_to_read: /* send read confirm */ 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 */ host->mg_do_intr = mg_read_intr; mod_timer(&host->timer, jiffies + 3 * HZ); @@ -595,14 +600,11 @@ ok_to_read: static void mg_write_intr(struct mg_host *host) { + struct request *req = host->req; u32 i, j; u16 *buff; - struct request *req; bool rem; - /* get current segment of request */ - req = elv_next_request(host->breq); - /* check status */ do { i = inb((unsigned long)host->dev_base + MG_REG_STATUS); @@ -619,7 +621,7 @@ static void mg_write_intr(struct mg_host *host) return; 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 */ buff = (u16 *)req->buffer; 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; char *name; - struct request *req; spin_lock_irq(&host->lock); - req = elv_next_request(host->breq); - if (!req) + if (!host->req) goto out_unlock; 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); host->error = MG_ERR_TIMEOUT; mg_bad_rw_intr(host); - mg_request(host->breq); out_unlock: + mg_request(host->breq); spin_unlock_irq(&host->lock); } static void mg_request_poll(struct request_queue *q) { - struct request *req; - struct mg_host *host; + struct mg_host *host = q->queuedata; - while ((req = elv_next_request(q)) != NULL) { - host = req->rq_disk->private_data; + while (1) { + 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))) { - __blk_end_request_cur(req, -EIO); + if (unlikely(!blk_fs_request(host->req))) { + mg_end_request_cur(host, -EIO); continue; } - if (rq_data_dir(req) == READ) - mg_read(req); + if (rq_data_dir(host->req) == READ) + mg_read(host->req); 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 */ static void mg_request(struct request_queue *q) { + struct mg_host *host = q->queuedata; struct request *req; - struct mg_host *host; u32 sect_num, sect_cnt; while (1) { - req = elv_next_request(q); - if (!req) - return; - - 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; + } + req = host->req; /* check unwanted request call */ 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", req->rq_disk->disk_name, sect_num, sect_cnt); - __blk_end_request_cur(req, -EIO); + mg_end_request_cur(host, -EIO); continue; } if (unlikely(!blk_fs_request(req))) { - __blk_end_request_cur(req, -EIO); + mg_end_request_cur(host, -EIO); continue; } @@ -981,6 +989,7 @@ static int mg_probe(struct platform_device *plat_dev) __func__, __LINE__); goto probe_err_5; } + host->breq->queuedata = host; /* mflash is random device, thanx for the noop */ elevator_exit(host->breq->elevator); -- cgit v0.10.2 From 8a12c4a456c7ee261a85c2cbec835601e6aae05a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 8 May 2009 11:54:02 +0900 Subject: hd: dequeue and track in-flight request hd has at most single request in flight. Till now, whenever it needs to access the in-flight request it called elv_next_request(). This patch makes hd track the in-flight request directly and dequeue it when processing starts. The added complexity is minimal and this will help future block layer changes. [ Impact: dequeue in-flight request, one elv_next_request() per request ] Signed-off-by: Tejun Heo Signed-off-by: Jens Axboe diff --git a/drivers/block/hd.c b/drivers/block/hd.c index a3b3994..288ab63 100644 --- a/drivers/block/hd.c +++ b/drivers/block/hd.c @@ -98,10 +98,9 @@ static DEFINE_SPINLOCK(hd_lock); static struct request_queue *hd_queue; +static struct request *hd_req; #define MAJOR_NR HD_MAJOR -#define QUEUE (hd_queue) -#define CURRENT elv_next_request(hd_queue) #define TIMEOUT_VALUE (6*HZ) #define HD_DELAY 0 @@ -195,11 +194,24 @@ static void __init hd_setup(char *str, int *ints) NR_HD = hdind+1; } +static bool hd_end_request(int err, unsigned int bytes) +{ + if (__blk_end_request(hd_req, err, bytes)) + return true; + hd_req = NULL; + return false; +} + +static bool hd_end_request_cur(int err) +{ + return hd_end_request(err, blk_rq_cur_bytes(hd_req)); +} + static void dump_status(const char *msg, unsigned int stat) { char *name = "hd?"; - if (CURRENT) - name = CURRENT->rq_disk->disk_name; + if (hd_req) + name = hd_req->rq_disk->disk_name; #ifdef VERBOSE_ERRORS printk("%s: %s: status=0x%02x { ", name, msg, stat & 0xff); @@ -227,8 +239,8 @@ static void dump_status(const char *msg, unsigned int stat) if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) { printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL), inb(HD_CURRENT) & 0xf, inb(HD_SECTOR)); - if (CURRENT) - printk(", sector=%ld", blk_rq_pos(CURRENT)); + if (hd_req) + printk(", sector=%ld", blk_rq_pos(hd_req)); } printk("\n"); } @@ -406,11 +418,12 @@ static void unexpected_hd_interrupt(void) */ static void bad_rw_intr(void) { - struct request *req = CURRENT; + struct request *req = hd_req; + if (req != NULL) { struct hd_i_struct *disk = req->rq_disk->private_data; if (++req->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) { - __blk_end_request_cur(req, -EIO); + hd_end_request_cur(-EIO); disk->special_op = disk->recalibrate = 1; } else if (req->errors % RESET_FREQ == 0) reset = 1; @@ -454,14 +467,14 @@ static void read_intr(void) return; ok_to_read: - req = CURRENT; + req = hd_req; insw(HD_DATA, req->buffer, 256); #ifdef DEBUG printk("%s: read: sector %ld, remaining = %u, buffer=%p\n", req->rq_disk->disk_name, blk_rq_pos(req) + 1, blk_rq_sectors(req) - 1, req->buffer+512); #endif - if (__blk_end_request(req, 0, 512)) { + if (hd_end_request(0, 512)) { SET_HANDLER(&read_intr); return; } @@ -475,7 +488,7 @@ ok_to_read: static void write_intr(void) { - struct request *req = CURRENT; + struct request *req = hd_req; int i; int retries = 100000; @@ -494,7 +507,7 @@ static void write_intr(void) return; ok_to_write: - if (__blk_end_request(req, 0, 512)) { + if (hd_end_request(0, 512)) { SET_HANDLER(&write_intr); outsw(HD_DATA, req->buffer, 256); return; @@ -525,18 +538,18 @@ static void hd_times_out(unsigned long dummy) do_hd = NULL; - if (!CURRENT) + if (!hd_req) return; spin_lock_irq(hd_queue->queue_lock); reset = 1; - name = CURRENT->rq_disk->disk_name; + name = hd_req->rq_disk->disk_name; printk("%s: timeout\n", name); - if (++CURRENT->errors >= MAX_ERRORS) { + if (++hd_req->errors >= MAX_ERRORS) { #ifdef DEBUG printk("%s: too many errors\n", name); #endif - __blk_end_request_cur(CURRENT, -EIO); + hd_end_request_cur(-EIO); } hd_request(); spin_unlock_irq(hd_queue->queue_lock); @@ -551,7 +564,7 @@ static int do_special_op(struct hd_i_struct *disk, struct request *req) } if (disk->head > 16) { printk("%s: cannot handle device with more than 16 heads - giving up\n", req->rq_disk->disk_name); - __blk_end_request_cur(req, -EIO); + hd_end_request_cur(-EIO); } disk->special_op = 0; return 1; @@ -578,11 +591,15 @@ static void hd_request(void) repeat: del_timer(&device_timer); - req = CURRENT; - if (!req) { - do_hd = NULL; - return; + if (!hd_req) { + hd_req = elv_next_request(hd_queue); + if (!hd_req) { + do_hd = NULL; + return; + } + blkdev_dequeue_request(hd_req); } + req = hd_req; if (reset) { reset_hd(); @@ -595,7 +612,7 @@ repeat: ((block+nsect) > get_capacity(req->rq_disk))) { printk("%s: bad access: block=%d, count=%d\n", req->rq_disk->disk_name, block, nsect); - __blk_end_request_cur(req, -EIO); + hd_end_request_cur(-EIO); goto repeat; } @@ -635,7 +652,7 @@ repeat: break; default: printk("unknown hd-command\n"); - __blk_end_request_cur(req, -EIO); + hd_end_request_cur(-EIO); break; } } -- cgit v0.10.2 From a336ca6fe6e0c46b2eef0e520951acb4e6cb2976 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 8 May 2009 11:54:03 +0900 Subject: ataflop: dequeue and track in-flight request ataflop has single request in flight. Till now, whenever it needs to access the in-flight request it called elv_next_request(). This patch makes ataflop track the in-flight request directly and dequeue it when processing starts. The added complexity is minimal and this will help future block layer changes. [ Impact: dequeue in-flight request, one elv_next_request() per request ] Signed-off-by: Tejun Heo Signed-off-by: Jens Axboe diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index 234024c..89a591d 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -79,9 +79,7 @@ #undef DEBUG static struct request_queue *floppy_queue; - -#define QUEUE (floppy_queue) -#define CURRENT elv_next_request(floppy_queue) +static struct request *fd_request; /* Disk types: DD, HD, ED */ static struct atari_disk_type { @@ -376,6 +374,12 @@ static DEFINE_TIMER(readtrack_timer, fd_readtrack_check, 0, 0); static DEFINE_TIMER(timeout_timer, fd_times_out, 0, 0); static DEFINE_TIMER(fd_timer, check_change, 0, 0); +static void fd_end_request_cur(int err) +{ + if (!__blk_end_request_cur(fd_request, err)) + fd_request = NULL; +} + static inline void start_motor_off_timer(void) { mod_timer(&motor_off_timer, jiffies + FD_MOTOR_OFF_DELAY); @@ -606,15 +610,15 @@ static void fd_error( void ) return; } - if (!CURRENT) + if (!fd_request) return; - CURRENT->errors++; - if (CURRENT->errors >= MAX_ERRORS) { + fd_request->errors++; + if (fd_request->errors >= MAX_ERRORS) { printk(KERN_ERR "fd%d: too many errors.\n", SelectedDrive ); - __blk_end_request_cur(CURRENT, -EIO); + fd_end_request_cur(-EIO); } - else if (CURRENT->errors == RECALIBRATE_ERRORS) { + else if (fd_request->errors == RECALIBRATE_ERRORS) { printk(KERN_WARNING "fd%d: recalibrating\n", SelectedDrive ); if (SelectedDrive != -1) SUD.track = -1; @@ -725,14 +729,14 @@ static void do_fd_action( int drive ) if (IS_BUFFERED( drive, ReqSide, ReqTrack )) { if (ReqCmd == READ) { copy_buffer( SECTOR_BUFFER(ReqSector), ReqData ); - if (++ReqCnt < blk_rq_cur_sectors(CURRENT)) { + if (++ReqCnt < blk_rq_cur_sectors(fd_request)) { /* read next sector */ setup_req_params( drive ); goto repeat; } else { /* all sectors finished */ - __blk_end_request_cur(CURRENT, 0); + fd_end_request_cur(0); redo_fd_request(); return; } @@ -1130,14 +1134,14 @@ static void fd_rwsec_done1(int status) } } - if (++ReqCnt < blk_rq_cur_sectors(CURRENT)) { + if (++ReqCnt < blk_rq_cur_sectors(fd_request)) { /* read next sector */ setup_req_params( SelectedDrive ); do_fd_action( SelectedDrive ); } else { /* all sectors finished */ - __blk_end_request_cur(CURRENT, 0); + fd_end_request_cur(0); redo_fd_request(); } return; @@ -1378,7 +1382,7 @@ static void setup_req_params( int drive ) ReqData = ReqBuffer + 512 * ReqCnt; if (UseTrackbuffer) - read_track = (ReqCmd == READ && CURRENT->errors == 0); + read_track = (ReqCmd == READ && fd_request->errors == 0); else read_track = 0; @@ -1392,25 +1396,28 @@ static void redo_fd_request(void) int drive, type; struct atari_floppy_struct *floppy; - DPRINT(("redo_fd_request: CURRENT=%p dev=%s CURRENT->sector=%ld\n", - CURRENT, CURRENT ? CURRENT->rq_disk->disk_name : "", - CURRENT ? blk_rq_pos(CURRENT) : 0 )); + DPRINT(("redo_fd_request: fd_request=%p dev=%s fd_request->sector=%ld\n", + fd_request, fd_request ? fd_request->rq_disk->disk_name : "", + fd_request ? blk_rq_pos(fd_request) : 0 )); IsFormatting = 0; repeat: + if (!fd_request) { + fd_request = elv_next_request(floppy_queue); + if (!fd_request) + goto the_end; + blkdev_dequeue_request(fd_request); + } - if (!CURRENT) - goto the_end; - - floppy = CURRENT->rq_disk->private_data; + floppy = fd_request->rq_disk->private_data; drive = floppy - unit; type = floppy->type; if (!UD.connected) { /* drive not connected */ printk(KERN_ERR "Unknown Device: fd%d\n", drive ); - __blk_end_request_cur(CURRENT, -EIO); + fd_end_request_cur(-EIO); goto repeat; } @@ -1426,12 +1433,12 @@ repeat: /* user supplied disk type */ if (--type >= NUM_DISK_MINORS) { printk(KERN_WARNING "fd%d: invalid disk format", drive ); - __blk_end_request_cur(CURRENT, -EIO); + fd_end_request_cur(-EIO); goto repeat; } if (minor2disktype[type].drive_types > DriveType) { printk(KERN_WARNING "fd%d: unsupported disk format", drive ); - __blk_end_request_cur(CURRENT, -EIO); + fd_end_request_cur(-EIO); goto repeat; } type = minor2disktype[type].index; @@ -1440,8 +1447,8 @@ repeat: UD.autoprobe = 0; } - if (blk_rq_pos(CURRENT) + 1 > UDT->blocks) { - __blk_end_request_cur(CURRENT, -EIO); + if (blk_rq_pos(fd_request) + 1 > UDT->blocks) { + fd_end_request_cur(-EIO); goto repeat; } @@ -1449,9 +1456,9 @@ repeat: del_timer( &motor_off_timer ); ReqCnt = 0; - ReqCmd = rq_data_dir(CURRENT); - ReqBlock = blk_rq_pos(CURRENT); - ReqBuffer = CURRENT->buffer; + ReqCmd = rq_data_dir(fd_request); + ReqBlock = blk_rq_pos(fd_request); + ReqBuffer = fd_request->buffer; setup_req_params( drive ); do_fd_action( drive ); -- cgit v0.10.2 From f4bd4b90bfa86e867111aa182895cb5ac203aa7a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 8 May 2009 11:54:04 +0900 Subject: swim3: dequeue in-flight request swim3 has at most single request in flight and already tracks it using fd_req. Convert it to dequeuing model by updating request fetching and wrapping completion function. [ Impact: dequeue in-flight request ] Signed-off-by: Tejun Heo Signed-off-by: Jens Axboe diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index c1b9a4d..f48c6dd 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -251,6 +251,20 @@ static int floppy_release(struct gendisk *disk, fmode_t mode); static int floppy_check_change(struct gendisk *disk); static int floppy_revalidate(struct gendisk *disk); +static bool swim3_end_request(int err, unsigned int nr_bytes) +{ + if (__blk_end_request(fd_req, err, nr_bytes)) + return true; + + fd_req = NULL; + return false; +} + +static bool swim3_end_request_cur(int err) +{ + return swim3_end_request(err, blk_rq_cur_bytes(fd_req)); +} + static void swim3_select(struct floppy_state *fs, int sel) { struct swim3 __iomem *sw = fs->swim3; @@ -310,7 +324,14 @@ static void start_request(struct floppy_state *fs) wake_up(&fs->wait); return; } - while (fs->state == idle && (req = elv_next_request(swim3_queue))) { + while (fs->state == idle) { + if (!fd_req) { + fd_req = elv_next_request(swim3_queue); + if (!fd_req) + break; + blkdev_dequeue_request(fd_req); + } + req = fd_req; #if 0 printk("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%u buf=%p\n", req->rq_disk->disk_name, req->cmd, @@ -320,11 +341,11 @@ static void start_request(struct floppy_state *fs) #endif if (blk_rq_pos(req) >= fs->total_secs) { - __blk_end_request_cur(req, -EIO); + swim3_end_request_cur(-EIO); continue; } if (fs->ejected) { - __blk_end_request_cur(req, -EIO); + swim3_end_request_cur(-EIO); continue; } @@ -332,7 +353,7 @@ static void start_request(struct floppy_state *fs) if (fs->write_prot < 0) fs->write_prot = swim3_readbit(fs, WRITE_PROT); if (fs->write_prot) { - __blk_end_request_cur(req, -EIO); + swim3_end_request_cur(-EIO); continue; } } @@ -505,7 +526,7 @@ static void act(struct floppy_state *fs) case do_transfer: if (fs->cur_cyl != fs->req_cyl) { if (fs->retries > 5) { - __blk_end_request_cur(fd_req, -EIO); + swim3_end_request_cur(-EIO); fs->state = idle; return; } @@ -537,7 +558,7 @@ static void scan_timeout(unsigned long data) out_8(&sw->intr_enable, 0); fs->cur_cyl = -1; if (fs->retries > 5) { - __blk_end_request_cur(fd_req, -EIO); + swim3_end_request_cur(-EIO); fs->state = idle; start_request(fs); } else { @@ -556,7 +577,7 @@ static void seek_timeout(unsigned long data) out_8(&sw->select, RELAX); out_8(&sw->intr_enable, 0); printk(KERN_ERR "swim3: seek timeout\n"); - __blk_end_request_cur(fd_req, -EIO); + swim3_end_request_cur(-EIO); fs->state = idle; start_request(fs); } @@ -580,7 +601,7 @@ static void settle_timeout(unsigned long data) return; } printk(KERN_ERR "swim3: seek settle timeout\n"); - __blk_end_request_cur(fd_req, -EIO); + swim3_end_request_cur(-EIO); fs->state = idle; start_request(fs); } @@ -603,7 +624,7 @@ static void xfer_timeout(unsigned long data) printk(KERN_ERR "swim3: timeout %sing sector %ld\n", (rq_data_dir(fd_req)==WRITE? "writ": "read"), (long)blk_rq_pos(fd_req)); - __blk_end_request_cur(fd_req, -EIO); + swim3_end_request_cur(-EIO); fs->state = idle; start_request(fs); } @@ -634,7 +655,7 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id) printk(KERN_ERR "swim3: seen sector but cyl=ff?\n"); fs->cur_cyl = -1; if (fs->retries > 5) { - __blk_end_request_cur(fd_req, -EIO); + swim3_end_request_cur(-EIO); fs->state = idle; start_request(fs); } else { @@ -717,7 +738,7 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id) printk("swim3: error %sing block %ld (err=%x)\n", rq_data_dir(fd_req) == WRITE? "writ": "read", (long)blk_rq_pos(fd_req), err); - __blk_end_request_cur(fd_req, -EIO); + swim3_end_request_cur(-EIO); fs->state = idle; } } else { @@ -726,12 +747,12 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id) printk(KERN_ERR "swim3: fd dma: stat=%x resid=%d\n", stat, resid); printk(KERN_ERR " state=%d, dir=%x, intr=%x, err=%x\n", fs->state, rq_data_dir(fd_req), intr, err); - __blk_end_request_cur(fd_req, -EIO); + swim3_end_request_cur(-EIO); fs->state = idle; start_request(fs); break; } - if (__blk_end_request(fd_req, 0, fs->scount << 9)) { + if (swim3_end_request(0, fs->scount << 9)) { fs->req_sector += fs->scount; if (fs->req_sector > fs->secpertrack) { fs->req_sector -= fs->secpertrack; -- cgit v0.10.2 From 2d75ce084eec2a8154225c7e978191b364029003 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 8 May 2009 11:54:05 +0900 Subject: xsysace: dequeue in-flight request xsysace already tracks in-flight request using ace->req. Converting to dequeueing model is mostly a matter of adding dequeueing call after request fetching. The only tricky part is handling CF removal which should complete both in flight and on queue requests. Convert to dequeueing model. While at it, remove explicit blk_rq_cur_bytes() and use __blk_end_request_cur() instead. [ Impact: dequeue in-flight request ] Signed-off-by: Tejun Heo Cc: Grant Likely Signed-off-by: Jens Axboe diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 97c99b43..edf137b 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -466,7 +466,8 @@ struct request *ace_get_next_request(struct request_queue * q) while ((req = elv_next_request(q)) != NULL) { if (blk_fs_request(req)) break; - __blk_end_request_cur(req, -EIO); + blkdev_dequeue_request(req); + __blk_end_request_all(req, -EIO); } return req; } @@ -492,9 +493,15 @@ static void ace_fsm_dostate(struct ace_device *ace) set_capacity(ace->gd, 0); dev_info(ace->dev, "No CF in slot\n"); - /* Drop all pending requests */ - while ((req = elv_next_request(ace->queue)) != NULL) - __blk_end_request_cur(req, -EIO); + /* Drop all in-flight and pending requests */ + if (ace->req) { + __blk_end_request_all(ace->req, -EIO); + ace->req = NULL; + } + while ((req = elv_next_request(ace->queue)) != NULL) { + blkdev_dequeue_request(req); + __blk_end_request_all(req, -EIO); + } /* Drop back to IDLE state and notify waiters */ ace->fsm_state = ACE_FSM_STATE_IDLE; @@ -642,6 +649,7 @@ static void ace_fsm_dostate(struct ace_device *ace) ace->fsm_state = ACE_FSM_STATE_IDLE; break; } + blkdev_dequeue_request(req); /* Okay, it's a data request, set it up for transfer */ dev_dbg(ace->dev, @@ -718,8 +726,7 @@ static void ace_fsm_dostate(struct ace_device *ace) } /* bio finished; is there another one? */ - if (__blk_end_request(ace->req, 0, - blk_rq_cur_bytes(ace->req))) { + if (__blk_end_request_cur(ace->req, 0)) { /* dev_dbg(ace->dev, "next block; h=%u c=%u\n", * blk_rq_sectors(ace->req), * blk_rq_cur_sectors(ace->req)); -- cgit v0.10.2 From b12d4f82c1a3cdcb2441c803a3368a9426f2f47f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 8 May 2009 11:54:06 +0900 Subject: paride: dequeue in-flight request pd/pf/pcd have track in-flight request by pd/pf/pcd_req. They can be converted to dequeueing model by updating fetching and completion paths. Convert them. Note that removal of elv_next_request() call from pf_next_buf() doesn't make any functional difference. The path is traveled only during partial completion of a request and elv_next_request() call must return the same request anyway. [ Impact: dequeue in-flight request ] Signed-off-by: Tejun Heo Cc: Tim Waugh Signed-off-by: Jens Axboe diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c index 2d5dc0a..425f815 100644 --- a/drivers/block/paride/pcd.c +++ b/drivers/block/paride/pcd.c @@ -719,9 +719,12 @@ static void do_pcd_request(struct request_queue * q) if (pcd_busy) return; while (1) { - pcd_req = elv_next_request(q); - if (!pcd_req) - return; + if (!pcd_req) { + pcd_req = elv_next_request(q); + if (!pcd_req) + return; + blkdev_dequeue_request(pcd_req); + } if (rq_data_dir(pcd_req) == READ) { struct pcd_unit *cd = pcd_req->rq_disk->private_data; @@ -734,8 +737,10 @@ static void do_pcd_request(struct request_queue * q) pcd_busy = 1; ps_set_intr(do_pcd_read, NULL, 0, nice); return; - } else - __blk_end_request_cur(pcd_req, -EIO); + } else { + __blk_end_request_all(pcd_req, -EIO); + pcd_req = NULL; + } } } @@ -744,7 +749,8 @@ static inline void next_request(int err) unsigned long saved_flags; spin_lock_irqsave(&pcd_lock, saved_flags); - __blk_end_request_cur(pcd_req, err); + if (!__blk_end_request_cur(pcd_req, err)) + pcd_req = NULL; pcd_busy = 0; do_pcd_request(pcd_queue); spin_unlock_irqrestore(&pcd_lock, saved_flags); diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 9ec5d4a..d2ca3f5 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -410,11 +410,14 @@ static void run_fsm(void) pd_claimed = 0; phase = NULL; spin_lock_irqsave(&pd_lock, saved_flags); - __blk_end_request_cur(pd_req, - res == Ok ? 0 : -EIO); - pd_req = elv_next_request(pd_queue); - if (!pd_req) - stop = 1; + if (!__blk_end_request_cur(pd_req, + res == Ok ? 0 : -EIO)) { + pd_req = elv_next_request(pd_queue); + if (!pd_req) + stop = 1; + else + blkdev_dequeue_request(pd_req); + } spin_unlock_irqrestore(&pd_lock, saved_flags); if (stop) return; @@ -706,6 +709,7 @@ static void do_pd_request(struct request_queue * q) pd_req = elv_next_request(q); if (!pd_req) return; + blkdev_dequeue_request(pd_req); schedule_fsm(); } diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index e88c889..d6f7bd8 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -752,10 +752,8 @@ static struct request_queue *pf_queue; static void pf_end_request(int err) { - if (pf_req) { - __blk_end_request_cur(pf_req, err); + if (pf_req && !__blk_end_request_cur(pf_req, err)) pf_req = NULL; - } } static void do_pf_request(struct request_queue * q) @@ -763,9 +761,12 @@ static void do_pf_request(struct request_queue * q) if (pf_busy) return; repeat: - pf_req = elv_next_request(q); - if (!pf_req) - return; + if (!pf_req) { + pf_req = elv_next_request(q); + if (!pf_req) + return; + blkdev_dequeue_request(pf_req); + } pf_current = pf_req->rq_disk->private_data; pf_block = blk_rq_pos(pf_req); @@ -806,7 +807,6 @@ static int pf_next_buf(void) if (!pf_count) { spin_lock_irqsave(&pf_spin_lock, saved_flags); pf_end_request(0); - pf_req = elv_next_request(pf_queue); spin_unlock_irqrestore(&pf_spin_lock, saved_flags); if (!pf_req) return 1; -- cgit v0.10.2 From 10e1e629b386aef97bf66de6ef28d450bec06ee3 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 8 May 2009 11:54:07 +0900 Subject: ps3disk: dequeue in-flight request Other than in issue error paths, ps3disk always completely finishes fetched requests. With full completion on error paths, it can be easily converted to dequeueing model. * After L1 r/w call failure, ps3disk_submit_request_sg() now fails the whole request. Issue failure isn't likely to benefit from partial retry anyway and ps3disk uses full failure in completion error path too, so I don't think this amounts to any meaningful functionality loss. * flush completion is converted to _all for consistency. It doesn't make any functional difference. [ Impact: dequeue in-flight request ] Signed-off-by: Tejun Heo Cc: Geert Uytterhoeven Signed-off-by: Jens Axboe diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index 8d58308..f4d8db9 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -157,7 +157,7 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev, if (res) { dev_err(&dev->sbd.core, "%s:%u: %s failed %d\n", __func__, __LINE__, op, res); - __blk_end_request_cur(req, -EIO); + __blk_end_request_all(req, -EIO); return 0; } @@ -179,7 +179,7 @@ static int ps3disk_submit_flush_request(struct ps3_storage_device *dev, if (res) { dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%llx\n", __func__, __LINE__, res); - __blk_end_request_cur(req, -EIO); + __blk_end_request_all(req, -EIO); return 0; } @@ -195,6 +195,8 @@ static void ps3disk_do_request(struct ps3_storage_device *dev, dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__); while ((req = elv_next_request(q))) { + blkdev_dequeue_request(req); + if (blk_fs_request(req)) { if (ps3disk_submit_request_sg(dev, req)) break; @@ -204,7 +206,7 @@ static void ps3disk_do_request(struct ps3_storage_device *dev, break; } else { blk_dump_rq_flags(req, DEVICE_NAME " bad request"); - __blk_end_request_cur(req, -EIO); + __blk_end_request_all(req, -EIO); continue; } } -- cgit v0.10.2 From 9e31bebee2d8b5f8abe9677f2a29b90cba848657 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 8 May 2009 11:54:08 +0900 Subject: amiflop: dequeue in-flight request Request processing in amiflop is done sequentially in redo_fd_request() proper and redo_fd_request() can easily be converted to track in-flight request. Remove CURRENT, track in-flight request directly and dequeue it when processing starts. [ Impact: dequeue in-flight request ] Signed-off-by: Tejun Heo Signed-off-by: Jens Axboe diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index e4a14b9..80a68b2 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -112,8 +112,6 @@ module_param(fd_def_df0, ulong, 0); MODULE_LICENSE("GPL"); static struct request_queue *floppy_queue; -#define QUEUE (floppy_queue) -#define CURRENT elv_next_request(floppy_queue) /* * Macros @@ -1335,59 +1333,61 @@ static int get_track(int drive, int track) static void redo_fd_request(void) { + struct request *rq; unsigned int cnt, block, track, sector; int drive; struct amiga_floppy_struct *floppy; char *data; unsigned long flags; + int err; - repeat: - if (!CURRENT) { +next_req: + rq = elv_next_request(floppy_queue); + if (!rq) { /* Nothing left to do */ return; } + blkdev_dequeue_request(rq); - floppy = CURRENT->rq_disk->private_data; + floppy = rq->rq_disk->private_data; drive = floppy - unit; +next_segment: /* Here someone could investigate to be more efficient */ - for (cnt = 0; cnt < blk_rq_cur_sectors(CURRENT); cnt++) { + for (cnt = 0, err = 0; cnt < blk_rq_cur_sectors(rq); cnt++) { #ifdef DEBUG printk("fd: sector %ld + %d requested for %s\n", - blk_rq_pos(CURRENT), cnt, - (rq_data_dir(CURRENT) == READ) ? "read" : "write"); + blk_rq_pos(rq), cnt, + (rq_data_dir(rq) == READ) ? "read" : "write"); #endif - block = blk_rq_pos(CURRENT) + cnt; + block = blk_rq_pos(rq) + cnt; if ((int)block > floppy->blocks) { - __blk_end_request_cur(CURRENT, -EIO); - goto repeat; + err = -EIO; + break; } track = block / (floppy->dtype->sects * floppy->type->sect_mult); sector = block % (floppy->dtype->sects * floppy->type->sect_mult); - data = CURRENT->buffer + 512 * cnt; + data = rq->buffer + 512 * cnt; #ifdef DEBUG printk("access to track %d, sector %d, with buffer at " "0x%08lx\n", track, sector, data); #endif if (get_track(drive, track) == -1) { - __blk_end_request_cur(CURRENT, -EIO); - goto repeat; + err = -EIO; + break; } - switch (rq_data_dir(CURRENT)) { - case READ: + if (rq_data_dir(rq) == READ) { memcpy(data, floppy->trackbuf + sector * 512, 512); - break; - - case WRITE: + } else { memcpy(floppy->trackbuf + sector * 512, data, 512); /* keep the drive spinning while writes are scheduled */ if (!fd_motor_on(drive)) { - __blk_end_request_cur(CURRENT, -EIO); - goto repeat; + err = -EIO; + break; } /* * setup a callback to write the track buffer @@ -1399,12 +1399,12 @@ static void redo_fd_request(void) /* reset the timer */ mod_timer (flush_track_timer + drive, jiffies + 1); local_irq_restore(flags); - break; } } - __blk_end_request_cur(CURRENT, 0); - goto repeat; + if (__blk_end_request_cur(rq, err)) + goto next_segment; + goto next_req; } static void do_fd_request(struct request_queue * q) -- cgit v0.10.2 From 06b0608e2b46465e8e663214e7db982ddb000346 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 8 May 2009 11:54:09 +0900 Subject: swim: dequeue in-flight request swim processes requests one-by-one synchronously and can easily be converted to dequeuing model. Convert it. [ Impact: dequeue in-flight request ] Signed-off-by: Tejun Heo Cc: Laurent Vivier Signed-off-by: Jens Axboe diff --git a/drivers/block/swim.c b/drivers/block/swim.c index fc6a1c3..dedd489 100644 --- a/drivers/block/swim.c +++ b/drivers/block/swim.c @@ -514,7 +514,7 @@ static int floppy_read_sectors(struct floppy_state *fs, ret = swim_read_sector(fs, side, track, sector, buffer); if (try-- == 0) - return -1; + return -EIO; } while (ret != 512); buffer += ret; @@ -528,38 +528,37 @@ static void redo_fd_request(struct request_queue *q) struct request *req; struct floppy_state *fs; - while ((req = elv_next_request(q))) { + req = elv_next_request(q); + if (req) + blkdev_dequeue_request(req); + + while (req) { + int err = -EIO; fs = req->rq_disk->private_data; - if (blk_rq_pos(req) >= fs->total_secs) { - __blk_end_request_cur(req, -EIO); - continue; - } - if (!fs->disk_in) { - __blk_end_request_cur(req, -EIO); - continue; - } - if (rq_data_dir(req) == WRITE) { - if (fs->write_protected) { - __blk_end_request_cur(req, -EIO); - continue; - } - } + if (blk_rq_pos(req) >= fs->total_secs) + goto done; + if (!fs->disk_in) + goto done; + if (rq_data_dir(req) == WRITE && fs->write_protected) + goto done; + switch (rq_data_dir(req)) { case WRITE: /* NOT IMPLEMENTED */ - __blk_end_request_cur(req, -EIO); break; case READ: - if (floppy_read_sectors(fs, blk_rq_pos(req), - blk_rq_cur_sectors(req), - req->buffer)) { - __blk_end_request_cur(req, -EIO); - continue; - } - __blk_end_request_cur(req, 0); + err = floppy_read_sectors(fs, blk_rq_pos(req), + blk_rq_cur_sectors(req), + req->buffer); break; } + done: + if (!__blk_end_request_cur(req, err)) { + req = elv_next_request(q); + if (req) + blkdev_dequeue_request(req); + } } } -- cgit v0.10.2 From bab2a807a489822ded0c9d4a5344c80bcac10b0a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 8 May 2009 11:54:10 +0900 Subject: xd: dequeue in-flight request xd processes requests one-by-one synchronously and can be easily converted to dequeueing model. Convert it. While at it, use rq_cur_bytes instead of rq_bytes when checking for sector overflow. This is for for consistency and better behavior for merged requests. [ Impact: dequeue in-flight request ] Signed-off-by: Tejun Heo Signed-off-by: Jens Axboe diff --git a/drivers/block/xd.c b/drivers/block/xd.c index 4ef8801..d4c4352 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -305,26 +305,31 @@ static void do_xd_request (struct request_queue * q) if (xdc_busy) return; - while ((req = elv_next_request(q)) != NULL) { + req = elv_next_request(q); + if (req) + blkdev_dequeue_request(req); + + while (req) { unsigned block = blk_rq_pos(req); - unsigned count = blk_rq_sectors(req); + unsigned count = blk_rq_cur_sectors(req); XD_INFO *disk = req->rq_disk->private_data; - int res = 0; + int res = -EIO; int retry; - if (!blk_fs_request(req)) { - __blk_end_request_cur(req, -EIO); - continue; - } - if (block + count > get_capacity(req->rq_disk)) { - __blk_end_request_cur(req, -EIO); - continue; - } + if (!blk_fs_request(req)) + goto done; + if (block + count > get_capacity(req->rq_disk)) + goto done; for (retry = 0; (retry < XD_RETRIES) && !res; retry++) res = xd_readwrite(rq_data_dir(req), disk, req->buffer, block, count); + done: /* wrap up, 0 = success, -errno = fail */ - __blk_end_request_cur(req, res); + if (!__blk_end_request_cur(req, res)) { + req = elv_next_request(q); + if (req) + blkdev_dequeue_request(req); + } } } -- cgit v0.10.2 From 1498ada7a8e80afe324f2b8d86158925d0096ec9 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 8 May 2009 11:54:11 +0900 Subject: mtd_blkdevs: dequeue in-flight request mtd_blkdevs processes requests one-by-one synchronously from a kthread and can be easily converted to dequeueing model. Convert it. [ Impact: dequeue in-flight request ] Signed-off-by: Tejun Heo Cc: David Woodhouse Signed-off-by: Jens Axboe diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 50c76a2..3e10442 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -89,18 +89,22 @@ static int mtd_blktrans_thread(void *arg) { struct mtd_blktrans_ops *tr = arg; struct request_queue *rq = tr->blkcore_priv->rq; + struct request *req = NULL; /* we might get involved when memory gets low, so use PF_MEMALLOC */ current->flags |= PF_MEMALLOC; spin_lock_irq(rq->queue_lock); + while (!kthread_should_stop()) { - struct request *req; struct mtd_blktrans_dev *dev; int res; - req = elv_next_request(rq); - + if (!req) { + req = elv_next_request(rq); + if (req) + blkdev_dequeue_request(req); + } if (!req) { set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irq(rq->queue_lock); @@ -120,8 +124,13 @@ static int mtd_blktrans_thread(void *arg) spin_lock_irq(rq->queue_lock); - __blk_end_request_cur(req, res); + if (!__blk_end_request_cur(req, res)) + req = NULL; } + + if (req) + __blk_end_request_all(req, -EIO); + spin_unlock_irq(rq->queue_lock); return 0; -- cgit v0.10.2 From 6b0bf407b586b6ba8e060ad9979cb2bc3370b7eb Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 8 May 2009 11:54:12 +0900 Subject: jsflash: dequeue in-flight request jsflash processes requests one-by-one synchronously from a kthread and can be easily converted to dequeueing model. Convert it. [ Impact: dequeue in-flight request ] Signed-off-by: Tejun Heo Cc: Pete Zaitcev Signed-off-by: Jens Axboe diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c index d56ddaa..f572a4a 100644 --- a/drivers/sbus/char/jsflash.c +++ b/drivers/sbus/char/jsflash.c @@ -186,31 +186,37 @@ static void jsfd_do_request(struct request_queue *q) { struct request *req; - while ((req = elv_next_request(q)) != NULL) { + req = elv_next_request(q); + if (req) + blkdev_dequeue_request(req); + + while (req) { struct jsfd_part *jdp = req->rq_disk->private_data; unsigned long offset = blk_rq_pos(req) << 9; size_t len = blk_rq_cur_bytes(req); + int err = -EIO; - if ((offset + len) > jdp->dsize) { - __blk_end_request_cur(req, -EIO); - continue; - } + if ((offset + len) > jdp->dsize) + goto end; if (rq_data_dir(req) != READ) { printk(KERN_ERR "jsfd: write\n"); - __blk_end_request_cur(req, -EIO); - continue; + goto end; } if ((jdp->dbase & 0xff000000) != 0x20000000) { printk(KERN_ERR "jsfd: bad base %x\n", (int)jdp->dbase); - __blk_end_request_cur(req, -EIO); - continue; + goto end; } jsfd_read(req->buffer, jdp->dbase + offset, len); - - __blk_end_request_cur(req, 0); + err = 0; + end: + if (!__blk_end_request_cur(req, err)) { + req = elv_next_request(q); + if (req) + blkdev_dequeue_request(req); + } } } -- cgit v0.10.2 From fb3ac7f6b811eac8e0aafa3df1c16ed872e898a8 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 8 May 2009 11:54:13 +0900 Subject: z2ram: dequeue in-flight request z2ram processes requests one-by-one synchronously and can be easily converted to dequeueing model. Convert it. [ Impact: dequeue in-flight request ] Signed-off-by: Tejun Heo Signed-off-by: Jens Axboe diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c index 6a13838..c909c1a 100644 --- a/drivers/block/z2ram.c +++ b/drivers/block/z2ram.c @@ -70,15 +70,21 @@ static struct gendisk *z2ram_gendisk; static void do_z2_request(struct request_queue *q) { struct request *req; - while ((req = elv_next_request(q)) != NULL) { + + req = elv_next_request(q); + if (req) + blkdev_dequeue_request(req); + + while (req) { unsigned long start = blk_rq_pos(req) << 9; unsigned long len = blk_rq_cur_bytes(req); + int err = 0; if (start + len > z2ram_size) { printk( KERN_ERR DEVICE_NAME ": bad access: block=%lu, count=%u\n", blk_rq_pos(req), blk_rq_cur_sectors(req)); - __blk_end_request_cur(req, -EIO); - continue; + err = -EIO; + goto done; } while (len) { unsigned long addr = start & Z2RAM_CHUNKMASK; @@ -93,7 +99,12 @@ static void do_z2_request(struct request_queue *q) start += size; len -= size; } - __blk_end_request_cur(req, 0); + done: + if (!__blk_end_request_cur(req, err)) { + req = elv_next_request(q); + if (req) + blkdev_dequeue_request(req); + } } } -- cgit v0.10.2 From 296b2f6ae654581adc27f0d6f0af454c7f3d06ee Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 8 May 2009 11:54:15 +0900 Subject: block: convert to dequeueing model (easy ones) plat-omap/mailbox, floppy, viocd, mspro_block, i2o_block and mmc/card/queue are already pretty close to dequeueing model and can be converted with simple changes. Convert them. While at it, * xen-blkfront: !fs check moved downwards to share dequeue call with normal path. * mspro_block: __blk_end_request(..., blk_rq_cur_byte()) converted to __blk_end_request_cur() * mmc/card/queue: loop of __blk_end_request() converted to __blk_end_request_all() [ Impact: dequeue in-flight request ] Signed-off-by: Tejun Heo Cc: Rusty Russell Cc: Jeremy Fitzhardinge Cc: Stephen Rothwell Cc: Alex Dubov Cc: Markus Lidel Cc: Pierre Ossman Signed-off-by: Jens Axboe diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c index 538ba75..7a1f5c2 100644 --- a/arch/arm/plat-omap/mailbox.c +++ b/arch/arm/plat-omap/mailbox.c @@ -198,6 +198,8 @@ static void mbox_tx_work(struct work_struct *work) spin_lock(q->queue_lock); rq = elv_next_request(q); + if (rq) + blkdev_dequeue_request(rq); spin_unlock(q->queue_lock); if (!rq) @@ -208,6 +210,9 @@ static void mbox_tx_work(struct work_struct *work) ret = __mbox_msg_send(mbox, tx_data->msg, tx_data->arg); if (ret) { enable_mbox_irq(mbox, IRQ_TX); + spin_lock(q->queue_lock); + blk_requeue_request(q, rq); + spin_unlock(q->queue_lock); return; } @@ -238,6 +243,8 @@ static void mbox_rx_work(struct work_struct *work) while (1) { spin_lock_irqsave(q->queue_lock, flags); rq = elv_next_request(q); + if (rq) + blkdev_dequeue_request(rq); spin_unlock_irqrestore(q->queue_lock, flags); if (!rq) break; @@ -345,6 +352,8 @@ omap_mbox_read(struct device *dev, struct device_attribute *attr, char *buf) while (1) { spin_lock_irqsave(q->queue_lock, flags); rq = elv_next_request(q); + if (rq) + blkdev_dequeue_request(rq); spin_unlock_irqrestore(q->queue_lock, flags); if (!rq) diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 1e27ed9..e2c70d2 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -931,7 +931,7 @@ static inline void unlock_fdc(void) del_timer(&fd_timeout); cont = NULL; clear_bit(0, &fdc_busy); - if (elv_next_request(floppy_queue)) + if (current_req || elv_next_request(floppy_queue)) do_fd_request(floppy_queue); spin_unlock_irqrestore(&floppy_lock, flags); wake_up(&fdc_wait); @@ -2913,6 +2913,8 @@ static void redo_fd_request(void) spin_lock_irq(floppy_queue->queue_lock); req = elv_next_request(floppy_queue); + if (req) + blkdev_dequeue_request(req); spin_unlock_irq(floppy_queue->queue_lock); if (!req) { do_floppy = NULL; diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 91fc565..66f8345 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -301,22 +301,23 @@ static void do_blkif_request(struct request_queue *rq) while ((req = elv_next_request(rq)) != NULL) { info = req->rq_disk->private_data; - if (!blk_fs_request(req)) { - __blk_end_request_cur(req, -EIO); - continue; - } if (RING_FULL(&info->ring)) goto wait; + blkdev_dequeue_request(req); + + if (!blk_fs_request(req)) { + __blk_end_request_all(req, -EIO); + continue; + } + pr_debug("do_blk_req %p: cmd %p, sec %lx, " "(%u/%u) buffer:%p [%s]\n", req, req->cmd, (unsigned long)blk_rq_pos(req), blk_rq_cur_sectors(req), blk_rq_sectors(req), req->buffer, rq_data_dir(req) ? "write" : "read"); - - blkdev_dequeue_request(req); if (blkif_queue_request(req)) { blk_requeue_request(rq, req); wait: diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index 6e190a9..bbe9f08 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -298,6 +298,8 @@ static void do_viocd_request(struct request_queue *q) struct request *req; while ((rwreq == 0) && ((req = elv_next_request(q)) != NULL)) { + blkdev_dequeue_request(req); + if (!blk_fs_request(req)) __blk_end_request_all(req, -EIO); else if (send_request(req) < 0) { diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index 93b2c61..58f5be8 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -672,8 +672,7 @@ try_again: msb->req_sg); if (!msb->seg_count) { - chunk = __blk_end_request(msb->block_req, -ENOMEM, - blk_rq_cur_bytes(msb->block_req)); + chunk = __blk_end_request_cur(msb->block_req, -ENOMEM); continue; } @@ -711,6 +710,7 @@ try_again: dev_dbg(&card->dev, "issue end\n"); return -EAGAIN; } + blkdev_dequeue_request(msb->block_req); dev_dbg(&card->dev, "trying again\n"); chunk = 1; @@ -825,8 +825,10 @@ static void mspro_block_submit_req(struct request_queue *q) return; if (msb->eject) { - while ((req = elv_next_request(q)) != NULL) + while ((req = elv_next_request(q)) != NULL) { + blkdev_dequeue_request(req); __blk_end_request_all(req, -ENODEV); + } return; } diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index e153f5d..8b5cbfc 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -916,8 +916,10 @@ static void i2o_block_request_fn(struct request_queue *q) blk_stop_queue(q); break; } - } else - __blk_end_request_cur(req, -EIO); + } else { + blkdev_dequeue_request(req); + __blk_end_request_all(req, -EIO); + } } }; diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index 7a72e75..4b70f1e 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -54,8 +54,11 @@ static int mmc_queue_thread(void *d) spin_lock_irq(q->queue_lock); set_current_state(TASK_INTERRUPTIBLE); - if (!blk_queue_plugged(q)) + if (!blk_queue_plugged(q)) { req = elv_next_request(q); + if (req) + blkdev_dequeue_request(req); + } mq->req = req; spin_unlock_irq(q->queue_lock); @@ -88,15 +91,12 @@ static void mmc_request(struct request_queue *q) { struct mmc_queue *mq = q->queuedata; struct request *req; - int ret; if (!mq) { printk(KERN_ERR "MMC: killing requests for dead queue\n"); while ((req = elv_next_request(q)) != NULL) { - do { - ret = __blk_end_request(req, -EIO, - blk_rq_cur_bytes(req)); - } while (ret); + blkdev_dequeue_request(req); + __blk_end_request_all(req, -EIO); } return; } -- cgit v0.10.2 From 2343046826a8ca426b07601d9593ee046c298b68 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 8 May 2009 11:54:14 +0900 Subject: gdrom: dequeue in-flight request gdrom already dequeues and fully completes requests on normal path and the error paths can be easily converted to do so too. Clean it up and dequeue requests on error paths too. While at it remove superflous blk_fs_request() && !blk_rq_sectors() condition check. [ Impact: dequeue in-flight request, cleanup ] Signed-off-by: Tejun Heo Cc: Adrian McMenamin Signed-off-by: Jens Axboe diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c index 488423c..3cc02bf 100644 --- a/drivers/cdrom/gdrom.c +++ b/drivers/cdrom/gdrom.c @@ -638,33 +638,31 @@ static void gdrom_readdisk_dma(struct work_struct *work) kfree(read_command); } -static void gdrom_request_handler_dma(struct request *req) -{ - /* dequeue, add to list of deferred work - * and then schedule workqueue */ - blkdev_dequeue_request(req); - list_add_tail(&req->queuelist, &gdrom_deferred); - schedule_work(&work); -} - static void gdrom_request(struct request_queue *rq) { struct request *req; while ((req = elv_next_request(rq)) != NULL) { + blkdev_dequeue_request(req); + if (!blk_fs_request(req)) { printk(KERN_DEBUG "GDROM: Non-fs request ignored\n"); - __blk_end_request_cur(req, -EIO); + __blk_end_request_all(req, -EIO); + continue; } if (rq_data_dir(req) != READ) { printk(KERN_NOTICE "GDROM: Read only device -"); printk(" write request ignored\n"); - __blk_end_request_cur(req, -EIO); + __blk_end_request_all(req, -EIO); + continue; } - if (blk_rq_sectors(req)) - gdrom_request_handler_dma(req); - else - __blk_end_request_cur(req, -EIO); + + /* + * Add to list of deferred work and then schedule + * workqueue. + */ + list_add_tail(&req->queuelist, &gdrom_deferred); + schedule_work(&work); } } -- cgit v0.10.2 From 9934c8c04561413609d2bc38c6b9f268cba774a4 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 8 May 2009 11:54:16 +0900 Subject: block: implement and enforce request peek/start/fetch Till now block layer allowed two separate modes of request execution. A request is always acquired from the request queue via elv_next_request(). After that, drivers are free to either dequeue it or process it without dequeueing. Dequeue allows elv_next_request() to return the next request so that multiple requests can be in flight. Executing requests without dequeueing has its merits mostly in allowing drivers for simpler devices which can't do sg to deal with segments only without considering request boundary. However, the benefit this brings is dubious and declining while the cost of the API ambiguity is increasing. Segment based drivers are usually for very old or limited devices and as converting to dequeueing model isn't difficult, it doesn't justify the API overhead it puts on block layer and its more modern users. Previous patches converted all block low level drivers to dequeueing model. This patch completes the API transition by... * renaming elv_next_request() to blk_peek_request() * renaming blkdev_dequeue_request() to blk_start_request() * adding blk_fetch_request() which is combination of peek and start * disallowing completion of queued (not started) requests * applying new API to all LLDs Renamings are for consistency and to break out of tree code so that it's apparent that out of tree drivers need updating. [ Impact: block request issue API cleanup, no functional change ] Signed-off-by: Tejun Heo Cc: Rusty Russell Cc: James Bottomley Cc: Mike Miller Cc: unsik Kim Cc: Paul Clements Cc: Tim Waugh Cc: Geert Uytterhoeven Cc: David S. Miller Cc: Laurent Vivier Cc: Jeff Garzik Cc: Jeremy Fitzhardinge Cc: Grant Likely Cc: Adrian McMenamin Cc: Stephen Rothwell Cc: Bartlomiej Zolnierkiewicz Cc: Borislav Petkov Cc: Sergei Shtylyov Cc: Alex Dubov Cc: Pierre Ossman Cc: David Woodhouse Cc: Markus Lidel Cc: Stefan Weinhuber Cc: Martin Schwidefsky Cc: Pete Zaitcev Cc: FUJITA Tomonori Signed-off-by: Jens Axboe diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c index 7a1f5c2..40424ed 100644 --- a/arch/arm/plat-omap/mailbox.c +++ b/arch/arm/plat-omap/mailbox.c @@ -197,9 +197,7 @@ static void mbox_tx_work(struct work_struct *work) struct omap_msg_tx_data *tx_data; spin_lock(q->queue_lock); - rq = elv_next_request(q); - if (rq) - blkdev_dequeue_request(rq); + rq = blk_fetch_request(q); spin_unlock(q->queue_lock); if (!rq) @@ -242,9 +240,7 @@ static void mbox_rx_work(struct work_struct *work) while (1) { spin_lock_irqsave(q->queue_lock, flags); - rq = elv_next_request(q); - if (rq) - blkdev_dequeue_request(rq); + rq = blk_fetch_request(q); spin_unlock_irqrestore(q->queue_lock, flags); if (!rq) break; @@ -351,9 +347,7 @@ omap_mbox_read(struct device *dev, struct device_attribute *attr, char *buf) while (1) { spin_lock_irqsave(q->queue_lock, flags); - rq = elv_next_request(q); - if (rq) - blkdev_dequeue_request(rq); + rq = blk_fetch_request(q); spin_unlock_irqrestore(q->queue_lock, flags); if (!rq) diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 402ba8f..aa9e926e 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -1228,12 +1228,11 @@ static void do_ubd_request(struct request_queue *q) while(1){ struct ubd *dev = q->queuedata; if(dev->end_sg == 0){ - struct request *req = elv_next_request(q); + struct request *req = blk_fetch_request(q); if(req == NULL) return; dev->request = req; - blkdev_dequeue_request(req); dev->start_sg = 0; dev->end_sg = blk_rq_map_sg(q, req, dev->sg); } diff --git a/block/blk-barrier.c b/block/blk-barrier.c index 8713c2f..0ab81a0 100644 --- a/block/blk-barrier.c +++ b/block/blk-barrier.c @@ -180,7 +180,7 @@ static inline bool start_ordered(struct request_queue *q, struct request **rqp) } /* stash away the original request */ - elv_dequeue_request(q, rq); + blk_dequeue_request(rq); q->orig_bar_rq = rq; rq = NULL; @@ -248,7 +248,7 @@ bool blk_do_ordered(struct request_queue *q, struct request **rqp) * Queue ordering not supported. Terminate * with prejudice. */ - elv_dequeue_request(q, rq); + blk_dequeue_request(rq); __blk_end_request_all(rq, -EOPNOTSUPP); *rqp = NULL; return false; diff --git a/block/blk-core.c b/block/blk-core.c index 6226a38..93691d2 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -902,6 +902,8 @@ EXPORT_SYMBOL(blk_get_request); */ void blk_requeue_request(struct request_queue *q, struct request *rq) { + BUG_ON(blk_queued_rq(rq)); + blk_delete_timer(rq); blk_clear_rq_complete(rq); trace_block_rq_requeue(q, rq); @@ -1610,28 +1612,6 @@ int blk_insert_cloned_request(struct request_queue *q, struct request *rq) } EXPORT_SYMBOL_GPL(blk_insert_cloned_request); -/** - * blkdev_dequeue_request - dequeue request and start timeout timer - * @req: request to dequeue - * - * Dequeue @req and start timeout timer on it. This hands off the - * request to the driver. - * - * Block internal functions which don't want to start timer should - * call elv_dequeue_request(). - */ -void blkdev_dequeue_request(struct request *req) -{ - elv_dequeue_request(req->q, req); - - /* - * We are now handing the request to the hardware, add the - * timeout handler. - */ - blk_add_timer(req); -} -EXPORT_SYMBOL(blkdev_dequeue_request); - static void blk_account_io_completion(struct request *req, unsigned int bytes) { if (blk_do_io_stat(req)) { @@ -1671,7 +1651,23 @@ static void blk_account_io_done(struct request *req) } } -struct request *elv_next_request(struct request_queue *q) +/** + * blk_peek_request - peek at the top of a request queue + * @q: request queue to peek at + * + * Description: + * Return the request at the top of @q. The returned request + * should be started using blk_start_request() before LLD starts + * processing it. + * + * Return: + * Pointer to the request at the top of @q if available. Null + * otherwise. + * + * Context: + * queue_lock must be held. + */ +struct request *blk_peek_request(struct request_queue *q) { struct request *rq; int ret; @@ -1748,10 +1744,12 @@ struct request *elv_next_request(struct request_queue *q) return rq; } -EXPORT_SYMBOL(elv_next_request); +EXPORT_SYMBOL(blk_peek_request); -void elv_dequeue_request(struct request_queue *q, struct request *rq) +void blk_dequeue_request(struct request *rq) { + struct request_queue *q = rq->q; + BUG_ON(list_empty(&rq->queuelist)); BUG_ON(ELV_ON_HASH(rq)); @@ -1767,6 +1765,58 @@ void elv_dequeue_request(struct request_queue *q, struct request *rq) } /** + * blk_start_request - start request processing on the driver + * @req: request to dequeue + * + * Description: + * Dequeue @req and start timeout timer on it. This hands off the + * request to the driver. + * + * Block internal functions which don't want to start timer should + * call blk_dequeue_request(). + * + * Context: + * queue_lock must be held. + */ +void blk_start_request(struct request *req) +{ + blk_dequeue_request(req); + + /* + * We are now handing the request to the hardware, add the + * timeout handler. + */ + blk_add_timer(req); +} +EXPORT_SYMBOL(blk_start_request); + +/** + * blk_fetch_request - fetch a request from a request queue + * @q: request queue to fetch a request from + * + * Description: + * Return the request at the top of @q. The request is started on + * return and LLD can start processing it immediately. + * + * Return: + * Pointer to the request at the top of @q if available. Null + * otherwise. + * + * Context: + * queue_lock must be held. + */ +struct request *blk_fetch_request(struct request_queue *q) +{ + struct request *rq; + + rq = blk_peek_request(q); + if (rq) + blk_start_request(rq); + return rq; +} +EXPORT_SYMBOL(blk_fetch_request); + +/** * blk_update_request - Special helper function for request stacking drivers * @rq: the request being processed * @error: %0 for success, < %0 for error @@ -1937,12 +1987,11 @@ static bool blk_update_bidi_request(struct request *rq, int error, */ static void blk_finish_request(struct request *req, int error) { + BUG_ON(blk_queued_rq(req)); + if (blk_rq_tagged(req)) blk_queue_end_tag(req->q, req); - if (blk_queued_rq(req)) - elv_dequeue_request(req->q, req); - if (unlikely(laptop_mode) && blk_fs_request(req)) laptop_io_completion(); diff --git a/block/blk-tag.c b/block/blk-tag.c index 3c518e3..c260f7c 100644 --- a/block/blk-tag.c +++ b/block/blk-tag.c @@ -374,7 +374,7 @@ int blk_queue_start_tag(struct request_queue *q, struct request *rq) rq->cmd_flags |= REQ_QUEUED; rq->tag = tag; bqt->tag_index[tag] = rq; - blkdev_dequeue_request(rq); + blk_start_request(rq); list_add(&rq->queuelist, &q->tag_busy_list); return 0; } diff --git a/block/blk.h b/block/blk.h index ab54529..9e0042c 100644 --- a/block/blk.h +++ b/block/blk.h @@ -13,6 +13,7 @@ extern struct kobj_type blk_queue_ktype; void init_request_from_bio(struct request *req, struct bio *bio); void blk_rq_bio_prep(struct request_queue *q, struct request *rq, struct bio *bio); +void blk_dequeue_request(struct request *rq); void __blk_queue_free_tags(struct request_queue *q); void blk_unplug_work(struct work_struct *work); diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 774ab05..668dc23 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -3321,7 +3321,7 @@ static int DAC960_process_queue(DAC960_Controller_T *Controller, struct request_ DAC960_Command_T *Command; while(1) { - Request = elv_next_request(req_q); + Request = blk_peek_request(req_q); if (!Request) return 1; @@ -3341,7 +3341,7 @@ static int DAC960_process_queue(DAC960_Controller_T *Controller, struct request_ Command->BlockNumber = blk_rq_pos(Request); Command->BlockCount = blk_rq_sectors(Request); Command->Request = Request; - blkdev_dequeue_request(Request); + blk_start_request(Request); Command->SegmentCount = blk_rq_map_sg(req_q, Command->Request, Command->cmd_sglist); /* pci_map_sg MAY change the value of SegCount */ diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 80a68b2..9c6e5b0 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -1342,12 +1342,11 @@ static void redo_fd_request(void) int err; next_req: - rq = elv_next_request(floppy_queue); + rq = blk_fetch_request(floppy_queue); if (!rq) { /* Nothing left to do */ return; } - blkdev_dequeue_request(rq); floppy = rq->rq_disk->private_data; drive = floppy - unit; diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index 89a591d..f5e7180 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -1404,10 +1404,9 @@ static void redo_fd_request(void) repeat: if (!fd_request) { - fd_request = elv_next_request(floppy_queue); + fd_request = blk_fetch_request(floppy_queue); if (!fd_request) goto the_end; - blkdev_dequeue_request(fd_request); } floppy = fd_request->rq_disk->private_data; diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index ab7b04c..e714e7c 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -2801,7 +2801,7 @@ static void do_cciss_request(struct request_queue *q) goto startio; queue: - creq = elv_next_request(q); + creq = blk_peek_request(q); if (!creq) goto startio; @@ -2810,7 +2810,7 @@ static void do_cciss_request(struct request_queue *q) if ((c = cmd_alloc(h, 1)) == NULL) goto full; - blkdev_dequeue_request(creq); + blk_start_request(creq); spin_unlock_irq(q->queue_lock); diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index a5caeff..a02dcfc 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -903,7 +903,7 @@ static void do_ida_request(struct request_queue *q) goto startio; queue_next: - creq = elv_next_request(q); + creq = blk_peek_request(q); if (!creq) goto startio; @@ -912,7 +912,7 @@ queue_next: if ((c = cmd_alloc(h,1)) == NULL) goto startio; - blkdev_dequeue_request(creq); + blk_start_request(creq); c->ctlr = h->ctlr; c->hdr.unit = (drv_info_t *)(creq->rq_disk->private_data) - h->drv; diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index e2c70d2..90877fe 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -931,7 +931,7 @@ static inline void unlock_fdc(void) del_timer(&fd_timeout); cont = NULL; clear_bit(0, &fdc_busy); - if (current_req || elv_next_request(floppy_queue)) + if (current_req || blk_peek_request(floppy_queue)) do_fd_request(floppy_queue); spin_unlock_irqrestore(&floppy_lock, flags); wake_up(&fdc_wait); @@ -2912,9 +2912,7 @@ static void redo_fd_request(void) struct request *req; spin_lock_irq(floppy_queue->queue_lock); - req = elv_next_request(floppy_queue); - if (req) - blkdev_dequeue_request(req); + req = blk_fetch_request(floppy_queue); spin_unlock_irq(floppy_queue->queue_lock); if (!req) { do_floppy = NULL; diff --git a/drivers/block/hd.c b/drivers/block/hd.c index 288ab63..961de56 100644 --- a/drivers/block/hd.c +++ b/drivers/block/hd.c @@ -592,12 +592,11 @@ repeat: del_timer(&device_timer); if (!hd_req) { - hd_req = elv_next_request(hd_queue); + hd_req = blk_fetch_request(hd_queue); if (!hd_req) { do_hd = NULL; return; } - blkdev_dequeue_request(hd_req); } req = hd_req; diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index 1ca5d14..c0cd0a0 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c @@ -671,10 +671,8 @@ static void mg_request_poll(struct request_queue *q) while (1) { if (!host->req) { - host->req = elv_next_request(q); - if (host->req) - blkdev_dequeue_request(host->req); - else + host->req = blk_fetch_request(q); + if (!host->req) break; } @@ -744,10 +742,8 @@ static void mg_request(struct request_queue *q) while (1) { if (!host->req) { - host->req = elv_next_request(q); - if (host->req) - blkdev_dequeue_request(host->req); - else + host->req = blk_fetch_request(q); + if (!host->req) break; } req = host->req; diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index fad167de..5d23ffa 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -533,11 +533,9 @@ static void do_nbd_request(struct request_queue *q) { struct request *req; - while ((req = elv_next_request(q)) != NULL) { + while ((req = blk_fetch_request(q)) != NULL) { struct nbd_device *lo; - blkdev_dequeue_request(req); - spin_unlock_irq(q->queue_lock); dprintk(DBG_BLKDEV, "%s: request %p: dequeued (flags=%x)\n", diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c index 425f815..911dfd9 100644 --- a/drivers/block/paride/pcd.c +++ b/drivers/block/paride/pcd.c @@ -720,10 +720,9 @@ static void do_pcd_request(struct request_queue * q) return; while (1) { if (!pcd_req) { - pcd_req = elv_next_request(q); + pcd_req = blk_fetch_request(q); if (!pcd_req) return; - blkdev_dequeue_request(pcd_req); } if (rq_data_dir(pcd_req) == READ) { diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index d2ca3f5..bf5955b 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -412,11 +412,9 @@ static void run_fsm(void) spin_lock_irqsave(&pd_lock, saved_flags); if (!__blk_end_request_cur(pd_req, res == Ok ? 0 : -EIO)) { - pd_req = elv_next_request(pd_queue); + pd_req = blk_fetch_request(pd_queue); if (!pd_req) stop = 1; - else - blkdev_dequeue_request(pd_req); } spin_unlock_irqrestore(&pd_lock, saved_flags); if (stop) @@ -706,10 +704,9 @@ static void do_pd_request(struct request_queue * q) { if (pd_req) return; - pd_req = elv_next_request(q); + pd_req = blk_fetch_request(q); if (!pd_req) return; - blkdev_dequeue_request(pd_req); schedule_fsm(); } diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index d6f7bd8..68a90834 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -762,10 +762,9 @@ static void do_pf_request(struct request_queue * q) return; repeat: if (!pf_req) { - pf_req = elv_next_request(q); + pf_req = blk_fetch_request(q); if (!pf_req) return; - blkdev_dequeue_request(pf_req); } pf_current = pf_req->rq_disk->private_data; diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index f4d8db9..338cee4 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -194,9 +194,7 @@ static void ps3disk_do_request(struct ps3_storage_device *dev, dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__); - while ((req = elv_next_request(q))) { - blkdev_dequeue_request(req); - + while ((req = blk_fetch_request(q))) { if (blk_fs_request(req)) { if (ps3disk_submit_request_sg(dev, req)) break; diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c index 9f351bf..cbfd9c0 100644 --- a/drivers/block/sunvdc.c +++ b/drivers/block/sunvdc.c @@ -441,12 +441,11 @@ out: static void do_vdc_request(struct request_queue *q) { while (1) { - struct request *req = elv_next_request(q); + struct request *req = blk_fetch_request(q); if (!req) break; - blkdev_dequeue_request(req); if (__send_request(req) < 0) __blk_end_request_all(req, -EIO); } diff --git a/drivers/block/swim.c b/drivers/block/swim.c index dedd489..cf7877f 100644 --- a/drivers/block/swim.c +++ b/drivers/block/swim.c @@ -528,10 +528,7 @@ static void redo_fd_request(struct request_queue *q) struct request *req; struct floppy_state *fs; - req = elv_next_request(q); - if (req) - blkdev_dequeue_request(req); - + req = blk_fetch_request(q); while (req) { int err = -EIO; @@ -554,11 +551,8 @@ static void redo_fd_request(struct request_queue *q) break; } done: - if (!__blk_end_request_cur(req, err)) { - req = elv_next_request(q); - if (req) - blkdev_dequeue_request(req); - } + if (!__blk_end_request_cur(req, err)) + req = blk_fetch_request(q); } } diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index f48c6dd..80df93e 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -326,10 +326,9 @@ static void start_request(struct floppy_state *fs) } while (fs->state == idle) { if (!fd_req) { - fd_req = elv_next_request(swim3_queue); + fd_req = blk_fetch_request(swim3_queue); if (!fd_req) break; - blkdev_dequeue_request(fd_req); } req = fd_req; #if 0 diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index 087c94c..da403b6 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -810,12 +810,10 @@ static void carm_oob_rq_fn(struct request_queue *q) while (1) { DPRINTK("get req\n"); - rq = elv_next_request(q); + rq = blk_fetch_request(q); if (!rq) break; - blkdev_dequeue_request(rq); - crq = rq->special; assert(crq != NULL); assert(crq->rq == rq); @@ -846,7 +844,7 @@ static void carm_rq_fn(struct request_queue *q) queue_one_request: VPRINTK("get req\n"); - rq = elv_next_request(q); + rq = blk_peek_request(q); if (!rq) return; @@ -857,7 +855,7 @@ queue_one_request: } crq->rq = rq; - blkdev_dequeue_request(rq); + blk_start_request(rq); if (rq_data_dir(rq) == WRITE) { writing = 1; diff --git a/drivers/block/ub.c b/drivers/block/ub.c index 40d03cf..178f459 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -627,7 +627,7 @@ static void ub_request_fn(struct request_queue *q) struct ub_lun *lun = q->queuedata; struct request *rq; - while ((rq = elv_next_request(q)) != NULL) { + while ((rq = blk_peek_request(q)) != NULL) { if (ub_request_fn_1(lun, rq) != 0) { blk_stop_queue(q); break; @@ -643,13 +643,13 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq) int n_elem; if (atomic_read(&sc->poison)) { - blkdev_dequeue_request(rq); + blk_start_request(rq); ub_end_rq(rq, DID_NO_CONNECT << 16, blk_rq_bytes(rq)); return 0; } if (lun->changed && !blk_pc_request(rq)) { - blkdev_dequeue_request(rq); + blk_start_request(rq); ub_end_rq(rq, SAM_STAT_CHECK_CONDITION, blk_rq_bytes(rq)); return 0; } @@ -660,7 +660,7 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq) return -1; memset(cmd, 0, sizeof(struct ub_scsi_cmd)); - blkdev_dequeue_request(rq); + blk_start_request(rq); urq = &lun->urq; memset(urq, 0, sizeof(struct ub_request)); diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index 2086cb1..390d69b 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c @@ -361,11 +361,9 @@ static void do_viodasd_request(struct request_queue *q) * back later. */ while (num_req_outstanding < VIOMAXREQ) { - req = elv_next_request(q); + req = blk_fetch_request(q); if (req == NULL) return; - /* dequeue the current request from the queue */ - blkdev_dequeue_request(req); /* check that request contains a valid command */ if (!blk_fs_request(req)) { viodasd_end_request(req, -EIO, blk_rq_sectors(req)); diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 1980ab4..29a9daf 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -128,7 +128,7 @@ static void do_virtblk_request(struct request_queue *q) struct request *req; unsigned int issued = 0; - while ((req = elv_next_request(q)) != NULL) { + while ((req = blk_peek_request(q)) != NULL) { vblk = req->rq_disk->private_data; BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems); @@ -138,7 +138,7 @@ static void do_virtblk_request(struct request_queue *q) blk_stop_queue(q); break; } - blkdev_dequeue_request(req); + blk_start_request(req); issued++; } diff --git a/drivers/block/xd.c b/drivers/block/xd.c index d4c4352..ce24292 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -305,10 +305,7 @@ static void do_xd_request (struct request_queue * q) if (xdc_busy) return; - req = elv_next_request(q); - if (req) - blkdev_dequeue_request(req); - + req = blk_fetch_request(q); while (req) { unsigned block = blk_rq_pos(req); unsigned count = blk_rq_cur_sectors(req); @@ -325,11 +322,8 @@ static void do_xd_request (struct request_queue * q) block, count); done: /* wrap up, 0 = success, -errno = fail */ - if (!__blk_end_request_cur(req, res)) { - req = elv_next_request(q); - if (req) - blkdev_dequeue_request(req); - } + if (!__blk_end_request_cur(req, res)) + req = blk_fetch_request(q); } } diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 66f8345..6d4ac76 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -299,13 +299,13 @@ static void do_blkif_request(struct request_queue *rq) queued = 0; - while ((req = elv_next_request(rq)) != NULL) { + while ((req = blk_peek_request(rq)) != NULL) { info = req->rq_disk->private_data; if (RING_FULL(&info->ring)) goto wait; - blkdev_dequeue_request(req); + blk_start_request(req); if (!blk_fs_request(req)) { __blk_end_request_all(req, -EIO); diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index edf137b..3a4397e 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -463,10 +463,10 @@ struct request *ace_get_next_request(struct request_queue * q) { struct request *req; - while ((req = elv_next_request(q)) != NULL) { + while ((req = blk_peek_request(q)) != NULL) { if (blk_fs_request(req)) break; - blkdev_dequeue_request(req); + blk_start_request(req); __blk_end_request_all(req, -EIO); } return req; @@ -498,10 +498,8 @@ static void ace_fsm_dostate(struct ace_device *ace) __blk_end_request_all(ace->req, -EIO); ace->req = NULL; } - while ((req = elv_next_request(ace->queue)) != NULL) { - blkdev_dequeue_request(req); + while ((req = blk_fetch_request(ace->queue)) != NULL) __blk_end_request_all(req, -EIO); - } /* Drop back to IDLE state and notify waiters */ ace->fsm_state = ACE_FSM_STATE_IDLE; @@ -649,7 +647,7 @@ static void ace_fsm_dostate(struct ace_device *ace) ace->fsm_state = ACE_FSM_STATE_IDLE; break; } - blkdev_dequeue_request(req); + blk_start_request(req); /* Okay, it's a data request, set it up for transfer */ dev_dbg(ace->dev, diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c index c909c1a..4575171 100644 --- a/drivers/block/z2ram.c +++ b/drivers/block/z2ram.c @@ -71,10 +71,7 @@ static void do_z2_request(struct request_queue *q) { struct request *req; - req = elv_next_request(q); - if (req) - blkdev_dequeue_request(req); - + req = blk_fetch_request(q); while (req) { unsigned long start = blk_rq_pos(req) << 9; unsigned long len = blk_rq_cur_bytes(req); @@ -100,11 +97,8 @@ static void do_z2_request(struct request_queue *q) len -= size; } done: - if (!__blk_end_request_cur(req, err)) { - req = elv_next_request(q); - if (req) - blkdev_dequeue_request(req); - } + if (!__blk_end_request_cur(req, err)) + req = blk_fetch_request(q); } } diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c index 3cc02bf..1e366ad 100644 --- a/drivers/cdrom/gdrom.c +++ b/drivers/cdrom/gdrom.c @@ -642,9 +642,7 @@ static void gdrom_request(struct request_queue *rq) { struct request *req; - while ((req = elv_next_request(rq)) != NULL) { - blkdev_dequeue_request(req); - + while ((req = blk_fetch_request(rq)) != NULL) { if (!blk_fs_request(req)) { printk(KERN_DEBUG "GDROM: Non-fs request ignored\n"); __blk_end_request_all(req, -EIO); diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index bbe9f08..ca741c2 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -297,9 +297,7 @@ static void do_viocd_request(struct request_queue *q) { struct request *req; - while ((rwreq == 0) && ((req = elv_next_request(q)) != NULL)) { - blkdev_dequeue_request(req); - + while ((rwreq == 0) && ((req = blk_fetch_request(q)) != NULL)) { if (!blk_fs_request(req)) __blk_end_request_all(req, -EIO); else if (send_request(req) < 0) { diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c index 2874c3d..8a894fa 100644 --- a/drivers/ide/ide-atapi.c +++ b/drivers/ide/ide-atapi.c @@ -269,7 +269,7 @@ void ide_retry_pc(ide_drive_t *drive) blk_requeue_request(failed_rq->q, failed_rq); drive->hwif->rq = NULL; if (ide_queue_sense_rq(drive, pc)) { - blkdev_dequeue_request(failed_rq); + blk_start_request(failed_rq); ide_complete_rq(drive, -EIO, blk_rq_bytes(failed_rq)); } } diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index abda733..e4e3a0e3 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -519,11 +519,8 @@ repeat: * we know that the queue isn't empty, but this can happen * if the q->prep_rq_fn() decides to kill a request */ - if (!rq) { - rq = elv_next_request(drive->queue); - if (rq) - blkdev_dequeue_request(rq); - } + if (!rq) + rq = blk_fetch_request(drive->queue); spin_unlock_irq(q->queue_lock); spin_lock_irq(&hwif->lock); @@ -536,7 +533,7 @@ repeat: /* * Sanity: don't accept a request that isn't a PM request * if we are currently power managed. This is very important as - * blk_stop_queue() doesn't prevent the elv_next_request() + * blk_stop_queue() doesn't prevent the blk_fetch_request() * above to return us whatever is in the queue. Since we call * ide_do_request() ourselves, we end up taking requests while * the queue is blocked... diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index 58f5be8..c0bebc6 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -704,13 +704,12 @@ try_again: return 0; } - dev_dbg(&card->dev, "elv_next\n"); - msb->block_req = elv_next_request(msb->queue); + dev_dbg(&card->dev, "blk_fetch\n"); + msb->block_req = blk_fetch_request(msb->queue); if (!msb->block_req) { dev_dbg(&card->dev, "issue end\n"); return -EAGAIN; } - blkdev_dequeue_request(msb->block_req); dev_dbg(&card->dev, "trying again\n"); chunk = 1; @@ -825,10 +824,8 @@ static void mspro_block_submit_req(struct request_queue *q) return; if (msb->eject) { - while ((req = elv_next_request(q)) != NULL) { - blkdev_dequeue_request(req); + while ((req = blk_fetch_request(q)) != NULL) __blk_end_request_all(req, -ENODEV); - } return; } diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index 8b5cbfc..6573ef4 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -877,7 +877,7 @@ static void i2o_block_request_fn(struct request_queue *q) struct request *req; while (!blk_queue_plugged(q)) { - req = elv_next_request(q); + req = blk_peek_request(q); if (!req) break; @@ -890,7 +890,7 @@ static void i2o_block_request_fn(struct request_queue *q) if (queue_depth < I2O_BLOCK_MAX_OPEN_REQUESTS) { if (!i2o_block_transfer(req)) { - blkdev_dequeue_request(req); + blk_start_request(req); continue; } else osm_info("transfer error\n"); @@ -917,7 +917,7 @@ static void i2o_block_request_fn(struct request_queue *q) break; } } else { - blkdev_dequeue_request(req); + blk_start_request(req); __blk_end_request_all(req, -EIO); } } diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index 4b70f1e..49e5823 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -54,11 +54,8 @@ static int mmc_queue_thread(void *d) spin_lock_irq(q->queue_lock); set_current_state(TASK_INTERRUPTIBLE); - if (!blk_queue_plugged(q)) { - req = elv_next_request(q); - if (req) - blkdev_dequeue_request(req); - } + if (!blk_queue_plugged(q)) + req = blk_fetch_request(q); mq->req = req; spin_unlock_irq(q->queue_lock); @@ -94,10 +91,8 @@ static void mmc_request(struct request_queue *q) if (!mq) { printk(KERN_ERR "MMC: killing requests for dead queue\n"); - while ((req = elv_next_request(q)) != NULL) { - blkdev_dequeue_request(req); + while ((req = blk_fetch_request(q)) != NULL) __blk_end_request_all(req, -EIO); - } return; } diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 3e10442..502622f 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -100,12 +100,7 @@ static int mtd_blktrans_thread(void *arg) struct mtd_blktrans_dev *dev; int res; - if (!req) { - req = elv_next_request(rq); - if (req) - blkdev_dequeue_request(req); - } - if (!req) { + if (!req && !(req = blk_fetch_request(rq))) { set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irq(rq->queue_lock); schedule(); diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 7df03c7a..e64f62d 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1656,17 +1656,13 @@ static void __dasd_process_request_queue(struct dasd_block *block) if (basedev->state < DASD_STATE_READY) return; /* Now we try to fetch requests from the request queue */ - while (!blk_queue_plugged(queue) && - elv_next_request(queue)) { - - req = elv_next_request(queue); - + while (!blk_queue_plugged(queue) && (req = blk_peek_request(queue))) { if (basedev->features & DASD_FEATURE_READONLY && rq_data_dir(req) == WRITE) { DBF_DEV_EVENT(DBF_ERR, basedev, "Rejecting write request %p", req); - blkdev_dequeue_request(req); + blk_start_request(req); __blk_end_request_all(req, -EIO); continue; } @@ -1695,7 +1691,7 @@ static void __dasd_process_request_queue(struct dasd_block *block) "CCW creation failed (rc=%ld) " "on request %p", PTR_ERR(cqr), req); - blkdev_dequeue_request(req); + blk_start_request(req); __blk_end_request_all(req, -EIO); continue; } @@ -1705,7 +1701,7 @@ static void __dasd_process_request_queue(struct dasd_block *block) */ cqr->callback_data = (void *) req; cqr->status = DASD_CQR_FILLED; - blkdev_dequeue_request(req); + blk_start_request(req); list_add_tail(&cqr->blocklist, &block->ccw_queue); dasd_profile_start(block, cqr, req); } @@ -2029,10 +2025,8 @@ static void dasd_flush_request_queue(struct dasd_block *block) return; spin_lock_irq(&block->request_queue_lock); - while ((req = elv_next_request(block->request_queue))) { - blkdev_dequeue_request(req); + while ((req = blk_fetch_request(block->request_queue))) __blk_end_request_all(req, -EIO); - } spin_unlock_irq(&block->request_queue_lock); } diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index 5d035e4..1e79676 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -93,7 +93,7 @@ __tapeblock_end_request(struct tape_request *ccw_req, void *data) device->blk_data.block_position = -1; device->discipline->free_bread(ccw_req); if (!list_empty(&device->req_queue) || - elv_next_request(device->blk_data.request_queue)) + blk_peek_request(device->blk_data.request_queue)) tapeblock_trigger_requeue(device); } @@ -162,19 +162,16 @@ tapeblock_requeue(struct work_struct *work) { spin_lock_irq(&device->blk_data.request_queue_lock); while ( !blk_queue_plugged(queue) && - elv_next_request(queue) && + (req = blk_fetch_request(queue)) && nr_queued < TAPEBLOCK_MIN_REQUEUE ) { - req = elv_next_request(queue); if (rq_data_dir(req) == WRITE) { DBF_EVENT(1, "TBLOCK: Rejecting write request\n"); - blkdev_dequeue_request(req); spin_unlock_irq(&device->blk_data.request_queue_lock); blk_end_request_all(req, -EIO); spin_lock_irq(&device->blk_data.request_queue_lock); continue; } - blkdev_dequeue_request(req); nr_queued++; spin_unlock_irq(&device->blk_data.request_queue_lock); rc = tapeblock_start_request(device, req); diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c index f572a4a..6d46516 100644 --- a/drivers/sbus/char/jsflash.c +++ b/drivers/sbus/char/jsflash.c @@ -186,10 +186,7 @@ static void jsfd_do_request(struct request_queue *q) { struct request *req; - req = elv_next_request(q); - if (req) - blkdev_dequeue_request(req); - + req = blk_fetch_request(q); while (req) { struct jsfd_part *jdp = req->rq_disk->private_data; unsigned long offset = blk_rq_pos(req) << 9; @@ -212,11 +209,8 @@ static void jsfd_do_request(struct request_queue *q) jsfd_read(req->buffer, jdp->dbase + offset, len); err = 0; end: - if (!__blk_end_request_cur(req, err)) { - req = elv_next_request(q); - if (req) - blkdev_dequeue_request(req); - } + if (!__blk_end_request_cur(req, err)) + req = blk_fetch_request(q); } } diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index ee308f6..b12750f 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1207,7 +1207,7 @@ int scsi_prep_return(struct request_queue *q, struct request *req, int ret) break; case BLKPREP_DEFER: /* - * If we defer, the elv_next_request() returns NULL, but the + * If we defer, the blk_peek_request() returns NULL, but the * queue must be restarted, so we plug here if no returning * command will automatically do that. */ @@ -1385,7 +1385,7 @@ static void scsi_kill_request(struct request *req, struct request_queue *q) struct scsi_target *starget = scsi_target(sdev); struct Scsi_Host *shost = sdev->host; - blkdev_dequeue_request(req); + blk_start_request(req); if (unlikely(cmd == NULL)) { printk(KERN_CRIT "impossible request in %s.\n", @@ -1477,7 +1477,7 @@ static void scsi_request_fn(struct request_queue *q) if (!sdev) { printk("scsi: killing requests for dead queue\n"); - while ((req = elv_next_request(q)) != NULL) + while ((req = blk_peek_request(q)) != NULL) scsi_kill_request(req, q); return; } @@ -1498,7 +1498,7 @@ static void scsi_request_fn(struct request_queue *q) * that the request is fully prepared even if we cannot * accept it. */ - req = elv_next_request(q); + req = blk_peek_request(q); if (!req || !scsi_dev_queue_ready(q, sdev)) break; @@ -1514,7 +1514,7 @@ static void scsi_request_fn(struct request_queue *q) * Remove the request from the request list. */ if (!(blk_queue_tagged(q) && !blk_queue_start_tag(q, req))) - blkdev_dequeue_request(req); + blk_start_request(req); sdev->device_busy++; spin_unlock(q->queue_lock); diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 50988cb..d606452 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -163,12 +163,10 @@ static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost, int (*handler)(struct Scsi_Host *, struct sas_rphy *, struct request *); while (!blk_queue_plugged(q)) { - req = elv_next_request(q); + req = blk_fetch_request(q); if (!req) break; - blkdev_dequeue_request(req); - spin_unlock_irq(q->queue_lock); handler = to_sas_internal(shost->transportt)->f->smp_handler; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index c755803..6e59d3b 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -818,8 +818,6 @@ static inline void blk_run_address_space(struct address_space *mapping) blk_run_backing_dev(mapping->backing_dev_info, NULL); } -extern void blkdev_dequeue_request(struct request *req); - /* * blk_rq_pos() : the current sector * blk_rq_bytes() : bytes left in the entire request @@ -853,6 +851,13 @@ static inline unsigned int blk_rq_cur_sectors(const struct request *rq) } /* + * Request issue related functions. + */ +extern struct request *blk_peek_request(struct request_queue *q); +extern void blk_start_request(struct request *rq); +extern struct request *blk_fetch_request(struct request_queue *q); + +/* * Request completion related functions. * * blk_update_request() completes given number of bytes and updates diff --git a/include/linux/elevator.h b/include/linux/elevator.h index 4e46287..1cb3372e 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h @@ -103,10 +103,8 @@ extern int elv_merge(struct request_queue *, struct request **, struct bio *); extern void elv_merge_requests(struct request_queue *, struct request *, struct request *); extern void elv_merged_request(struct request_queue *, struct request *, int); -extern void elv_dequeue_request(struct request_queue *, struct request *); extern void elv_requeue_request(struct request_queue *, struct request *); extern int elv_queue_empty(struct request_queue *); -extern struct request *elv_next_request(struct request_queue *q); extern struct request *elv_former_request(struct request_queue *, struct request *); extern struct request *elv_latter_request(struct request_queue *, struct request *); extern int elv_register_queue(struct request_queue *q); -- cgit v0.10.2 From 1822952ba2b9f22f79019d07ebbeca31dc14b718 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Mon, 11 May 2009 17:56:07 +0900 Subject: block: let blk_end_request_all handle bidi requests blk_end_request_all() and __blk_end_request_all() should finish all bytes including bidi, by definition. That's what all bidi users need , bidi requests must be complete as a whole (partial completion is impossible). Signed-off-by: FUJITA Tomonori Signed-off-by: Jens Axboe diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 6e59d3b..1069f44 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -910,8 +910,12 @@ static inline bool blk_end_request(struct request *rq, int error, static inline void blk_end_request_all(struct request *rq, int error) { bool pending; + unsigned int bidi_bytes = 0; - pending = blk_end_request(rq, error, blk_rq_bytes(rq)); + if (unlikely(blk_bidi_rq(rq))) + bidi_bytes = blk_rq_bytes(rq->next_rq); + + pending = blk_end_bidi_request(rq, error, blk_rq_bytes(rq), bidi_bytes); BUG_ON(pending); } @@ -962,8 +966,12 @@ static inline bool __blk_end_request(struct request *rq, int error, static inline void __blk_end_request_all(struct request *rq, int error) { bool pending; + unsigned int bidi_bytes = 0; + + if (unlikely(blk_bidi_rq(rq))) + bidi_bytes = blk_rq_bytes(rq->next_rq); - pending = __blk_end_request(rq, error, blk_rq_bytes(rq)); + pending = __blk_end_bidi_request(rq, error, blk_rq_bytes(rq), bidi_bytes); BUG_ON(pending); } -- cgit v0.10.2 From e6bb7a96c2c36f20c05ef648f15bd3c2b1834c78 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Mon, 11 May 2009 17:56:08 +0900 Subject: scsi: simplify the bidi completion Let's use blk_end_request_all() instead of blk_end_bidi_request(). Signed-off-by: FUJITA Tomonori Signed-off-by: Jens Axboe diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index b12750f..a54bec9 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -673,33 +673,6 @@ void scsi_release_buffers(struct scsi_cmnd *cmd) EXPORT_SYMBOL(scsi_release_buffers); /* - * Bidi commands Must be complete as a whole, both sides at once. If - * part of the bytes were written and lld returned scsi_in()->resid - * and/or scsi_out()->resid this information will be left in - * req->resid_len and req->next_rq->resid_len. The upper-layer driver - * can decide what to do with this information. - */ -static void scsi_end_bidi_request(struct scsi_cmnd *cmd) -{ - struct request *req = cmd->request; - - req->resid_len = scsi_out(cmd)->resid; - req->next_rq->resid_len = scsi_in(cmd)->resid; - - /* The req and req->next_rq have not been completed */ - BUG_ON(blk_end_bidi_request(req, 0, blk_rq_bytes(req), - blk_rq_bytes(req->next_rq))); - - scsi_release_buffers(cmd); - - /* - * This will goose the queue request function at the end, so we don't - * need to worry about launching another command. - */ - scsi_next_command(cmd); -} - -/* * Function: scsi_io_completion() * * Purpose: Completion processing for block device I/O requests. @@ -772,12 +745,22 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) if (!sense_deferred) error = -EIO; } + + req->resid_len = scsi_get_resid(cmd); + if (scsi_bidi_cmnd(cmd)) { - /* will also release_buffers */ - scsi_end_bidi_request(cmd); + /* + * Bidi commands Must be complete as a whole, + * both sides at once. + */ + req->next_rq->resid_len = scsi_in(cmd)->resid; + + blk_end_request_all(req, 0); + + scsi_release_buffers(cmd); + scsi_next_command(cmd); return; } - req->resid_len = scsi_get_resid(cmd); } BUG_ON(blk_bidi_rq(req)); /* bidi not support for !blk_pc_request yet */ -- cgit v0.10.2 From b1f744937f1be3e6d3009382a755679133cf782d Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Mon, 11 May 2009 17:56:09 +0900 Subject: block: move completion related functions back to blk-core.c Let's put the completion related functions back to block/blk-core.c where they have lived. We can also unexport blk_end_bidi_request() and __blk_end_bidi_request(), which nobody uses. Signed-off-by: FUJITA Tomonori Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index 93691d2..a2d97de 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -2026,8 +2026,8 @@ static void blk_finish_request(struct request *req, int error) * %false - we are done with this request * %true - still buffers pending for this request **/ -bool blk_end_bidi_request(struct request *rq, int error, - unsigned int nr_bytes, unsigned int bidi_bytes) +static bool blk_end_bidi_request(struct request *rq, int error, + unsigned int nr_bytes, unsigned int bidi_bytes) { struct request_queue *q = rq->q; unsigned long flags; @@ -2041,7 +2041,6 @@ bool blk_end_bidi_request(struct request *rq, int error, return false; } -EXPORT_SYMBOL_GPL(blk_end_bidi_request); /** * __blk_end_bidi_request - Complete a bidi request with queue lock held @@ -2058,8 +2057,8 @@ EXPORT_SYMBOL_GPL(blk_end_bidi_request); * %false - we are done with this request * %true - still buffers pending for this request **/ -bool __blk_end_bidi_request(struct request *rq, int error, - unsigned int nr_bytes, unsigned int bidi_bytes) +static bool __blk_end_bidi_request(struct request *rq, int error, + unsigned int nr_bytes, unsigned int bidi_bytes) { if (blk_update_bidi_request(rq, error, nr_bytes, bidi_bytes)) return true; @@ -2068,7 +2067,124 @@ bool __blk_end_bidi_request(struct request *rq, int error, return false; } -EXPORT_SYMBOL_GPL(__blk_end_bidi_request); + +/** + * blk_end_request - Helper function for drivers to complete the request. + * @rq: the request being processed + * @error: %0 for success, < %0 for error + * @nr_bytes: number of bytes to complete + * + * Description: + * Ends I/O on a number of bytes attached to @rq. + * If @rq has leftover, sets it up for the next range of segments. + * + * Return: + * %false - we are done with this request + * %true - still buffers pending for this request + **/ +bool blk_end_request(struct request *rq, int error, unsigned int nr_bytes) +{ + return blk_end_bidi_request(rq, error, nr_bytes, 0); +} +EXPORT_SYMBOL_GPL(blk_end_request); + +/** + * blk_end_request_all - Helper function for drives to finish the request. + * @rq: the request to finish + * @err: %0 for success, < %0 for error + * + * Description: + * Completely finish @rq. + */ +void blk_end_request_all(struct request *rq, int error) +{ + bool pending; + unsigned int bidi_bytes = 0; + + if (unlikely(blk_bidi_rq(rq))) + bidi_bytes = blk_rq_bytes(rq->next_rq); + + pending = blk_end_bidi_request(rq, error, blk_rq_bytes(rq), bidi_bytes); + BUG_ON(pending); +} +EXPORT_SYMBOL_GPL(blk_end_request_all); + +/** + * blk_end_request_cur - Helper function to finish the current request chunk. + * @rq: the request to finish the current chunk for + * @err: %0 for success, < %0 for error + * + * Description: + * Complete the current consecutively mapped chunk from @rq. + * + * Return: + * %false - we are done with this request + * %true - still buffers pending for this request + */ +bool blk_end_request_cur(struct request *rq, int error) +{ + return blk_end_request(rq, error, blk_rq_cur_bytes(rq)); +} +EXPORT_SYMBOL_GPL(blk_end_request_cur); + +/** + * __blk_end_request - Helper function for drivers to complete the request. + * @rq: the request being processed + * @error: %0 for success, < %0 for error + * @nr_bytes: number of bytes to complete + * + * Description: + * Must be called with queue lock held unlike blk_end_request(). + * + * Return: + * %false - we are done with this request + * %true - still buffers pending for this request + **/ +bool __blk_end_request(struct request *rq, int error, unsigned int nr_bytes) +{ + return __blk_end_bidi_request(rq, error, nr_bytes, 0); +} +EXPORT_SYMBOL_GPL(__blk_end_request); + +/** + * __blk_end_request_all - Helper function for drives to finish the request. + * @rq: the request to finish + * @err: %0 for success, < %0 for error + * + * Description: + * Completely finish @rq. Must be called with queue lock held. + */ +void __blk_end_request_all(struct request *rq, int error) +{ + bool pending; + unsigned int bidi_bytes = 0; + + if (unlikely(blk_bidi_rq(rq))) + bidi_bytes = blk_rq_bytes(rq->next_rq); + + pending = __blk_end_bidi_request(rq, error, blk_rq_bytes(rq), bidi_bytes); + BUG_ON(pending); +} +EXPORT_SYMBOL_GPL(__blk_end_request_all); + +/** + * __blk_end_request_cur - Helper function to finish the current request chunk. + * @rq: the request to finish the current chunk for + * @err: %0 for success, < %0 for error + * + * Description: + * Complete the current consecutively mapped chunk from @rq. Must + * be called with queue lock held. + * + * Return: + * %false - we are done with this request + * %true - still buffers pending for this request + */ +bool __blk_end_request_cur(struct request *rq, int error) +{ + return __blk_end_request(rq, error, blk_rq_cur_bytes(rq)); +} +EXPORT_SYMBOL_GPL(__blk_end_request_cur); void blk_rq_bio_prep(struct request_queue *q, struct request *rq, struct bio *bio) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 1069f44..f9d60a7 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -872,126 +872,14 @@ extern struct request *blk_fetch_request(struct request_queue *q); */ extern bool blk_update_request(struct request *rq, int error, unsigned int nr_bytes); -extern bool blk_end_bidi_request(struct request *rq, int error, - unsigned int nr_bytes, - unsigned int bidi_bytes); -extern bool __blk_end_bidi_request(struct request *rq, int error, - unsigned int nr_bytes, - unsigned int bidi_bytes); - -/** - * blk_end_request - Helper function for drivers to complete the request. - * @rq: the request being processed - * @error: %0 for success, < %0 for error - * @nr_bytes: number of bytes to complete - * - * Description: - * Ends I/O on a number of bytes attached to @rq. - * If @rq has leftover, sets it up for the next range of segments. - * - * Return: - * %false - we are done with this request - * %true - still buffers pending for this request - **/ -static inline bool blk_end_request(struct request *rq, int error, - unsigned int nr_bytes) -{ - return blk_end_bidi_request(rq, error, nr_bytes, 0); -} - -/** - * blk_end_request_all - Helper function for drives to finish the request. - * @rq: the request to finish - * @err: %0 for success, < %0 for error - * - * Description: - * Completely finish @rq. - */ -static inline void blk_end_request_all(struct request *rq, int error) -{ - bool pending; - unsigned int bidi_bytes = 0; - - if (unlikely(blk_bidi_rq(rq))) - bidi_bytes = blk_rq_bytes(rq->next_rq); - - pending = blk_end_bidi_request(rq, error, blk_rq_bytes(rq), bidi_bytes); - BUG_ON(pending); -} - -/** - * blk_end_request_cur - Helper function to finish the current request chunk. - * @rq: the request to finish the current chunk for - * @err: %0 for success, < %0 for error - * - * Description: - * Complete the current consecutively mapped chunk from @rq. - * - * Return: - * %false - we are done with this request - * %true - still buffers pending for this request - */ -static inline bool blk_end_request_cur(struct request *rq, int error) -{ - return blk_end_request(rq, error, blk_rq_cur_bytes(rq)); -} - -/** - * __blk_end_request - Helper function for drivers to complete the request. - * @rq: the request being processed - * @error: %0 for success, < %0 for error - * @nr_bytes: number of bytes to complete - * - * Description: - * Must be called with queue lock held unlike blk_end_request(). - * - * Return: - * %false - we are done with this request - * %true - still buffers pending for this request - **/ -static inline bool __blk_end_request(struct request *rq, int error, - unsigned int nr_bytes) -{ - return __blk_end_bidi_request(rq, error, nr_bytes, 0); -} - -/** - * __blk_end_request_all - Helper function for drives to finish the request. - * @rq: the request to finish - * @err: %0 for success, < %0 for error - * - * Description: - * Completely finish @rq. Must be called with queue lock held. - */ -static inline void __blk_end_request_all(struct request *rq, int error) -{ - bool pending; - unsigned int bidi_bytes = 0; - - if (unlikely(blk_bidi_rq(rq))) - bidi_bytes = blk_rq_bytes(rq->next_rq); - - pending = __blk_end_bidi_request(rq, error, blk_rq_bytes(rq), bidi_bytes); - BUG_ON(pending); -} - -/** - * __blk_end_request_cur - Helper function to finish the current request chunk. - * @rq: the request to finish the current chunk for - * @err: %0 for success, < %0 for error - * - * Description: - * Complete the current consecutively mapped chunk from @rq. Must - * be called with queue lock held. - * - * Return: - * %false - we are done with this request - * %true - still buffers pending for this request - */ -static inline bool __blk_end_request_cur(struct request *rq, int error) -{ - return __blk_end_request(rq, error, blk_rq_cur_bytes(rq)); -} +extern bool blk_end_request(struct request *rq, int error, + unsigned int nr_bytes); +extern void blk_end_request_all(struct request *rq, int error); +extern bool blk_end_request_cur(struct request *rq, int error); +extern bool __blk_end_request(struct request *rq, int error, + unsigned int nr_bytes); +extern void __blk_end_request_all(struct request *rq, int error); +extern bool __blk_end_request_cur(struct request *rq, int error); extern void blk_complete_request(struct request *); extern void __blk_complete_request(struct request *); -- cgit v0.10.2 From 7c77f0b3f9208c339a4b40737bb2cb0f0319bb8d Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 7 May 2009 15:37:35 +0200 Subject: splice: implement pipe to pipe splicing Allow splice(2) to work when both the input and the output is a pipe. Based on the impementation of the tee(2) syscall, but instead of duplicating the buffer references move the buffers from the input pipe to the output pipe. Moving the whole buffer only succeeds if the full length of the buffer is spliced. Otherwise duplicate the buffer, just like tee(2), set the length of the output buffer and advance the offset on the input buffer. Since splice is operating on two pipes, special care needs to be taken with locking to prevent AN ABBA deadlock. Again this is done similarly to the tee(2) syscall, first preparing the input and output pipes so there's data to consume and space for that data, and then doing the move operation while holding both locks. If other processes are doing I/O on the same pipes parallel to the splice, then by the time both inodes are locked there might be no buffers left to move, or no space to move them to. In this case retry the whole operation, including the preparation phase. This could lead to starvation, but I'm not sure if that's serious enough to worry about. Signed-off-by: Miklos Szeredi Signed-off-by: Jens Axboe diff --git a/fs/splice.c b/fs/splice.c index 666953d5..e405cf5 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -1112,6 +1112,9 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, return ret; } +static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe, + struct pipe_inode_info *opipe, + size_t len, unsigned int flags); /* * After the inode slimming patch, i_pipe/i_bdev/i_cdev share the same * location, so checking ->i_pipe is not enough to verify that this is a @@ -1132,12 +1135,32 @@ static long do_splice(struct file *in, loff_t __user *off_in, struct file *out, loff_t __user *off_out, size_t len, unsigned int flags) { - struct pipe_inode_info *pipe; + struct pipe_inode_info *ipipe; + struct pipe_inode_info *opipe; loff_t offset, *off; long ret; - pipe = pipe_info(in->f_path.dentry->d_inode); - if (pipe) { + ipipe = pipe_info(in->f_path.dentry->d_inode); + opipe = pipe_info(out->f_path.dentry->d_inode); + + if (ipipe && opipe) { + if (off_in || off_out) + return -ESPIPE; + + if (!(in->f_mode & FMODE_READ)) + return -EBADF; + + if (!(out->f_mode & FMODE_WRITE)) + return -EBADF; + + /* Splicing to self would be fun, but... */ + if (ipipe == opipe) + return -EINVAL; + + return splice_pipe_to_pipe(ipipe, opipe, len, flags); + } + + if (ipipe) { if (off_in) return -ESPIPE; if (off_out) { @@ -1149,7 +1172,7 @@ static long do_splice(struct file *in, loff_t __user *off_in, } else off = &out->f_pos; - ret = do_splice_from(pipe, out, off, len, flags); + ret = do_splice_from(ipipe, out, off, len, flags); if (off_out && copy_to_user(off_out, off, sizeof(loff_t))) ret = -EFAULT; @@ -1157,8 +1180,7 @@ static long do_splice(struct file *in, loff_t __user *off_in, return ret; } - pipe = pipe_info(out->f_path.dentry->d_inode); - if (pipe) { + if (opipe) { if (off_out) return -ESPIPE; if (off_in) { @@ -1170,7 +1192,7 @@ static long do_splice(struct file *in, loff_t __user *off_in, } else off = &in->f_pos; - ret = do_splice_to(in, off, pipe, len, flags); + ret = do_splice_to(in, off, opipe, len, flags); if (off_in && copy_to_user(off_in, off, sizeof(loff_t))) ret = -EFAULT; @@ -1511,7 +1533,7 @@ SYSCALL_DEFINE6(splice, int, fd_in, loff_t __user *, off_in, * Make sure there's data to read. Wait for input if we can, otherwise * return an appropriate error. */ -static int link_ipipe_prep(struct pipe_inode_info *pipe, unsigned int flags) +static int ipipe_prep(struct pipe_inode_info *pipe, unsigned int flags) { int ret; @@ -1549,7 +1571,7 @@ static int link_ipipe_prep(struct pipe_inode_info *pipe, unsigned int flags) * Make sure there's writeable room. Wait for room if we can, otherwise * return an appropriate error. */ -static int link_opipe_prep(struct pipe_inode_info *pipe, unsigned int flags) +static int opipe_prep(struct pipe_inode_info *pipe, unsigned int flags) { int ret; @@ -1587,6 +1609,124 @@ static int link_opipe_prep(struct pipe_inode_info *pipe, unsigned int flags) } /* + * Splice contents of ipipe to opipe. + */ +static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe, + struct pipe_inode_info *opipe, + size_t len, unsigned int flags) +{ + struct pipe_buffer *ibuf, *obuf; + int ret = 0, nbuf; + bool input_wakeup = false; + + +retry: + ret = ipipe_prep(ipipe, flags); + if (ret) + return ret; + + ret = opipe_prep(opipe, flags); + if (ret) + return ret; + + /* + * Potential ABBA deadlock, work around it by ordering lock + * grabbing by pipe info address. Otherwise two different processes + * could deadlock (one doing tee from A -> B, the other from B -> A). + */ + pipe_double_lock(ipipe, opipe); + + do { + if (!opipe->readers) { + send_sig(SIGPIPE, current, 0); + if (!ret) + ret = -EPIPE; + break; + } + + if (!ipipe->nrbufs && !ipipe->writers) + break; + + /* + * Cannot make any progress, because either the input + * pipe is empty or the output pipe is full. + */ + if (!ipipe->nrbufs || opipe->nrbufs >= PIPE_BUFFERS) { + /* Already processed some buffers, break */ + if (ret) + break; + + if (flags & SPLICE_F_NONBLOCK) { + ret = -EAGAIN; + break; + } + + /* + * We raced with another reader/writer and haven't + * managed to process any buffers. A zero return + * value means EOF, so retry instead. + */ + pipe_unlock(ipipe); + pipe_unlock(opipe); + goto retry; + } + + ibuf = ipipe->bufs + ipipe->curbuf; + nbuf = (opipe->curbuf + opipe->nrbufs) % PIPE_BUFFERS; + obuf = opipe->bufs + nbuf; + + if (len >= ibuf->len) { + /* + * Simply move the whole buffer from ipipe to opipe + */ + *obuf = *ibuf; + ibuf->ops = NULL; + opipe->nrbufs++; + ipipe->curbuf = (ipipe->curbuf + 1) % PIPE_BUFFERS; + ipipe->nrbufs--; + input_wakeup = true; + } else { + /* + * Get a reference to this pipe buffer, + * so we can copy the contents over. + */ + ibuf->ops->get(ipipe, ibuf); + *obuf = *ibuf; + + /* + * Don't inherit the gift flag, we need to + * prevent multiple steals of this page. + */ + obuf->flags &= ~PIPE_BUF_FLAG_GIFT; + + obuf->len = len; + opipe->nrbufs++; + ibuf->offset += obuf->len; + ibuf->len -= obuf->len; + } + ret += obuf->len; + len -= obuf->len; + } while (len); + + pipe_unlock(ipipe); + pipe_unlock(opipe); + + /* + * If we put data in the output pipe, wakeup any potential readers. + */ + if (ret > 0) { + smp_mb(); + if (waitqueue_active(&opipe->wait)) + wake_up_interruptible(&opipe->wait); + kill_fasync(&opipe->fasync_readers, SIGIO, POLL_IN); + } + if (input_wakeup) + wakeup_pipe_writers(ipipe); + + return ret; +} + +/* * Link contents of ipipe to opipe. */ static int link_pipe(struct pipe_inode_info *ipipe, @@ -1690,9 +1830,9 @@ static long do_tee(struct file *in, struct file *out, size_t len, * Keep going, unless we encounter an error. The ipipe/opipe * ordering doesn't really matter. */ - ret = link_ipipe_prep(ipipe, flags); + ret = ipipe_prep(ipipe, flags); if (!ret) { - ret = link_opipe_prep(opipe, flags); + ret = opipe_prep(opipe, flags); if (!ret) ret = link_pipe(ipipe, opipe, len, flags); } -- cgit v0.10.2 From 6818173bd658439b83896a2a7586f64ab51bf29c Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 7 May 2009 15:37:36 +0200 Subject: splice: implement default splice_read method If f_op->splice_read() is not implemented, fall back to a plain read. Use vfs_readv() to read into previously allocated pages. This will allow splice and functions using splice, such as the loop device, to work on all filesystems. This includes "direct_io" files in fuse which bypass the page cache. Signed-off-by: Miklos Szeredi Signed-off-by: Jens Axboe diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 9ca4bb0..801f4ab 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -709,10 +709,6 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode)) goto out_putf; - /* new backing store needs to support loop (eg splice_read) */ - if (!inode->i_fop->splice_read) - goto out_putf; - /* size of the new backing store needs to be the same */ if (get_loop_size(lo, file) != get_loop_size(lo, old_file)) goto out_putf; @@ -788,12 +784,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, error = -EINVAL; if (S_ISREG(inode->i_mode) || S_ISBLK(inode->i_mode)) { const struct address_space_operations *aops = mapping->a_ops; - /* - * If we can't read - sorry. If we only can't write - well, - * it's going to be read-only. - */ - if (!file->f_op->splice_read) - goto out_putf; + if (aops->write_begin) lo_flags |= LO_FLAGS_USE_AOPS; if (!(lo_flags & LO_FLAGS_USE_AOPS) && !file->f_op->write) diff --git a/fs/coda/file.c b/fs/coda/file.c index 6a347fb..ffd4281 100644 --- a/fs/coda/file.c +++ b/fs/coda/file.c @@ -47,6 +47,8 @@ coda_file_splice_read(struct file *coda_file, loff_t *ppos, struct pipe_inode_info *pipe, size_t count, unsigned int flags) { + ssize_t (*splice_read)(struct file *, loff_t *, + struct pipe_inode_info *, size_t, unsigned int); struct coda_file_info *cfi; struct file *host_file; @@ -54,10 +56,11 @@ coda_file_splice_read(struct file *coda_file, loff_t *ppos, BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); host_file = cfi->cfi_container; - if (!host_file->f_op || !host_file->f_op->splice_read) - return -EINVAL; + splice_read = host_file->f_op->splice_read; + if (!splice_read) + splice_read = default_file_splice_read; - return host_file->f_op->splice_read(host_file, ppos, pipe, count,flags); + return splice_read(host_file, ppos, pipe, count, flags); } static ssize_t diff --git a/fs/pipe.c b/fs/pipe.c index 13414ec..f7dd21a 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -302,6 +302,20 @@ int generic_pipe_buf_confirm(struct pipe_inode_info *info, return 0; } +/** + * generic_pipe_buf_release - put a reference to a &struct pipe_buffer + * @pipe: the pipe that the buffer belongs to + * @buf: the buffer to put a reference to + * + * Description: + * This function releases a reference to @buf. + */ +void generic_pipe_buf_release(struct pipe_inode_info *pipe, + struct pipe_buffer *buf) +{ + page_cache_release(buf->page); +} + static const struct pipe_buf_operations anon_pipe_buf_ops = { .can_merge = 1, .map = generic_pipe_buf_map, diff --git a/fs/read_write.c b/fs/read_write.c index 9d1e76b..6c8c55d 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -805,12 +805,6 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, goto out; if (!(in_file->f_mode & FMODE_READ)) goto fput_in; - retval = -EINVAL; - in_inode = in_file->f_path.dentry->d_inode; - if (!in_inode) - goto fput_in; - if (!in_file->f_op || !in_file->f_op->splice_read) - goto fput_in; retval = -ESPIPE; if (!ppos) ppos = &in_file->f_pos; @@ -834,6 +828,7 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, retval = -EINVAL; if (!out_file->f_op || !out_file->f_op->sendpage) goto fput_out; + in_inode = in_file->f_path.dentry->d_inode; out_inode = out_file->f_path.dentry->d_inode; retval = rw_verify_area(WRITE, out_file, &out_file->f_pos, count); if (retval < 0) diff --git a/fs/splice.c b/fs/splice.c index e405cf5..3bd9cb2 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -507,9 +507,116 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos, return ret; } - EXPORT_SYMBOL(generic_file_splice_read); +static const struct pipe_buf_operations default_pipe_buf_ops = { + .can_merge = 0, + .map = generic_pipe_buf_map, + .unmap = generic_pipe_buf_unmap, + .confirm = generic_pipe_buf_confirm, + .release = generic_pipe_buf_release, + .steal = generic_pipe_buf_steal, + .get = generic_pipe_buf_get, +}; + +static ssize_t kernel_readv(struct file *file, const struct iovec *vec, + unsigned long vlen, loff_t offset) +{ + mm_segment_t old_fs; + loff_t pos = offset; + ssize_t res; + + old_fs = get_fs(); + set_fs(get_ds()); + /* The cast to a user pointer is valid due to the set_fs() */ + res = vfs_readv(file, (const struct iovec __user *)vec, vlen, &pos); + set_fs(old_fs); + + return res; +} + +ssize_t default_file_splice_read(struct file *in, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags) +{ + unsigned int nr_pages; + unsigned int nr_freed; + size_t offset; + struct page *pages[PIPE_BUFFERS]; + struct partial_page partial[PIPE_BUFFERS]; + struct iovec vec[PIPE_BUFFERS]; + pgoff_t index; + ssize_t res; + size_t this_len; + int error; + int i; + struct splice_pipe_desc spd = { + .pages = pages, + .partial = partial, + .flags = flags, + .ops = &default_pipe_buf_ops, + .spd_release = spd_release_page, + }; + + index = *ppos >> PAGE_CACHE_SHIFT; + offset = *ppos & ~PAGE_CACHE_MASK; + nr_pages = (len + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; + + for (i = 0; i < nr_pages && i < PIPE_BUFFERS && len; i++) { + struct page *page; + + page = alloc_page(GFP_HIGHUSER); + error = -ENOMEM; + if (!page) + goto err; + + this_len = min_t(size_t, len, PAGE_CACHE_SIZE - offset); + vec[i].iov_base = (void __user *) kmap(page); + vec[i].iov_len = this_len; + pages[i] = page; + spd.nr_pages++; + len -= this_len; + offset = 0; + } + + res = kernel_readv(in, vec, spd.nr_pages, *ppos); + if (res < 0) + goto err; + + error = 0; + if (!res) + goto err; + + nr_freed = 0; + for (i = 0; i < spd.nr_pages; i++) { + kunmap(pages[i]); + this_len = min_t(size_t, vec[i].iov_len, res); + partial[i].offset = 0; + partial[i].len = this_len; + if (!this_len) { + __free_page(pages[i]); + pages[i] = NULL; + nr_freed++; + } + res -= this_len; + } + spd.nr_pages -= nr_freed; + + res = splice_to_pipe(pipe, &spd); + if (res > 0) + *ppos += res; + + return res; + +err: + for (i = 0; i < spd.nr_pages; i++) { + kunmap(pages[i]); + __free_page(pages[i]); + } + return error; +} +EXPORT_SYMBOL(default_file_splice_read); + /* * Send 'sd->len' bytes to socket from 'sd->file' at position 'sd->pos' * using sendpage(). Return the number of bytes sent. @@ -933,11 +1040,10 @@ static long do_splice_to(struct file *in, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags) { + ssize_t (*splice_read)(struct file *, loff_t *, + struct pipe_inode_info *, size_t, unsigned int); int ret; - if (unlikely(!in->f_op || !in->f_op->splice_read)) - return -EINVAL; - if (unlikely(!(in->f_mode & FMODE_READ))) return -EBADF; @@ -945,7 +1051,11 @@ static long do_splice_to(struct file *in, loff_t *ppos, if (unlikely(ret < 0)) return ret; - return in->f_op->splice_read(in, ppos, pipe, len, flags); + splice_read = in->f_op->splice_read; + if (!splice_read) + splice_read = default_file_splice_read; + + return splice_read(in, ppos, pipe, len, flags); } /** diff --git a/include/linux/fs.h b/include/linux/fs.h index 5bed436..d926c2b 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2204,6 +2204,8 @@ extern int generic_segment_checks(const struct iovec *iov, /* fs/splice.c */ extern ssize_t generic_file_splice_read(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); +extern ssize_t default_file_splice_read(struct file *, loff_t *, + struct pipe_inode_info *, size_t, unsigned int); extern ssize_t generic_file_splice_write(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h index c8f0385..b43a9e0 100644 --- a/include/linux/pipe_fs_i.h +++ b/include/linux/pipe_fs_i.h @@ -152,5 +152,6 @@ void generic_pipe_buf_unmap(struct pipe_inode_info *, struct pipe_buffer *, void void generic_pipe_buf_get(struct pipe_inode_info *, struct pipe_buffer *); int generic_pipe_buf_confirm(struct pipe_inode_info *, struct pipe_buffer *); int generic_pipe_buf_steal(struct pipe_inode_info *, struct pipe_buffer *); +void generic_pipe_buf_release(struct pipe_inode_info *, struct pipe_buffer *); #endif -- cgit v0.10.2 From 0b0a47f5c4a30b58432e20ae1706a27baea91a88 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 7 May 2009 15:37:37 +0200 Subject: splice: implement default splice_write method If f_op->splice_write() is not implemented, fall back to a plain write. Use vfs_writev() to write from the pipe buffers. This will allow splice on all filesystems and file types. This includes "direct_io" files in fuse which bypass the page cache. Signed-off-by: Miklos Szeredi Signed-off-by: Jens Axboe diff --git a/fs/splice.c b/fs/splice.c index 3bd9cb2..eefd96b 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -535,6 +535,21 @@ static ssize_t kernel_readv(struct file *file, const struct iovec *vec, return res; } +static ssize_t kernel_writev(struct file *file, const struct iovec *vec, + unsigned long vlen, loff_t *ppos) +{ + mm_segment_t old_fs; + ssize_t res; + + old_fs = get_fs(); + set_fs(get_ds()); + /* The cast to a user pointer is valid due to the set_fs() */ + res = vfs_writev(file, (const struct iovec __user *)vec, vlen, ppos); + set_fs(old_fs); + + return res; +} + ssize_t default_file_splice_read(struct file *in, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags) @@ -988,6 +1003,122 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, EXPORT_SYMBOL(generic_file_splice_write); +static struct pipe_buffer *nth_pipe_buf(struct pipe_inode_info *pipe, int n) +{ + return &pipe->bufs[(pipe->curbuf + n) % PIPE_BUFFERS]; +} + +static ssize_t default_file_splice_write(struct pipe_inode_info *pipe, + struct file *out, loff_t *ppos, + size_t len, unsigned int flags) +{ + ssize_t ret = 0; + ssize_t total_len = 0; + int do_wakeup = 0; + + pipe_lock(pipe); + while (len) { + struct pipe_buffer *buf; + void *data[PIPE_BUFFERS]; + struct iovec vec[PIPE_BUFFERS]; + unsigned int nr_pages = 0; + unsigned int write_len = 0; + unsigned int now_len = len; + unsigned int this_len; + int i; + + BUG_ON(pipe->nrbufs > PIPE_BUFFERS); + for (i = 0; i < pipe->nrbufs && now_len; i++) { + buf = nth_pipe_buf(pipe, i); + + ret = buf->ops->confirm(pipe, buf); + if (ret) + break; + + data[i] = buf->ops->map(pipe, buf, 0); + this_len = min(buf->len, now_len); + vec[i].iov_base = (void __user *) data[i] + buf->offset; + vec[i].iov_len = this_len; + now_len -= this_len; + write_len += this_len; + nr_pages++; + } + + if (nr_pages) { + ret = kernel_writev(out, vec, nr_pages, ppos); + if (ret == 0) + ret = -EIO; + if (ret > 0) { + len -= ret; + total_len += ret; + } + } + + for (i = 0; i < nr_pages; i++) { + buf = nth_pipe_buf(pipe, i); + buf->ops->unmap(pipe, buf, data[i]); + + if (ret > 0) { + this_len = min_t(unsigned, vec[i].iov_len, ret); + buf->offset += this_len; + buf->len -= this_len; + ret -= this_len; + } + } + + if (ret < 0) + break; + + while (pipe->nrbufs) { + const struct pipe_buf_operations *ops; + + buf = nth_pipe_buf(pipe, 0); + if (buf->len) + break; + + ops = buf->ops; + buf->ops = NULL; + ops->release(pipe, buf); + pipe->curbuf = (pipe->curbuf + 1) % PIPE_BUFFERS; + pipe->nrbufs--; + if (pipe->inode) + do_wakeup = 1; + } + + if (pipe->nrbufs) + continue; + if (!pipe->writers) + break; + if (!pipe->waiting_writers) { + if (total_len) + break; + } + + if (flags & SPLICE_F_NONBLOCK) { + ret = -EAGAIN; + break; + } + + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + + if (do_wakeup) { + wakeup_pipe_writers(pipe); + do_wakeup = 0; + } + + pipe_wait(pipe); + } + pipe_unlock(pipe); + + if (do_wakeup) + wakeup_pipe_writers(pipe); + + return total_len ? total_len : ret; +} + /** * generic_splice_sendpage - splice data from a pipe to a socket * @pipe: pipe to splice from @@ -1015,11 +1146,10 @@ EXPORT_SYMBOL(generic_splice_sendpage); static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, loff_t *ppos, size_t len, unsigned int flags) { + ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, + loff_t *, size_t, unsigned int); int ret; - if (unlikely(!out->f_op || !out->f_op->splice_write)) - return -EINVAL; - if (unlikely(!(out->f_mode & FMODE_WRITE))) return -EBADF; @@ -1030,7 +1160,11 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, if (unlikely(ret < 0)) return ret; - return out->f_op->splice_write(pipe, out, ppos, len, flags); + splice_write = out->f_op->splice_write; + if (!splice_write) + splice_write = default_file_splice_write; + + return splice_write(pipe, out, ppos, len, flags); } /* -- cgit v0.10.2 From e458824f9d32e9bf7700d1eb0d201749af48eee0 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 12 May 2009 08:49:32 +0200 Subject: scsi: fix resid_len mis-conversion in scsi_end_request() Commit c3a4d78c580de4edc9ef0f7c59812fb02ceb037f introduced rq->data_len and converted residual count users to it. While converting, it mistakenly converted scsi_end_request() to finish requests with residual count when it wants to do is fully complete the request. Fix it by using blk_end_request_all() instead. This bug was spotted by Boaz Harrosh. Signed-off-by: Tejun Heo Spotted-by: Boaz Harrosh Cc: FUJITA Tomonori Cc: James Bottomley Signed-off-by: Jens Axboe diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index a54bec9..e410d66 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -546,14 +546,9 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int error, * to queue the remainder of them. */ if (blk_end_request(req, error, bytes)) { - int leftover = blk_rq_bytes(req); - - if (blk_pc_request(req)) - leftover = req->resid_len; - /* kill remainder if no retrys */ if (error && scsi_noretry_cmd(cmd)) - blk_end_request(req, error, leftover); + blk_end_request_all(req, error); else { if (requeue) { /* -- cgit v0.10.2 From 2b1ccc0ee918a653d0483fdad9dd6112ce8e9043 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 12 May 2009 11:11:48 +0200 Subject: splice: fix misleading comment Splice is tied to pipes by design, it'll not change. And now that the splice stuff is in splice.h (and note pipe.h), the rest of the comment is out-of-date as well. Signed-off-by: Jens Axboe diff --git a/include/linux/splice.h b/include/linux/splice.h index 5f3faa9..18e7c7c 100644 --- a/include/linux/splice.h +++ b/include/linux/splice.h @@ -11,8 +11,7 @@ #include /* - * splice is tied to pipes as a transport (at least for now), so we'll just - * add the splice flags here. + * Flags passed in from splice/tee/vmsplice */ #define SPLICE_F_MOVE (0x01) /* move pages instead of copying */ #define SPLICE_F_NONBLOCK (0x02) /* don't block on the pipe splicing (but */ -- cgit v0.10.2 From 4f23122858a27ba97444b9b37a066d83edebd4c8 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 13 May 2009 08:35:35 +0200 Subject: splice: fix repeated kmap()'s in default_file_splice_read() We cannot reliably map more than one page at the time, or we risk deadlocking. Just allocate the pages from low mem instead. Reported-by: Andrew Morton Signed-off-by: Jens Axboe diff --git a/fs/splice.c b/fs/splice.c index eefd96b..c5e3c79 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -580,13 +580,13 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos, for (i = 0; i < nr_pages && i < PIPE_BUFFERS && len; i++) { struct page *page; - page = alloc_page(GFP_HIGHUSER); + page = alloc_page(GFP_USER); error = -ENOMEM; if (!page) goto err; this_len = min_t(size_t, len, PAGE_CACHE_SIZE - offset); - vec[i].iov_base = (void __user *) kmap(page); + vec[i].iov_base = (void __user *) page_address(page); vec[i].iov_len = this_len; pages[i] = page; spd.nr_pages++; @@ -604,7 +604,6 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos, nr_freed = 0; for (i = 0; i < spd.nr_pages; i++) { - kunmap(pages[i]); this_len = min_t(size_t, vec[i].iov_len, res); partial[i].offset = 0; partial[i].len = this_len; @@ -624,10 +623,9 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos, return res; err: - for (i = 0; i < spd.nr_pages; i++) { - kunmap(pages[i]); + for (i = 0; i < spd.nr_pages; i++) __free_page(pages[i]); - } + return error; } EXPORT_SYMBOL(default_file_splice_read); -- cgit v0.10.2 From 77f6bf57ba9d2c50173536dbfdacdab27cb867ca Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 14 May 2009 09:49:44 +0200 Subject: splice: fix error return code fs/splice.c: In function 'default_file_splice_read': fs/splice.c:566: warning: 'error' may be used uninitialized in this function which is sort-of true. The code will in fact return -ENOMEM instead of the kernel_readv() return value. Cc: Miklos Szeredi Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe diff --git a/fs/splice.c b/fs/splice.c index c5e3c79..41179c0 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -595,8 +595,10 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos, } res = kernel_readv(in, vec, spd.nr_pages, *ppos); - if (res < 0) + if (res < 0) { + error = res; goto err; + } error = 0; if (!res) -- cgit v0.10.2 From 6c3b46f74587d46e71b8c2b78fdca626a3aca280 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 18 May 2009 14:38:28 +0200 Subject: virtio_blk: don't blindly derefence req->rq_disk request->rq_disk is only set for FS requests or BLOCK_PC requests originating from the generic block layer scsi ioctls. It's not set for requests origination from other soures or internal cache flush commands implemented by the patch I'll send after this. So instead of using it to get at the private data in do_virtblk_request setup queue->queuedata and use it. Signed-off-by: Christoph Hellwig Signed-off-by: Rusty Russell Signed-off-by: Jens Axboe diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 29a9daf..dfe9ee5 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -124,12 +124,11 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk, static void do_virtblk_request(struct request_queue *q) { - struct virtio_blk *vblk = NULL; + struct virtio_blk *vblk = q->queuedata; struct request *req; unsigned int issued = 0; while ((req = blk_peek_request(q)) != NULL) { - vblk = req->rq_disk->private_data; BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems); /* If this request fails, stop queue and wait for something to @@ -249,6 +248,7 @@ static int virtblk_probe(struct virtio_device *vdev) goto out_put_disk; } + vblk->disk->queue->queuedata = vblk; queue_flag_set_unlocked(QUEUE_FLAG_VIRT, vblk->disk->queue); if (index < 26) { -- cgit v0.10.2 From 1cde26f928863d90e9e7c1217880c8450464d305 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 18 May 2009 14:41:30 +0200 Subject: virtio_blk: SG_IO passthru support Add support for SG_IO passthru to virtio_blk. We add the scsi command block after the normal outhdr, and the scsi inhdr with full status information aswell as the sense buffer before the regular inhdr. [hch: forward ported, added the VIRTIO_BLK_F_SCSI flags, some comments and tested the whole beast] [axboe: updated to use ->resid and not dual-path the byte count] Signed-off-by: Hannes Reinecke Signed-off-by: Christoph Hellwig Signed-off-by: Rusty Russell (+ checkpatch.pl tweak) Signed-off-by: Jens Axboe diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index dfe9ee5..62275db 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -37,6 +37,7 @@ struct virtblk_req struct list_head list; struct request *req; struct virtio_blk_outhdr out_hdr; + struct virtio_scsi_inhdr in_hdr; u8 status; }; @@ -49,7 +50,9 @@ static void blk_done(struct virtqueue *vq) spin_lock_irqsave(&vblk->lock, flags); while ((vbr = vblk->vq->vq_ops->get_buf(vblk->vq, &len)) != NULL) { + unsigned int nr_bytes; int error; + switch (vbr->status) { case VIRTIO_BLK_S_OK: error = 0; @@ -62,6 +65,12 @@ static void blk_done(struct virtqueue *vq) break; } + if (blk_pc_request(vbr->req)) { + vbr->req->resid_len = vbr->in_hdr.residual; + vbr->req->sense_len = vbr->in_hdr.sense_len; + vbr->req->errors = vbr->in_hdr.errors; + } + __blk_end_request_all(vbr->req, error); list_del(&vbr->list); mempool_free(vbr, vblk->pool); @@ -74,7 +83,7 @@ static void blk_done(struct virtqueue *vq) static bool do_req(struct request_queue *q, struct virtio_blk *vblk, struct request *req) { - unsigned long num, out, in; + unsigned long num, out = 0, in = 0; struct virtblk_req *vbr; vbr = mempool_alloc(vblk->pool, GFP_ATOMIC); @@ -99,18 +108,36 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk, if (blk_barrier_rq(vbr->req)) vbr->out_hdr.type |= VIRTIO_BLK_T_BARRIER; - sg_set_buf(&vblk->sg[0], &vbr->out_hdr, sizeof(vbr->out_hdr)); - num = blk_rq_map_sg(q, vbr->req, vblk->sg+1); - sg_set_buf(&vblk->sg[num+1], &vbr->status, sizeof(vbr->status)); + sg_set_buf(&vblk->sg[out++], &vbr->out_hdr, sizeof(vbr->out_hdr)); - if (rq_data_dir(vbr->req) == WRITE) { - vbr->out_hdr.type |= VIRTIO_BLK_T_OUT; - out = 1 + num; - in = 1; - } else { - vbr->out_hdr.type |= VIRTIO_BLK_T_IN; - out = 1; - in = 1 + num; + /* + * If this is a packet command we need a couple of additional headers. + * Behind the normal outhdr we put a segment with the scsi command + * block, and before the normal inhdr we put the sense data and the + * inhdr with additional status information before the normal inhdr. + */ + if (blk_pc_request(vbr->req)) + sg_set_buf(&vblk->sg[out++], vbr->req->cmd, vbr->req->cmd_len); + + num = blk_rq_map_sg(q, vbr->req, vblk->sg + out); + + if (blk_pc_request(vbr->req)) { + sg_set_buf(&vblk->sg[num + out + in++], vbr->req->sense, 96); + sg_set_buf(&vblk->sg[num + out + in++], &vbr->in_hdr, + sizeof(vbr->in_hdr)); + } + + sg_set_buf(&vblk->sg[num + out + in++], &vbr->status, + sizeof(vbr->status)); + + if (num) { + if (rq_data_dir(vbr->req) == WRITE) { + vbr->out_hdr.type |= VIRTIO_BLK_T_OUT; + out += num; + } else { + vbr->out_hdr.type |= VIRTIO_BLK_T_IN; + in += num; + } } if (vblk->vq->vq_ops->add_buf(vblk->vq, vblk->sg, out, in, vbr)) { @@ -148,8 +175,16 @@ static void do_virtblk_request(struct request_queue *q) static int virtblk_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, unsigned long data) { - return scsi_cmd_ioctl(bdev->bd_disk->queue, - bdev->bd_disk, mode, cmd, + struct gendisk *disk = bdev->bd_disk; + struct virtio_blk *vblk = disk->private_data; + + /* + * Only allow the generic SCSI ioctls if the host can support it. + */ + if (!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_SCSI)) + return -ENOIOCTLCMD; + + return scsi_cmd_ioctl(disk->queue, disk, mode, cmd, (void __user *)data); } @@ -356,6 +391,7 @@ static struct virtio_device_id id_table[] = { static unsigned int features[] = { VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, + VIRTIO_BLK_F_SCSI, }; static struct virtio_driver virtio_blk = { diff --git a/include/linux/virtio_blk.h b/include/linux/virtio_blk.h index 94c56d2..4dbcbc1 100644 --- a/include/linux/virtio_blk.h +++ b/include/linux/virtio_blk.h @@ -15,6 +15,7 @@ #define VIRTIO_BLK_F_GEOMETRY 4 /* Legacy geometry available */ #define VIRTIO_BLK_F_RO 5 /* Disk is read-only */ #define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available*/ +#define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */ struct virtio_blk_config { @@ -55,6 +56,13 @@ struct virtio_blk_outhdr __u64 sector; }; +struct virtio_scsi_inhdr { + __u32 errors; + __u32 data_len; + __u32 sense_len; + __u32 residual; +}; + /* And this is the final byte of the write scatter-gather list. */ #define VIRTIO_BLK_S_OK 0 #define VIRTIO_BLK_S_IOERR 1 -- cgit v0.10.2 From f831cc03490c78a76e2d35ad77ec2292d0323728 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 18 May 2009 14:44:45 +0200 Subject: virtio_blk: get rid of unused variable drivers/block/virtio_blk.c: In function 'blk_done': drivers/block/virtio_blk.c:53: warning: unused variable 'nr_bytes' Leftover from commit 1cde26f928863d90e9e7c1217880c8450464d305 Signed-off-by: Jens Axboe diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 62275db..511d4ae 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -50,7 +50,6 @@ static void blk_done(struct virtqueue *vq) spin_lock_irqsave(&vblk->lock, flags); while ((vbr = vblk->vq->vq_ops->get_buf(vblk->vq, &len)) != NULL) { - unsigned int nr_bytes; int error; switch (vbr->status) { -- cgit v0.10.2 From 3755100dd5f66761aaaa7ae44c70b319a7c78a56 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 19 May 2009 18:33:04 +0900 Subject: ub: use __blk_end_request_all() ub_end_rq() always tries to complete full request. The @cmd_len parameter was there because rq->data_len used to be overwritten with residue count. Drop @cmd_len and use __blk_end_request_all(). Signed-off-by: Tejun Heo Cc: Pete Zaitcev Signed-off-by: Jens Axboe diff --git a/drivers/block/ub.c b/drivers/block/ub.c index 178f459..f32781c 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -360,8 +360,7 @@ static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun, static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun, struct ub_scsi_cmd *cmd, struct ub_request *urq); static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd); -static void ub_end_rq(struct request *rq, unsigned int status, - unsigned int cmd_len); +static void ub_end_rq(struct request *rq, unsigned int status); static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun, struct ub_request *urq, struct ub_scsi_cmd *cmd); static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd); @@ -644,13 +643,13 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq) if (atomic_read(&sc->poison)) { blk_start_request(rq); - ub_end_rq(rq, DID_NO_CONNECT << 16, blk_rq_bytes(rq)); + ub_end_rq(rq, DID_NO_CONNECT << 16); return 0; } if (lun->changed && !blk_pc_request(rq)) { blk_start_request(rq); - ub_end_rq(rq, SAM_STAT_CHECK_CONDITION, blk_rq_bytes(rq)); + ub_end_rq(rq, SAM_STAT_CHECK_CONDITION); return 0; } @@ -702,7 +701,7 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq) drop: ub_put_cmd(lun, cmd); - ub_end_rq(rq, DID_ERROR << 16, blk_rq_bytes(rq)); + ub_end_rq(rq, DID_ERROR << 16); return 0; } @@ -777,7 +776,6 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) struct ub_request *urq = cmd->back; struct request *rq; unsigned int scsi_status; - unsigned int cmd_len; rq = urq->rq; @@ -816,17 +814,14 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) urq->rq = NULL; - cmd_len = cmd->len; ub_put_cmd(lun, cmd); - ub_end_rq(rq, scsi_status, cmd_len); + ub_end_rq(rq, scsi_status); blk_start_queue(lun->disk->queue); } -static void ub_end_rq(struct request *rq, unsigned int scsi_status, - unsigned int cmd_len) +static void ub_end_rq(struct request *rq, unsigned int scsi_status) { int error; - long rqlen; if (scsi_status == 0) { error = 0; @@ -834,12 +829,7 @@ static void ub_end_rq(struct request *rq, unsigned int scsi_status, error = -EIO; rq->errors = scsi_status; } - rqlen = blk_rq_bytes(rq); /* Oddly enough, this is the residue. */ - if (__blk_end_request(rq, error, cmd_len)) { - printk(KERN_WARNING DRV_NAME - ": __blk_end_request blew, %s-cmd total %u rqlen %ld\n", - blk_pc_request(rq)? "pc": "fs", cmd_len, rqlen); - } + __blk_end_request_all(rq, error); } static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun, -- cgit v0.10.2 From 5f49f63178360b07a095bd33b0d850d60edf7590 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 19 May 2009 18:33:05 +0900 Subject: block: set rq->resid_len to blk_rq_bytes() on issue In commit c3a4d78c580de4edc9ef0f7c59812fb02ceb037f, while introducing rq->resid_len, the default value of residue count was changed from full count to zero. The conversion was done under the assumption that when a request fails residue count wasn't defined. However, Boaz and James pointed out that this wasn't true and the residue count should be preserved for failed requests too. This patchset restores the original behavior by setting rq->resid_len to blk_rq_bytes(rq) on request start and restoring explicit clearing in affected drivers. While at it, take advantage of the fact that rq->resid_len is set to full count where applicable. * ide-cd: rq->resid_len cleared on pc success * mptsas: req->resid_len cleared on success * sas_expander: rsp/req->resid_len cleared on success * mpt2sas_transport: req->resid_len cleared on success * ide-cd, ide-tape, mptsas, sas_host_smp, mpt2sas_transport, ub: take advantage of initial full count to simplify code Boaz Harrosh spotted bug in resid_len initialization. Fixed as suggested. Signed-off-by: Tejun Heo Acked-by: Borislav Petkov Cc: Boaz Harrosh Cc: James Bottomley Cc: Pete Zaitcev Cc: Bartlomiej Zolnierkiewicz Cc: Sergei Shtylyov Cc: Eric Moore Cc: Darrick J. Wong Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index a2d97de..e3f7e6a 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1783,9 +1783,10 @@ void blk_start_request(struct request *req) blk_dequeue_request(req); /* - * We are now handing the request to the hardware, add the - * timeout handler. + * We are now handing the request to the hardware, initialize + * resid_len to full count and add the timeout handler. */ + req->resid_len = blk_rq_bytes(req); blk_add_timer(req); } EXPORT_SYMBOL(blk_start_request); diff --git a/drivers/block/ub.c b/drivers/block/ub.c index f32781c..e67bbae 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -781,8 +781,10 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) if (cmd->error == 0) { if (blk_pc_request(rq)) { - if (cmd->act_len < blk_rq_bytes(rq)) - rq->resid_len = blk_rq_bytes(rq) - cmd->act_len; + if (cmd->act_len >= rq->resid_len) + rq->resid_len = 0; + else + rq->resid_len -= cmd->act_len; scsi_status = 0; } else { if (cmd->act_len != cmd->len) { diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 4c7792f..081aed6 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -699,6 +699,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) out_end: if (blk_pc_request(rq) && rc == 0) { + rq->resid_len = 0; blk_end_request_all(rq, 0); hwif->rq = NULL; } else { @@ -718,8 +719,7 @@ out_end: /* make sure it's fully ended */ if (blk_fs_request(rq) == 0) { - rq->resid_len = blk_rq_bytes(rq) - - (cmd->nbytes - cmd->nleft); + rq->resid_len -= cmd->nbytes - cmd->nleft; if (uptodate == 0 && (cmd->tf_flags & IDE_TFLAG_WRITE)) rq->resid_len += cmd->last_xfer_len; } diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index e166045..683ff37 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -380,7 +380,7 @@ static int ide_tape_callback(ide_drive_t *drive, int dsc) } tape->first_frame += blocks; - rq->resid_len = blk_rq_bytes(rq) - blocks * tape->blk_size; + rq->resid_len -= blocks * tape->blk_size; if (pc->error) { uptodate = 0; diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 4e6fcf0..79f5433 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -1357,7 +1357,8 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; memcpy(req->sense, smprep, sizeof(*smprep)); req->sense_len = sizeof(*smprep); - rsp->resid_len = blk_rq_bytes(rsp) - smprep->ResponseDataLength; + req->resid_len = 0; + rsp->resid_len -= smprep->ResponseDataLength; } else { printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n", ioc->name, __func__); diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 531af9e..54fa1e4 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -1937,7 +1937,11 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, if (ret > 0) { /* positive number is the untransferred residual */ rsp->resid_len = ret; + req->resid_len = 0; ret = 0; + } else if (ret == 0) { + rsp->resid_len = 0; + req->resid_len = 0; } return ret; diff --git a/drivers/scsi/libsas/sas_host_smp.c b/drivers/scsi/libsas/sas_host_smp.c index be9a951..1bc3b75 100644 --- a/drivers/scsi/libsas/sas_host_smp.c +++ b/drivers/scsi/libsas/sas_host_smp.c @@ -176,9 +176,6 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, resp_data[1] = req_data[1]; resp_data[2] = SMP_RESP_FUNC_UNK; - req->resid_len = blk_rq_bytes(req); - rsp->resid_len = blk_rq_bytes(rsp); - switch (req_data[1]) { case SMP_REPORT_GENERAL: req->resid_len -= 8; diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index af95a44..5c65da5 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c @@ -1170,8 +1170,8 @@ transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, memcpy(req->sense, mpi_reply, sizeof(*mpi_reply)); req->sense_len = sizeof(*mpi_reply); - rsp->resid_len = blk_rq_bytes(rsp) - - mpi_reply->ResponseDataLength; + req->resid_len = 0; + rsp->resid_len -= mpi_reply->ResponseDataLength; } else { dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - no reply\n", ioc->name, __func__)); -- cgit v0.10.2 From 4fc981ef9e7c0953d5c4896ce088b19c50cb018f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 19 May 2009 18:33:06 +0900 Subject: bio: always copy back data for copied kernel requests When a read bio_copy_kern() request fails, the content of the bounce buffer is not copied back. However, as request failure doesn't necessarily mean complete failure, the buffer state can be useful. This behavior is also inconsistent with the user map counterpart and causes the subtle difference between bounced and unbounced IO causes confusion. This patch makes bio_copy_kern_endio() ignore @err and always copy back data on request completion. Signed-off-by: Tejun Heo Cc: Boaz Harrosh Cc: James Bottomley Signed-off-by: Jens Axboe diff --git a/fs/bio.c b/fs/bio.c index 7bbc98f..ee3bc67 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -1198,7 +1198,7 @@ static void bio_copy_kern_endio(struct bio *bio, int err) char *addr = page_address(bvec->bv_page); int len = bmd->iovecs[i].bv_len; - if (read && !err) + if (read) memcpy(p, addr, len); __free_page(bvec->bv_page); -- cgit v0.10.2 From b2858d7d1639c04ca3c54988d76c5f7300b76f1c Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 19 May 2009 11:37:46 +0200 Subject: splice: fix kmaps in default_file_splice_write() Unfortunately multiple kmap() within a single thread are deadlockable, so writing out multiple buffers with writev() isn't possible. Change the implementation so that it does a separate write() for each buffer. This actually simplifies the code a lot since the splice_from_pipe() helper can be used. This limitation is caused by HIGHMEM pages, and so only affects a subset of architectures and configurations. In the future it may be worth to implement default_file_splice_write() in a more efficient way on configs that allow it. Signed-off-by: Miklos Szeredi Signed-off-by: Jens Axboe diff --git a/fs/splice.c b/fs/splice.c index 41179c0..73766d2 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -535,8 +535,8 @@ static ssize_t kernel_readv(struct file *file, const struct iovec *vec, return res; } -static ssize_t kernel_writev(struct file *file, const struct iovec *vec, - unsigned long vlen, loff_t *ppos) +static ssize_t kernel_write(struct file *file, const char *buf, size_t count, + loff_t pos) { mm_segment_t old_fs; ssize_t res; @@ -544,7 +544,7 @@ static ssize_t kernel_writev(struct file *file, const struct iovec *vec, old_fs = get_fs(); set_fs(get_ds()); /* The cast to a user pointer is valid due to the set_fs() */ - res = vfs_writev(file, (const struct iovec __user *)vec, vlen, ppos); + res = vfs_write(file, (const char __user *)buf, count, &pos); set_fs(old_fs); return res; @@ -1003,120 +1003,34 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, EXPORT_SYMBOL(generic_file_splice_write); -static struct pipe_buffer *nth_pipe_buf(struct pipe_inode_info *pipe, int n) +static int write_pipe_buf(struct pipe_inode_info *pipe, struct pipe_buffer *buf, + struct splice_desc *sd) { - return &pipe->bufs[(pipe->curbuf + n) % PIPE_BUFFERS]; + int ret; + void *data; + + ret = buf->ops->confirm(pipe, buf); + if (ret) + return ret; + + data = buf->ops->map(pipe, buf, 0); + ret = kernel_write(sd->u.file, data + buf->offset, sd->len, sd->pos); + buf->ops->unmap(pipe, buf, data); + + return ret; } static ssize_t default_file_splice_write(struct pipe_inode_info *pipe, struct file *out, loff_t *ppos, size_t len, unsigned int flags) { - ssize_t ret = 0; - ssize_t total_len = 0; - int do_wakeup = 0; - - pipe_lock(pipe); - while (len) { - struct pipe_buffer *buf; - void *data[PIPE_BUFFERS]; - struct iovec vec[PIPE_BUFFERS]; - unsigned int nr_pages = 0; - unsigned int write_len = 0; - unsigned int now_len = len; - unsigned int this_len; - int i; - - BUG_ON(pipe->nrbufs > PIPE_BUFFERS); - for (i = 0; i < pipe->nrbufs && now_len; i++) { - buf = nth_pipe_buf(pipe, i); - - ret = buf->ops->confirm(pipe, buf); - if (ret) - break; - - data[i] = buf->ops->map(pipe, buf, 0); - this_len = min(buf->len, now_len); - vec[i].iov_base = (void __user *) data[i] + buf->offset; - vec[i].iov_len = this_len; - now_len -= this_len; - write_len += this_len; - nr_pages++; - } - - if (nr_pages) { - ret = kernel_writev(out, vec, nr_pages, ppos); - if (ret == 0) - ret = -EIO; - if (ret > 0) { - len -= ret; - total_len += ret; - } - } - - for (i = 0; i < nr_pages; i++) { - buf = nth_pipe_buf(pipe, i); - buf->ops->unmap(pipe, buf, data[i]); - - if (ret > 0) { - this_len = min_t(unsigned, vec[i].iov_len, ret); - buf->offset += this_len; - buf->len -= this_len; - ret -= this_len; - } - } - - if (ret < 0) - break; - - while (pipe->nrbufs) { - const struct pipe_buf_operations *ops; - - buf = nth_pipe_buf(pipe, 0); - if (buf->len) - break; - - ops = buf->ops; - buf->ops = NULL; - ops->release(pipe, buf); - pipe->curbuf = (pipe->curbuf + 1) % PIPE_BUFFERS; - pipe->nrbufs--; - if (pipe->inode) - do_wakeup = 1; - } - - if (pipe->nrbufs) - continue; - if (!pipe->writers) - break; - if (!pipe->waiting_writers) { - if (total_len) - break; - } - - if (flags & SPLICE_F_NONBLOCK) { - ret = -EAGAIN; - break; - } - - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - - if (do_wakeup) { - wakeup_pipe_writers(pipe); - do_wakeup = 0; - } - - pipe_wait(pipe); - } - pipe_unlock(pipe); + ssize_t ret; - if (do_wakeup) - wakeup_pipe_writers(pipe); + ret = splice_from_pipe(pipe, out, ppos, len, flags, write_pipe_buf); + if (ret > 0) + *ppos += ret; - return total_len ? total_len : ret; + return ret; } /** -- cgit v0.10.2 From 3a5a39276d2a32b05b1ee25b384516805b17cf87 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 17 May 2009 18:55:18 +0300 Subject: block: allow blk_rq_map_kern to append to requests Use blk_rq_append_bio() internally instead of blk_rq_bio_prep() so blk_rq_map_kern can be called multiple times, to map multiple buffers. This is in the effort to un-export blk_rq_append_bio() Signed-off-by: James Bottomley Signed-off-by: Boaz Harrosh Signed-off-by: Jens Axboe diff --git a/block/blk-map.c b/block/blk-map.c index 56082be..caa05a6 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -282,7 +282,8 @@ EXPORT_SYMBOL(blk_rq_unmap_user); * * Description: * Data will be mapped directly if possible. Otherwise a bounce - * buffer is used. + * buffer is used. Can be called multple times to append multple + * buffers. */ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf, unsigned int len, gfp_t gfp_mask) @@ -290,6 +291,7 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf, int reading = rq_data_dir(rq) == READ; int do_copy = 0; struct bio *bio; + int ret; if (len > (q->max_hw_sectors << 9)) return -EINVAL; @@ -311,7 +313,13 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf, if (do_copy) rq->cmd_flags |= REQ_COPY_USER; - blk_rq_bio_prep(q, rq, bio); + ret = blk_rq_append_bio(q, rq, bio); + if (unlikely(ret)) { + /* request is too big */ + bio_put(bio); + return ret; + } + blk_queue_bounce(q, &rq->bio); rq->buffer = NULL; return 0; -- cgit v0.10.2 From bc38bf106c967389a465d926be22c7371abba69d Mon Sep 17 00:00:00 2001 From: Boaz Harrosh Date: Sun, 17 May 2009 18:56:17 +0300 Subject: libosd: Use new blk_rq_map_kern Now that blk_rq_map_kern will append the buffer onto the request we can use it easily for adding extra segments (eg. attributes) This patch is dependent on a block layer patch titled: [BLOCK] allow blk_rq_map_kern to append to requests Signed-off-by: Boaz Harrosh Signed-off-by: Jens Axboe diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index d178a8b..bf66e30 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c @@ -826,26 +826,6 @@ int osd_req_add_set_attr_list(struct osd_request *or, } EXPORT_SYMBOL(osd_req_add_set_attr_list); -static int _append_map_kern(struct request *req, - void *buff, unsigned len, gfp_t flags) -{ - struct bio *bio; - int ret; - - bio = bio_map_kern(req->q, buff, len, flags); - if (IS_ERR(bio)) { - OSD_ERR("Failed bio_map_kern(%p, %d) => %ld\n", buff, len, - PTR_ERR(bio)); - return PTR_ERR(bio); - } - ret = blk_rq_append_bio(req->q, req, bio); - if (ret) { - OSD_ERR("Failed blk_rq_append_bio(%p) => %d\n", bio, ret); - bio_put(bio); - } - return ret; -} - static int _req_append_segment(struct osd_request *or, unsigned padding, struct _osd_req_data_segment *seg, struct _osd_req_data_segment *last_seg, struct _osd_io_info *io) @@ -861,14 +841,14 @@ static int _req_append_segment(struct osd_request *or, else pad_buff = io->pad_buff; - ret = _append_map_kern(io->req, pad_buff, padding, + ret = blk_rq_map_kern(io->req->q, io->req, pad_buff, padding, or->alloc_flags); if (ret) return ret; io->total_bytes += padding; } - ret = _append_map_kern(io->req, seg->buff, seg->total_bytes, + ret = blk_rq_map_kern(io->req->q, io->req, seg->buff, seg->total_bytes, or->alloc_flags); if (ret) return ret; -- cgit v0.10.2 From 79eb63e9e5875b84341a3a05f8e6ae9cdb4bb6f6 Mon Sep 17 00:00:00 2001 From: Boaz Harrosh Date: Sun, 17 May 2009 18:57:15 +0300 Subject: block: Add blk_make_request(), takes bio, returns a request New block API: given a struct bio allocates a new request. This is the parallel of generic_make_request for BLOCK_PC commands users. The passed bio may be a chained-bio. The bio is bounced if needed inside the call to this member. This is in the effort of un-exporting blk_rq_append_bio(). Signed-off-by: Boaz Harrosh CC: Jeff Garzik Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index e3f7e6a..bec1d69 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -891,6 +891,51 @@ struct request *blk_get_request(struct request_queue *q, int rw, gfp_t gfp_mask) EXPORT_SYMBOL(blk_get_request); /** + * blk_make_request - given a bio, allocate a corresponding struct request. + * + * @bio: The bio describing the memory mappings that will be submitted for IO. + * It may be a chained-bio properly constructed by block/bio layer. + * + * blk_make_request is the parallel of generic_make_request for BLOCK_PC + * type commands. Where the struct request needs to be farther initialized by + * the caller. It is passed a &struct bio, which describes the memory info of + * the I/O transfer. + * + * The caller of blk_make_request must make sure that bi_io_vec + * are set to describe the memory buffers. That bio_data_dir() will return + * the needed direction of the request. (And all bio's in the passed bio-chain + * are properly set accordingly) + * + * If called under none-sleepable conditions, mapped bio buffers must not + * need bouncing, by calling the appropriate masked or flagged allocator, + * suitable for the target device. Otherwise the call to blk_queue_bounce will + * BUG. + */ +struct request *blk_make_request(struct request_queue *q, struct bio *bio, + gfp_t gfp_mask) +{ + struct request *rq = blk_get_request(q, bio_data_dir(bio), gfp_mask); + + if (unlikely(!rq)) + return ERR_PTR(-ENOMEM); + + for_each_bio(bio) { + struct bio *bounce_bio = bio; + int ret; + + blk_queue_bounce(q, &bounce_bio); + ret = blk_rq_append_bio(q, rq, bounce_bio); + if (unlikely(ret)) { + blk_put_request(rq); + return ERR_PTR(ret); + } + } + + return rq; +} +EXPORT_SYMBOL(blk_make_request); + +/** * blk_requeue_request - put a request back on queue * @q: request queue where request should be inserted * @rq: request to be inserted diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index f9d60a7..88a83e1 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -740,6 +740,8 @@ extern void blk_rq_init(struct request_queue *q, struct request *rq); extern void blk_put_request(struct request *); extern void __blk_put_request(struct request_queue *, struct request *); extern struct request *blk_get_request(struct request_queue *, int, gfp_t); +extern struct request *blk_make_request(struct request_queue *, struct bio *, + gfp_t); extern void blk_insert_request(struct request_queue *, struct request *, int, void *); extern void blk_requeue_request(struct request_queue *, struct request *); extern int blk_rq_check_limits(struct request_queue *q, struct request *rq); -- cgit v0.10.2 From c29b70f6ee4f2fa3ef07f55bc9082945861e5391 Mon Sep 17 00:00:00 2001 From: Boaz Harrosh Date: Sun, 17 May 2009 18:58:41 +0300 Subject: libosd: Use of new blk_make_request Use new blk_make_request() to allocate a request from bio and avoid using deprecated blk_rq_append_bio(). This patch is dependent on a block layer patch titled: [BLOCK] New blk_make_request() takes bio returns request This is the last usage of blk_rq_append_bio in osd, it can now be un-exported. Signed-off-by: Boaz Harrosh CC: Jeff Garzik CC: FUJITA Tomonori Signed-off-by: Jens Axboe diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index bf66e30..865ec0f 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c @@ -1200,6 +1200,21 @@ static int _osd_req_finalize_data_integrity(struct osd_request *or, /* * osd_finalize_request and helpers */ +static struct request *_make_request(struct request_queue *q, bool has_write, + struct _osd_io_info *oii, gfp_t flags) +{ + if (oii->bio) + return blk_make_request(q, oii->bio, flags); + else { + struct request *req; + + req = blk_get_request(q, has_write ? WRITE : READ, flags); + if (unlikely(!req)) + return ERR_PTR(-ENOMEM); + + return req; + } +} static int _init_blk_request(struct osd_request *or, bool has_in, bool has_out) @@ -1208,11 +1223,13 @@ static int _init_blk_request(struct osd_request *or, struct scsi_device *scsi_device = or->osd_dev->scsi_device; struct request_queue *q = scsi_device->request_queue; struct request *req; - int ret = -ENOMEM; + int ret; - req = blk_get_request(q, has_out, flags); - if (!req) + req = _make_request(q, has_out, has_out ? &or->out : &or->in, flags); + if (IS_ERR(req)) { + ret = PTR_ERR(req); goto out; + } or->request = req; req->cmd_type = REQ_TYPE_BLOCK_PC; @@ -1225,9 +1242,10 @@ static int _init_blk_request(struct osd_request *or, or->out.req = req; if (has_in) { /* allocate bidi request */ - req = blk_get_request(q, READ, flags); - if (!req) { + req = _make_request(q, false, &or->in, flags); + if (IS_ERR(req)) { OSD_DEBUG("blk_get_request for bidi failed\n"); + ret = PTR_ERR(req); goto out; } req->cmd_type = REQ_TYPE_BLOCK_PC; @@ -1271,26 +1289,6 @@ int osd_finalize_request(struct osd_request *or, return ret; } - if (or->out.bio) { - ret = blk_rq_append_bio(or->request->q, or->out.req, - or->out.bio); - if (ret) { - OSD_DEBUG("blk_rq_append_bio out failed\n"); - return ret; - } - OSD_DEBUG("out bytes=%llu (bytes_req=%u)\n", - _LLU(or->out.total_bytes), blk_rq_bytes(or->out.req)); - } - if (or->in.bio) { - ret = blk_rq_append_bio(or->request->q, or->in.req, or->in.bio); - if (ret) { - OSD_DEBUG("blk_rq_append_bio in failed\n"); - return ret; - } - OSD_DEBUG("in bytes=%llu (bytes_req=%u)\n", - _LLU(or->in.total_bytes), blk_rq_bytes(or->in.req)); - } - or->out.pad_buff = sg_out_pad_buffer; or->in.pad_buff = sg_in_pad_buffer; -- cgit v0.10.2 From a411f4bbb89f1f08687b344064d6775bce1e4658 Mon Sep 17 00:00:00 2001 From: Boaz Harrosh Date: Sun, 17 May 2009 19:00:01 +0300 Subject: block: Un-export blk_rq_append_bio OSD was the last in-tree user of blk_rq_append_bio(). Now that it is fixed blk_rq_append_bio is un-exported and is only used internally by block layer. Signed-off-by: Boaz Harrosh Signed-off-by: Jens Axboe diff --git a/block/blk-map.c b/block/blk-map.c index caa05a6..ef2492a 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -24,7 +24,6 @@ int blk_rq_append_bio(struct request_queue *q, struct request *rq, } return 0; } -EXPORT_SYMBOL(blk_rq_append_bio); static int __blk_rq_unmap_user(struct bio *bio) { diff --git a/block/blk.h b/block/blk.h index 9e0042c..c863ec2 100644 --- a/block/blk.h +++ b/block/blk.h @@ -13,6 +13,8 @@ extern struct kobj_type blk_queue_ktype; void init_request_from_bio(struct request *req, struct bio *bio); void blk_rq_bio_prep(struct request_queue *q, struct request *rq, struct bio *bio); +int blk_rq_append_bio(struct request_queue *q, struct request *rq, + struct bio *bio); void blk_dequeue_request(struct request *rq); void __blk_queue_free_tags(struct request_queue *q); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 88a83e1..564445b 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -758,12 +758,6 @@ extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t, struct scsi_ioctl_command __user *); /* - * Temporary export, until SCSI gets fixed up. - */ -extern int blk_rq_append_bio(struct request_queue *q, struct request *rq, - struct bio *bio); - -/* * A queue has just exitted congestion. Note this in the global counter of * congested queues, and wake up anyone who was waiting for requests to be * put back. -- cgit v0.10.2 From 53674ac5a997a8eedbb2dfdc308b895170746c8b Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 19 May 2009 19:52:35 +0200 Subject: block: add warning to blk_make_request() Add a note about how one needs to be careful when setting up these bio chains. Extracted from Boaz's updated patch. Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index bec1d69..4906507 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -910,6 +910,15 @@ EXPORT_SYMBOL(blk_get_request); * need bouncing, by calling the appropriate masked or flagged allocator, * suitable for the target device. Otherwise the call to blk_queue_bounce will * BUG. + * + * WARNING: When allocating/cloning a bio-chain, careful consideration should be + * given to how you allocate bios. In particular, you cannot use __GFP_WAIT for + * anything but the first bio in the chain. Otherwise you risk waiting for IO + * completion of a bio that hasn't been submitted yet, thus resulting in a + * deadlock. Alternatively bios should be allocated using bio_kmalloc() instead + * of bio_alloc(), as that avoids the mempool deadlock. + * If possible a big IO should be split into smaller parts when allocation + * fails. Partial allocation should not be an error, or you risk a live-lock. */ struct request *blk_make_request(struct request_queue *q, struct bio *bio, gfp_t gfp_mask) -- cgit v0.10.2 From ac36552a52a6ec8563ac0a109e2a0935673f4abb Mon Sep 17 00:00:00 2001 From: Boaz Harrosh Date: Tue, 19 May 2009 19:54:09 +0200 Subject: scsi_lib: remove unused variable The last request completion cleanup in scsi_lib left an unused this_count variable in scsi_io_completion(). (It was used before in a code segment that now uses blk_end_request_all()) Signed-off-by: Boaz Harrosh Acked-by: Tejun Heo Acked-by: FUJITA Tomonori Signed-off-by: Jens Axboe diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index e410d66..d7c6c75 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -706,7 +706,6 @@ EXPORT_SYMBOL(scsi_release_buffers); void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) { int result = cmd->result; - int this_count; struct request_queue *q = cmd->device->request_queue; struct request *req = cmd->request; int error = 0; @@ -789,7 +788,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) */ if (scsi_end_request(cmd, error, good_bytes, result == 0) == NULL) return; - this_count = blk_rq_bytes(req); error = -EIO; -- cgit v0.10.2 From 0a7ae2ff0d29bb3b327edff4c8ab67b3834fa811 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 20 May 2009 08:54:31 +0200 Subject: block: change the tag sync vs async restriction logic Make them fully share the tag space, but disallow async requests using the last any two slots. Signed-off-by: Jens Axboe diff --git a/block/blk-barrier.c b/block/blk-barrier.c index 0ab81a0..0d98054 100644 --- a/block/blk-barrier.c +++ b/block/blk-barrier.c @@ -218,7 +218,7 @@ static inline bool start_ordered(struct request_queue *q, struct request **rqp) } else skip |= QUEUE_ORDSEQ_PREFLUSH; - if ((q->ordered & QUEUE_ORDERED_BY_DRAIN) && q->in_flight) + if ((q->ordered & QUEUE_ORDERED_BY_DRAIN) && queue_in_flight(q)) rq = NULL; else skip |= QUEUE_ORDSEQ_DRAIN; diff --git a/block/blk-core.c b/block/blk-core.c index 4906507..1c74840 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1815,7 +1815,7 @@ void blk_dequeue_request(struct request *rq) * the driver side. */ if (blk_account_rq(rq)) - q->in_flight++; + q->in_flight[rq_is_sync(rq)]++; } /** diff --git a/block/blk-tag.c b/block/blk-tag.c index c260f7c..2e5cfeb 100644 --- a/block/blk-tag.c +++ b/block/blk-tag.c @@ -336,7 +336,7 @@ EXPORT_SYMBOL(blk_queue_end_tag); int blk_queue_start_tag(struct request_queue *q, struct request *rq) { struct blk_queue_tag *bqt = q->queue_tags; - unsigned max_depth, offset; + unsigned max_depth; int tag; if (unlikely((rq->cmd_flags & REQ_QUEUED))) { @@ -355,13 +355,16 @@ int blk_queue_start_tag(struct request_queue *q, struct request *rq) * to starve sync IO on behalf of flooding async IO. */ max_depth = bqt->max_depth; - if (rq_is_sync(rq)) - offset = 0; - else - offset = max_depth >> 2; + if (!rq_is_sync(rq) && max_depth > 1) { + max_depth -= 2; + if (!max_depth) + max_depth = 1; + if (q->in_flight[0] > max_depth) + return 1; + } do { - tag = find_next_zero_bit(bqt->tag_map, max_depth, offset); + tag = find_first_zero_bit(bqt->tag_map, max_depth); if (tag >= max_depth) return 1; diff --git a/block/elevator.c b/block/elevator.c index 9189200..ebee948 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -546,7 +546,7 @@ void elv_requeue_request(struct request_queue *q, struct request *rq) * in_flight count again */ if (blk_account_rq(rq)) { - q->in_flight--; + q->in_flight[rq_is_sync(rq)]--; if (blk_sorted_rq(rq)) elv_deactivate_rq(q, rq); } @@ -685,7 +685,7 @@ void elv_insert(struct request_queue *q, struct request *rq, int where) if (unplug_it && blk_queue_plugged(q)) { int nrq = q->rq.count[BLK_RW_SYNC] + q->rq.count[BLK_RW_ASYNC] - - q->in_flight; + - queue_in_flight(q); if (nrq >= q->unplug_thresh) __generic_unplug_device(q); @@ -823,7 +823,7 @@ void elv_completed_request(struct request_queue *q, struct request *rq) * request is released from the driver, io must be done */ if (blk_account_rq(rq)) { - q->in_flight--; + q->in_flight[rq_is_sync(rq)]--; if (blk_sorted_rq(rq) && e->ops->elevator_completed_req_fn) e->ops->elevator_completed_req_fn(q, rq); } @@ -838,7 +838,7 @@ void elv_completed_request(struct request_queue *q, struct request *rq) if (!list_empty(&q->queue_head)) next = list_entry_rq(q->queue_head.next); - if (!q->in_flight && + if (!queue_in_flight(q) && blk_ordered_cur_seq(q) == QUEUE_ORDSEQ_DRAIN && (!next || blk_ordered_req_seq(next) > QUEUE_ORDSEQ_DRAIN)) { blk_ordered_complete_seq(q, QUEUE_ORDSEQ_DRAIN, 0); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 564445b..a967dd77 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -404,7 +404,7 @@ struct request_queue struct list_head tag_busy_list; unsigned int nr_sorted; - unsigned int in_flight; + unsigned int in_flight[2]; unsigned int rq_timeout; struct timer_list timeout; @@ -511,6 +511,11 @@ static inline void queue_flag_clear_unlocked(unsigned int flag, __clear_bit(flag, &q->queue_flags); } +static inline int queue_in_flight(struct request_queue *q) +{ + return q->in_flight[0] + q->in_flight[1]; +} + static inline void queue_flag_clear(unsigned int flag, struct request_queue *q) { WARN_ON_ONCE(!queue_is_locked(q)); -- cgit v0.10.2 From b9ed7252d219c1c663944bf03846eabb515dbe75 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Fri, 22 May 2009 09:25:32 +0200 Subject: xen-blkfront: beyond ARRAY_SIZE of info->shadow Do not go beyond ARRAY_SIZE of info->shadow Signed-off-by: Roel Kluin Acked-by: Jeremy Fitzhardinge Signed-off-by: Jens Axboe diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 6d4ac76..6d59508 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -122,7 +122,7 @@ static DEFINE_SPINLOCK(blkif_io_lock); static int get_id_from_freelist(struct blkfront_info *info) { unsigned long free = info->shadow_free; - BUG_ON(free > BLK_RING_SIZE); + BUG_ON(free >= BLK_RING_SIZE); info->shadow_free = info->shadow[free].req.id; info->shadow[free].req.id = 0x0fffffee; /* debug */ return free; -- cgit v0.10.2 From e1defc4ff0cf57aca6c5e3ff99fa503f5943c1f1 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Fri, 22 May 2009 17:17:49 -0400 Subject: block: Do away with the notion of hardsect_size Until now we have had a 1:1 mapping between storage device physical block size and the logical block sized used when addressing the device. With SATA 4KB drives coming out that will no longer be the case. The sector size will be 4KB but the logical block size will remain 512-bytes. Hence we need to distinguish between the physical block size and the logical ditto. This patch renames hardsect_size to logical_block_size. Signed-off-by: Martin K. Petersen Signed-off-by: Jens Axboe diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c index 9e105cb..a477991 100644 --- a/arch/powerpc/sysdev/axonram.c +++ b/arch/powerpc/sysdev/axonram.c @@ -250,7 +250,7 @@ axon_ram_probe(struct of_device *device, const struct of_device_id *device_id) set_capacity(bank->disk, bank->size >> AXON_RAM_SECTOR_SHIFT); blk_queue_make_request(bank->disk->queue, axon_ram_make_request); - blk_queue_hardsect_size(bank->disk->queue, AXON_RAM_SECTOR_SIZE); + blk_queue_logical_block_size(bank->disk->queue, AXON_RAM_SECTOR_SIZE); add_disk(bank->disk); bank->irq_id = irq_of_parse_and_map(device->node, 0); diff --git a/block/blk-integrity.c b/block/blk-integrity.c index 91fa8e0..73e28d3 100644 --- a/block/blk-integrity.c +++ b/block/blk-integrity.c @@ -340,7 +340,7 @@ int blk_integrity_register(struct gendisk *disk, struct blk_integrity *template) kobject_uevent(&bi->kobj, KOBJ_ADD); bi->flags |= INTEGRITY_FLAG_READ | INTEGRITY_FLAG_WRITE; - bi->sector_size = disk->queue->hardsect_size; + bi->sector_size = queue_logical_block_size(disk->queue); disk->integrity = bi; } else bi = disk->integrity; diff --git a/block/blk-settings.c b/block/blk-settings.c index 57af728..15c3164 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -134,7 +134,7 @@ void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn) q->backing_dev_info.state = 0; q->backing_dev_info.capabilities = BDI_CAP_MAP_COPY; blk_queue_max_sectors(q, SAFE_MAX_SECTORS); - blk_queue_hardsect_size(q, 512); + blk_queue_logical_block_size(q, 512); blk_queue_dma_alignment(q, 511); blk_queue_congestion_threshold(q); q->nr_batching = BLK_BATCH_REQ; @@ -288,21 +288,20 @@ void blk_queue_max_segment_size(struct request_queue *q, unsigned int max_size) EXPORT_SYMBOL(blk_queue_max_segment_size); /** - * blk_queue_hardsect_size - set hardware sector size for the queue + * blk_queue_logical_block_size - set logical block size for the queue * @q: the request queue for the device - * @size: the hardware sector size, in bytes + * @size: the logical block size, in bytes * * Description: - * This should typically be set to the lowest possible sector size - * that the hardware can operate on (possible without reverting to - * even internal read-modify-write operations). Usually the default - * of 512 covers most hardware. + * This should be set to the lowest possible block size that the + * storage device can address. The default of 512 covers most + * hardware. **/ -void blk_queue_hardsect_size(struct request_queue *q, unsigned short size) +void blk_queue_logical_block_size(struct request_queue *q, unsigned short size) { - q->hardsect_size = size; + q->logical_block_size = size; } -EXPORT_SYMBOL(blk_queue_hardsect_size); +EXPORT_SYMBOL(blk_queue_logical_block_size); /* * Returns the minimum that is _not_ zero, unless both are zero. @@ -324,7 +323,7 @@ void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b) t->max_phys_segments = min_not_zero(t->max_phys_segments, b->max_phys_segments); t->max_hw_segments = min_not_zero(t->max_hw_segments, b->max_hw_segments); t->max_segment_size = min_not_zero(t->max_segment_size, b->max_segment_size); - t->hardsect_size = max(t->hardsect_size, b->hardsect_size); + t->logical_block_size = max(t->logical_block_size, b->logical_block_size); if (!t->queue_lock) WARN_ON_ONCE(1); else if (!test_bit(QUEUE_FLAG_CLUSTER, &b->queue_flags)) { diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 3ff9bba..13d38b7 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -100,9 +100,9 @@ static ssize_t queue_max_sectors_show(struct request_queue *q, char *page) return queue_var_show(max_sectors_kb, (page)); } -static ssize_t queue_hw_sector_size_show(struct request_queue *q, char *page) +static ssize_t queue_logical_block_size_show(struct request_queue *q, char *page) { - return queue_var_show(q->hardsect_size, page); + return queue_var_show(queue_logical_block_size(q), page); } static ssize_t @@ -249,7 +249,12 @@ static struct queue_sysfs_entry queue_iosched_entry = { static struct queue_sysfs_entry queue_hw_sector_size_entry = { .attr = {.name = "hw_sector_size", .mode = S_IRUGO }, - .show = queue_hw_sector_size_show, + .show = queue_logical_block_size_show, +}; + +static struct queue_sysfs_entry queue_logical_block_size_entry = { + .attr = {.name = "logical_block_size", .mode = S_IRUGO }, + .show = queue_logical_block_size_show, }; static struct queue_sysfs_entry queue_nonrot_entry = { @@ -283,6 +288,7 @@ static struct attribute *default_attrs[] = { &queue_max_sectors_entry.attr, &queue_iosched_entry.attr, &queue_hw_sector_size_entry.attr, + &queue_logical_block_size_entry.attr, &queue_nonrot_entry.attr, &queue_nomerges_entry.attr, &queue_rq_affinity_entry.attr, diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c index f87615d..9eaa194 100644 --- a/block/compat_ioctl.c +++ b/block/compat_ioctl.c @@ -763,7 +763,7 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg) case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */ return compat_put_int(arg, block_size(bdev)); case BLKSSZGET: /* get block device hardware sector size */ - return compat_put_int(arg, bdev_hardsect_size(bdev)); + return compat_put_int(arg, bdev_logical_block_size(bdev)); case BLKSECTGET: return compat_put_ushort(arg, bdev_get_queue(bdev)->max_sectors); diff --git a/block/ioctl.c b/block/ioctl.c index ad474d4..7aa97f6 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -311,7 +311,7 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, case BLKBSZGET: /* get the logical block size (cf. BLKSSZGET) */ return put_int(arg, block_size(bdev)); case BLKSSZGET: /* get block device hardware sector size */ - return put_int(arg, bdev_hardsect_size(bdev)); + return put_int(arg, bdev_logical_block_size(bdev)); case BLKSECTGET: return put_ushort(arg, bdev_get_queue(bdev)->max_sectors); case BLKRASET: diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index e714e7c..94474f5 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1389,8 +1389,8 @@ static void cciss_add_disk(ctlr_info_t *h, struct gendisk *disk, disk->queue->queuedata = h; - blk_queue_hardsect_size(disk->queue, - h->drv[drv_index].block_size); + blk_queue_logical_block_size(disk->queue, + h->drv[drv_index].block_size); /* Make sure all queue data is written out before */ /* setting h->drv[drv_index].queue, as setting this */ @@ -2298,7 +2298,7 @@ static int cciss_revalidate(struct gendisk *disk) cciss_geometry_inquiry(h->ctlr, logvol, 1, total_size, block_size, inq_buff, drv); - blk_queue_hardsect_size(drv->queue, drv->block_size); + blk_queue_logical_block_size(drv->queue, drv->block_size); set_capacity(disk, drv->nr_blocks); kfree(inq_buff); diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index a02dcfc..44fa201 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -474,7 +474,7 @@ static int __init cpqarray_register_ctlr( int i, struct pci_dev *pdev) disk->fops = &ida_fops; if (j && !drv->nr_blks) continue; - blk_queue_hardsect_size(hba[i]->queue, drv->blk_size); + blk_queue_logical_block_size(hba[i]->queue, drv->blk_size); set_capacity(disk, drv->nr_blks); disk->queue = hba[i]->queue; disk->private_data = drv; @@ -1546,7 +1546,7 @@ static int revalidate_allvol(ctlr_info_t *host) drv_info_t *drv = &host->drv[i]; if (i && !drv->nr_blks) continue; - blk_queue_hardsect_size(host->queue, drv->blk_size); + blk_queue_logical_block_size(host->queue, drv->blk_size); set_capacity(disk, drv->nr_blks); disk->queue = host->queue; disk->private_data = drv; diff --git a/drivers/block/hd.c b/drivers/block/hd.c index 961de56..f65b3f3 100644 --- a/drivers/block/hd.c +++ b/drivers/block/hd.c @@ -724,7 +724,7 @@ static int __init hd_init(void) blk_queue_max_sectors(hd_queue, 255); init_timer(&device_timer); device_timer.function = hd_times_out; - blk_queue_hardsect_size(hd_queue, 512); + blk_queue_logical_block_size(hd_queue, 512); if (!NR_HD) { /* diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index c0cd0a0..60de5a0 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c @@ -996,7 +996,7 @@ static int mg_probe(struct platform_device *plat_dev) goto probe_err_6; } blk_queue_max_sectors(host->breq, MG_MAX_SECTS); - blk_queue_hardsect_size(host->breq, MG_SECTOR_SIZE); + blk_queue_logical_block_size(host->breq, MG_SECTOR_SIZE); init_timer(&host->timer); host->timer.function = mg_times_out; diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index dc7a8c3..293f585 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -2657,7 +2657,7 @@ static void pkt_init_queue(struct pktcdvd_device *pd) struct request_queue *q = pd->disk->queue; blk_queue_make_request(q, pkt_make_request); - blk_queue_hardsect_size(q, CD_FRAMESIZE); + blk_queue_logical_block_size(q, CD_FRAMESIZE); blk_queue_max_sectors(q, PACKET_MAX_SECTORS); blk_queue_merge_bvec(q, pkt_merge_bvec); q->queuedata = pd; diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index 338cee4..aaeeb54 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -477,7 +477,7 @@ static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev) blk_queue_max_sectors(queue, dev->bounce_size >> 9); blk_queue_segment_boundary(queue, -1UL); blk_queue_dma_alignment(queue, dev->blk_size-1); - blk_queue_hardsect_size(queue, dev->blk_size); + blk_queue_logical_block_size(queue, dev->blk_size); blk_queue_ordered(queue, QUEUE_ORDERED_DRAIN_FLUSH, ps3disk_prepare_flush); diff --git a/drivers/block/ub.c b/drivers/block/ub.c index e67bbae..cc54473 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -722,7 +722,7 @@ static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun, /* * build the command * - * The call to blk_queue_hardsect_size() guarantees that request + * The call to blk_queue_logical_block_size() guarantees that request * is aligned, but it is given in terms of 512 byte units, always. */ block = blk_rq_pos(rq) >> lun->capacity.bshift; @@ -1749,7 +1749,7 @@ static int ub_bd_revalidate(struct gendisk *disk) ub_revalidate(lun->udev, lun); /* XXX Support sector size switching like in sr.c */ - blk_queue_hardsect_size(disk->queue, lun->capacity.bsize); + blk_queue_logical_block_size(disk->queue, lun->capacity.bsize); set_capacity(disk, lun->capacity.nsec); // set_disk_ro(sdkp->disk, lun->readonly); @@ -2324,7 +2324,7 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum) blk_queue_max_phys_segments(q, UB_MAX_REQ_SG); blk_queue_segment_boundary(q, 0xffffffff); /* Dubious. */ blk_queue_max_sectors(q, UB_MAX_SECTORS); - blk_queue_hardsect_size(q, lun->capacity.bsize); + blk_queue_logical_block_size(q, lun->capacity.bsize); lun->disk = disk; q->queuedata = lun; diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 511d4ae..c4845b1 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -347,7 +347,7 @@ static int virtblk_probe(struct virtio_device *vdev) offsetof(struct virtio_blk_config, blk_size), &blk_size); if (!err) - blk_queue_hardsect_size(vblk->disk->queue, blk_size); + blk_queue_logical_block_size(vblk->disk->queue, blk_size); add_disk(vblk->disk); return 0; diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 132120a..c199682 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -344,7 +344,7 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size) queue_flag_set_unlocked(QUEUE_FLAG_VIRT, rq); /* Hard sector size and max sectors impersonate the equiv. hardware. */ - blk_queue_hardsect_size(rq, sector_size); + blk_queue_logical_block_size(rq, sector_size); blk_queue_max_sectors(rq, 512); /* Each segment in a request is up to an aligned page in size. */ diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 3a4397e..f08491a 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -984,7 +984,7 @@ static int __devinit ace_setup(struct ace_device *ace) ace->queue = blk_init_queue(ace_request, &ace->lock); if (ace->queue == NULL) goto err_blk_initq; - blk_queue_hardsect_size(ace->queue, 512); + blk_queue_logical_block_size(ace->queue, 512); /* * Allocate and initialize GD structure diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c index 1e366ad..b5621f2 100644 --- a/drivers/cdrom/gdrom.c +++ b/drivers/cdrom/gdrom.c @@ -739,7 +739,7 @@ static void __devinit probe_gdrom_setupdisk(void) static int __devinit probe_gdrom_setupqueue(void) { - blk_queue_hardsect_size(gd.gdrom_rq, GDROM_HARD_SECTOR); + blk_queue_logical_block_size(gd.gdrom_rq, GDROM_HARD_SECTOR); /* using DMA so memory will need to be contiguous */ blk_queue_max_hw_segments(gd.gdrom_rq, 1); /* set a large max size to get most from DMA */ diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index f177c2d..0fff646 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -469,8 +469,8 @@ static void vio_handle_cd_event(struct HvLpEvent *event) case viocdopen: if (event->xRc == 0) { di = &viocd_diskinfo[bevent->disk]; - blk_queue_hardsect_size(di->viocd_disk->queue, - bevent->block_size); + blk_queue_logical_block_size(di->viocd_disk->queue, + bevent->block_size); set_capacity(di->viocd_disk, bevent->media_size * bevent->block_size / 512); diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 20d90e6..db32f0e 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -71,7 +71,7 @@ static int raw_open(struct inode *inode, struct file *filp) err = bd_claim(bdev, raw_open); if (err) goto out1; - err = set_blocksize(bdev, bdev_hardsect_size(bdev)); + err = set_blocksize(bdev, bdev_logical_block_size(bdev)); if (err) goto out2; filp->f_flags |= O_DIRECT; diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 1799328..424140c 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -182,7 +182,7 @@ static void cdrom_analyze_sense_data(ide_drive_t *drive, (sense->information[2] << 8) | (sense->information[3]); - if (drive->queue->hardsect_size == 2048) + if (queue_logical_block_size(drive->queue) == 2048) /* device sector size is 2K */ sector <<= 2; @@ -737,7 +737,7 @@ static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq) struct request_queue *q = drive->queue; int write = rq_data_dir(rq) == WRITE; unsigned short sectors_per_frame = - queue_hardsect_size(q) >> SECTOR_BITS; + queue_logical_block_size(q) >> SECTOR_BITS; ide_debug_log(IDE_DBG_RQ, "rq->cmd[0]: 0x%x, rq->cmd_flags: 0x%x, " "secs_per_frame: %u", @@ -1021,8 +1021,8 @@ int ide_cd_read_toc(ide_drive_t *drive, struct request_sense *sense) /* save a private copy of the TOC capacity for error handling */ drive->probed_capacity = toc->capacity * sectors_per_frame; - blk_queue_hardsect_size(drive->queue, - sectors_per_frame << SECTOR_BITS); + blk_queue_logical_block_size(drive->queue, + sectors_per_frame << SECTOR_BITS); /* first read just the header, so we know how long the TOC is */ stat = cdrom_read_tocentry(drive, 0, 1, 0, (char *) &toc->hdr, @@ -1338,7 +1338,7 @@ static int ide_cdrom_probe_capabilities(ide_drive_t *drive) /* standard prep_rq_fn that builds 10 byte cmds */ static int ide_cdrom_prep_fs(struct request_queue *q, struct request *rq) { - int hard_sect = queue_hardsect_size(q); + int hard_sect = queue_logical_block_size(q); long block = (long)blk_rq_pos(rq) / (hard_sect >> 9); unsigned long blocks = blk_rq_sectors(rq) / (hard_sect >> 9); @@ -1543,7 +1543,7 @@ static int ide_cdrom_setup(ide_drive_t *drive) nslots = ide_cdrom_probe_capabilities(drive); - blk_queue_hardsect_size(q, CD_FRAMESIZE); + blk_queue_logical_block_size(q, CD_FRAMESIZE); if (ide_cdrom_register(drive, nslots)) { printk(KERN_ERR PFX "%s: %s failed to register device with the" diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 47c68bc..06b0ded 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -232,7 +232,7 @@ static struct page *read_sb_page(mddev_t *mddev, long offset, target = rdev->sb_start + offset + index * (PAGE_SIZE/512); if (sync_page_io(rdev->bdev, target, - roundup(size, bdev_hardsect_size(rdev->bdev)), + roundup(size, bdev_logical_block_size(rdev->bdev)), page, READ)) { page->index = index; attach_page_buffers(page, NULL); /* so that free_buffer will @@ -287,7 +287,7 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait) int size = PAGE_SIZE; if (page->index == bitmap->file_pages-1) size = roundup(bitmap->last_page_size, - bdev_hardsect_size(rdev->bdev)); + bdev_logical_block_size(rdev->bdev)); /* Just make sure we aren't corrupting data or * metadata */ diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c index a2e26c2..75d8081 100644 --- a/drivers/md/dm-exception-store.c +++ b/drivers/md/dm-exception-store.c @@ -178,7 +178,7 @@ static int set_chunk_size(struct dm_exception_store *store, } /* Validate the chunk size against the device block size */ - if (chunk_size_ulong % (bdev_hardsect_size(store->cow->bdev) >> 9)) { + if (chunk_size_ulong % (bdev_logical_block_size(store->cow->bdev) >> 9)) { *error = "Chunk size is not a multiple of device blocksize"; return -EINVAL; } diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c index be233bc..6fa8ccf 100644 --- a/drivers/md/dm-log.c +++ b/drivers/md/dm-log.c @@ -413,7 +413,8 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti, * Buffer holds both header and bitset. */ buf_size = dm_round_up((LOG_OFFSET << SECTOR_SHIFT) + - bitset_size, ti->limits.hardsect_size); + bitset_size, + ti->limits.logical_block_size); if (buf_size > dev->bdev->bd_inode->i_size) { DMWARN("log device %s too small: need %llu bytes", diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c index e75c6dd..2662a41 100644 --- a/drivers/md/dm-snap-persistent.c +++ b/drivers/md/dm-snap-persistent.c @@ -282,7 +282,7 @@ static int read_header(struct pstore *ps, int *new_snapshot) */ if (!ps->store->chunk_size) { ps->store->chunk_size = max(DM_CHUNK_SIZE_DEFAULT_SECTORS, - bdev_hardsect_size(ps->store->cow->bdev) >> 9); + bdev_logical_block_size(ps->store->cow->bdev) >> 9); ps->store->chunk_mask = ps->store->chunk_size - 1; ps->store->chunk_shift = ffs(ps->store->chunk_size) - 1; chunk_size_supplied = 0; diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 429b50b..65e2d97 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -108,7 +108,8 @@ static void combine_restrictions_low(struct io_restrictions *lhs, lhs->max_hw_segments = min_not_zero(lhs->max_hw_segments, rhs->max_hw_segments); - lhs->hardsect_size = max(lhs->hardsect_size, rhs->hardsect_size); + lhs->logical_block_size = max(lhs->logical_block_size, + rhs->logical_block_size); lhs->max_segment_size = min_not_zero(lhs->max_segment_size, rhs->max_segment_size); @@ -529,7 +530,8 @@ void dm_set_device_limits(struct dm_target *ti, struct block_device *bdev) rs->max_hw_segments = min_not_zero(rs->max_hw_segments, q->max_hw_segments); - rs->hardsect_size = max(rs->hardsect_size, q->hardsect_size); + rs->logical_block_size = max(rs->logical_block_size, + queue_logical_block_size(q)); rs->max_segment_size = min_not_zero(rs->max_segment_size, q->max_segment_size); @@ -683,8 +685,8 @@ static void check_for_valid_limits(struct io_restrictions *rs) rs->max_phys_segments = MAX_PHYS_SEGMENTS; if (!rs->max_hw_segments) rs->max_hw_segments = MAX_HW_SEGMENTS; - if (!rs->hardsect_size) - rs->hardsect_size = 1 << SECTOR_SHIFT; + if (!rs->logical_block_size) + rs->logical_block_size = 1 << SECTOR_SHIFT; if (!rs->max_segment_size) rs->max_segment_size = MAX_SEGMENT_SIZE; if (!rs->seg_boundary_mask) @@ -914,7 +916,7 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q) blk_queue_max_sectors(q, t->limits.max_sectors); q->max_phys_segments = t->limits.max_phys_segments; q->max_hw_segments = t->limits.max_hw_segments; - q->hardsect_size = t->limits.hardsect_size; + q->logical_block_size = t->limits.logical_block_size; q->max_segment_size = t->limits.max_segment_size; q->max_hw_sectors = t->limits.max_hw_sectors; q->seg_boundary_mask = t->limits.seg_boundary_mask; diff --git a/drivers/md/md.c b/drivers/md/md.c index fccc834..4cbc19f 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1202,7 +1202,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version) atomic_set(&rdev->corrected_errors, le32_to_cpu(sb->cnt_corrected_read)); rdev->sb_size = le32_to_cpu(sb->max_dev) * 2 + 256; - bmask = queue_hardsect_size(rdev->bdev->bd_disk->queue)-1; + bmask = queue_logical_block_size(rdev->bdev->bd_disk->queue)-1; if (rdev->sb_size & bmask) rdev->sb_size = (rdev->sb_size | bmask) + 1; diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index c0bebc6..7847bbc 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -1242,7 +1242,7 @@ static int mspro_block_init_disk(struct memstick_dev *card) sprintf(msb->disk->disk_name, "mspblk%d", disk_id); - blk_queue_hardsect_size(msb->queue, msb->page_size); + blk_queue_logical_block_size(msb->queue, msb->page_size); capacity = be16_to_cpu(sys_info->user_block_count); capacity *= be16_to_cpu(sys_info->block_size); diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index 6573ef4..335d4c7 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -794,8 +794,9 @@ static int i2o_block_transfer(struct request *req) if (c->adaptec) { u8 cmd[10]; u32 scsi_flags; - u16 hwsec = queue_hardsect_size(req->q) >> KERNEL_SECTOR_SHIFT; + u16 hwsec; + hwsec = queue_logical_block_size(req->q) >> KERNEL_SECTOR_SHIFT; memset(cmd, 0, 10); sgl_offset = SGL_OFFSET_12; @@ -1078,7 +1079,7 @@ static int i2o_block_probe(struct device *dev) */ if (!i2o_parm_field_get(i2o_dev, 0x0004, 1, &blocksize, 4) || !i2o_parm_field_get(i2o_dev, 0x0000, 3, &blocksize, 4)) { - blk_queue_hardsect_size(queue, le32_to_cpu(blocksize)); + blk_queue_logical_block_size(queue, le32_to_cpu(blocksize)); } else osm_warn("unable to get blocksize of %s\n", gd->disk_name); diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index c5df865..98ffc41e 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -521,7 +521,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) sprintf(md->disk->disk_name, "mmcblk%d", devidx); - blk_queue_hardsect_size(md->queue.queue, 512); + blk_queue_logical_block_size(md->queue.queue, 512); if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) { /* diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 502622f..aaac3b6 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -378,7 +378,7 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr) } tr->blkcore_priv->rq->queuedata = tr; - blk_queue_hardsect_size(tr->blkcore_priv->rq, tr->blksize); + blk_queue_logical_block_size(tr->blkcore_priv->rq, tr->blksize); if (tr->discard) blk_queue_set_discard(tr->blkcore_priv->rq, blktrans_discard_request); diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index e64f62d..27a1be0 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1990,7 +1990,7 @@ static void dasd_setup_queue(struct dasd_block *block) { int max; - blk_queue_hardsect_size(block->request_queue, block->bp_block); + blk_queue_logical_block_size(block->request_queue, block->bp_block); max = block->base->discipline->max_blocks << block->s2b_shift; blk_queue_max_sectors(block->request_queue, max); blk_queue_max_phys_segments(block->request_queue, -1L); diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index cfdcf1a..a4c7ffc 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -602,7 +602,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char dev_info->gd->private_data = dev_info; dev_info->gd->driverfs_dev = &dev_info->dev; blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request); - blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096); + blk_queue_logical_block_size(dev_info->dcssblk_queue, 4096); seg_byte_size = (dev_info->end - dev_info->start + 1); set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 76814f3..0ae0c83 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -343,7 +343,7 @@ static int __init xpram_setup_blkdev(void) goto out; } blk_queue_make_request(xpram_queues[i], xpram_make_request); - blk_queue_hardsect_size(xpram_queues[i], 4096); + blk_queue_logical_block_size(xpram_queues[i], 4096); } /* diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index 1e79676..47ff695 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -222,7 +222,7 @@ tapeblock_setup_device(struct tape_device * device) if (rc) goto cleanup_queue; - blk_queue_hardsect_size(blkdat->request_queue, TAPEBLOCK_HSEC_SIZE); + blk_queue_logical_block_size(blkdat->request_queue, TAPEBLOCK_HSEC_SIZE); blk_queue_max_sectors(blkdat->request_queue, TAPEBLOCK_MAX_SEC); blk_queue_max_phys_segments(blkdat->request_queue, -1L); blk_queue_max_hw_segments(blkdat->request_queue, -1L); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 40d2860..bcf3bd4 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1510,7 +1510,7 @@ got_data: */ sector_size = 512; } - blk_queue_hardsect_size(sdp->request_queue, sector_size); + blk_queue_logical_block_size(sdp->request_queue, sector_size); { char cap_str_2[10], cap_str_10[10]; diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index fddba53..cd350df 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -727,7 +727,7 @@ static void get_sectorsize(struct scsi_cd *cd) } queue = cd->device->request_queue; - blk_queue_hardsect_size(queue, sector_size); + blk_queue_logical_block_size(queue, sector_size); return; } diff --git a/fs/bio.c b/fs/bio.c index 81dc93e..4445c38 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -1490,11 +1490,12 @@ struct bio_pair *bio_split(struct bio *bi, int first_sectors) sector_t bio_sector_offset(struct bio *bio, unsigned short index, unsigned int offset) { - unsigned int sector_sz = queue_hardsect_size(bio->bi_bdev->bd_disk->queue); + unsigned int sector_sz; struct bio_vec *bv; sector_t sectors; int i; + sector_sz = queue_logical_block_size(bio->bi_bdev->bd_disk->queue); sectors = 0; if (index >= bio->bi_idx) diff --git a/fs/block_dev.c b/fs/block_dev.c index a85fe31..a29b4dc 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -76,7 +76,7 @@ int set_blocksize(struct block_device *bdev, int size) return -EINVAL; /* Size cannot be smaller than the size supported by the device */ - if (size < bdev_hardsect_size(bdev)) + if (size < bdev_logical_block_size(bdev)) return -EINVAL; /* Don't change the size if it is same as current */ @@ -106,7 +106,7 @@ EXPORT_SYMBOL(sb_set_blocksize); int sb_min_blocksize(struct super_block *sb, int size) { - int minsize = bdev_hardsect_size(sb->s_bdev); + int minsize = bdev_logical_block_size(sb->s_bdev); if (size < minsize) size = minsize; return sb_set_blocksize(sb, size); @@ -1117,7 +1117,7 @@ EXPORT_SYMBOL(check_disk_change); void bd_set_size(struct block_device *bdev, loff_t size) { - unsigned bsize = bdev_hardsect_size(bdev); + unsigned bsize = bdev_logical_block_size(bdev); bdev->bd_inode->i_size = size; while (bsize < PAGE_CACHE_SIZE) { diff --git a/fs/buffer.c b/fs/buffer.c index aed2977..36e2bbc 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1085,12 +1085,12 @@ static struct buffer_head * __getblk_slow(struct block_device *bdev, sector_t block, int size) { /* Size must be multiple of hard sectorsize */ - if (unlikely(size & (bdev_hardsect_size(bdev)-1) || + if (unlikely(size & (bdev_logical_block_size(bdev)-1) || (size < 512 || size > PAGE_SIZE))) { printk(KERN_ERR "getblk(): invalid block size %d requested\n", size); - printk(KERN_ERR "hardsect size: %d\n", - bdev_hardsect_size(bdev)); + printk(KERN_ERR "logical block size: %d\n", + bdev_logical_block_size(bdev)); dump_stack(); return NULL; diff --git a/fs/direct-io.c b/fs/direct-io.c index 05763bb..8b10b87 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -1127,7 +1127,7 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, rw = WRITE_ODIRECT; if (bdev) - bdev_blkbits = blksize_bits(bdev_hardsect_size(bdev)); + bdev_blkbits = blksize_bits(bdev_logical_block_size(bdev)); if (offset & blocksize_mask) { if (bdev) diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 599dbfe..acbb94f 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -1696,7 +1696,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) goto failed_mount; } - hblock = bdev_hardsect_size(sb->s_bdev); + hblock = bdev_logical_block_size(sb->s_bdev); if (sb->s_blocksize != blocksize) { /* * Make sure the blocksize for the filesystem is larger @@ -2119,7 +2119,7 @@ static journal_t *ext3_get_dev_journal(struct super_block *sb, } blocksize = sb->s_blocksize; - hblock = bdev_hardsect_size(bdev); + hblock = bdev_logical_block_size(bdev); if (blocksize < hblock) { printk(KERN_ERR "EXT3-fs: blocksize too small for journal device.\n"); diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 2958f4e..a30549f 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -2962,7 +2962,7 @@ static journal_t *ext4_get_dev_journal(struct super_block *sb, } blocksize = sb->s_blocksize; - hblock = bdev_hardsect_size(bdev); + hblock = bdev_logical_block_size(bdev); if (blocksize < hblock) { printk(KERN_ERR "EXT4-fs: blocksize too small for journal device.\n"); diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 1ff9473..a3b2ac9 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -526,11 +526,11 @@ static int init_sb(struct gfs2_sbd *sdp, int silent) } /* Set up the buffer cache and SB for real */ - if (sdp->sd_sb.sb_bsize < bdev_hardsect_size(sb->s_bdev)) { + if (sdp->sd_sb.sb_bsize < bdev_logical_block_size(sb->s_bdev)) { ret = -EINVAL; fs_err(sdp, "FS block size (%u) is too small for device " "block size (%u)\n", - sdp->sd_sb.sb_bsize, bdev_hardsect_size(sb->s_bdev)); + sdp->sd_sb.sb_bsize, bdev_logical_block_size(sb->s_bdev)); goto out; } if (sdp->sd_sb.sb_bsize > PAGE_SIZE) { diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 5650382..a971d24 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -845,7 +845,7 @@ static void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset, struct super_block *sb = sdp->sd_vfs; struct block_device *bdev = sb->s_bdev; const unsigned int sects_per_blk = sdp->sd_sb.sb_bsize / - bdev_hardsect_size(sb->s_bdev); + bdev_logical_block_size(sb->s_bdev); u64 blk; sector_t start = 0; sector_t nr_sects = 0; diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 7f65b3b..a91f15b 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c @@ -515,7 +515,7 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size); if (sb->s_blocksize != blocksize) { - int hw_blocksize = bdev_hardsect_size(sb->s_bdev); + int hw_blocksize = bdev_logical_block_size(sb->s_bdev); if (blocksize < hw_blocksize) { printk(KERN_ERR diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index f76951d..6aa7c47 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -25,7 +25,7 @@ #include #include #include -#include /* For bdev_hardsect_size(). */ +#include /* For bdev_logical_block_size(). */ #include #include #include @@ -2785,13 +2785,13 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) goto err_out_now; /* We support sector sizes up to the PAGE_CACHE_SIZE. */ - if (bdev_hardsect_size(sb->s_bdev) > PAGE_CACHE_SIZE) { + if (bdev_logical_block_size(sb->s_bdev) > PAGE_CACHE_SIZE) { if (!silent) ntfs_error(sb, "Device has unsupported sector size " "(%i). The maximum supported sector " "size on this architecture is %lu " "bytes.", - bdev_hardsect_size(sb->s_bdev), + bdev_logical_block_size(sb->s_bdev), PAGE_CACHE_SIZE); goto err_out_now; } diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 4f85ece..09cc25d 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -1371,7 +1371,7 @@ static ssize_t o2hb_region_dev_write(struct o2hb_region *reg, bdevname(reg->hr_bdev, reg->hr_dev_name); - sectsize = bdev_hardsect_size(reg->hr_bdev); + sectsize = bdev_logical_block_size(reg->hr_bdev); if (sectsize != reg->hr_block_bytes) { mlog(ML_ERROR, "blocksize %u incorrect for device, expected %d", diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 79ff8d9..5c6163f 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -713,7 +713,7 @@ static int ocfs2_sb_probe(struct super_block *sb, *bh = NULL; /* may be > 512 */ - *sector_size = bdev_hardsect_size(sb->s_bdev); + *sector_size = bdev_logical_block_size(sb->s_bdev); if (*sector_size > OCFS2_MAX_BLOCKSIZE) { mlog(ML_ERROR, "Hardware sector size too large: %d (max=%d)\n", *sector_size, OCFS2_MAX_BLOCKSIZE); diff --git a/fs/partitions/ibm.c b/fs/partitions/ibm.c index 4629768..fc71aab 100644 --- a/fs/partitions/ibm.c +++ b/fs/partitions/ibm.c @@ -76,7 +76,7 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev) Sector sect; res = 0; - blocksize = bdev_hardsect_size(bdev); + blocksize = bdev_logical_block_size(bdev); if (blocksize <= 0) goto out_exit; i_size = i_size_read(bdev->bd_inode); diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c index 7965118..0028d2e 100644 --- a/fs/partitions/msdos.c +++ b/fs/partitions/msdos.c @@ -110,7 +110,7 @@ parse_extended(struct parsed_partitions *state, struct block_device *bdev, Sector sect; unsigned char *data; u32 this_sector, this_size; - int sector_size = bdev_hardsect_size(bdev) / 512; + int sector_size = bdev_logical_block_size(bdev) / 512; int loopct = 0; /* number of links followed without finding a data partition */ int i; @@ -415,7 +415,7 @@ static struct { int msdos_partition(struct parsed_partitions *state, struct block_device *bdev) { - int sector_size = bdev_hardsect_size(bdev) / 512; + int sector_size = bdev_logical_block_size(bdev) / 512; Sector sect; unsigned char *data; struct partition *p; diff --git a/fs/udf/super.c b/fs/udf/super.c index 72348cc..0ba4410 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1915,7 +1915,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) if (uopt.flags & (1 << UDF_FLAG_BLOCKSIZE_SET)) { ret = udf_load_vrs(sb, &uopt, silent, &fileset); } else { - uopt.blocksize = bdev_hardsect_size(sb->s_bdev); + uopt.blocksize = bdev_logical_block_size(sb->s_bdev); ret = udf_load_vrs(sb, &uopt, silent, &fileset); if (!ret && uopt.blocksize != UDF_DEFAULT_BLOCKSIZE) { if (!silent) diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index e28800a..1418b91 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -1501,7 +1501,7 @@ xfs_setsize_buftarg_early( struct block_device *bdev) { return xfs_setsize_buftarg_flags(btp, - PAGE_CACHE_SIZE, bdev_hardsect_size(bdev), 0); + PAGE_CACHE_SIZE, bdev_logical_block_size(bdev), 0); } int diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 56ce53f..872b78b 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -391,7 +391,7 @@ struct request_queue unsigned int max_hw_sectors; unsigned short max_phys_segments; unsigned short max_hw_segments; - unsigned short hardsect_size; + unsigned short logical_block_size; unsigned int max_segment_size; unsigned long seg_boundary_mask; @@ -901,7 +901,7 @@ extern void blk_queue_max_sectors(struct request_queue *, unsigned int); extern void blk_queue_max_phys_segments(struct request_queue *, unsigned short); extern void blk_queue_max_hw_segments(struct request_queue *, unsigned short); extern void blk_queue_max_segment_size(struct request_queue *, unsigned int); -extern void blk_queue_hardsect_size(struct request_queue *, unsigned short); +extern void blk_queue_logical_block_size(struct request_queue *, unsigned short); extern void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b); extern void blk_queue_dma_pad(struct request_queue *, unsigned int); extern void blk_queue_update_dma_pad(struct request_queue *, unsigned int); @@ -988,19 +988,19 @@ extern void blk_set_cmd_filter_defaults(struct blk_cmd_filter *filter); #define blkdev_entry_to_request(entry) list_entry((entry), struct request, queuelist) -static inline int queue_hardsect_size(struct request_queue *q) +static inline unsigned short queue_logical_block_size(struct request_queue *q) { int retval = 512; - if (q && q->hardsect_size) - retval = q->hardsect_size; + if (q && q->logical_block_size) + retval = q->logical_block_size; return retval; } -static inline int bdev_hardsect_size(struct block_device *bdev) +static inline unsigned short bdev_logical_block_size(struct block_device *bdev) { - return queue_hardsect_size(bdev_get_queue(bdev)); + return queue_logical_block_size(bdev_get_queue(bdev)); } static inline int queue_dma_alignment(struct request_queue *q) diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index ded2d7c..49c2362 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h @@ -149,7 +149,7 @@ struct io_restrictions { unsigned max_hw_sectors; unsigned max_sectors; unsigned max_segment_size; - unsigned short hardsect_size; + unsigned short logical_block_size; unsigned short max_hw_segments; unsigned short max_phys_segments; unsigned char no_cluster; /* inverted so that 0 is default */ -- cgit v0.10.2 From ae03bf639a5027d27270123f5f6e3ee6a412781d Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Fri, 22 May 2009 17:17:50 -0400 Subject: block: Use accessor functions for queue limits Convert all external users of queue limits to using wrapper functions instead of poking the request queue variables directly. Signed-off-by: Martin K. Petersen Signed-off-by: Jens Axboe diff --git a/block/blk-barrier.c b/block/blk-barrier.c index 0d98054..30022b4 100644 --- a/block/blk-barrier.c +++ b/block/blk-barrier.c @@ -388,10 +388,10 @@ int blkdev_issue_discard(struct block_device *bdev, bio->bi_sector = sector; - if (nr_sects > q->max_hw_sectors) { - bio->bi_size = q->max_hw_sectors << 9; - nr_sects -= q->max_hw_sectors; - sector += q->max_hw_sectors; + if (nr_sects > queue_max_hw_sectors(q)) { + bio->bi_size = queue_max_hw_sectors(q) << 9; + nr_sects -= queue_max_hw_sectors(q); + sector += queue_max_hw_sectors(q); } else { bio->bi_size = nr_sects << 9; nr_sects = 0; diff --git a/block/blk-core.c b/block/blk-core.c index 59c4af5..7a4c401 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1437,11 +1437,11 @@ static inline void __generic_make_request(struct bio *bio) goto end_io; } - if (unlikely(nr_sectors > q->max_hw_sectors)) { + if (unlikely(nr_sectors > queue_max_hw_sectors(q))) { printk(KERN_ERR "bio too big device %s (%u > %u)\n", - bdevname(bio->bi_bdev, b), - bio_sectors(bio), - q->max_hw_sectors); + bdevname(bio->bi_bdev, b), + bio_sectors(bio), + queue_max_hw_sectors(q)); goto end_io; } @@ -1608,8 +1608,8 @@ EXPORT_SYMBOL(submit_bio); */ int blk_rq_check_limits(struct request_queue *q, struct request *rq) { - if (blk_rq_sectors(rq) > q->max_sectors || - blk_rq_bytes(rq) > q->max_hw_sectors << 9) { + if (blk_rq_sectors(rq) > queue_max_sectors(q) || + blk_rq_bytes(rq) > queue_max_hw_sectors(q) << 9) { printk(KERN_ERR "%s: over max size limit.\n", __func__); return -EIO; } @@ -1621,8 +1621,8 @@ int blk_rq_check_limits(struct request_queue *q, struct request *rq) * limitation. */ blk_recalc_rq_segments(rq); - if (rq->nr_phys_segments > q->max_phys_segments || - rq->nr_phys_segments > q->max_hw_segments) { + if (rq->nr_phys_segments > queue_max_phys_segments(q) || + rq->nr_phys_segments > queue_max_hw_segments(q)) { printk(KERN_ERR "%s: over max segments limit.\n", __func__); return -EIO; } diff --git a/block/blk-map.c b/block/blk-map.c index ef2492a..9083cf0 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -115,7 +115,7 @@ int blk_rq_map_user(struct request_queue *q, struct request *rq, struct bio *bio = NULL; int ret; - if (len > (q->max_hw_sectors << 9)) + if (len > (queue_max_hw_sectors(q) << 9)) return -EINVAL; if (!len) return -EINVAL; @@ -292,7 +292,7 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf, struct bio *bio; int ret; - if (len > (q->max_hw_sectors << 9)) + if (len > (queue_max_hw_sectors(q) << 9)) return -EINVAL; if (!len || !kbuf) return -EINVAL; diff --git a/block/blk-merge.c b/block/blk-merge.c index 4974dd5..39ce644 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -32,11 +32,12 @@ static unsigned int __blk_recalc_rq_segments(struct request_queue *q, * never considered part of another segment, since that * might change with the bounce page. */ - high = page_to_pfn(bv->bv_page) > q->bounce_pfn; + high = page_to_pfn(bv->bv_page) > queue_bounce_pfn(q); if (high || highprv) goto new_segment; if (cluster) { - if (seg_size + bv->bv_len > q->max_segment_size) + if (seg_size + bv->bv_len + > queue_max_segment_size(q)) goto new_segment; if (!BIOVEC_PHYS_MERGEABLE(bvprv, bv)) goto new_segment; @@ -91,7 +92,7 @@ static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio, return 0; if (bio->bi_seg_back_size + nxt->bi_seg_front_size > - q->max_segment_size) + queue_max_segment_size(q)) return 0; if (!bio_has_data(bio)) @@ -134,7 +135,7 @@ int blk_rq_map_sg(struct request_queue *q, struct request *rq, int nbytes = bvec->bv_len; if (bvprv && cluster) { - if (sg->length + nbytes > q->max_segment_size) + if (sg->length + nbytes > queue_max_segment_size(q)) goto new_segment; if (!BIOVEC_PHYS_MERGEABLE(bvprv, bvec)) @@ -205,8 +206,8 @@ static inline int ll_new_hw_segment(struct request_queue *q, { int nr_phys_segs = bio_phys_segments(q, bio); - if (req->nr_phys_segments + nr_phys_segs > q->max_hw_segments - || req->nr_phys_segments + nr_phys_segs > q->max_phys_segments) { + if (req->nr_phys_segments + nr_phys_segs > queue_max_hw_segments(q) || + req->nr_phys_segments + nr_phys_segs > queue_max_phys_segments(q)) { req->cmd_flags |= REQ_NOMERGE; if (req == q->last_merge) q->last_merge = NULL; @@ -227,9 +228,9 @@ int ll_back_merge_fn(struct request_queue *q, struct request *req, unsigned short max_sectors; if (unlikely(blk_pc_request(req))) - max_sectors = q->max_hw_sectors; + max_sectors = queue_max_hw_sectors(q); else - max_sectors = q->max_sectors; + max_sectors = queue_max_sectors(q); if (blk_rq_sectors(req) + bio_sectors(bio) > max_sectors) { req->cmd_flags |= REQ_NOMERGE; @@ -251,9 +252,9 @@ int ll_front_merge_fn(struct request_queue *q, struct request *req, unsigned short max_sectors; if (unlikely(blk_pc_request(req))) - max_sectors = q->max_hw_sectors; + max_sectors = queue_max_hw_sectors(q); else - max_sectors = q->max_sectors; + max_sectors = queue_max_sectors(q); if (blk_rq_sectors(req) + bio_sectors(bio) > max_sectors) { @@ -287,7 +288,7 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req, /* * Will it become too large? */ - if ((blk_rq_sectors(req) + blk_rq_sectors(next)) > q->max_sectors) + if ((blk_rq_sectors(req) + blk_rq_sectors(next)) > queue_max_sectors(q)) return 0; total_phys_segments = req->nr_phys_segments + next->nr_phys_segments; @@ -299,10 +300,10 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req, total_phys_segments--; } - if (total_phys_segments > q->max_phys_segments) + if (total_phys_segments > queue_max_phys_segments(q)) return 0; - if (total_phys_segments > q->max_hw_segments) + if (total_phys_segments > queue_max_hw_segments(q)) return 0; /* Merge is OK... */ diff --git a/block/blk-settings.c b/block/blk-settings.c index 15c3164..0b32f98 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -219,6 +219,15 @@ void blk_queue_max_sectors(struct request_queue *q, unsigned int max_sectors) } EXPORT_SYMBOL(blk_queue_max_sectors); +void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_sectors) +{ + if (BLK_DEF_MAX_SECTORS > max_sectors) + q->max_hw_sectors = BLK_DEF_MAX_SECTORS; + else + q->max_hw_sectors = max_sectors; +} +EXPORT_SYMBOL(blk_queue_max_hw_sectors); + /** * blk_queue_max_phys_segments - set max phys segments for a request for this queue * @q: the request queue for the device @@ -395,11 +404,11 @@ int blk_queue_dma_drain(struct request_queue *q, dma_drain_needed_fn *dma_drain_needed, void *buf, unsigned int size) { - if (q->max_hw_segments < 2 || q->max_phys_segments < 2) + if (queue_max_hw_segments(q) < 2 || queue_max_phys_segments(q) < 2) return -EINVAL; /* make room for appending the drain */ - --q->max_hw_segments; - --q->max_phys_segments; + blk_queue_max_hw_segments(q, queue_max_hw_segments(q) - 1); + blk_queue_max_phys_segments(q, queue_max_phys_segments(q) - 1); q->dma_drain_needed = dma_drain_needed; q->dma_drain_buffer = buf; q->dma_drain_size = size; diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 13d38b7..142a4ac 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -95,7 +95,7 @@ queue_ra_store(struct request_queue *q, const char *page, size_t count) static ssize_t queue_max_sectors_show(struct request_queue *q, char *page) { - int max_sectors_kb = q->max_sectors >> 1; + int max_sectors_kb = queue_max_sectors(q) >> 1; return queue_var_show(max_sectors_kb, (page)); } @@ -109,7 +109,7 @@ static ssize_t queue_max_sectors_store(struct request_queue *q, const char *page, size_t count) { unsigned long max_sectors_kb, - max_hw_sectors_kb = q->max_hw_sectors >> 1, + max_hw_sectors_kb = queue_max_hw_sectors(q) >> 1, page_kb = 1 << (PAGE_CACHE_SHIFT - 10); ssize_t ret = queue_var_store(&max_sectors_kb, page, count); @@ -117,7 +117,7 @@ queue_max_sectors_store(struct request_queue *q, const char *page, size_t count) return -EINVAL; spin_lock_irq(q->queue_lock); - q->max_sectors = max_sectors_kb << 1; + blk_queue_max_sectors(q, max_sectors_kb << 1); spin_unlock_irq(q->queue_lock); return ret; @@ -125,7 +125,7 @@ queue_max_sectors_store(struct request_queue *q, const char *page, size_t count) static ssize_t queue_max_hw_sectors_show(struct request_queue *q, char *page) { - int max_hw_sectors_kb = q->max_hw_sectors >> 1; + int max_hw_sectors_kb = queue_max_hw_sectors(q) >> 1; return queue_var_show(max_hw_sectors_kb, (page)); } diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c index 9eaa194..df18a15 100644 --- a/block/compat_ioctl.c +++ b/block/compat_ioctl.c @@ -766,7 +766,7 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg) return compat_put_int(arg, bdev_logical_block_size(bdev)); case BLKSECTGET: return compat_put_ushort(arg, - bdev_get_queue(bdev)->max_sectors); + queue_max_sectors(bdev_get_queue(bdev))); case BLKRASET: /* compatible, but no compat_ptr (!) */ case BLKFRASET: if (!capable(CAP_SYS_ADMIN)) diff --git a/block/ioctl.c b/block/ioctl.c index 7aa97f6..500e4c7 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -152,10 +152,10 @@ static int blk_ioctl_discard(struct block_device *bdev, uint64_t start, bio->bi_private = &wait; bio->bi_sector = start; - if (len > q->max_hw_sectors) { - bio->bi_size = q->max_hw_sectors << 9; - len -= q->max_hw_sectors; - start += q->max_hw_sectors; + if (len > queue_max_hw_sectors(q)) { + bio->bi_size = queue_max_hw_sectors(q) << 9; + len -= queue_max_hw_sectors(q); + start += queue_max_hw_sectors(q); } else { bio->bi_size = len << 9; len = 0; @@ -313,7 +313,7 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, case BLKSSZGET: /* get block device hardware sector size */ return put_int(arg, bdev_logical_block_size(bdev)); case BLKSECTGET: - return put_ushort(arg, bdev_get_queue(bdev)->max_sectors); + return put_ushort(arg, queue_max_sectors(bdev_get_queue(bdev))); case BLKRASET: case BLKFRASET: if(!capable(CAP_SYS_ADMIN)) diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index a9670dd..5f8e798 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -75,7 +75,7 @@ static int sg_set_timeout(struct request_queue *q, int __user *p) static int sg_get_reserved_size(struct request_queue *q, int __user *p) { - unsigned val = min(q->sg_reserved_size, q->max_sectors << 9); + unsigned val = min(q->sg_reserved_size, queue_max_sectors(q) << 9); return put_user(val, p); } @@ -89,8 +89,8 @@ static int sg_set_reserved_size(struct request_queue *q, int __user *p) if (size < 0) return -EINVAL; - if (size > (q->max_sectors << 9)) - size = q->max_sectors << 9; + if (size > (queue_max_sectors(q) << 9)) + size = queue_max_sectors(q) << 9; q->sg_reserved_size = size; return 0; @@ -264,7 +264,7 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk, if (hdr->cmd_len > BLK_MAX_CDB) return -EINVAL; - if (hdr->dxfer_len > (q->max_hw_sectors << 9)) + if (hdr->dxfer_len > (queue_max_hw_sectors(q) << 9)) return -EIO; if (hdr->dxfer_len) diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 293f585..d57f117 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -991,13 +991,15 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd) */ static int pkt_set_segment_merging(struct pktcdvd_device *pd, struct request_queue *q) { - if ((pd->settings.size << 9) / CD_FRAMESIZE <= q->max_phys_segments) { + if ((pd->settings.size << 9) / CD_FRAMESIZE + <= queue_max_phys_segments(q)) { /* * The cdrom device can handle one segment/frame */ clear_bit(PACKET_MERGE_SEGS, &pd->flags); return 0; - } else if ((pd->settings.size << 9) / PAGE_SIZE <= q->max_phys_segments) { + } else if ((pd->settings.size << 9) / PAGE_SIZE + <= queue_max_phys_segments(q)) { /* * We can handle this case at the expense of some extra memory * copies during write operations diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index cceace6..71d1b9b 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -2101,8 +2101,8 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, nr = nframes; if (cdi->cdda_method == CDDA_BPC_SINGLE) nr = 1; - if (nr * CD_FRAMESIZE_RAW > (q->max_sectors << 9)) - nr = (q->max_sectors << 9) / CD_FRAMESIZE_RAW; + if (nr * CD_FRAMESIZE_RAW > (queue_max_sectors(q) << 9)) + nr = (queue_max_sectors(q) << 9) / CD_FRAMESIZE_RAW; len = nr * CD_FRAMESIZE_RAW; diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 65e2d97..e9a73bb 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -510,7 +510,7 @@ void dm_set_device_limits(struct dm_target *ti, struct block_device *bdev) * combine_restrictions_low() */ rs->max_sectors = - min_not_zero(rs->max_sectors, q->max_sectors); + min_not_zero(rs->max_sectors, queue_max_sectors(q)); /* * Check if merge fn is supported. @@ -525,25 +525,25 @@ void dm_set_device_limits(struct dm_target *ti, struct block_device *bdev) rs->max_phys_segments = min_not_zero(rs->max_phys_segments, - q->max_phys_segments); + queue_max_phys_segments(q)); rs->max_hw_segments = - min_not_zero(rs->max_hw_segments, q->max_hw_segments); + min_not_zero(rs->max_hw_segments, queue_max_hw_segments(q)); rs->logical_block_size = max(rs->logical_block_size, queue_logical_block_size(q)); rs->max_segment_size = - min_not_zero(rs->max_segment_size, q->max_segment_size); + min_not_zero(rs->max_segment_size, queue_max_segment_size(q)); rs->max_hw_sectors = - min_not_zero(rs->max_hw_sectors, q->max_hw_sectors); + min_not_zero(rs->max_hw_sectors, queue_max_hw_sectors(q)); rs->seg_boundary_mask = min_not_zero(rs->seg_boundary_mask, - q->seg_boundary_mask); + queue_segment_boundary(q)); - rs->bounce_pfn = min_not_zero(rs->bounce_pfn, q->bounce_pfn); + rs->bounce_pfn = min_not_zero(rs->bounce_pfn, queue_bounce_pfn(q)); rs->no_cluster |= !test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); } @@ -914,13 +914,13 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q) * restrictions. */ blk_queue_max_sectors(q, t->limits.max_sectors); - q->max_phys_segments = t->limits.max_phys_segments; - q->max_hw_segments = t->limits.max_hw_segments; - q->logical_block_size = t->limits.logical_block_size; - q->max_segment_size = t->limits.max_segment_size; - q->max_hw_sectors = t->limits.max_hw_sectors; - q->seg_boundary_mask = t->limits.seg_boundary_mask; - q->bounce_pfn = t->limits.bounce_pfn; + blk_queue_max_phys_segments(q, t->limits.max_phys_segments); + blk_queue_max_hw_segments(q, t->limits.max_hw_segments); + blk_queue_logical_block_size(q, t->limits.logical_block_size); + blk_queue_max_segment_size(q, t->limits.max_segment_size); + blk_queue_max_hw_sectors(q, t->limits.max_hw_sectors); + blk_queue_segment_boundary(q, t->limits.seg_boundary_mask); + blk_queue_bounce_limit(q, t->limits.bounce_pfn); if (t->limits.no_cluster) queue_flag_clear_unlocked(QUEUE_FLAG_CLUSTER, q); diff --git a/drivers/md/linear.c b/drivers/md/linear.c index 7a36e38..64f1f3e0 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -146,7 +146,7 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks) * a one page request is never in violation. */ if (rdev->bdev->bd_disk->queue->merge_bvec_fn && - mddev->queue->max_sectors > (PAGE_SIZE>>9)) + queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9)) blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); disk->num_sectors = rdev->sectors; diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 41ced0c..4ee31aa 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -303,7 +303,7 @@ static int multipath_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) * merge_bvec_fn will be involved in multipath.) */ if (q->merge_bvec_fn && - mddev->queue->max_sectors > (PAGE_SIZE>>9)) + queue_max_sectors(q) > (PAGE_SIZE>>9)) blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); conf->working_disks++; @@ -467,7 +467,7 @@ static int multipath_run (mddev_t *mddev) * violating it, not that we ever expect a device with * a merge_bvec_fn to be involved in multipath */ if (rdev->bdev->bd_disk->queue->merge_bvec_fn && - mddev->queue->max_sectors > (PAGE_SIZE>>9)) + queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9)) blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); if (!test_bit(Faulty, &rdev->flags)) diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index c08d755..925507e 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -144,7 +144,7 @@ static int create_strip_zones (mddev_t *mddev) */ if (rdev1->bdev->bd_disk->queue->merge_bvec_fn && - mddev->queue->max_sectors > (PAGE_SIZE>>9)) + queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9)) blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); if (!smallest || (rdev1->sectors < smallest->sectors)) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 36df910..e23758b 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1130,7 +1130,7 @@ static int raid1_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) * a one page request is never in violation. */ if (rdev->bdev->bd_disk->queue->merge_bvec_fn && - mddev->queue->max_sectors > (PAGE_SIZE>>9)) + queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9)) blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); p->head_position = 0; @@ -1996,7 +1996,7 @@ static int run(mddev_t *mddev) * a one page request is never in violation. */ if (rdev->bdev->bd_disk->queue->merge_bvec_fn && - mddev->queue->max_sectors > (PAGE_SIZE>>9)) + queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9)) blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); disk->head_position = 0; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 499620a..750550c 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1158,8 +1158,8 @@ static int raid10_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) * a one page request is never in violation. */ if (rdev->bdev->bd_disk->queue->merge_bvec_fn && - mddev->queue->max_sectors > (PAGE_SIZE>>9)) - mddev->queue->max_sectors = (PAGE_SIZE>>9); + queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9)) + blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); p->head_position = 0; rdev->raid_disk = mirror; @@ -2145,8 +2145,8 @@ static int run(mddev_t *mddev) * a one page request is never in violation. */ if (rdev->bdev->bd_disk->queue->merge_bvec_fn && - mddev->queue->max_sectors > (PAGE_SIZE>>9)) - mddev->queue->max_sectors = (PAGE_SIZE>>9); + queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9)) + blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); disk->head_position = 0; } diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 4616bc3..7970dc8 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3463,10 +3463,10 @@ static int bio_fits_rdev(struct bio *bi) { struct request_queue *q = bdev_get_queue(bi->bi_bdev); - if ((bi->bi_size>>9) > q->max_sectors) + if ((bi->bi_size>>9) > queue_max_sectors(q)) return 0; blk_recount_segments(q, bi); - if (bi->bi_phys_segments > q->max_phys_segments) + if (bi->bi_phys_segments > queue_max_phys_segments(q)) return 0; if (q->merge_bvec_fn) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 0fc2c0a..9bd407f 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -289,8 +289,8 @@ sg_open(struct inode *inode, struct file *filp) if (list_empty(&sdp->sfds)) { /* no existing opens on this device */ sdp->sgdebug = 0; q = sdp->device->request_queue; - sdp->sg_tablesize = min(q->max_hw_segments, - q->max_phys_segments); + sdp->sg_tablesize = min(queue_max_hw_segments(q), + queue_max_phys_segments(q)); } if ((sfp = sg_add_sfp(sdp, dev))) filp->private_data = sfp; @@ -909,7 +909,7 @@ sg_ioctl(struct inode *inode, struct file *filp, if (val < 0) return -EINVAL; val = min_t(int, val, - sdp->device->request_queue->max_sectors * 512); + queue_max_sectors(sdp->device->request_queue) * 512); if (val != sfp->reserve.bufflen) { if (sg_res_in_use(sfp) || sfp->mmap_called) return -EBUSY; @@ -919,7 +919,7 @@ sg_ioctl(struct inode *inode, struct file *filp, return 0; case SG_GET_RESERVED_SIZE: val = min_t(int, sfp->reserve.bufflen, - sdp->device->request_queue->max_sectors * 512); + queue_max_sectors(sdp->device->request_queue) * 512); return put_user(val, ip); case SG_SET_COMMAND_Q: result = get_user(val, ip); @@ -1059,7 +1059,7 @@ sg_ioctl(struct inode *inode, struct file *filp, return -ENODEV; return scsi_ioctl(sdp->device, cmd_in, p); case BLKSECTGET: - return put_user(sdp->device->request_queue->max_sectors * 512, + return put_user(queue_max_sectors(sdp->device->request_queue) * 512, ip); case BLKTRACESETUP: return blk_trace_setup(sdp->device->request_queue, @@ -1377,7 +1377,8 @@ static Sg_device *sg_alloc(struct gendisk *disk, struct scsi_device *scsidp) sdp->device = scsidp; INIT_LIST_HEAD(&sdp->sfds); init_waitqueue_head(&sdp->o_excl_wait); - sdp->sg_tablesize = min(q->max_hw_segments, q->max_phys_segments); + sdp->sg_tablesize = min(queue_max_hw_segments(q), + queue_max_phys_segments(q)); sdp->index = k; kref_init(&sdp->d_ref); @@ -2055,7 +2056,7 @@ sg_add_sfp(Sg_device * sdp, int dev) sg_big_buff = def_reserved_size; bufflen = min_t(int, sg_big_buff, - sdp->device->request_queue->max_sectors * 512); + queue_max_sectors(sdp->device->request_queue) * 512); sg_build_reserve(sfp, bufflen); SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: bufflen=%d, k_use_sg=%d\n", sfp->reserve.bufflen, sfp->reserve.k_use_sg)); diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 8681b7083..89bd438 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -3983,8 +3983,8 @@ static int st_probe(struct device *dev) return -ENODEV; } - i = min(SDp->request_queue->max_hw_segments, - SDp->request_queue->max_phys_segments); + i = min(queue_max_hw_segments(SDp->request_queue), + queue_max_phys_segments(SDp->request_queue)); if (st_max_sg_segs < i) i = st_max_sg_segs; buffer = new_tape_buffer((SDp->host)->unchecked_isa_dma, i); diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 4ca3b58..cfa26d5 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -132,7 +132,7 @@ static int slave_configure(struct scsi_device *sdev) if (us->fflags & US_FL_MAX_SECTORS_MIN) max_sectors = PAGE_CACHE_SIZE >> 9; - if (sdev->request_queue->max_sectors > max_sectors) + if (queue_max_sectors(sdev->request_queue) > max_sectors) blk_queue_max_sectors(sdev->request_queue, max_sectors); } else if (sdev->type == TYPE_TAPE) { @@ -483,7 +483,7 @@ static ssize_t show_max_sectors(struct device *dev, struct device_attribute *att { struct scsi_device *sdev = to_scsi_device(dev); - return sprintf(buf, "%u\n", sdev->request_queue->max_sectors); + return sprintf(buf, "%u\n", queue_max_sectors(sdev->request_queue)); } /* Input routine for the sysfs max_sectors file */ diff --git a/fs/bio.c b/fs/bio.c index 4445c38..ab423a1 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -499,11 +499,11 @@ int bio_get_nr_vecs(struct block_device *bdev) struct request_queue *q = bdev_get_queue(bdev); int nr_pages; - nr_pages = ((q->max_sectors << 9) + PAGE_SIZE - 1) >> PAGE_SHIFT; - if (nr_pages > q->max_phys_segments) - nr_pages = q->max_phys_segments; - if (nr_pages > q->max_hw_segments) - nr_pages = q->max_hw_segments; + nr_pages = ((queue_max_sectors(q) << 9) + PAGE_SIZE - 1) >> PAGE_SHIFT; + if (nr_pages > queue_max_phys_segments(q)) + nr_pages = queue_max_phys_segments(q); + if (nr_pages > queue_max_hw_segments(q)) + nr_pages = queue_max_hw_segments(q); return nr_pages; } @@ -562,8 +562,8 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page * make this too complex. */ - while (bio->bi_phys_segments >= q->max_phys_segments - || bio->bi_phys_segments >= q->max_hw_segments) { + while (bio->bi_phys_segments >= queue_max_phys_segments(q) + || bio->bi_phys_segments >= queue_max_hw_segments(q)) { if (retried_segments) return 0; @@ -634,7 +634,8 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page int bio_add_pc_page(struct request_queue *q, struct bio *bio, struct page *page, unsigned int len, unsigned int offset) { - return __bio_add_page(q, bio, page, len, offset, q->max_hw_sectors); + return __bio_add_page(q, bio, page, len, offset, + queue_max_hw_sectors(q)); } /** @@ -654,7 +655,7 @@ int bio_add_page(struct bio *bio, struct page *page, unsigned int len, unsigned int offset) { struct request_queue *q = bdev_get_queue(bio->bi_bdev); - return __bio_add_page(q, bio, page, len, offset, q->max_sectors); + return __bio_add_page(q, bio, page, len, offset, queue_max_sectors(q)); } struct bio_map_data { diff --git a/include/linux/bio.h b/include/linux/bio.h index d30ec6f..12737be 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -279,7 +279,7 @@ static inline int bio_has_allocated_vec(struct bio *bio) #define __BIO_SEG_BOUNDARY(addr1, addr2, mask) \ (((addr1) | (mask)) == (((addr2) - 1) | (mask))) #define BIOVEC_SEG_BOUNDARY(q, b1, b2) \ - __BIO_SEG_BOUNDARY(bvec_to_phys((b1)), bvec_to_phys((b2)) + (b2)->bv_len, (q)->seg_boundary_mask) + __BIO_SEG_BOUNDARY(bvec_to_phys((b1)), bvec_to_phys((b2)) + (b2)->bv_len, queue_segment_boundary((q))) #define BIO_SEG_BOUNDARY(q, b1, b2) \ BIOVEC_SEG_BOUNDARY((q), __BVEC_END((b1)), __BVEC_START((b2))) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 872b78b..29b48f7 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -898,6 +898,7 @@ extern void blk_cleanup_queue(struct request_queue *); extern void blk_queue_make_request(struct request_queue *, make_request_fn *); extern void blk_queue_bounce_limit(struct request_queue *, u64); extern void blk_queue_max_sectors(struct request_queue *, unsigned int); +extern void blk_queue_max_hw_sectors(struct request_queue *, unsigned int); extern void blk_queue_max_phys_segments(struct request_queue *, unsigned short); extern void blk_queue_max_hw_segments(struct request_queue *, unsigned short); extern void blk_queue_max_segment_size(struct request_queue *, unsigned int); @@ -988,6 +989,41 @@ extern void blk_set_cmd_filter_defaults(struct blk_cmd_filter *filter); #define blkdev_entry_to_request(entry) list_entry((entry), struct request, queuelist) +static inline unsigned long queue_bounce_pfn(struct request_queue *q) +{ + return q->bounce_pfn; +} + +static inline unsigned long queue_segment_boundary(struct request_queue *q) +{ + return q->seg_boundary_mask; +} + +static inline unsigned int queue_max_sectors(struct request_queue *q) +{ + return q->max_sectors; +} + +static inline unsigned int queue_max_hw_sectors(struct request_queue *q) +{ + return q->max_hw_sectors; +} + +static inline unsigned short queue_max_hw_segments(struct request_queue *q) +{ + return q->max_hw_segments; +} + +static inline unsigned short queue_max_phys_segments(struct request_queue *q) +{ + return q->max_phys_segments; +} + +static inline unsigned int queue_max_segment_size(struct request_queue *q) +{ + return q->max_segment_size; +} + static inline unsigned short queue_logical_block_size(struct request_queue *q) { int retval = 512; diff --git a/mm/bounce.c b/mm/bounce.c index e590272..8dcd431 100644 --- a/mm/bounce.c +++ b/mm/bounce.c @@ -192,7 +192,7 @@ static void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig, /* * is destination page below bounce pfn? */ - if (page_to_pfn(page) <= q->bounce_pfn) + if (page_to_pfn(page) <= queue_bounce_pfn(q)) continue; /* @@ -284,7 +284,7 @@ void blk_queue_bounce(struct request_queue *q, struct bio **bio_orig) * don't waste time iterating over bio segments */ if (!(q->bounce_gfp & GFP_DMA)) { - if (q->bounce_pfn >= blk_max_pfn) + if (queue_bounce_pfn(q) >= blk_max_pfn) return; pool = page_pool; } else { -- cgit v0.10.2 From 025146e13b63483add912706c101fb0fb6f015cc Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Fri, 22 May 2009 17:17:51 -0400 Subject: block: Move queue limits to an embedded struct To accommodate stacking drivers that do not have an associated request queue we're moving the limits to a separate, embedded structure. Signed-off-by: Martin K. Petersen Signed-off-by: Jens Axboe diff --git a/block/blk-settings.c b/block/blk-settings.c index 0b32f98..b0f547c 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -179,16 +179,16 @@ void blk_queue_bounce_limit(struct request_queue *q, u64 dma_mask) */ if (b_pfn < (min_t(u64, 0xffffffffUL, BLK_BOUNCE_HIGH) >> PAGE_SHIFT)) dma = 1; - q->bounce_pfn = max_low_pfn; + q->limits.bounce_pfn = max_low_pfn; #else if (b_pfn < blk_max_low_pfn) dma = 1; - q->bounce_pfn = b_pfn; + q->limits.bounce_pfn = b_pfn; #endif if (dma) { init_emergency_isa_pool(); q->bounce_gfp = GFP_NOIO | GFP_DMA; - q->bounce_pfn = b_pfn; + q->limits.bounce_pfn = b_pfn; } } EXPORT_SYMBOL(blk_queue_bounce_limit); @@ -211,10 +211,10 @@ void blk_queue_max_sectors(struct request_queue *q, unsigned int max_sectors) } if (BLK_DEF_MAX_SECTORS > max_sectors) - q->max_hw_sectors = q->max_sectors = max_sectors; + q->limits.max_hw_sectors = q->limits.max_sectors = max_sectors; else { - q->max_sectors = BLK_DEF_MAX_SECTORS; - q->max_hw_sectors = max_sectors; + q->limits.max_sectors = BLK_DEF_MAX_SECTORS; + q->limits.max_hw_sectors = max_sectors; } } EXPORT_SYMBOL(blk_queue_max_sectors); @@ -222,9 +222,9 @@ EXPORT_SYMBOL(blk_queue_max_sectors); void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_sectors) { if (BLK_DEF_MAX_SECTORS > max_sectors) - q->max_hw_sectors = BLK_DEF_MAX_SECTORS; + q->limits.max_hw_sectors = BLK_DEF_MAX_SECTORS; else - q->max_hw_sectors = max_sectors; + q->limits.max_hw_sectors = max_sectors; } EXPORT_SYMBOL(blk_queue_max_hw_sectors); @@ -247,7 +247,7 @@ void blk_queue_max_phys_segments(struct request_queue *q, __func__, max_segments); } - q->max_phys_segments = max_segments; + q->limits.max_phys_segments = max_segments; } EXPORT_SYMBOL(blk_queue_max_phys_segments); @@ -271,7 +271,7 @@ void blk_queue_max_hw_segments(struct request_queue *q, __func__, max_segments); } - q->max_hw_segments = max_segments; + q->limits.max_hw_segments = max_segments; } EXPORT_SYMBOL(blk_queue_max_hw_segments); @@ -292,7 +292,7 @@ void blk_queue_max_segment_size(struct request_queue *q, unsigned int max_size) __func__, max_size); } - q->max_segment_size = max_size; + q->limits.max_segment_size = max_size; } EXPORT_SYMBOL(blk_queue_max_segment_size); @@ -308,7 +308,7 @@ EXPORT_SYMBOL(blk_queue_max_segment_size); **/ void blk_queue_logical_block_size(struct request_queue *q, unsigned short size) { - q->logical_block_size = size; + q->limits.logical_block_size = size; } EXPORT_SYMBOL(blk_queue_logical_block_size); @@ -325,14 +325,27 @@ EXPORT_SYMBOL(blk_queue_logical_block_size); void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b) { /* zero is "infinity" */ - t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors); - t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors); - t->seg_boundary_mask = min_not_zero(t->seg_boundary_mask, b->seg_boundary_mask); - - t->max_phys_segments = min_not_zero(t->max_phys_segments, b->max_phys_segments); - t->max_hw_segments = min_not_zero(t->max_hw_segments, b->max_hw_segments); - t->max_segment_size = min_not_zero(t->max_segment_size, b->max_segment_size); - t->logical_block_size = max(t->logical_block_size, b->logical_block_size); + t->limits.max_sectors = min_not_zero(queue_max_sectors(t), + queue_max_sectors(b)); + + t->limits.max_hw_sectors = min_not_zero(queue_max_hw_sectors(t), + queue_max_hw_sectors(b)); + + t->limits.seg_boundary_mask = min_not_zero(queue_segment_boundary(t), + queue_segment_boundary(b)); + + t->limits.max_phys_segments = min_not_zero(queue_max_phys_segments(t), + queue_max_phys_segments(b)); + + t->limits.max_hw_segments = min_not_zero(queue_max_hw_segments(t), + queue_max_hw_segments(b)); + + t->limits.max_segment_size = min_not_zero(queue_max_segment_size(t), + queue_max_segment_size(b)); + + t->limits.logical_block_size = max(queue_logical_block_size(t), + queue_logical_block_size(b)); + if (!t->queue_lock) WARN_ON_ONCE(1); else if (!test_bit(QUEUE_FLAG_CLUSTER, &b->queue_flags)) { @@ -430,7 +443,7 @@ void blk_queue_segment_boundary(struct request_queue *q, unsigned long mask) __func__, mask); } - q->seg_boundary_mask = mask; + q->limits.seg_boundary_mask = mask; } EXPORT_SYMBOL(blk_queue_segment_boundary); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 29b48f7..b7bb6fd 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -307,6 +307,21 @@ struct blk_cmd_filter { struct kobject kobj; }; +struct queue_limits { + unsigned long bounce_pfn; + unsigned long seg_boundary_mask; + + unsigned int max_hw_sectors; + unsigned int max_sectors; + unsigned int max_segment_size; + + unsigned short logical_block_size; + unsigned short max_hw_segments; + unsigned short max_phys_segments; + + unsigned char no_cluster; +}; + struct request_queue { /* @@ -358,7 +373,6 @@ struct request_queue /* * queue needs bounce pages for pages above this limit */ - unsigned long bounce_pfn; gfp_t bounce_gfp; /* @@ -387,14 +401,6 @@ struct request_queue unsigned int nr_congestion_off; unsigned int nr_batching; - unsigned int max_sectors; - unsigned int max_hw_sectors; - unsigned short max_phys_segments; - unsigned short max_hw_segments; - unsigned short logical_block_size; - unsigned int max_segment_size; - - unsigned long seg_boundary_mask; void *dma_drain_buffer; unsigned int dma_drain_size; unsigned int dma_pad_mask; @@ -410,6 +416,8 @@ struct request_queue struct timer_list timeout; struct list_head timeout_list; + struct queue_limits limits; + /* * sg stuff */ @@ -991,45 +999,45 @@ extern void blk_set_cmd_filter_defaults(struct blk_cmd_filter *filter); static inline unsigned long queue_bounce_pfn(struct request_queue *q) { - return q->bounce_pfn; + return q->limits.bounce_pfn; } static inline unsigned long queue_segment_boundary(struct request_queue *q) { - return q->seg_boundary_mask; + return q->limits.seg_boundary_mask; } static inline unsigned int queue_max_sectors(struct request_queue *q) { - return q->max_sectors; + return q->limits.max_sectors; } static inline unsigned int queue_max_hw_sectors(struct request_queue *q) { - return q->max_hw_sectors; + return q->limits.max_hw_sectors; } static inline unsigned short queue_max_hw_segments(struct request_queue *q) { - return q->max_hw_segments; + return q->limits.max_hw_segments; } static inline unsigned short queue_max_phys_segments(struct request_queue *q) { - return q->max_phys_segments; + return q->limits.max_phys_segments; } static inline unsigned int queue_max_segment_size(struct request_queue *q) { - return q->max_segment_size; + return q->limits.max_segment_size; } static inline unsigned short queue_logical_block_size(struct request_queue *q) { int retval = 512; - if (q && q->logical_block_size) - retval = q->logical_block_size; + if (q && q->limits.logical_block_size) + retval = q->limits.logical_block_size; return retval; } -- cgit v0.10.2 From cd43e26f071524647e660706b784ebcbefbd2e44 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Fri, 22 May 2009 17:17:52 -0400 Subject: block: Expose stacked device queues in sysfs Currently stacking devices do not have a queue directory in sysfs. However, many of the I/O characteristics like sector size, maximum request size, etc. are queue properties. This patch enables the queue directory for MD/DM devices. The elevator code has been modified to deal with queues that do not have an I/O scheduler. Signed-off-by: Martin K. Petersen Signed-off-by: Jens Axboe diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 142a4ac..3ccdadb 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -395,9 +395,6 @@ int blk_register_queue(struct gendisk *disk) if (WARN_ON(!q)) return -ENXIO; - if (!q->request_fn) - return 0; - ret = kobject_add(&q->kobj, kobject_get(&disk_to_dev(disk)->kobj), "%s", "queue"); if (ret < 0) @@ -405,6 +402,9 @@ int blk_register_queue(struct gendisk *disk) kobject_uevent(&q->kobj, KOBJ_ADD); + if (!q->request_fn) + return 0; + ret = elv_register_queue(q); if (ret) { kobject_uevent(&q->kobj, KOBJ_REMOVE); diff --git a/block/elevator.c b/block/elevator.c index ebee948..bd78f69 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -575,6 +575,9 @@ void elv_drain_elevator(struct request_queue *q) */ void elv_quiesce_start(struct request_queue *q) { + if (!q->elevator) + return; + queue_flag_set(QUEUE_FLAG_ELVSWITCH, q); /* @@ -1050,6 +1053,9 @@ ssize_t elv_iosched_store(struct request_queue *q, const char *name, char elevator_name[ELV_NAME_MAX]; struct elevator_type *e; + if (!q->elevator) + return count; + strlcpy(elevator_name, name, sizeof(elevator_name)); strstrip(elevator_name); @@ -1073,10 +1079,15 @@ ssize_t elv_iosched_store(struct request_queue *q, const char *name, ssize_t elv_iosched_show(struct request_queue *q, char *name) { struct elevator_queue *e = q->elevator; - struct elevator_type *elv = e->elevator_type; + struct elevator_type *elv; struct elevator_type *__e; int len = 0; + if (!q->elevator) + return sprintf(name, "none\n"); + + elv = e->elevator_type; + spin_lock(&elv_list_lock); list_for_each_entry(__e, &elv_list, list) { if (!strcmp(elv->elevator_name, __e->elevator_name)) -- cgit v0.10.2 From c72758f33784e5e2a1a4bb9421ef3e6de8f9fcf3 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Fri, 22 May 2009 17:17:53 -0400 Subject: block: Export I/O topology for block devices and partitions To support devices with physical block sizes bigger than 512 bytes we need to ensure proper alignment. This patch adds support for exposing I/O topology characteristics as devices are stacked. logical_block_size is the smallest unit the device can address. physical_block_size indicates the smallest I/O the device can write without incurring a read-modify-write penalty. The io_min parameter is the smallest preferred I/O size reported by the device. In many cases this is the same as the physical block size. However, the io_min parameter can be scaled up when stacking (RAID5 chunk size > physical block size). The io_opt characteristic indicates the optimal I/O size reported by the device. This is usually the stripe width for arrays. The alignment_offset parameter indicates the number of bytes the start of the device/partition is offset from the device's natural alignment. Partition tools and MD/DM utilities can use this to pad their offsets so filesystems start on proper boundaries. Signed-off-by: Martin K. Petersen Signed-off-by: Jens Axboe diff --git a/Documentation/ABI/testing/sysfs-block b/Documentation/ABI/testing/sysfs-block index 44f52a4..cbbd3e0 100644 --- a/Documentation/ABI/testing/sysfs-block +++ b/Documentation/ABI/testing/sysfs-block @@ -60,3 +60,62 @@ Description: Indicates whether the block layer should automatically generate checksums for write requests bound for devices that support receiving integrity metadata. + +What: /sys/block//alignment_offset +Date: April 2009 +Contact: Martin K. Petersen +Description: + Storage devices may report a physical block size that is + bigger than the logical block size (for instance a drive + with 4KB physical sectors exposing 512-byte logical + blocks to the operating system). This parameter + indicates how many bytes the beginning of the device is + offset from the disk's natural alignment. + +What: /sys/block///alignment_offset +Date: April 2009 +Contact: Martin K. Petersen +Description: + Storage devices may report a physical block size that is + bigger than the logical block size (for instance a drive + with 4KB physical sectors exposing 512-byte logical + blocks to the operating system). This parameter + indicates how many bytes the beginning of the partition + is offset from the disk's natural alignment. + +What: /sys/block//queue/logical_block_size +Date: May 2009 +Contact: Martin K. Petersen +Description: + This is the smallest unit the storage device can + address. It is typically 512 bytes. + +What: /sys/block//queue/physical_block_size +Date: May 2009 +Contact: Martin K. Petersen +Description: + This is the smallest unit the storage device can write + without resorting to read-modify-write operation. It is + usually the same as the logical block size but may be + bigger. One example is SATA drives with 4KB sectors + that expose a 512-byte logical block size to the + operating system. + +What: /sys/block//queue/minimum_io_size +Date: April 2009 +Contact: Martin K. Petersen +Description: + Storage devices may report a preferred minimum I/O size, + which is the smallest request the device can perform + without incurring a read-modify-write penalty. For disk + drives this is often the physical block size. For RAID + arrays it is often the stripe chunk size. + +What: /sys/block//queue/optimal_io_size +Date: April 2009 +Contact: Martin K. Petersen +Description: + Storage devices may report an optimal I/O size, which is + the device's preferred unit of receiving I/O. This is + rarely reported for disk drives. For RAID devices it is + usually the stripe width or the internal block size. diff --git a/block/blk-settings.c b/block/blk-settings.c index b0f547c..5649f34 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -309,9 +309,94 @@ EXPORT_SYMBOL(blk_queue_max_segment_size); void blk_queue_logical_block_size(struct request_queue *q, unsigned short size) { q->limits.logical_block_size = size; + + if (q->limits.physical_block_size < size) + q->limits.physical_block_size = size; + + if (q->limits.io_min < q->limits.physical_block_size) + q->limits.io_min = q->limits.physical_block_size; } EXPORT_SYMBOL(blk_queue_logical_block_size); +/** + * blk_queue_physical_block_size - set physical block size for the queue + * @q: the request queue for the device + * @size: the physical block size, in bytes + * + * Description: + * This should be set to the lowest possible sector size that the + * hardware can operate on without reverting to read-modify-write + * operations. + */ +void blk_queue_physical_block_size(struct request_queue *q, unsigned short size) +{ + q->limits.physical_block_size = size; + + if (q->limits.physical_block_size < q->limits.logical_block_size) + q->limits.physical_block_size = q->limits.logical_block_size; + + if (q->limits.io_min < q->limits.physical_block_size) + q->limits.io_min = q->limits.physical_block_size; +} +EXPORT_SYMBOL(blk_queue_physical_block_size); + +/** + * blk_queue_alignment_offset - set physical block alignment offset + * @q: the request queue for the device + * @alignment: alignment offset in bytes + * + * Description: + * Some devices are naturally misaligned to compensate for things like + * the legacy DOS partition table 63-sector offset. Low-level drivers + * should call this function for devices whose first sector is not + * naturally aligned. + */ +void blk_queue_alignment_offset(struct request_queue *q, unsigned int offset) +{ + q->limits.alignment_offset = + offset & (q->limits.physical_block_size - 1); + q->limits.misaligned = 0; +} +EXPORT_SYMBOL(blk_queue_alignment_offset); + +/** + * blk_queue_io_min - set minimum request size for the queue + * @q: the request queue for the device + * @io_min: smallest I/O size in bytes + * + * Description: + * Some devices have an internal block size bigger than the reported + * hardware sector size. This function can be used to signal the + * smallest I/O the device can perform without incurring a performance + * penalty. + */ +void blk_queue_io_min(struct request_queue *q, unsigned int min) +{ + q->limits.io_min = min; + + if (q->limits.io_min < q->limits.logical_block_size) + q->limits.io_min = q->limits.logical_block_size; + + if (q->limits.io_min < q->limits.physical_block_size) + q->limits.io_min = q->limits.physical_block_size; +} +EXPORT_SYMBOL(blk_queue_io_min); + +/** + * blk_queue_io_opt - set optimal request size for the queue + * @q: the request queue for the device + * @io_opt: optimal request size in bytes + * + * Description: + * Drivers can call this function to set the preferred I/O request + * size for devices that report such a value. + */ +void blk_queue_io_opt(struct request_queue *q, unsigned int opt) +{ + q->limits.io_opt = opt; +} +EXPORT_SYMBOL(blk_queue_io_opt); + /* * Returns the minimum that is _not_ zero, unless both are zero. */ @@ -358,6 +443,107 @@ void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b) EXPORT_SYMBOL(blk_queue_stack_limits); /** + * blk_stack_limits - adjust queue_limits for stacked devices + * @t: the stacking driver limits (top) + * @bdev: the underlying queue limits (bottom) + * @offset: offset to beginning of data within component device + * + * Description: + * Merges two queue_limit structs. Returns 0 if alignment didn't + * change. Returns -1 if adding the bottom device caused + * misalignment. + */ +int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, + sector_t offset) +{ + t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors); + t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors); + + t->seg_boundary_mask = min_not_zero(t->seg_boundary_mask, + b->seg_boundary_mask); + + t->max_phys_segments = min_not_zero(t->max_phys_segments, + b->max_phys_segments); + + t->max_hw_segments = min_not_zero(t->max_hw_segments, + b->max_hw_segments); + + t->max_segment_size = min_not_zero(t->max_segment_size, + b->max_segment_size); + + t->logical_block_size = max(t->logical_block_size, + b->logical_block_size); + + t->physical_block_size = max(t->physical_block_size, + b->physical_block_size); + + t->io_min = max(t->io_min, b->io_min); + t->no_cluster |= b->no_cluster; + + /* Bottom device offset aligned? */ + if (offset && + (offset & (b->physical_block_size - 1)) != b->alignment_offset) { + t->misaligned = 1; + return -1; + } + + /* If top has no alignment offset, inherit from bottom */ + if (!t->alignment_offset) + t->alignment_offset = + b->alignment_offset & (b->physical_block_size - 1); + + /* Top device aligned on logical block boundary? */ + if (t->alignment_offset & (t->logical_block_size - 1)) { + t->misaligned = 1; + return -1; + } + + return 0; +} + +/** + * disk_stack_limits - adjust queue limits for stacked drivers + * @t: MD/DM gendisk (top) + * @bdev: the underlying block device (bottom) + * @offset: offset to beginning of data within component device + * + * Description: + * Merges the limits for two queues. Returns 0 if alignment + * didn't change. Returns -1 if adding the bottom device caused + * misalignment. + */ +void disk_stack_limits(struct gendisk *disk, struct block_device *bdev, + sector_t offset) +{ + struct request_queue *t = disk->queue; + struct request_queue *b = bdev_get_queue(bdev); + + offset += get_start_sect(bdev) << 9; + + if (blk_stack_limits(&t->limits, &b->limits, offset) < 0) { + char top[BDEVNAME_SIZE], bottom[BDEVNAME_SIZE]; + + disk_name(disk, 0, top); + bdevname(bdev, bottom); + + printk(KERN_NOTICE "%s: Warning: Device %s is misaligned\n", + top, bottom); + } + + if (!t->queue_lock) + WARN_ON_ONCE(1); + else if (!test_bit(QUEUE_FLAG_CLUSTER, &b->queue_flags)) { + unsigned long flags; + + spin_lock_irqsave(t->queue_lock, flags); + if (!test_bit(QUEUE_FLAG_CLUSTER, &b->queue_flags)) + queue_flag_clear(QUEUE_FLAG_CLUSTER, t); + spin_unlock_irqrestore(t->queue_lock, flags); + } +} +EXPORT_SYMBOL(disk_stack_limits); + +/** * blk_queue_dma_pad - set pad mask * @q: the request queue for the device * @mask: pad mask diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 3ccdadb..9337e17 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -105,6 +105,21 @@ static ssize_t queue_logical_block_size_show(struct request_queue *q, char *page return queue_var_show(queue_logical_block_size(q), page); } +static ssize_t queue_physical_block_size_show(struct request_queue *q, char *page) +{ + return queue_var_show(queue_physical_block_size(q), page); +} + +static ssize_t queue_io_min_show(struct request_queue *q, char *page) +{ + return queue_var_show(queue_io_min(q), page); +} + +static ssize_t queue_io_opt_show(struct request_queue *q, char *page) +{ + return queue_var_show(queue_io_opt(q), page); +} + static ssize_t queue_max_sectors_store(struct request_queue *q, const char *page, size_t count) { @@ -257,6 +272,21 @@ static struct queue_sysfs_entry queue_logical_block_size_entry = { .show = queue_logical_block_size_show, }; +static struct queue_sysfs_entry queue_physical_block_size_entry = { + .attr = {.name = "physical_block_size", .mode = S_IRUGO }, + .show = queue_physical_block_size_show, +}; + +static struct queue_sysfs_entry queue_io_min_entry = { + .attr = {.name = "minimum_io_size", .mode = S_IRUGO }, + .show = queue_io_min_show, +}; + +static struct queue_sysfs_entry queue_io_opt_entry = { + .attr = {.name = "optimal_io_size", .mode = S_IRUGO }, + .show = queue_io_opt_show, +}; + static struct queue_sysfs_entry queue_nonrot_entry = { .attr = {.name = "rotational", .mode = S_IRUGO | S_IWUSR }, .show = queue_nonrot_show, @@ -289,6 +319,9 @@ static struct attribute *default_attrs[] = { &queue_iosched_entry.attr, &queue_hw_sector_size_entry.attr, &queue_logical_block_size_entry.attr, + &queue_physical_block_size_entry.attr, + &queue_io_min_entry.attr, + &queue_io_opt_entry.attr, &queue_nonrot_entry.attr, &queue_nomerges_entry.attr, &queue_rq_affinity_entry.attr, diff --git a/block/genhd.c b/block/genhd.c index 1a4916e..fe7ccc0 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -852,11 +852,21 @@ static ssize_t disk_capability_show(struct device *dev, return sprintf(buf, "%x\n", disk->flags); } +static ssize_t disk_alignment_offset_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct gendisk *disk = dev_to_disk(dev); + + return sprintf(buf, "%d\n", queue_alignment_offset(disk->queue)); +} + static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL); static DEVICE_ATTR(ext_range, S_IRUGO, disk_ext_range_show, NULL); static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL); static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL); static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL); +static DEVICE_ATTR(alignment_offset, S_IRUGO, disk_alignment_offset_show, NULL); static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL); static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL); #ifdef CONFIG_FAIL_MAKE_REQUEST @@ -875,6 +885,7 @@ static struct attribute *disk_attrs[] = { &dev_attr_removable.attr, &dev_attr_ro.attr, &dev_attr_size.attr, + &dev_attr_alignment_offset.attr, &dev_attr_capability.attr, &dev_attr_stat.attr, #ifdef CONFIG_FAIL_MAKE_REQUEST diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 99e33ef..0af3608 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -219,6 +219,13 @@ ssize_t part_size_show(struct device *dev, return sprintf(buf, "%llu\n",(unsigned long long)p->nr_sects); } +ssize_t part_alignment_offset_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct hd_struct *p = dev_to_part(dev); + return sprintf(buf, "%llu\n", (unsigned long long)p->alignment_offset); +} + ssize_t part_stat_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -272,6 +279,7 @@ ssize_t part_fail_store(struct device *dev, static DEVICE_ATTR(partition, S_IRUGO, part_partition_show, NULL); static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL); static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL); +static DEVICE_ATTR(alignment_offset, S_IRUGO, part_alignment_offset_show, NULL); static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL); #ifdef CONFIG_FAIL_MAKE_REQUEST static struct device_attribute dev_attr_fail = @@ -282,6 +290,7 @@ static struct attribute *part_attrs[] = { &dev_attr_partition.attr, &dev_attr_start.attr, &dev_attr_size.attr, + &dev_attr_alignment_offset.attr, &dev_attr_stat.attr, #ifdef CONFIG_FAIL_MAKE_REQUEST &dev_attr_fail.attr, @@ -383,6 +392,7 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno, pdev = part_to_dev(p); p->start_sect = start; + p->alignment_offset = queue_sector_alignment_offset(disk->queue, start); p->nr_sects = len; p->partno = partno; p->policy = get_disk_ro(disk); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index b7bb6fd..5e740a1 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -314,11 +314,16 @@ struct queue_limits { unsigned int max_hw_sectors; unsigned int max_sectors; unsigned int max_segment_size; + unsigned int physical_block_size; + unsigned int alignment_offset; + unsigned int io_min; + unsigned int io_opt; unsigned short logical_block_size; unsigned short max_hw_segments; unsigned short max_phys_segments; + unsigned char misaligned; unsigned char no_cluster; }; @@ -911,6 +916,15 @@ extern void blk_queue_max_phys_segments(struct request_queue *, unsigned short); extern void blk_queue_max_hw_segments(struct request_queue *, unsigned short); extern void blk_queue_max_segment_size(struct request_queue *, unsigned int); extern void blk_queue_logical_block_size(struct request_queue *, unsigned short); +extern void blk_queue_physical_block_size(struct request_queue *, unsigned short); +extern void blk_queue_alignment_offset(struct request_queue *q, + unsigned int alignment); +extern void blk_queue_io_min(struct request_queue *q, unsigned int min); +extern void blk_queue_io_opt(struct request_queue *q, unsigned int opt); +extern int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, + sector_t offset); +extern void disk_stack_limits(struct gendisk *disk, struct block_device *bdev, + sector_t offset); extern void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b); extern void blk_queue_dma_pad(struct request_queue *, unsigned int); extern void blk_queue_update_dma_pad(struct request_queue *, unsigned int); @@ -1047,6 +1061,39 @@ static inline unsigned short bdev_logical_block_size(struct block_device *bdev) return queue_logical_block_size(bdev_get_queue(bdev)); } +static inline unsigned int queue_physical_block_size(struct request_queue *q) +{ + return q->limits.physical_block_size; +} + +static inline unsigned int queue_io_min(struct request_queue *q) +{ + return q->limits.io_min; +} + +static inline unsigned int queue_io_opt(struct request_queue *q) +{ + return q->limits.io_opt; +} + +static inline int queue_alignment_offset(struct request_queue *q) +{ + if (q && q->limits.misaligned) + return -1; + + if (q && q->limits.alignment_offset) + return q->limits.alignment_offset; + + return 0; +} + +static inline int queue_sector_alignment_offset(struct request_queue *q, + sector_t sector) +{ + return ((sector << 9) - q->limits.alignment_offset) + & (q->limits.io_min - 1); +} + static inline int queue_dma_alignment(struct request_queue *q) { return q ? q->dma_alignment : 511; diff --git a/include/linux/genhd.h b/include/linux/genhd.h index a1a28ca..149fda2 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -90,6 +90,7 @@ struct disk_stats { struct hd_struct { sector_t start_sect; sector_t nr_sects; + sector_t alignment_offset; struct device __dev; struct kobject *holder_dir; int policy, partno; -- cgit v0.10.2 From 3b77f777b8f1c001b63e317c4ce317292ff0ff94 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Sat, 23 May 2009 08:23:16 +0200 Subject: ide-disk: fix missing max_sectors accessor function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The recent move to accessor functions for querying queue limits missed an entry in ide-disk.c: drivers/ide/ide-disk.c: In function ‘ide_disk_setup’: drivers/ide/ide-disk.c:642: error: ‘struct request_queue’ has no member named ‘max_sectors’ Fix it. Signed-off-by: Martin K. Petersen Signed-off-by: Jens Axboe diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index ad18e14..c6f7fcf 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -639,7 +639,7 @@ static void ide_disk_setup(ide_drive_t *drive) } printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name, - q->max_sectors / 2); + queue_max_sectors(q) / 2); if (ata_id_is_ssd(id)) queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q); -- cgit v0.10.2 From ba396a6c104682dfe5c8b4fbbf5974d5ac9f3687 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Wed, 27 May 2009 14:17:08 +0200 Subject: block: fix oops with block tag queueing commit e8939a50466fd963eb1ba9118c34b9ffb7ff6aa6 Author: Tejun Heo Date: Fri May 8 11:54:16 2009 +0900 block: implement and enforce request peek/start/fetch Added a BUG_ON(blk_queued_rq(req)) to the top of blk_finish_req(). Unfortunately, this checks whether req->queuelist is empty. This list is doing double duty both as the queue list and the tag list, so tagged requests come in here with this not empty and boom (the tag list is emptied by blk_queue_end_tag() lower down). Fix this by moving the BUG_ON to below the end tag we also seem vulnerable to this in blk_requeue_request() as well. I think all uses of blk_queued_rq() need auditing because the check is clearly wrong in the tagged case. Signed-off-by: James Bottomley Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index 7a4c401..8b3b74e 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -956,8 +956,6 @@ EXPORT_SYMBOL(blk_make_request); */ void blk_requeue_request(struct request_queue *q, struct request *rq) { - BUG_ON(blk_queued_rq(rq)); - blk_delete_timer(rq); blk_clear_rq_complete(rq); trace_block_rq_requeue(q, rq); @@ -965,6 +963,8 @@ void blk_requeue_request(struct request_queue *q, struct request *rq) if (blk_rq_tagged(rq)) blk_queue_end_tag(q, rq); + BUG_ON(blk_queued_rq(rq)); + elv_requeue_request(q, rq); } EXPORT_SYMBOL(blk_requeue_request); @@ -2042,11 +2042,11 @@ static bool blk_update_bidi_request(struct request *rq, int error, */ static void blk_finish_request(struct request *req, int error) { - BUG_ON(blk_queued_rq(req)); - if (blk_rq_tagged(req)) blk_queue_end_tag(req->q, req); + BUG_ON(blk_queued_rq(req)); + if (unlikely(laptop_mode) && blk_fs_request(req)) laptop_io_completion(); -- cgit v0.10.2 From 3c4198e874cde694f5ea1463706873e7907bdb18 Mon Sep 17 00:00:00 2001 From: Kiyoshi Ueda Date: Wed, 27 May 2009 14:50:02 +0200 Subject: block: fix no diskstat problem The commit below in 2.6-block/for-2.6.31 causes no diskstat problem because the blk_discard_rq() check was added with '&&'. It should be 'blk_fs_request() || blk_discard_rq()'. This patch does it and fixes the no diskstat problem. Please review and apply. ------ /proc/diskstat without this patch ------------------------------------- 8 0 sda 0 0 0 0 0 0 0 0 0 0 0 ------------------------------------------------------------------------------ ----- /proc/diskstat with this patch applied --------------------------------- 8 0 sda 4186 303 373621 61600 9578 3859 107468 169479 2 89755 231059 ------------------------------------------------------------------------------ -------------------------------------------------------------------------- commit c69d48540c201394d08cb4d48b905e001313d9b8 Author: Jens Axboe Date: Fri Apr 24 08:12:19 2009 +0200 block: include discard requests in IO accounting We currently don't do merging on discard requests, but we potentially could. If we do, then we need to include discard requests in the IO accounting, or merging would end up decrementing in_flight IO counters for an IO which never incremented them. So enable accounting for discard requests. static inline int blk_do_io_stat(struct request *rq) { - return rq->rq_disk && blk_rq_io_stat(rq) && blk_fs_request(rq); + return rq->rq_disk && blk_rq_io_stat(rq) && blk_fs_request(rq) && + blk_discard_rq(rq); } -------------------------------------------------------------------------- Signed-off-by: Kiyoshi Ueda Signed-off-by: Jun'ichi Nomura Signed-off-by: Jens Axboe diff --git a/block/blk.h b/block/blk.h index c863ec2..3fae6ad 100644 --- a/block/blk.h +++ b/block/blk.h @@ -156,12 +156,12 @@ static inline int blk_cpu_to_group(int cpu) * * a) it's attached to a gendisk, and * b) the queue had IO stats enabled when this request was started, and - * c) it's a file system request + * c) it's a file system request or a discard request */ static inline int blk_do_io_stat(struct request *rq) { - return rq->rq_disk && blk_rq_io_stat(rq) && blk_fs_request(rq) && - blk_discard_rq(rq); + return rq->rq_disk && blk_rq_io_stat(rq) && + (blk_fs_request(rq) || blk_discard_rq(rq)); } #endif -- cgit v0.10.2 From 5d85d3247cc3555215d7d11c78576a396c98e4d9 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Thu, 28 May 2009 11:04:53 +0200 Subject: block: export blk_stack_limits() DM needs to use blk_stack_limits(), so it needs to be exported. Acked-by: Martin K. Petersen Signed-off-by: Jens Axboe diff --git a/block/blk-settings.c b/block/blk-settings.c index 5649f34..8d33934 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -500,6 +500,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, return 0; } +EXPORT_SYMBOL(blk_stack_limits); /** * disk_stack_limits - adjust queue limits for stacked drivers -- cgit v0.10.2 From c143dc903d7c0b15f5052e00b2c7de33a8b4299c Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sat, 30 May 2009 06:43:49 +0200 Subject: block: fix an oops on BLKPREP_KILL Doing a bit of torture testing, I ran across a BUG in the block subsystem (at blk-core.c:2048): the test for if the request is queued. It turns out the trigger was a BLKPREP_KILL coming out of the SCSI prep function. Currently for BLKPREP_KILL requests, we send them straight into __blk_end_request_all() with an error, but they've never been dequeued, so they trip the bug. Fix this by starting requests before killing them. Signed-off-by: James Bottomley Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index 8b3b74e..7ae83a1 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1789,6 +1789,11 @@ struct request *blk_peek_request(struct request_queue *q) break; } else if (ret == BLKPREP_KILL) { rq->cmd_flags |= REQ_QUIET; + /* + * Mark this request as started so we don't trigger + * any debug logic in the end I/O path. + */ + blk_start_request(rq); __blk_end_request_all(rq, -EIO); } else { printk(KERN_ERR "%s: bad return=%d\n", __func__, ret); -- cgit v0.10.2 From 53c663ce0f39ba8e8ef652e400b317bc60ac7f19 Mon Sep 17 00:00:00 2001 From: Kiyoshi Ueda Date: Tue, 2 Jun 2009 08:44:01 +0200 Subject: block: fix a possible oops on elv_abort_queue() I found one more mis-conversion to the 'request is always dequeued when completing' model in elv_abort_queue() during code inspection. Although I haven't hit any problem caused by this mis-conversion yet and just done compile/boot test, please apply if you have no problem. Request must be dequeued when it completes. However, elv_abort_queue() completes requests without dequeueing. This will cause oops in the __blk_end_request_all(). This patch fixes the oops. Signed-off-by: Kiyoshi Ueda Signed-off-by: Jun'ichi Nomura Signed-off-by: Jens Axboe diff --git a/block/elevator.c b/block/elevator.c index bd78f69..a029cfe 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -813,6 +813,11 @@ void elv_abort_queue(struct request_queue *q) rq = list_entry_rq(q->queue_head.next); rq->cmd_flags |= REQ_QUIET; trace_block_rq_abort(q, rq); + /* + * Mark this request as started so we don't trigger + * any debug logic in the end I/O path. + */ + blk_start_request(rq); __blk_end_request_all(rq, -EIO); } } -- cgit v0.10.2 From 4a4b2d7684c66dbd8ed04eb284bc94a78e061d29 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 2 Jun 2009 14:47:50 +0200 Subject: cciss: factor out core of sendcmd() for a more sane interface Factor out the core of sendcmd() to provide a simpler interface which exposes all the error information to the caller and make the original sendcmd use this new function. Rationale: The SCSI error handling routines need to send commands with interrupts turned off, but they also need access to the full error information. Signed-off-by: Stephen M. Cameron Cc: Mike Miller Signed-off-by: Jens Axboe diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 94474f5..8d0f893 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -2373,41 +2373,21 @@ static int add_sendcmd_reject(__u8 cmd, int ctlr, unsigned long complete) return 0; } -/* - * Send a command to the controller, and wait for it to complete. - * Only used at init time. +/* Send command c to controller h and poll for it to complete. + * Turns interrupts off on the board. Used at driver init time + * and during SCSI error recovery. */ -static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use_unit_num, /* 0: address the controller, - 1: address logical volume log_unit, - 2: periph device address is scsi3addr */ - unsigned int log_unit, - __u8 page_code, unsigned char *scsi3addr, int cmd_type) +static int sendcmd_core(ctlr_info_t *h, CommandList_struct *c) { - CommandList_struct *c; int i; unsigned long complete; - ctlr_info_t *info_p = hba[ctlr]; + int status = IO_ERROR; u64bit buff_dma_handle; - int status, done = 0; - if ((c = cmd_alloc(info_p, 1)) == NULL) { - printk(KERN_WARNING "cciss: unable to get memory"); - return IO_ERROR; - } - status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num, - log_unit, page_code, scsi3addr, cmd_type); - if (status != IO_OK) { - cmd_free(info_p, c, 1); - return status; - } - resend_cmd1: - /* - * Disable interrupt - */ -#ifdef CCISS_DEBUG - printk(KERN_DEBUG "cciss: turning intr off\n"); -#endif /* CCISS_DEBUG */ - info_p->access.set_intr_mask(info_p, CCISS_INTR_OFF); +resend_cmd1: + + /* Disable interrupt on the board. */ + h->access.set_intr_mask(h, CCISS_INTR_OFF); /* Make sure there is room in the command FIFO */ /* Actually it should be completely empty at this time */ @@ -2415,21 +2395,15 @@ static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use /* tape side of the driver. */ for (i = 200000; i > 0; i--) { /* if fifo isn't full go */ - if (!(info_p->access.fifo_full(info_p))) { - + if (!(h->access.fifo_full(h))) break; - } udelay(10); printk(KERN_WARNING "cciss cciss%d: SendCmd FIFO full," - " waiting!\n", ctlr); + " waiting!\n", h->ctlr); } - /* - * Send the cmd - */ - info_p->access.submit_command(info_p, c); - done = 0; + h->access.submit_command(h, c); /* Send the cmd */ do { - complete = pollcomplete(ctlr); + complete = pollcomplete(h->ctlr); #ifdef CCISS_DEBUG printk(KERN_DEBUG "cciss: command completed\n"); @@ -2438,97 +2412,116 @@ static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use if (complete == 1) { printk(KERN_WARNING "cciss cciss%d: SendCmd Timeout out, " - "No command list address returned!\n", ctlr); + "No command list address returned!\n", h->ctlr); status = IO_ERROR; - done = 1; break; } - /* This will need to change for direct lookup completions */ - if ((complete & CISS_ERROR_BIT) - && (complete & ~CISS_ERROR_BIT) == c->busaddr) { - /* if data overrun or underun on Report command - ignore it - */ - if (((c->Request.CDB[0] == CISS_REPORT_LOG) || - (c->Request.CDB[0] == CISS_REPORT_PHYS) || - (c->Request.CDB[0] == CISS_INQUIRY)) && - ((c->err_info->CommandStatus == - CMD_DATA_OVERRUN) || - (c->err_info->CommandStatus == CMD_DATA_UNDERRUN) - )) { - complete = c->busaddr; - } else { - if (c->err_info->CommandStatus == - CMD_UNSOLICITED_ABORT) { - printk(KERN_WARNING "cciss%d: " - "unsolicited abort %p\n", - ctlr, c); - if (c->retry_count < MAX_CMD_RETRIES) { - printk(KERN_WARNING - "cciss%d: retrying %p\n", - ctlr, c); - c->retry_count++; - /* erase the old error */ - /* information */ - memset(c->err_info, 0, - sizeof - (ErrorInfo_struct)); - goto resend_cmd1; - } else { - printk(KERN_WARNING - "cciss%d: retried %p too " - "many times\n", ctlr, c); - status = IO_ERROR; - goto cleanup1; - } - } else if (c->err_info->CommandStatus == - CMD_UNABORTABLE) { - printk(KERN_WARNING - "cciss%d: command could not be aborted.\n", - ctlr); - status = IO_ERROR; - goto cleanup1; - } - printk(KERN_WARNING "ciss ciss%d: sendcmd" - " Error %x \n", ctlr, - c->err_info->CommandStatus); - printk(KERN_WARNING "ciss ciss%d: sendcmd" - " offensive info\n" - " size %x\n num %x value %x\n", - ctlr, - c->err_info->MoreErrInfo.Invalid_Cmd. - offense_size, - c->err_info->MoreErrInfo.Invalid_Cmd. - offense_num, - c->err_info->MoreErrInfo.Invalid_Cmd. - offense_value); - status = IO_ERROR; - goto cleanup1; - } + /* If it's not the cmd we're looking for, save it for later */ + if ((complete & ~CISS_ERROR_BIT) != c->busaddr) { + if (add_sendcmd_reject(c->Request.CDB[0], + h->ctlr, complete) != 0) + BUG(); /* we are hosed if we get here. */ + continue; + } + + /* It is our command. If no error, we're done. */ + if (!(complete & CISS_ERROR_BIT)) { + status = IO_OK; + break; + } + + /* There is an error... */ + + /* if data overrun or underun on Report command ignore it */ + if (((c->Request.CDB[0] == CISS_REPORT_LOG) || + (c->Request.CDB[0] == CISS_REPORT_PHYS) || + (c->Request.CDB[0] == CISS_INQUIRY)) && + ((c->err_info->CommandStatus == CMD_DATA_OVERRUN) || + (c->err_info->CommandStatus == CMD_DATA_UNDERRUN))) { + complete = c->busaddr; + status = IO_OK; + break; } - /* This will need changing for direct lookup completions */ - if (complete != c->busaddr) { - if (add_sendcmd_reject(cmd, ctlr, complete) != 0) { - BUG(); /* we are pretty much hosed if we get here. */ + + if (c->err_info->CommandStatus == CMD_UNSOLICITED_ABORT) { + printk(KERN_WARNING "cciss%d: unsolicited abort %p\n", + h->ctlr, c); + if (c->retry_count < MAX_CMD_RETRIES) { + printk(KERN_WARNING "cciss%d: retrying %p\n", + h->ctlr, c); + c->retry_count++; + /* erase the old error information */ + memset(c->err_info, 0, sizeof(c->err_info)); + goto resend_cmd1; } - continue; - } else - done = 1; - } while (!done); + printk(KERN_WARNING "cciss%d: retried %p too many " + "times\n", h->ctlr, c); + status = IO_ERROR; + goto cleanup1; + } + + if (c->err_info->CommandStatus == CMD_UNABORTABLE) { + printk(KERN_WARNING "cciss%d: command could not be " + "aborted.\n", h->ctlr); + status = IO_ERROR; + goto cleanup1; + } + + printk(KERN_WARNING "cciss%d: sendcmd error\n", h->ctlr); + printk(KERN_WARNING "cmd = 0x%02x, CommandStatus = 0x%02x\n", + c->Request.CDB[0], c->err_info->CommandStatus); + if (c->err_info->CommandStatus == CMD_TARGET_STATUS) { + printk(KERN_WARNING "Target status = 0x%02x\n", + c->err_info->ScsiStatus); + if (c->err_info->ScsiStatus == 2) /* chk cond */ + printk(KERN_WARNING "Sense key = 0x%02x\n", + 0xf & c->err_info->SenseInfo[2]); + } + + status = IO_ERROR; + goto cleanup1; + + } while (1); - cleanup1: +cleanup1: /* unlock the data buffer from DMA */ buff_dma_handle.val32.lower = c->SG[0].Addr.lower; buff_dma_handle.val32.upper = c->SG[0].Addr.upper; - pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val, + pci_unmap_single(h->pdev, (dma_addr_t) buff_dma_handle.val, c->SG[0].Len, PCI_DMA_BIDIRECTIONAL); #ifdef CONFIG_CISS_SCSI_TAPE /* if we saved some commands for later, process them now. */ - if (info_p->scsi_rejects.ncompletions > 0) - do_cciss_intr(0, info_p); + if (h->scsi_rejects.ncompletions > 0) + do_cciss_intr(0, h); #endif - cmd_free(info_p, c, 1); + return status; +} + +/* + * Send a command to the controller, and wait for it to complete. + * Used at init time, and during SCSI error recovery. + */ +static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, + unsigned int use_unit_num,/* 0: address the controller, + 1: address logical volume log_unit, + 2: periph device address is scsi3addr */ + unsigned int log_unit, + __u8 page_code, unsigned char *scsi3addr, int cmd_type) +{ + CommandList_struct *c; + int status; + + c = cmd_alloc(hba[ctlr], 1); + if (!c) { + printk(KERN_WARNING "cciss: unable to get memory"); + return IO_ERROR; + } + status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num, + log_unit, page_code, scsi3addr, cmd_type); + if (status == IO_OK) + status = sendcmd_core(hba[ctlr], c); + cmd_free(hba[ctlr], c, 1); return status; } -- cgit v0.10.2 From 88f627ae394eadd75ada669904269f1a4a77b3bd Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 2 Jun 2009 14:48:11 +0200 Subject: cciss: fix SCSI device reset handler Fix the SCSI reset error handler to send a working, properly addressed reset message to the target device and add code to wait for the target device to become ready by polling it with Test Unit Ready. The existing reset code was broken in that it didn't bother to set the 8-byte LUN address to anything besides zero, so the command was addressed to the controller, which pretended to the driver that the command succeeded, while doing nothing. Ages ago I tested this code, but unbeknownst to me, my test was flawed, and what I thought was a tape drive getting reset was actually nothing of the sort. Unfortunately, there is still lots of Smartarray firmware that doesn't handle doing target resets right, and this code won't help in those cases, but it also shouldn't make things worse in those cases than they already are. Signed-off-by: Stephen M. Cameron Cc: Mike Miller Signed-off-by: Jens Axboe diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 8d0f893..cb43fb3 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1974,6 +1974,13 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_ c->Request.CDB[0] = BMIC_WRITE; c->Request.CDB[6] = BMIC_CACHE_FLUSH; break; + case TEST_UNIT_READY: + memcpy(c->Header. LUN.LunAddrBytes, scsi3addr, 8); + c->Request.CDBLen = 6; + c->Request.Type.Attribute = ATTR_SIMPLE; + c->Request.Type.Direction = XFER_NONE; + c->Request.Timeout = 0; + break; default: printk(KERN_WARNING "cciss%d: Unknown Command 0x%c\n", ctlr, cmd); @@ -1992,13 +1999,14 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_ memcpy(&c->Request.CDB[4], buff, 8); break; case 1: /* RESET message */ - c->Request.CDBLen = 12; + memcpy(c->Header.LUN.LunAddrBytes, scsi3addr, 8); + c->Request.CDBLen = 16; c->Request.Type.Attribute = ATTR_SIMPLE; - c->Request.Type.Direction = XFER_WRITE; + c->Request.Type.Direction = XFER_NONE; c->Request.Timeout = 0; memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB)); c->Request.CDB[0] = cmd; /* reset */ - c->Request.CDB[1] = 0x04; /* reset a LUN */ + c->Request.CDB[1] = 0x03; /* reset a target */ break; case 3: /* No-Op message */ c->Request.CDBLen = 1; diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index a3fd87b..8575c48 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -58,6 +58,18 @@ static int sendcmd( unsigned char *scsi3addr, int cmd_type); +static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, + size_t size, + unsigned int use_unit_num, /* 0: address the controller, + 1: address logical volume log_unit, + 2: periph device address is scsi3addr */ + unsigned int log_unit, __u8 page_code, unsigned char *scsi3addr, + int cmd_type); + +static int sendcmd_core(ctlr_info_t *h, CommandList_struct *c); + +static CommandList_struct *cmd_alloc(ctlr_info_t *h, int get_from_pool); +static void cmd_free(ctlr_info_t *h, CommandList_struct *c, int got_from_pool); static int cciss_scsi_proc_info( struct Scsi_Host *sh, @@ -1575,6 +1587,68 @@ cciss_seq_tape_report(struct seq_file *seq, int ctlr) CPQ_TAPE_UNLOCK(ctlr, flags); } +static int wait_for_device_to_become_ready(ctlr_info_t *h, + unsigned char lunaddr[]) +{ + int rc; + int count = 0; + int waittime = HZ; + CommandList_struct *c; + + c = cmd_alloc(h, 1); + if (!c) { + printk(KERN_WARNING "cciss%d: out of memory in " + "wait_for_device_to_become_ready.\n", h->ctlr); + return IO_ERROR; + } + + /* Send test unit ready until device ready, or give up. */ + while (count < 20) { + + /* Wait for a bit. do this first, because if we send + * the TUR right away, the reset will just abort it. + */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(waittime); + count++; + + /* Increase wait time with each try, up to a point. */ + if (waittime < (HZ * 30)) + waittime = waittime * 2; + + /* Send the Test Unit Ready */ + rc = fill_cmd(c, TEST_UNIT_READY, h->ctlr, NULL, 0, 0, 0, 0, + lunaddr, TYPE_CMD); + if (rc == 0) { + rc = sendcmd_core(h, c); + /* sendcmd turned off interrupts, turn 'em back on. */ + h->access.set_intr_mask(h, CCISS_INTR_ON); + } + + if (rc == 0 && c->err_info->CommandStatus == CMD_SUCCESS) + break; + + if (rc == 0 && + c->err_info->CommandStatus == CMD_TARGET_STATUS && + c->err_info->ScsiStatus == SAM_STAT_CHECK_CONDITION && + (c->err_info->SenseInfo[2] == NO_SENSE || + c->err_info->SenseInfo[2] == UNIT_ATTENTION)) + break; + + printk(KERN_WARNING "cciss%d: Waiting %d secs " + "for device to become ready.\n", + h->ctlr, waittime / HZ); + rc = 1; /* device not ready. */ + } + + if (rc) + printk("cciss%d: giving up on device.\n", h->ctlr); + else + printk(KERN_WARNING "cciss%d: device is ready.\n", h->ctlr); + + cmd_free(h, c, 1); + return rc; +} /* Need at least one of these error handlers to keep ../scsi/hosts.c from * complaining. Doing a host- or bus-reset can't do anything good here. @@ -1591,6 +1665,7 @@ static int cciss_eh_device_reset_handler(struct scsi_cmnd *scsicmd) { int rc; CommandList_struct *cmd_in_trouble; + unsigned char lunaddr[8]; ctlr_info_t **c; int ctlr; @@ -1600,19 +1675,17 @@ static int cciss_eh_device_reset_handler(struct scsi_cmnd *scsicmd) return FAILED; ctlr = (*c)->ctlr; printk(KERN_WARNING "cciss%d: resetting tape drive or medium changer.\n", ctlr); - /* find the command that's giving us trouble */ cmd_in_trouble = (CommandList_struct *) scsicmd->host_scribble; - if (cmd_in_trouble == NULL) { /* paranoia */ + if (cmd_in_trouble == NULL) /* paranoia */ return FAILED; - } + memcpy(lunaddr, &cmd_in_trouble->Header.LUN.LunAddrBytes[0], 8); /* send a reset to the SCSI LUN which the command was sent to */ - rc = sendcmd(CCISS_RESET_MSG, ctlr, NULL, 0, 2, 0, 0, - (unsigned char *) &cmd_in_trouble->Header.LUN.LunAddrBytes[0], + rc = sendcmd(CCISS_RESET_MSG, ctlr, NULL, 0, 2, 0, 0, lunaddr, TYPE_MSG); /* sendcmd turned off interrupts on the board, turn 'em back on. */ (*c)->access.set_intr_mask(*c, CCISS_INTR_ON); - if (rc == 0) + if (rc == 0 && wait_for_device_to_become_ready(*c, lunaddr) == 0) return SUCCESS; printk(KERN_WARNING "cciss%d: resetting device failed.\n", ctlr); return FAILED; -- cgit v0.10.2 From 7fe063268e73681cdca1a6496a25f93d3332f517 Mon Sep 17 00:00:00 2001 From: Andrew Patterson Date: Tue, 2 Jun 2009 14:48:39 +0200 Subject: cciss: add cciss driver sysfs entries Add sysfs entries to the cciss driver needed for the dm/multipath tools. A file for vendor, model, rev, and unique_id is added for each logical drive under directory /sys/bus/pci/devices//ccissX/cXdY. Where X = the controller (or host) number and Y is the logical drive number. A link from /sys/bus/pci/devices//ccissX/cXdY/block:cciss!cXdY to /sys/block/cciss!cXdY/device is also created. A bus is created in /sys/bus/cciss. A link is created from the pci ccissX entry to /sys/bus/cciss/devices/ccissX. Please consider this for inclusion. Signed-off-by: Mike Miller Cc: Stephen M. Cameron Signed-off-by: Jens Axboe diff --git a/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss b/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss new file mode 100644 index 0000000..0a92a7c --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss @@ -0,0 +1,33 @@ +Where: /sys/bus/pci/devices//ccissX/cXdY/model +Date: March 2009 +Kernel Version: 2.6.30 +Contact: iss_storagedev@hp.com +Description: Displays the SCSI INQUIRY page 0 model for logical drive + Y of controller X. + +Where: /sys/bus/pci/devices//ccissX/cXdY/rev +Date: March 2009 +Kernel Version: 2.6.30 +Contact: iss_storagedev@hp.com +Description: Displays the SCSI INQUIRY page 0 revision for logical + drive Y of controller X. + +Where: /sys/bus/pci/devices//ccissX/cXdY/unique_id +Date: March 2009 +Kernel Version: 2.6.30 +Contact: iss_storagedev@hp.com +Description: Displays the SCSI INQUIRY page 83 serial number for logical + drive Y of controller X. + +Where: /sys/bus/pci/devices//ccissX/cXdY/vendor +Date: March 2009 +Kernel Version: 2.6.30 +Contact: iss_storagedev@hp.com +Description: Displays the SCSI INQUIRY page 0 vendor for logical drive + Y of controller X. + +Where: /sys/bus/pci/devices//ccissX/cXdY/block:cciss!cXdY +Date: March 2009 +Kernel Version: 2.6.30 +Contact: iss_storagedev@hp.com +Description: A symbolic link to /sys/block/cciss!cXdY diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index cb43fb3..e7d0095 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -437,6 +437,194 @@ static void __devinit cciss_procinit(int i) } #endif /* CONFIG_PROC_FS */ +#define MAX_PRODUCT_NAME_LEN 19 + +#define to_hba(n) container_of(n, struct ctlr_info, dev) +#define to_drv(n) container_of(n, drive_info_struct, dev) + +static struct device_type cciss_host_type = { + .name = "cciss_host", +}; + +static ssize_t dev_show_unique_id(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + drive_info_struct *drv = to_drv(dev); + struct ctlr_info *h = to_hba(drv->dev.parent); + __u8 sn[16]; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); + if (h->busy_configuring) + ret = -EBUSY; + else + memcpy(sn, drv->serial_no, sizeof(sn)); + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + + if (ret) + return ret; + else + return snprintf(buf, 16 * 2 + 2, + "%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X\n", + sn[0], sn[1], sn[2], sn[3], + sn[4], sn[5], sn[6], sn[7], + sn[8], sn[9], sn[10], sn[11], + sn[12], sn[13], sn[14], sn[15]); +} +DEVICE_ATTR(unique_id, S_IRUGO, dev_show_unique_id, NULL); + +static ssize_t dev_show_vendor(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + drive_info_struct *drv = to_drv(dev); + struct ctlr_info *h = to_hba(drv->dev.parent); + char vendor[VENDOR_LEN + 1]; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); + if (h->busy_configuring) + ret = -EBUSY; + else + memcpy(vendor, drv->vendor, VENDOR_LEN + 1); + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + + if (ret) + return ret; + else + return snprintf(buf, sizeof(vendor) + 1, "%s\n", drv->vendor); +} +DEVICE_ATTR(vendor, S_IRUGO, dev_show_vendor, NULL); + +static ssize_t dev_show_model(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + drive_info_struct *drv = to_drv(dev); + struct ctlr_info *h = to_hba(drv->dev.parent); + char model[MODEL_LEN + 1]; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); + if (h->busy_configuring) + ret = -EBUSY; + else + memcpy(model, drv->model, MODEL_LEN + 1); + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + + if (ret) + return ret; + else + return snprintf(buf, sizeof(model) + 1, "%s\n", drv->model); +} +DEVICE_ATTR(model, S_IRUGO, dev_show_model, NULL); + +static ssize_t dev_show_rev(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + drive_info_struct *drv = to_drv(dev); + struct ctlr_info *h = to_hba(drv->dev.parent); + char rev[REV_LEN + 1]; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); + if (h->busy_configuring) + ret = -EBUSY; + else + memcpy(rev, drv->rev, REV_LEN + 1); + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + + if (ret) + return ret; + else + return snprintf(buf, sizeof(rev) + 1, "%s\n", drv->rev); +} +DEVICE_ATTR(rev, S_IRUGO, dev_show_rev, NULL); + +static struct attribute *cciss_dev_attrs[] = { + &dev_attr_unique_id.attr, + &dev_attr_model.attr, + &dev_attr_vendor.attr, + &dev_attr_rev.attr, + NULL +}; + +static struct attribute_group cciss_dev_attr_group = { + .attrs = cciss_dev_attrs, +}; + +static struct attribute_group *cciss_dev_attr_groups[] = { + &cciss_dev_attr_group, + NULL +}; + +static struct device_type cciss_dev_type = { + .name = "cciss_device", + .groups = cciss_dev_attr_groups, +}; + +static struct bus_type cciss_bus_type = { + .name = "cciss", +}; + + +/* + * Initialize sysfs entry for each controller. This sets up and registers + * the 'cciss#' directory for each individual controller under + * /sys/bus/pci/devices//. + */ +static int cciss_create_hba_sysfs_entry(struct ctlr_info *h) +{ + device_initialize(&h->dev); + h->dev.type = &cciss_host_type; + h->dev.bus = &cciss_bus_type; + dev_set_name(&h->dev, "%s", h->devname); + h->dev.parent = &h->pdev->dev; + + return device_add(&h->dev); +} + +/* + * Remove sysfs entries for an hba. + */ +static void cciss_destroy_hba_sysfs_entry(struct ctlr_info *h) +{ + device_del(&h->dev); +} + +/* + * Initialize sysfs for each logical drive. This sets up and registers + * the 'c#d#' directory for each individual logical drive under + * /sys/bus/pci/devices/dev); + drv->dev.type = &cciss_dev_type; + drv->dev.bus = &cciss_bus_type; + dev_set_name(&drv->dev, "c%dd%d", h->ctlr, drv_index); + drv->dev.parent = &h->dev; + return device_add(&drv->dev); +} + +/* + * Remove sysfs entries for a logical drive. + */ +static void cciss_destroy_ld_sysfs_entry(drive_info_struct *drv) +{ + device_del(&drv->dev); +} + /* * For operations that cannot sleep, a command block is allocated at init, * and managed by cmd_alloc() and cmd_free() using a simple bitmap to track @@ -1332,6 +1520,45 @@ static void cciss_softirq_done(struct request *rq) spin_unlock_irqrestore(&h->lock, flags); } +/* This function gets the SCSI vendor, model, and revision of a logical drive + * via the inquiry page 0. Model, vendor, and rev are set to empty strings if + * they cannot be read. + */ +static void cciss_get_device_descr(int ctlr, int logvol, int withirq, + char *vendor, char *model, char *rev) +{ + int rc; + InquiryData_struct *inq_buf; + + *vendor = '\0'; + *model = '\0'; + *rev = '\0'; + + inq_buf = kzalloc(sizeof(InquiryData_struct), GFP_KERNEL); + if (!inq_buf) + return; + + if (withirq) + rc = sendcmd_withirq(CISS_INQUIRY, ctlr, inq_buf, + sizeof(InquiryData_struct), 1, logvol, + 0, TYPE_CMD); + else + rc = sendcmd(CISS_INQUIRY, ctlr, inq_buf, + sizeof(InquiryData_struct), 1, logvol, 0, NULL, + TYPE_CMD); + if (rc == IO_OK) { + memcpy(vendor, &inq_buf->data_byte[8], VENDOR_LEN); + vendor[VENDOR_LEN] = '\0'; + memcpy(model, &inq_buf->data_byte[16], MODEL_LEN); + model[MODEL_LEN] = '\0'; + memcpy(rev, &inq_buf->data_byte[32], REV_LEN); + rev[REV_LEN] = '\0'; + } + + kfree(inq_buf); + return; +} + /* This function gets the serial number of a logical drive via * inquiry page 0x83. Serial no. is 16 bytes. If the serial * number cannot be had, for whatever reason, 16 bytes of 0xff @@ -1372,7 +1599,7 @@ static void cciss_add_disk(ctlr_info_t *h, struct gendisk *disk, disk->first_minor = drv_index << NWD_SHIFT; disk->fops = &cciss_fops; disk->private_data = &h->drv[drv_index]; - disk->driverfs_dev = &h->pdev->dev; + disk->driverfs_dev = &h->drv[drv_index].dev; /* Set up queue information */ blk_queue_bounce_limit(disk->queue, h->pdev->dma_mask); @@ -1463,6 +1690,8 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time) drvinfo->block_size = block_size; drvinfo->nr_blocks = total_size + 1; + cciss_get_device_descr(ctlr, drv_index, 1, drvinfo->vendor, + drvinfo->model, drvinfo->rev); cciss_get_serial_no(ctlr, drv_index, 1, drvinfo->serial_no, sizeof(drvinfo->serial_no)); @@ -1512,6 +1741,9 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time) h->drv[drv_index].cylinders = drvinfo->cylinders; h->drv[drv_index].raid_level = drvinfo->raid_level; memcpy(h->drv[drv_index].serial_no, drvinfo->serial_no, 16); + memcpy(h->drv[drv_index].vendor, drvinfo->vendor, VENDOR_LEN + 1); + memcpy(h->drv[drv_index].model, drvinfo->model, MODEL_LEN + 1); + memcpy(h->drv[drv_index].rev, drvinfo->rev, REV_LEN + 1); ++h->num_luns; disk = h->gendisk[drv_index]; @@ -1586,6 +1818,8 @@ static int cciss_add_gendisk(ctlr_info_t *h, __u32 lunid, int controller_node) } } h->drv[drv_index].LunID = lunid; + if (cciss_create_ld_sysfs_entry(h, &h->drv[drv_index], drv_index)) + goto err_free_disk; /* Don't need to mark this busy because nobody */ /* else knows about this disk yet to contend */ @@ -1593,6 +1827,11 @@ static int cciss_add_gendisk(ctlr_info_t *h, __u32 lunid, int controller_node) h->drv[drv_index].busy_configuring = 0; wmb(); return drv_index; + +err_free_disk: + put_disk(h->gendisk[drv_index]); + h->gendisk[drv_index] = NULL; + return -1; } /* This is for the special case of a controller which @@ -1713,6 +1952,7 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time) h->drv[i].busy_configuring = 1; spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); return_code = deregister_disk(h, i, 1); + cciss_destroy_ld_sysfs_entry(&h->drv[i]); h->drv[i].busy_configuring = 0; } } @@ -3719,12 +3959,15 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, INIT_HLIST_HEAD(&hba[i]->reqQ); if (cciss_pci_init(hba[i], pdev) != 0) - goto clean1; + goto clean0; sprintf(hba[i]->devname, "cciss%d", i); hba[i]->ctlr = i; hba[i]->pdev = pdev; + if (cciss_create_hba_sysfs_entry(hba[i])) + goto clean0; + /* configure PCI DMA stuff */ if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) dac = 1; @@ -3868,6 +4111,8 @@ clean4: clean2: unregister_blkdev(hba[i]->major, hba[i]->devname); clean1: + cciss_destroy_hba_sysfs_entry(hba[i]); +clean0: hba[i]->busy_initializing = 0; /* cleanup any queues that may have been initialized */ for (j=0; j <= hba[i]->highest_lun; j++){ @@ -3978,6 +4223,7 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev) */ pci_release_regions(pdev); pci_set_drvdata(pdev, NULL); + cciss_destroy_hba_sysfs_entry(hba[i]); free_hba(i); } @@ -3995,6 +4241,8 @@ static struct pci_driver cciss_pci_driver = { */ static int __init cciss_init(void) { + int err; + /* * The hardware requires that commands are aligned on a 64-bit * boundary. Given that we use pci_alloc_consistent() to allocate an @@ -4004,8 +4252,20 @@ static int __init cciss_init(void) printk(KERN_INFO DRIVER_NAME "\n"); + err = bus_register(&cciss_bus_type); + if (err) + return err; + /* Register for our PCI devices */ - return pci_register_driver(&cciss_pci_driver); + err = pci_register_driver(&cciss_pci_driver); + if (err) + goto err_bus_register; + + return 0; + +err_bus_register: + bus_unregister(&cciss_bus_type); + return err; } static void __exit cciss_cleanup(void) @@ -4022,6 +4282,7 @@ static void __exit cciss_cleanup(void) } } remove_proc_entry("driver/cciss", NULL); + bus_unregister(&cciss_bus_type); } static void fail_all_cmds(unsigned long ctlr) diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index 703e080..dd1926d 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h @@ -12,6 +12,10 @@ #define IO_OK 0 #define IO_ERROR 1 +#define VENDOR_LEN 8 +#define MODEL_LEN 16 +#define REV_LEN 4 + struct ctlr_info; typedef struct ctlr_info ctlr_info_t; @@ -34,13 +38,18 @@ typedef struct _drive_info_struct int cylinders; int raid_level; /* set to -1 to indicate that * the drive is not in use/configured - */ - int busy_configuring; /*This is set when the drive is being removed - *to prevent it from being opened or it's queue - *from being started. - */ - __u8 serial_no[16]; /* from inquiry page 0x83, */ - /* not necc. null terminated. */ + */ + int busy_configuring; /* This is set when a drive is being removed + * to prevent it from being opened or it's + * queue from being started. + */ + struct device dev; + __u8 serial_no[16]; /* from inquiry page 0x83, + * not necc. null terminated. + */ + char vendor[VENDOR_LEN + 1]; /* SCSI vendor string */ + char model[MODEL_LEN + 1]; /* SCSI model string */ + char rev[REV_LEN + 1]; /* SCSI revision string */ } drive_info_struct; #ifdef CONFIG_CISS_SCSI_TAPE @@ -123,6 +132,7 @@ struct ctlr_info unsigned char alive; struct completion *rescan_wait; struct task_struct *cciss_scan_thread; + struct device dev; }; /* Defining the diffent access_menthods */ -- cgit v0.10.2 From 77b0308a0778861111184e097533000f7a458c37 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 2 Jun 2009 14:51:30 +0200 Subject: cciss: use schedule_timeout_interruptible() Use schedule_timeout_interruptible() instead of open-coding the set and schedule parts. Cc: Mike Miller Cc: Stephen M. Cameron Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index 8575c48..2edfc9b 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -1608,8 +1608,7 @@ static int wait_for_device_to_become_ready(ctlr_info_t *h, /* Wait for a bit. do this first, because if we send * the TUR right away, the reset will just abort it. */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(waittime); + schedule_timeout_interruptible(waittime); count++; /* Increase wait time with each try, up to a point. */ -- cgit v0.10.2 From dbdc9dd342f0a7e32f40f0d4ade662bdfe057484 Mon Sep 17 00:00:00 2001 From: vibi sreenivasan Date: Tue, 2 Jun 2009 14:52:32 +0200 Subject: Removed reference to non-existing file Documentation/PCI/PCI-DMA-mapping.txt File Documentation/PCI/PCI-DMA-mapping.txt does not exist. Documentation/DMA-mapping.txt contains DMA Mapping details Signed-off-by: vibi sreenivasan Signed-off-by: Jens Axboe diff --git a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt index 6fab97e..8d2158a 100644 --- a/Documentation/block/biodoc.txt +++ b/Documentation/block/biodoc.txt @@ -186,7 +186,7 @@ a virtual address mapping (unlike the earlier scheme of virtual address do not have a corresponding kernel virtual address space mapping) and low-memory pages. -Note: Please refer to Documentation/PCI/PCI-DMA-mapping.txt for a discussion +Note: Please refer to Documentation/DMA-mapping.txt for a discussion on PCI high mem DMA aspects and mapping of scatter gather lists, and support for 64 bit PCI. -- cgit v0.10.2 From a05c0205ba031c01bba33a21bf0a35920eb64833 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Wed, 3 Jun 2009 09:33:18 +0200 Subject: block: Fix bounce limit setting in DM blk_queue_bounce_limit() is more than a wrapper about the request queue limits.bounce_pfn variable. Introduce blk_queue_bounce_pfn() which can be called by stacking drivers that wish to set the bounce limit explicitly. Signed-off-by: Martin K. Petersen Signed-off-by: Jens Axboe diff --git a/block/blk-settings.c b/block/blk-settings.c index 8d33934..9acd0b7 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -194,6 +194,23 @@ void blk_queue_bounce_limit(struct request_queue *q, u64 dma_mask) EXPORT_SYMBOL(blk_queue_bounce_limit); /** + * blk_queue_bounce_pfn - set the bounce buffer limit for queue + * @q: the request queue for the device + * @pfn: max address + * + * Description: + * This function is similar to blk_queue_bounce_limit except it + * neither changes allocation flags, nor does it set up the ISA DMA + * pool. This function should only be used by stacking drivers. + * Hardware drivers should use blk_queue_bounce_limit instead. + */ +void blk_queue_bounce_pfn(struct request_queue *q, u64 pfn) +{ + q->limits.bounce_pfn = pfn; +} +EXPORT_SYMBOL(blk_queue_bounce_pfn); + +/** * blk_queue_max_sectors - set max sectors for a request for this queue * @q: the request queue for the device * @max_sectors: max sectors in the usual 512b unit diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index e9a73bb..3ca1604 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -920,7 +920,7 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q) blk_queue_max_segment_size(q, t->limits.max_segment_size); blk_queue_max_hw_sectors(q, t->limits.max_hw_sectors); blk_queue_segment_boundary(q, t->limits.seg_boundary_mask); - blk_queue_bounce_limit(q, t->limits.bounce_pfn); + blk_queue_bounce_pfn(q, t->limits.bounce_pfn); if (t->limits.no_cluster) queue_flag_clear_unlocked(QUEUE_FLAG_CLUSTER, q); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 5e740a1..989aa17 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -910,6 +910,7 @@ extern struct request_queue *blk_init_queue(request_fn_proc *, spinlock_t *); extern void blk_cleanup_queue(struct request_queue *); extern void blk_queue_make_request(struct request_queue *, make_request_fn *); extern void blk_queue_bounce_limit(struct request_queue *, u64); +extern void blk_queue_bounce_pfn(struct request_queue *, u64); extern void blk_queue_max_sectors(struct request_queue *, unsigned int); extern void blk_queue_max_hw_sectors(struct request_queue *, unsigned int); extern void blk_queue_max_phys_segments(struct request_queue *, unsigned short); -- cgit v0.10.2 From 172124e220f1854acc99ee394671781b8b5e2120 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 4 Jun 2009 22:34:44 +0200 Subject: Revert "block: implement blkdev_readpages" This reverts commit db2dbb12dc47a50c7a4c5678f526014063e486f6. It apparently causes problems with partition table read-ahead on archs with large page sizes. Until that problem is diagnosed further, just drop the readpages support on block devices. Signed-off-by: Jens Axboe diff --git a/fs/block_dev.c b/fs/block_dev.c index a29b4dc..2dfc6cd 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -331,12 +331,6 @@ static int blkdev_readpage(struct file * file, struct page * page) return block_read_full_page(page, blkdev_get_block); } -static int blkdev_readpages(struct file *file, struct address_space *mapping, - struct list_head *pages, unsigned nr_pages) -{ - return mpage_readpages(mapping, pages, nr_pages, blkdev_get_block); -} - static int blkdev_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata) @@ -1405,7 +1399,6 @@ static int blkdev_releasepage(struct page *page, gfp_t wait) static const struct address_space_operations def_blk_aops = { .readpage = blkdev_readpage, - .readpages = blkdev_readpages, .writepage = blkdev_writepage, .sync_page = block_sync_page, .write_begin = blkdev_write_begin, -- cgit v0.10.2 From dbb66c4be020b01dc2f3d7c609ddb0e09d2c0af7 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Tue, 9 Jun 2009 05:47:10 +0200 Subject: block: needs to set the residual length of a bidi request Tejun's "block: set rq->resid_len to blk_rq_bytes() on issue" patch seems to be incomplete; It doesn't set rq->resid_len to blk_rq_bytes() for a bidi request (req->next_rq). As a result, all bidi users are broken. Signed-off-by: FUJITA Tomonori Acked-by: Tejun Heo Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index 7ae83a1..03c5a64 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1846,6 +1846,9 @@ void blk_start_request(struct request *req) * resid_len to full count and add the timeout handler. */ req->resid_len = blk_rq_bytes(req); + if (unlikely(blk_bidi_rq(req))) + req->next_rq->resid_len = blk_rq_bytes(req->next_rq); + blk_add_timer(req); } EXPORT_SYMBOL(blk_start_request); -- cgit v0.10.2 From 40df6ae4277a67e97aa0a8bd8e293fdbb00e5623 Mon Sep 17 00:00:00 2001 From: "scameron@beardog.cca.cpqcorp.net" Date: Mon, 8 Jun 2009 15:59:38 -0500 Subject: cciss: Use schedule_timeout_uninterruptible in SCSI error handling code Use schedule_timeout_uninterruptible instead of schedule_timeout in the scsi error handling code when waiting between TUR polls since we are not interested in nor want to be interrupted by signals. Signed-off-by: Stephen M. Cameron Signed-off-by: Jens Axboe diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index 2edfc9b..134fdf2 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -1608,7 +1608,7 @@ static int wait_for_device_to_become_ready(ctlr_info_t *h, /* Wait for a bit. do this first, because if we send * the TUR right away, the reset will just abort it. */ - schedule_timeout_interruptible(waittime); + schedule_timeout_uninterruptible(waittime); count++; /* Increase wait time with each try, up to a point. */ -- cgit v0.10.2 From 5390cfc3fea49d015ae1eed8551c0bf00489b50e Mon Sep 17 00:00:00 2001 From: "scameron@beardog.cca.cpqcorp.net" Date: Mon, 8 Jun 2009 16:01:11 -0500 Subject: cciss: factor out core of sendcmd_withirq() for use by SCSI error handling code Factor the core of sendcmd_withirq out to provide a simpler interface which provides access to full error information. Signed-off-by: Stephen M. Cameron Signed-off-by: Jens Axboe diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index e7d0095..74fc85a 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -2278,114 +2278,123 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_ return status; } -static int sendcmd_withirq(__u8 cmd, - int ctlr, - void *buff, - size_t size, - unsigned int use_unit_num, - unsigned int log_unit, __u8 page_code, int cmd_type) +static int sendcmd_withirq_core(ctlr_info_t *h, CommandList_struct *c) { - ctlr_info_t *h = hba[ctlr]; - CommandList_struct *c; + DECLARE_COMPLETION_ONSTACK(wait); u64bit buff_dma_handle; unsigned long flags; - int return_status; - DECLARE_COMPLETION_ONSTACK(wait); + int return_status = IO_OK; - if ((c = cmd_alloc(h, 0)) == NULL) - return -ENOMEM; - return_status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num, - log_unit, page_code, NULL, cmd_type); - if (return_status != IO_OK) { - cmd_free(h, c, 0); - return return_status; - } - resend_cmd2: +resend_cmd2: c->waiting = &wait; - /* Put the request on the tail of the queue and send it */ - spin_lock_irqsave(CCISS_LOCK(ctlr), flags); + spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); addQ(&h->reqQ, c); h->Qdepth++; start_io(h); - spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); wait_for_completion(&wait); - if (c->err_info->CommandStatus != 0) { /* an error has occurred */ - switch (c->err_info->CommandStatus) { - case CMD_TARGET_STATUS: - printk(KERN_WARNING "cciss: cmd %p has " - " completed with errors\n", c); - if (c->err_info->ScsiStatus) { - printk(KERN_WARNING "cciss: cmd %p " - "has SCSI Status = %x\n", - c, c->err_info->ScsiStatus); - } + if (c->err_info->CommandStatus == 0) + goto command_done; - break; - case CMD_DATA_UNDERRUN: - case CMD_DATA_OVERRUN: - /* expected for inquire and report lun commands */ - break; - case CMD_INVALID: - printk(KERN_WARNING "cciss: Cmd %p is " - "reported invalid\n", c); - return_status = IO_ERROR; - break; - case CMD_PROTOCOL_ERR: - printk(KERN_WARNING "cciss: cmd %p has " - "protocol error \n", c); - return_status = IO_ERROR; - break; - case CMD_HARDWARE_ERR: - printk(KERN_WARNING "cciss: cmd %p had " - " hardware error\n", c); - return_status = IO_ERROR; - break; - case CMD_CONNECTION_LOST: - printk(KERN_WARNING "cciss: cmd %p had " - "connection lost\n", c); - return_status = IO_ERROR; - break; - case CMD_ABORTED: - printk(KERN_WARNING "cciss: cmd %p was " - "aborted\n", c); - return_status = IO_ERROR; - break; - case CMD_ABORT_FAILED: - printk(KERN_WARNING "cciss: cmd %p reports " - "abort failed\n", c); - return_status = IO_ERROR; - break; - case CMD_UNSOLICITED_ABORT: + switch (c->err_info->CommandStatus) { + case CMD_TARGET_STATUS: + printk(KERN_WARNING "cciss: cmd 0x%02x " + "has completed with errors\n", c->Request.CDB[0]); + if (c->err_info->ScsiStatus) { + printk(KERN_WARNING "cciss: cmd 0x%02x " + "has SCSI Status = %x\n", + c->Request.CDB[0], c->err_info->ScsiStatus); + } + break; + case CMD_DATA_UNDERRUN: + case CMD_DATA_OVERRUN: + /* expected for inquiry and report lun commands */ + break; + case CMD_INVALID: + printk(KERN_WARNING "cciss: Cmd 0x%02x is " + "reported invalid\n", c->Request.CDB[0]); + return_status = IO_ERROR; + break; + case CMD_PROTOCOL_ERR: + printk(KERN_WARNING "cciss: cmd 0x%02x has " + "protocol error \n", c->Request.CDB[0]); + return_status = IO_ERROR; + break; + case CMD_HARDWARE_ERR: + printk(KERN_WARNING "cciss: cmd 0x%02x had " + " hardware error\n", c->Request.CDB[0]); + return_status = IO_ERROR; + break; + case CMD_CONNECTION_LOST: + printk(KERN_WARNING "cciss: cmd 0x%02x had " + "connection lost\n", c->Request.CDB[0]); + return_status = IO_ERROR; + break; + case CMD_ABORTED: + printk(KERN_WARNING "cciss: cmd 0x%02x was " + "aborted\n", c->Request.CDB[0]); + return_status = IO_ERROR; + break; + case CMD_ABORT_FAILED: + printk(KERN_WARNING "cciss: cmd 0x%02x reports " + "abort failed\n", c->Request.CDB[0]); + return_status = IO_ERROR; + break; + case CMD_UNSOLICITED_ABORT: + printk(KERN_WARNING + "cciss%d: unsolicited abort 0x%02x\n", h->ctlr, + c->Request.CDB[0]); + if (c->retry_count < MAX_CMD_RETRIES) { printk(KERN_WARNING - "cciss%d: unsolicited abort %p\n", ctlr, c); - if (c->retry_count < MAX_CMD_RETRIES) { - printk(KERN_WARNING - "cciss%d: retrying %p\n", ctlr, c); - c->retry_count++; - /* erase the old error information */ - memset(c->err_info, 0, - sizeof(ErrorInfo_struct)); - return_status = IO_OK; - INIT_COMPLETION(wait); - goto resend_cmd2; - } - return_status = IO_ERROR; - break; - default: - printk(KERN_WARNING "cciss: cmd %p returned " - "unknown status %x\n", c, - c->err_info->CommandStatus); - return_status = IO_ERROR; + "cciss%d: retrying 0x%02x\n", h->ctlr, + c->Request.CDB[0]); + c->retry_count++; + /* erase the old error information */ + memset(c->err_info, 0, + sizeof(ErrorInfo_struct)); + return_status = IO_OK; + INIT_COMPLETION(wait); + goto resend_cmd2; } + return_status = IO_ERROR; + break; + default: + printk(KERN_WARNING "cciss: cmd 0x%02x returned " + "unknown status %x\n", c->Request.CDB[0], + c->err_info->CommandStatus); + return_status = IO_ERROR; } + +command_done: /* unlock the buffers from DMA */ buff_dma_handle.val32.lower = c->SG[0].Addr.lower; buff_dma_handle.val32.upper = c->SG[0].Addr.upper; pci_unmap_single(h->pdev, (dma_addr_t) buff_dma_handle.val, c->SG[0].Len, PCI_DMA_BIDIRECTIONAL); + return return_status; +} + +static int sendcmd_withirq(__u8 cmd, + int ctlr, + void *buff, + size_t size, + unsigned int use_unit_num, + unsigned int log_unit, __u8 page_code, int cmd_type) +{ + ctlr_info_t *h = hba[ctlr]; + CommandList_struct *c; + int return_status; + + c = cmd_alloc(h, 0); + if (!c) + return -ENOMEM; + return_status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num, + log_unit, page_code, NULL, cmd_type); + if (return_status == IO_OK) + return_status = sendcmd_withirq_core(h, c); cmd_free(h, c, 0); return return_status; } -- cgit v0.10.2 From b57695fe131b13d3f2460cfeb9175cff673ed337 Mon Sep 17 00:00:00 2001 From: "scameron@beardog.cca.cpqcorp.net" Date: Mon, 8 Jun 2009 16:02:17 -0500 Subject: cciss: simplify interface of sendcmd() and sendcmd_withirq() Simplify interfaces of sendcmd() and sendcmd_withirq() so that they provide only one way to address commands instead of three ways. Signed-off-by: Stephen M. Cameron Signed-off-by: Jens Axboe diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 74fc85a..885ea1e 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -180,11 +180,10 @@ static void __devinit cciss_interrupt_mode(ctlr_info_t *, struct pci_dev *, __u32); static void start_io(ctlr_info_t *h); static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, - unsigned int use_unit_num, unsigned int log_unit, __u8 page_code, unsigned char *scsi3addr, int cmd_type); static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size, - unsigned int use_unit_num, unsigned int log_unit, - __u8 page_code, int cmd_type); + __u8 page_code, unsigned char scsi3addr[], + int cmd_type); static void fail_all_cmds(unsigned long ctlr); static int scan_thread(void *data); @@ -1520,6 +1519,15 @@ static void cciss_softirq_done(struct request *rq) spin_unlock_irqrestore(&h->lock, flags); } +static void log_unit_to_scsi3addr(ctlr_info_t *h, unsigned char scsi3addr[], + uint32_t log_unit) +{ + log_unit = h->drv[log_unit].LunID & 0x03fff; + memset(&scsi3addr[4], 0, 4); + memcpy(&scsi3addr[0], &log_unit, 4); + scsi3addr[3] |= 0x40; +} + /* This function gets the SCSI vendor, model, and revision of a logical drive * via the inquiry page 0. Model, vendor, and rev are set to empty strings if * they cannot be read. @@ -1529,6 +1537,7 @@ static void cciss_get_device_descr(int ctlr, int logvol, int withirq, { int rc; InquiryData_struct *inq_buf; + unsigned char scsi3addr[8]; *vendor = '\0'; *model = '\0'; @@ -1538,14 +1547,15 @@ static void cciss_get_device_descr(int ctlr, int logvol, int withirq, if (!inq_buf) return; + log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol); if (withirq) rc = sendcmd_withirq(CISS_INQUIRY, ctlr, inq_buf, - sizeof(InquiryData_struct), 1, logvol, - 0, TYPE_CMD); + sizeof(InquiryData_struct), 0, + scsi3addr, TYPE_CMD); else rc = sendcmd(CISS_INQUIRY, ctlr, inq_buf, - sizeof(InquiryData_struct), 1, logvol, 0, NULL, - TYPE_CMD); + sizeof(InquiryData_struct), 0, + scsi3addr, TYPE_CMD); if (rc == IO_OK) { memcpy(vendor, &inq_buf->data_byte[8], VENDOR_LEN); vendor[VENDOR_LEN] = '\0'; @@ -1570,6 +1580,7 @@ static void cciss_get_serial_no(int ctlr, int logvol, int withirq, #define PAGE_83_INQ_BYTES 64 int rc; unsigned char *buf; + unsigned char scsi3addr[8]; if (buflen > 16) buflen = 16; @@ -1578,12 +1589,13 @@ static void cciss_get_serial_no(int ctlr, int logvol, int withirq, if (!buf) return; memset(serial_no, 0, buflen); + log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol); if (withirq) rc = sendcmd_withirq(CISS_INQUIRY, ctlr, buf, - PAGE_83_INQ_BYTES, 1, logvol, 0x83, TYPE_CMD); + PAGE_83_INQ_BYTES, 0x83, scsi3addr, TYPE_CMD); else rc = sendcmd(CISS_INQUIRY, ctlr, buf, - PAGE_83_INQ_BYTES, 1, logvol, 0x83, NULL, TYPE_CMD); + PAGE_83_INQ_BYTES, 0x83, scsi3addr, TYPE_CMD); if (rc == IO_OK) memcpy(serial_no, &buf[8], buflen); kfree(buf); @@ -1902,8 +1914,8 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time) goto mem_msg; return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff, - sizeof(ReportLunData_struct), 0, - 0, 0, TYPE_CMD); + sizeof(ReportLunData_struct), + 0, CTLR_LUNID, TYPE_CMD); if (return_code == IO_OK) listlength = be32_to_cpu(*(__be32 *) ld_buff->LUNListLength); @@ -2112,11 +2124,9 @@ static int deregister_disk(ctlr_info_t *h, int drv_index, return 0; } -static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_t size, unsigned int use_unit_num, /* 0: address the controller, - 1: address logical volume log_unit, - 2: periph device address is scsi3addr */ - unsigned int log_unit, __u8 page_code, - unsigned char *scsi3addr, int cmd_type) +static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, + size_t size, __u8 page_code, unsigned char *scsi3addr, + int cmd_type) { ctlr_info_t *h = hba[ctlr]; u64bit buff_dma_handle; @@ -2132,27 +2142,12 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_ c->Header.SGTotal = 0; } c->Header.Tag.lower = c->busaddr; + memcpy(c->Header.LUN.LunAddrBytes, scsi3addr, 8); c->Request.Type.Type = cmd_type; if (cmd_type == TYPE_CMD) { switch (cmd) { case CISS_INQUIRY: - /* If the logical unit number is 0 then, this is going - to controller so It's a physical command - mode = 0 target = 0. So we have nothing to write. - otherwise, if use_unit_num == 1, - mode = 1(volume set addressing) target = LUNID - otherwise, if use_unit_num == 2, - mode = 0(periph dev addr) target = scsi3addr */ - if (use_unit_num == 1) { - c->Header.LUN.LogDev.VolId = - h->drv[log_unit].LunID; - c->Header.LUN.LogDev.Mode = 1; - } else if (use_unit_num == 2) { - memcpy(c->Header.LUN.LunAddrBytes, scsi3addr, - 8); - c->Header.LUN.LogDev.Mode = 0; - } /* are we trying to read a vital product page */ if (page_code != 0) { c->Request.CDB[1] = 0x01; @@ -2182,8 +2177,6 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_ break; case CCISS_READ_CAPACITY: - c->Header.LUN.LogDev.VolId = h->drv[log_unit].LunID; - c->Header.LUN.LogDev.Mode = 1; c->Request.CDBLen = 10; c->Request.Type.Attribute = ATTR_SIMPLE; c->Request.Type.Direction = XFER_READ; @@ -2191,8 +2184,6 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_ c->Request.CDB[0] = cmd; break; case CCISS_READ_CAPACITY_16: - c->Header.LUN.LogDev.VolId = h->drv[log_unit].LunID; - c->Header.LUN.LogDev.Mode = 1; c->Request.CDBLen = 16; c->Request.Type.Attribute = ATTR_SIMPLE; c->Request.Type.Direction = XFER_READ; @@ -2215,7 +2206,6 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_ c->Request.CDB[6] = BMIC_CACHE_FLUSH; break; case TEST_UNIT_READY: - memcpy(c->Header. LUN.LunAddrBytes, scsi3addr, 8); c->Request.CDBLen = 6; c->Request.Type.Attribute = ATTR_SIMPLE; c->Request.Type.Direction = XFER_NONE; @@ -2239,7 +2229,6 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_ memcpy(&c->Request.CDB[4], buff, 8); break; case 1: /* RESET message */ - memcpy(c->Header.LUN.LunAddrBytes, scsi3addr, 8); c->Request.CDBLen = 16; c->Request.Type.Attribute = ATTR_SIMPLE; c->Request.Type.Direction = XFER_NONE; @@ -2307,6 +2296,9 @@ resend_cmd2: printk(KERN_WARNING "cciss: cmd 0x%02x " "has SCSI Status = %x\n", c->Request.CDB[0], c->err_info->ScsiStatus); + if (c->err_info->ScsiStatus == SAM_STAT_CHECK_CONDITION) + printk(KERN_WARNING "sense key = 0x%02x\n", + 0xf & c->err_info->SenseInfo[2]); } break; case CMD_DATA_UNDERRUN: @@ -2377,12 +2369,9 @@ command_done: return return_status; } -static int sendcmd_withirq(__u8 cmd, - int ctlr, - void *buff, - size_t size, - unsigned int use_unit_num, - unsigned int log_unit, __u8 page_code, int cmd_type) +static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size, + __u8 page_code, unsigned char scsi3addr[], + int cmd_type) { ctlr_info_t *h = hba[ctlr]; CommandList_struct *c; @@ -2391,8 +2380,8 @@ static int sendcmd_withirq(__u8 cmd, c = cmd_alloc(h, 0); if (!c) return -ENOMEM; - return_status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num, - log_unit, page_code, NULL, cmd_type); + return_status = fill_cmd(c, cmd, ctlr, buff, size, page_code, + scsi3addr, cmd_type); if (return_status == IO_OK) return_status = sendcmd_withirq_core(h, c); cmd_free(h, c, 0); @@ -2407,15 +2396,17 @@ static void cciss_geometry_inquiry(int ctlr, int logvol, { int return_code; unsigned long t; + unsigned char scsi3addr[8]; memset(inq_buff, 0, sizeof(InquiryData_struct)); + log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol); if (withirq) return_code = sendcmd_withirq(CISS_INQUIRY, ctlr, - inq_buff, sizeof(*inq_buff), 1, - logvol, 0xC1, TYPE_CMD); + inq_buff, sizeof(*inq_buff), + 0xC1, scsi3addr, TYPE_CMD); else return_code = sendcmd(CISS_INQUIRY, ctlr, inq_buff, - sizeof(*inq_buff), 1, logvol, 0xC1, NULL, + sizeof(*inq_buff), 0xC1, scsi3addr, TYPE_CMD); if (return_code == IO_OK) { if (inq_buff->data_byte[8] == 0xFF) { @@ -2456,6 +2447,7 @@ cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size, { ReadCapdata_struct *buf; int return_code; + unsigned char scsi3addr[8]; buf = kzalloc(sizeof(ReadCapdata_struct), GFP_KERNEL); if (!buf) { @@ -2463,14 +2455,15 @@ cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size, return; } + log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol); if (withirq) return_code = sendcmd_withirq(CCISS_READ_CAPACITY, ctlr, buf, sizeof(ReadCapdata_struct), - 1, logvol, 0, TYPE_CMD); + 0, scsi3addr, TYPE_CMD); else return_code = sendcmd(CCISS_READ_CAPACITY, ctlr, buf, sizeof(ReadCapdata_struct), - 1, logvol, 0, NULL, TYPE_CMD); + 0, scsi3addr, TYPE_CMD); if (return_code == IO_OK) { *total_size = be32_to_cpu(*(__be32 *) buf->total_size); *block_size = be32_to_cpu(*(__be32 *) buf->block_size); @@ -2490,6 +2483,7 @@ cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size, { ReadCapdata_struct_16 *buf; int return_code; + unsigned char scsi3addr[8]; buf = kzalloc(sizeof(ReadCapdata_struct_16), GFP_KERNEL); if (!buf) { @@ -2497,15 +2491,16 @@ cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size, return; } + log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol); if (withirq) { return_code = sendcmd_withirq(CCISS_READ_CAPACITY_16, ctlr, buf, sizeof(ReadCapdata_struct_16), - 1, logvol, 0, TYPE_CMD); + 0, scsi3addr, TYPE_CMD); } else { return_code = sendcmd(CCISS_READ_CAPACITY_16, ctlr, buf, sizeof(ReadCapdata_struct_16), - 1, logvol, 0, NULL, TYPE_CMD); + 0, scsi3addr, TYPE_CMD); } if (return_code == IO_OK) { *total_size = be64_to_cpu(*(__be64 *) buf->total_size); @@ -2760,10 +2755,6 @@ cleanup1: * Used at init time, and during SCSI error recovery. */ static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, - unsigned int use_unit_num,/* 0: address the controller, - 1: address logical volume log_unit, - 2: periph device address is scsi3addr */ - unsigned int log_unit, __u8 page_code, unsigned char *scsi3addr, int cmd_type) { CommandList_struct *c; @@ -2774,8 +2765,8 @@ static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, printk(KERN_WARNING "cciss: unable to get memory"); return IO_ERROR; } - status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num, - log_unit, page_code, scsi3addr, cmd_type); + status = fill_cmd(c, cmd, ctlr, buff, size, page_code, + scsi3addr, cmd_type); if (status == IO_OK) status = sendcmd_core(hba[ctlr], c); cmd_free(hba[ctlr], c, 1); @@ -4076,7 +4067,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, } return_code = sendcmd_withirq(CISS_INQUIRY, i, inq_buff, - sizeof(InquiryData_struct), 0, 0 , 0, TYPE_CMD); + sizeof(InquiryData_struct), 0, CTLR_LUNID, TYPE_CMD); if (return_code == IO_OK) { hba[i]->firm_ver[0] = inq_buff->data_byte[32]; hba[i]->firm_ver[1] = inq_buff->data_byte[33]; @@ -4157,8 +4148,8 @@ static void cciss_shutdown(struct pci_dev *pdev) /* sendcmd will turn off interrupt, and send the flush... * To write all data in the battery backed cache to disks */ memset(flush_buf, 0, 4); - return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0, 0, 0, NULL, - TYPE_CMD); + return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0, + CTLR_LUNID, TYPE_CMD); if (return_code == IO_OK) { printk(KERN_INFO "Completed flushing cache on controller %d\n", i); } else { diff --git a/drivers/block/cciss_cmd.h b/drivers/block/cciss_cmd.h index 40b1b92..cd665b0 100644 --- a/drivers/block/cciss_cmd.h +++ b/drivers/block/cciss_cmd.h @@ -217,6 +217,8 @@ typedef union _LUNAddr_struct { LogDevAddr_struct LogDev; } LUNAddr_struct; +#define CTLR_LUNID "\0\0\0\0\0\0\0\0" + typedef struct _CommandListHeader_struct { BYTE ReplyQueue; BYTE SGList; diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index 134fdf2..007ab8a 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -44,26 +44,9 @@ #define CCISS_ABORT_MSG 0x00 #define CCISS_RESET_MSG 0x01 -/* some prototypes... */ -static int sendcmd( - __u8 cmd, - int ctlr, - void *buff, - size_t size, - unsigned int use_unit_num, /* 0: address the controller, - 1: address logical volume log_unit, - 2: address is in scsi3addr */ - unsigned int log_unit, - __u8 page_code, - unsigned char *scsi3addr, - int cmd_type); - static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_t size, - unsigned int use_unit_num, /* 0: address the controller, - 1: address logical volume log_unit, - 2: periph device address is scsi3addr */ - unsigned int log_unit, __u8 page_code, unsigned char *scsi3addr, + __u8 page_code, unsigned char *scsi3addr, int cmd_type); static int sendcmd_core(ctlr_info_t *h, CommandList_struct *c); @@ -1616,7 +1599,7 @@ static int wait_for_device_to_become_ready(ctlr_info_t *h, waittime = waittime * 2; /* Send the Test Unit Ready */ - rc = fill_cmd(c, TEST_UNIT_READY, h->ctlr, NULL, 0, 0, 0, 0, + rc = fill_cmd(c, TEST_UNIT_READY, h->ctlr, NULL, 0, 0, lunaddr, TYPE_CMD); if (rc == 0) { rc = sendcmd_core(h, c); @@ -1680,7 +1663,7 @@ static int cciss_eh_device_reset_handler(struct scsi_cmnd *scsicmd) return FAILED; memcpy(lunaddr, &cmd_in_trouble->Header.LUN.LunAddrBytes[0], 8); /* send a reset to the SCSI LUN which the command was sent to */ - rc = sendcmd(CCISS_RESET_MSG, ctlr, NULL, 0, 2, 0, 0, lunaddr, + rc = sendcmd(CCISS_RESET_MSG, ctlr, NULL, 0, 0, lunaddr, TYPE_MSG); /* sendcmd turned off interrupts on the board, turn 'em back on. */ (*c)->access.set_intr_mask(*c, CCISS_INTR_ON); @@ -1708,8 +1691,7 @@ static int cciss_eh_abort_handler(struct scsi_cmnd *scsicmd) cmd_to_abort = (CommandList_struct *) scsicmd->host_scribble; if (cmd_to_abort == NULL) /* paranoia */ return FAILED; - rc = sendcmd(CCISS_ABORT_MSG, ctlr, &cmd_to_abort->Header.Tag, - 0, 2, 0, 0, + rc = sendcmd(CCISS_ABORT_MSG, ctlr, &cmd_to_abort->Header.Tag, 0, 0, (unsigned char *) &cmd_to_abort->Header.LUN.LunAddrBytes[0], TYPE_MSG); /* sendcmd turned off interrupts on the board, turn 'em back on. */ -- cgit v0.10.2 From 3c2ab40296894d1f7ad9714550fdf9b96d4e9ee6 Mon Sep 17 00:00:00 2001 From: "scameron@beardog.cca.cpqcorp.net" Date: Mon, 8 Jun 2009 16:04:35 -0500 Subject: cciss: factor out fix target status processing code from sendcmd functions Factor out code to process target status of completed commands in sendcmd() and sendcmd_withirq_core(), and fix problem that bad target status was ignored in sendcmd_withirq_core. Signed-off-by: Stephen M. Cameron Signed-off-by: Jens Axboe diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 885ea1e..2d12883 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -2267,6 +2267,31 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, return status; } +static int check_target_status(ctlr_info_t *h, CommandList_struct *c) +{ + switch (c->err_info->ScsiStatus) { + case SAM_STAT_GOOD: + return IO_OK; + case SAM_STAT_CHECK_CONDITION: + switch (0xf & c->err_info->SenseInfo[2]) { + case 0: return IO_OK; /* no sense */ + case 1: return IO_OK; /* recovered error */ + default: + printk(KERN_WARNING "cciss%d: cmd 0x%02x " + "check condition, sense key = 0x%02x\n", + h->ctlr, c->Request.CDB[0], + c->err_info->SenseInfo[2]); + } + break; + default: + printk(KERN_WARNING "cciss%d: cmd 0x%02x" + "scsi status = 0x%02x\n", h->ctlr, + c->Request.CDB[0], c->err_info->ScsiStatus); + break; + } + return IO_ERROR; +} + static int sendcmd_withirq_core(ctlr_info_t *h, CommandList_struct *c) { DECLARE_COMPLETION_ONSTACK(wait); @@ -2290,16 +2315,7 @@ resend_cmd2: switch (c->err_info->CommandStatus) { case CMD_TARGET_STATUS: - printk(KERN_WARNING "cciss: cmd 0x%02x " - "has completed with errors\n", c->Request.CDB[0]); - if (c->err_info->ScsiStatus) { - printk(KERN_WARNING "cciss: cmd 0x%02x " - "has SCSI Status = %x\n", - c->Request.CDB[0], c->err_info->ScsiStatus); - if (c->err_info->ScsiStatus == SAM_STAT_CHECK_CONDITION) - printk(KERN_WARNING "sense key = 0x%02x\n", - 0xf & c->err_info->SenseInfo[2]); - } + return_status = check_target_status(h, c); break; case CMD_DATA_UNDERRUN: case CMD_DATA_OVERRUN: @@ -2710,33 +2726,29 @@ resend_cmd1: printk(KERN_WARNING "cciss%d: retried %p too many " "times\n", h->ctlr, c); status = IO_ERROR; - goto cleanup1; + break; } if (c->err_info->CommandStatus == CMD_UNABORTABLE) { printk(KERN_WARNING "cciss%d: command could not be " "aborted.\n", h->ctlr); status = IO_ERROR; - goto cleanup1; + break; } - printk(KERN_WARNING "cciss%d: sendcmd error\n", h->ctlr); - printk(KERN_WARNING "cmd = 0x%02x, CommandStatus = 0x%02x\n", - c->Request.CDB[0], c->err_info->CommandStatus); if (c->err_info->CommandStatus == CMD_TARGET_STATUS) { - printk(KERN_WARNING "Target status = 0x%02x\n", - c->err_info->ScsiStatus); - if (c->err_info->ScsiStatus == 2) /* chk cond */ - printk(KERN_WARNING "Sense key = 0x%02x\n", - 0xf & c->err_info->SenseInfo[2]); + status = check_target_status(h, c); + break; } + printk(KERN_WARNING "cciss%d: sendcmd error\n", h->ctlr); + printk(KERN_WARNING "cmd = 0x%02x, CommandStatus = 0x%02x\n", + c->Request.CDB[0], c->err_info->CommandStatus); status = IO_ERROR; - goto cleanup1; + break; } while (1); -cleanup1: /* unlock the data buffer from DMA */ buff_dma_handle.val32.lower = c->SG[0].Addr.lower; buff_dma_handle.val32.upper = c->SG[0].Addr.upper; -- cgit v0.10.2 From 789a424ad1352b335960e7c56494d0410577fa61 Mon Sep 17 00:00:00 2001 From: "scameron@beardog.cca.cpqcorp.net" Date: Mon, 8 Jun 2009 16:05:56 -0500 Subject: cciss: separate error processing and command retrying code in sendcmd_withirq_core() Separate the error processing from sendcmd_withirq_core from the code which retries commands. The rationale for this is that the SCSI error handling code can then be made to use sendcmd_withirq_core, but avoid retrying commands. Signed-off-by: Stephen M. Cameron Signed-off-by: Jens Axboe diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 2d12883..7001707 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -2292,26 +2292,12 @@ static int check_target_status(ctlr_info_t *h, CommandList_struct *c) return IO_ERROR; } -static int sendcmd_withirq_core(ctlr_info_t *h, CommandList_struct *c) +static int process_sendcmd_error(ctlr_info_t *h, CommandList_struct *c) { - DECLARE_COMPLETION_ONSTACK(wait); - u64bit buff_dma_handle; - unsigned long flags; int return_status = IO_OK; -resend_cmd2: - c->waiting = &wait; - /* Put the request on the tail of the queue and send it */ - spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); - addQ(&h->reqQ, c); - h->Qdepth++; - start_io(h); - spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); - - wait_for_completion(&wait); - - if (c->err_info->CommandStatus == 0) - goto command_done; + if (c->err_info->CommandStatus == CMD_SUCCESS) + return IO_OK; switch (c->err_info->CommandStatus) { case CMD_TARGET_STATUS: @@ -2322,7 +2308,7 @@ resend_cmd2: /* expected for inquiry and report lun commands */ break; case CMD_INVALID: - printk(KERN_WARNING "cciss: Cmd 0x%02x is " + printk(KERN_WARNING "cciss: cmd 0x%02x is " "reported invalid\n", c->Request.CDB[0]); return_status = IO_ERROR; break; @@ -2355,19 +2341,7 @@ resend_cmd2: printk(KERN_WARNING "cciss%d: unsolicited abort 0x%02x\n", h->ctlr, c->Request.CDB[0]); - if (c->retry_count < MAX_CMD_RETRIES) { - printk(KERN_WARNING - "cciss%d: retrying 0x%02x\n", h->ctlr, - c->Request.CDB[0]); - c->retry_count++; - /* erase the old error information */ - memset(c->err_info, 0, - sizeof(ErrorInfo_struct)); - return_status = IO_OK; - INIT_COMPLETION(wait); - goto resend_cmd2; - } - return_status = IO_ERROR; + return_status = IO_NEEDS_RETRY; break; default: printk(KERN_WARNING "cciss: cmd 0x%02x returned " @@ -2375,6 +2349,44 @@ resend_cmd2: c->err_info->CommandStatus); return_status = IO_ERROR; } + return return_status; +} + +static int sendcmd_withirq_core(ctlr_info_t *h, CommandList_struct *c, + int attempt_retry) +{ + DECLARE_COMPLETION_ONSTACK(wait); + u64bit buff_dma_handle; + unsigned long flags; + int return_status = IO_OK; + +resend_cmd2: + c->waiting = &wait; + /* Put the request on the tail of the queue and send it */ + spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); + addQ(&h->reqQ, c); + h->Qdepth++; + start_io(h); + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + + wait_for_completion(&wait); + + if (c->err_info->CommandStatus == 0 || !attempt_retry) + goto command_done; + + return_status = process_sendcmd_error(h, c); + + if (return_status == IO_NEEDS_RETRY && + c->retry_count < MAX_CMD_RETRIES) { + printk(KERN_WARNING "cciss%d: retrying 0x%02x\n", h->ctlr, + c->Request.CDB[0]); + c->retry_count++; + /* erase the old error information */ + memset(c->err_info, 0, sizeof(ErrorInfo_struct)); + return_status = IO_OK; + INIT_COMPLETION(wait); + goto resend_cmd2; + } command_done: /* unlock the buffers from DMA */ @@ -2399,7 +2411,8 @@ static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size, return_status = fill_cmd(c, cmd, ctlr, buff, size, page_code, scsi3addr, cmd_type); if (return_status == IO_OK) - return_status = sendcmd_withirq_core(h, c); + return_status = sendcmd_withirq_core(h, c, 1); + cmd_free(h, c, 0); return return_status; } diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index dd1926d..25cd58e 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h @@ -11,6 +11,7 @@ #define IO_OK 0 #define IO_ERROR 1 +#define IO_NEEDS_RETRY 3 #define VENDOR_LEN 8 #define MODEL_LEN 16 -- cgit v0.10.2 From 85cc61ae41084cb6d8ecc6c9e01ac4563005c8ac Mon Sep 17 00:00:00 2001 From: "scameron@beardog.cca.cpqcorp.net" Date: Mon, 8 Jun 2009 16:07:45 -0500 Subject: cciss: change SCSI error handling routines to work with interrupts enabled. Change cciss scsi error handling routines to work with interrupts enabled. Signed-off-by: Stephen M. Cameron Signed-off-by: Jens Axboe diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 7001707..9a9db6d 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -184,6 +184,9 @@ static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size, __u8 page_code, unsigned char scsi3addr[], int cmd_type); +static int sendcmd_withirq_core(ctlr_info_t *h, CommandList_struct *c, + int attempt_retry); +static int process_sendcmd_error(ctlr_info_t *h, CommandList_struct *c); static void fail_all_cmds(unsigned long ctlr); static int scan_thread(void *data); diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index 007ab8a..d2eb489 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -49,8 +49,6 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, __u8 page_code, unsigned char *scsi3addr, int cmd_type); -static int sendcmd_core(ctlr_info_t *h, CommandList_struct *c); - static CommandList_struct *cmd_alloc(ctlr_info_t *h, int get_from_pool); static void cmd_free(ctlr_info_t *h, CommandList_struct *c, int got_from_pool); @@ -1601,11 +1599,10 @@ static int wait_for_device_to_become_ready(ctlr_info_t *h, /* Send the Test Unit Ready */ rc = fill_cmd(c, TEST_UNIT_READY, h->ctlr, NULL, 0, 0, lunaddr, TYPE_CMD); - if (rc == 0) { - rc = sendcmd_core(h, c); - /* sendcmd turned off interrupts, turn 'em back on. */ - h->access.set_intr_mask(h, CCISS_INTR_ON); - } + if (rc == 0) + rc = sendcmd_withirq_core(h, c, 0); + + (void) process_sendcmd_error(h, c); if (rc == 0 && c->err_info->CommandStatus == CMD_SUCCESS) break; @@ -1663,10 +1660,8 @@ static int cciss_eh_device_reset_handler(struct scsi_cmnd *scsicmd) return FAILED; memcpy(lunaddr, &cmd_in_trouble->Header.LUN.LunAddrBytes[0], 8); /* send a reset to the SCSI LUN which the command was sent to */ - rc = sendcmd(CCISS_RESET_MSG, ctlr, NULL, 0, 0, lunaddr, + rc = sendcmd_withirq(CCISS_RESET_MSG, ctlr, NULL, 0, 0, lunaddr, TYPE_MSG); - /* sendcmd turned off interrupts on the board, turn 'em back on. */ - (*c)->access.set_intr_mask(*c, CCISS_INTR_ON); if (rc == 0 && wait_for_device_to_become_ready(*c, lunaddr) == 0) return SUCCESS; printk(KERN_WARNING "cciss%d: resetting device failed.\n", ctlr); @@ -1677,6 +1672,7 @@ static int cciss_eh_abort_handler(struct scsi_cmnd *scsicmd) { int rc; CommandList_struct *cmd_to_abort; + unsigned char lunaddr[8]; ctlr_info_t **c; int ctlr; @@ -1691,11 +1687,9 @@ static int cciss_eh_abort_handler(struct scsi_cmnd *scsicmd) cmd_to_abort = (CommandList_struct *) scsicmd->host_scribble; if (cmd_to_abort == NULL) /* paranoia */ return FAILED; - rc = sendcmd(CCISS_ABORT_MSG, ctlr, &cmd_to_abort->Header.Tag, 0, 0, - (unsigned char *) &cmd_to_abort->Header.LUN.LunAddrBytes[0], - TYPE_MSG); - /* sendcmd turned off interrupts on the board, turn 'em back on. */ - (*c)->access.set_intr_mask(*c, CCISS_INTR_ON); + memcpy(lunaddr, &cmd_to_abort->Header.LUN.LunAddrBytes[0], 8); + rc = sendcmd_withirq(CCISS_ABORT_MSG, ctlr, &cmd_to_abort->Header.Tag, + 0, 0, lunaddr, TYPE_MSG); if (rc == 0) return SUCCESS; return FAILED; -- cgit v0.10.2 From 72f9f1324fc4cd450c92e4600a710231b0445c75 Mon Sep 17 00:00:00 2001 From: "scameron@beardog.cca.cpqcorp.net" Date: Mon, 8 Jun 2009 16:09:32 -0500 Subject: cciss: Remove no longer needed sendcmd reject processing code Now that the cciss SCSI error handling routines operate with interrupts enabled, we no longer need to maintain the list of command completions that sendcmd() might inadvertantly scoop up, since now it only runs at driver init time, and there won't be any other commands for it to scoop up. So we can remove that list and the code that adds to it and processes it. Signed-off-by: Stephen M. Cameron Signed-off-by: Jens Axboe diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 9a9db6d..b22cec9 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -2612,51 +2612,6 @@ static unsigned long pollcomplete(int ctlr) return 1; } -static int add_sendcmd_reject(__u8 cmd, int ctlr, unsigned long complete) -{ - /* We get in here if sendcmd() is polling for completions - and gets some command back that it wasn't expecting -- - something other than that which it just sent down. - Ordinarily, that shouldn't happen, but it can happen when - the scsi tape stuff gets into error handling mode, and - starts using sendcmd() to try to abort commands and - reset tape drives. In that case, sendcmd may pick up - completions of commands that were sent to logical drives - through the block i/o system, or cciss ioctls completing, etc. - In that case, we need to save those completions for later - processing by the interrupt handler. - */ - -#ifdef CONFIG_CISS_SCSI_TAPE - struct sendcmd_reject_list *srl = &hba[ctlr]->scsi_rejects; - - /* If it's not the scsi tape stuff doing error handling, (abort */ - /* or reset) then we don't expect anything weird. */ - if (cmd != CCISS_RESET_MSG && cmd != CCISS_ABORT_MSG) { -#endif - printk(KERN_WARNING "cciss cciss%d: SendCmd " - "Invalid command list address returned! (%lx)\n", - ctlr, complete); - /* not much we can do. */ -#ifdef CONFIG_CISS_SCSI_TAPE - return 1; - } - - /* We've sent down an abort or reset, but something else - has completed */ - if (srl->ncompletions >= (hba[ctlr]->nr_cmds + 2)) { - /* Uh oh. No room to save it for later... */ - printk(KERN_WARNING "cciss%d: Sendcmd: Invalid command addr, " - "reject list overflow, command lost!\n", ctlr); - return 1; - } - /* Save it for later */ - srl->complete[srl->ncompletions] = complete; - srl->ncompletions++; -#endif - return 0; -} - /* Send command c to controller h and poll for it to complete. * Turns interrupts off on the board. Used at driver init time * and during SCSI error recovery. @@ -2701,11 +2656,10 @@ resend_cmd1: break; } - /* If it's not the cmd we're looking for, save it for later */ + /* Make sure it's the command we're expecting. */ if ((complete & ~CISS_ERROR_BIT) != c->busaddr) { - if (add_sendcmd_reject(c->Request.CDB[0], - h->ctlr, complete) != 0) - BUG(); /* we are hosed if we get here. */ + printk(KERN_WARNING "cciss%d: Unexpected command " + "completion.\n", h->ctlr); continue; } @@ -2770,11 +2724,6 @@ resend_cmd1: buff_dma_handle.val32.upper = c->SG[0].Addr.upper; pci_unmap_single(h->pdev, (dma_addr_t) buff_dma_handle.val, c->SG[0].Len, PCI_DMA_BIDIRECTIONAL); -#ifdef CONFIG_CISS_SCSI_TAPE - /* if we saved some commands for later, process them now. */ - if (h->scsi_rejects.ncompletions > 0) - do_cciss_intr(0, h); -#endif return status; } @@ -3195,44 +3144,18 @@ startio: static inline unsigned long get_next_completion(ctlr_info_t *h) { -#ifdef CONFIG_CISS_SCSI_TAPE - /* Any rejects from sendcmd() lying around? Process them first */ - if (h->scsi_rejects.ncompletions == 0) - return h->access.command_completed(h); - else { - struct sendcmd_reject_list *srl; - int n; - srl = &h->scsi_rejects; - n = --srl->ncompletions; - /* printk("cciss%d: processing saved reject\n", h->ctlr); */ - printk("p"); - return srl->complete[n]; - } -#else return h->access.command_completed(h); -#endif } static inline int interrupt_pending(ctlr_info_t *h) { -#ifdef CONFIG_CISS_SCSI_TAPE - return (h->access.intr_pending(h) - || (h->scsi_rejects.ncompletions > 0)); -#else return h->access.intr_pending(h); -#endif } static inline long interrupt_not_for_us(ctlr_info_t *h) { -#ifdef CONFIG_CISS_SCSI_TAPE - return (((h->access.intr_pending(h) == 0) || - (h->interrupts_enabled == 0)) - && (h->scsi_rejects.ncompletions == 0)); -#else return (((h->access.intr_pending(h) == 0) || (h->interrupts_enabled == 0))); -#endif } static irqreturn_t do_cciss_intr(int irq, void *dev_id) @@ -4054,15 +3977,6 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, printk(KERN_ERR "cciss: out of memory"); goto clean4; } -#ifdef CONFIG_CISS_SCSI_TAPE - hba[i]->scsi_rejects.complete = - kmalloc(sizeof(hba[i]->scsi_rejects.complete[0]) * - (hba[i]->nr_cmds + 5), GFP_KERNEL); - if (hba[i]->scsi_rejects.complete == NULL) { - printk(KERN_ERR "cciss: out of memory"); - goto clean4; - } -#endif spin_lock_init(&hba[i]->lock); /* Initialize the pdev driver private data. @@ -4122,9 +4036,6 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, clean4: kfree(inq_buff); -#ifdef CONFIG_CISS_SCSI_TAPE - kfree(hba[i]->scsi_rejects.complete); -#endif kfree(hba[i]->cmd_pool_bits); if (hba[i]->cmd_pool) pci_free_consistent(hba[i]->pdev, @@ -4242,9 +4153,6 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev) pci_free_consistent(hba[i]->pdev, hba[i]->nr_cmds * sizeof(ErrorInfo_struct), hba[i]->errinfo_pool, hba[i]->errinfo_pool_dhandle); kfree(hba[i]->cmd_pool_bits); -#ifdef CONFIG_CISS_SCSI_TAPE - kfree(hba[i]->scsi_rejects.complete); -#endif /* * Deliberately omit pci_disable_device(): it does something nasty to * Smart Array controllers that pci_enable_device does not undo diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index 25cd58e..06a5db2 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h @@ -53,14 +53,6 @@ typedef struct _drive_info_struct char rev[REV_LEN + 1]; /* SCSI revision string */ } drive_info_struct; -#ifdef CONFIG_CISS_SCSI_TAPE - -struct sendcmd_reject_list { - int ncompletions; - unsigned long *complete; /* array of NR_CMDS tags */ -}; - -#endif struct ctlr_info { int ctlr; @@ -128,7 +120,6 @@ struct ctlr_info void *scsi_ctlr; /* ptr to structure containing scsi related stuff */ /* list of block side commands the scsi error handling sucked up */ /* and saved for later processing */ - struct sendcmd_reject_list scsi_rejects; #endif unsigned char alive; struct completion *rescan_wait; -- cgit v0.10.2 From 3969251b80a7b143d01576780073fe0cc9ef6253 Mon Sep 17 00:00:00 2001 From: "scameron@beardog.cca.cpqcorp.net" Date: Mon, 8 Jun 2009 16:10:57 -0500 Subject: cciss: decode unit attention in SCSI error handling code Make SCSI reset error handler decode unit attention ASC and after a target reset wait for a unit attention that indicates a reset occurred rather than just for any old unit attention. Signed-off-by: Stephen M. Cameron Signed-off-by: Jens Axboe diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index d2eb489..3315268 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -1604,16 +1604,25 @@ static int wait_for_device_to_become_ready(ctlr_info_t *h, (void) process_sendcmd_error(h, c); - if (rc == 0 && c->err_info->CommandStatus == CMD_SUCCESS) - break; + if (rc != 0) + goto retry_tur; - if (rc == 0 && - c->err_info->CommandStatus == CMD_TARGET_STATUS && - c->err_info->ScsiStatus == SAM_STAT_CHECK_CONDITION && - (c->err_info->SenseInfo[2] == NO_SENSE || - c->err_info->SenseInfo[2] == UNIT_ATTENTION)) + if (c->err_info->CommandStatus == CMD_SUCCESS) break; + if (c->err_info->CommandStatus == CMD_TARGET_STATUS && + c->err_info->ScsiStatus == SAM_STAT_CHECK_CONDITION) { + if (c->err_info->SenseInfo[2] == NO_SENSE) + break; + if (c->err_info->SenseInfo[2] == UNIT_ATTENTION) { + unsigned char asc; + asc = c->err_info->SenseInfo[12]; + check_for_unit_attention(h, c); + if (asc == POWER_OR_RESET) + break; + } + } +retry_tur: printk(KERN_WARNING "cciss%d: Waiting %d secs " "for device to become ready.\n", h->ctlr, waittime / HZ); -- cgit v0.10.2 From 9df1bb9b516daeece159ab7fb262d01a0359247c Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 9 Jun 2009 06:22:57 +0200 Subject: Revert "block: Fix bounce limit setting in DM" This reverts commit a05c0205ba031c01bba33a21bf0a35920eb64833. DM doesn't need to access the bounce_pfn directly. Signed-off-by: Jens Axboe diff --git a/block/blk-settings.c b/block/blk-settings.c index 9acd0b7..8d33934 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -194,23 +194,6 @@ void blk_queue_bounce_limit(struct request_queue *q, u64 dma_mask) EXPORT_SYMBOL(blk_queue_bounce_limit); /** - * blk_queue_bounce_pfn - set the bounce buffer limit for queue - * @q: the request queue for the device - * @pfn: max address - * - * Description: - * This function is similar to blk_queue_bounce_limit except it - * neither changes allocation flags, nor does it set up the ISA DMA - * pool. This function should only be used by stacking drivers. - * Hardware drivers should use blk_queue_bounce_limit instead. - */ -void blk_queue_bounce_pfn(struct request_queue *q, u64 pfn) -{ - q->limits.bounce_pfn = pfn; -} -EXPORT_SYMBOL(blk_queue_bounce_pfn); - -/** * blk_queue_max_sectors - set max sectors for a request for this queue * @q: the request queue for the device * @max_sectors: max sectors in the usual 512b unit diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 3ca1604..e9a73bb 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -920,7 +920,7 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q) blk_queue_max_segment_size(q, t->limits.max_segment_size); blk_queue_max_hw_sectors(q, t->limits.max_hw_sectors); blk_queue_segment_boundary(q, t->limits.seg_boundary_mask); - blk_queue_bounce_pfn(q, t->limits.bounce_pfn); + blk_queue_bounce_limit(q, t->limits.bounce_pfn); if (t->limits.no_cluster) queue_flag_clear_unlocked(QUEUE_FLAG_CLUSTER, q); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 989aa17..5e740a1 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -910,7 +910,6 @@ extern struct request_queue *blk_init_queue(request_fn_proc *, spinlock_t *); extern void blk_cleanup_queue(struct request_queue *); extern void blk_queue_make_request(struct request_queue *, make_request_fn *); extern void blk_queue_bounce_limit(struct request_queue *, u64); -extern void blk_queue_bounce_pfn(struct request_queue *, u64); extern void blk_queue_max_sectors(struct request_queue *, unsigned int); extern void blk_queue_max_hw_sectors(struct request_queue *, unsigned int); extern void blk_queue_max_phys_segments(struct request_queue *, unsigned short); -- cgit v0.10.2 From 77634f33d4078542cf1087995cced0ffdae25aa2 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Tue, 9 Jun 2009 06:23:22 +0200 Subject: block: Add missing bounce_pfn stacking and fix comments DM no longer needs to set limits explicitly when calling blk_stack_limits. Let the latter automatically deal with bounce_pfn scaling. Fix kerneldoc variable names. Signed-off-by: Martin K. Petersen Signed-off-by: Jens Axboe diff --git a/block/blk-settings.c b/block/blk-settings.c index 8d33934..1c4df9b 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -445,7 +445,7 @@ EXPORT_SYMBOL(blk_queue_stack_limits); /** * blk_stack_limits - adjust queue_limits for stacked devices * @t: the stacking driver limits (top) - * @bdev: the underlying queue limits (bottom) + * @b: the underlying queue limits (bottom) * @offset: offset to beginning of data within component device * * Description: @@ -458,6 +458,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, { t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors); t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors); + t->bounce_pfn = min_not_zero(t->bounce_pfn, b->bounce_pfn); t->seg_boundary_mask = min_not_zero(t->seg_boundary_mask, b->seg_boundary_mask); @@ -504,7 +505,7 @@ EXPORT_SYMBOL(blk_stack_limits); /** * disk_stack_limits - adjust queue limits for stacked drivers - * @t: MD/DM gendisk (top) + * @disk: MD/DM gendisk (top) * @bdev: the underlying block device (bottom) * @offset: offset to beginning of data within component device * -- cgit v0.10.2 From 1d589bb16b825b3a7b4edd34d997f1f1f953033d Mon Sep 17 00:00:00 2001 From: john cooper Date: Tue, 9 Jun 2009 14:41:40 +0200 Subject: Add serial number support for virtio_blk, V4a This patch extracts the opaque data from pci i/o region 0 via the added VIRTIO_BLK_F_IDENTIFY field. By convention this data takes the form of that returned by an ATA IDENTIFY DEVICE command, however the driver (except for structure size) makes no interpretation of the data. The structure data is copied wholesale to userspace via a HDIO_GET_IDENTITY ioctl command (eg: hdparm -i ). Signed-off-by: john cooper Signed-off-by: Rusty Russell Signed-off-by: Jens Axboe diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index c4845b1..c0facaa 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -171,11 +171,43 @@ static void do_virtblk_request(struct request_queue *q) vblk->vq->vq_ops->kick(vblk->vq); } +/* return ATA identify data + */ +static int virtblk_identify(struct gendisk *disk, void *argp) +{ + struct virtio_blk *vblk = disk->private_data; + void *opaque; + int err = -ENOMEM; + + opaque = kmalloc(VIRTIO_BLK_ID_BYTES, GFP_KERNEL); + if (!opaque) + goto out; + + err = virtio_config_buf(vblk->vdev, VIRTIO_BLK_F_IDENTIFY, + offsetof(struct virtio_blk_config, identify), opaque, + VIRTIO_BLK_ID_BYTES); + + if (err) + goto out_kfree; + + if (copy_to_user(argp, opaque, VIRTIO_BLK_ID_BYTES)) + err = -EFAULT; + +out_kfree: + kfree(opaque); +out: + return err; +} + static int virtblk_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, unsigned long data) { struct gendisk *disk = bdev->bd_disk; struct virtio_blk *vblk = disk->private_data; + void __user *argp = (void __user *)data; + + if (cmd == HDIO_GET_IDENTITY) + return virtblk_identify(disk, argp); /* * Only allow the generic SCSI ioctls if the host can support it. @@ -183,8 +215,7 @@ static int virtblk_ioctl(struct block_device *bdev, fmode_t mode, if (!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_SCSI)) return -ENOIOCTLCMD; - return scsi_cmd_ioctl(disk->queue, disk, mode, cmd, - (void __user *)data); + return scsi_cmd_ioctl(disk->queue, disk, mode, cmd, argp); } /* We provide getgeo only to please some old bootloader/partitioning tools */ @@ -390,7 +421,7 @@ static struct virtio_device_id id_table[] = { static unsigned int features[] = { VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, - VIRTIO_BLK_F_SCSI, + VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_IDENTIFY }; static struct virtio_driver virtio_blk = { diff --git a/include/linux/virtio_blk.h b/include/linux/virtio_blk.h index 4dbcbc1..be7d255 100644 --- a/include/linux/virtio_blk.h +++ b/include/linux/virtio_blk.h @@ -16,6 +16,9 @@ #define VIRTIO_BLK_F_RO 5 /* Disk is read-only */ #define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available*/ #define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */ +#define VIRTIO_BLK_F_IDENTIFY 8 /* ATA IDENTIFY supported */ + +#define VIRTIO_BLK_ID_BYTES (sizeof(__u16[256])) /* IDENTIFY DATA */ struct virtio_blk_config { @@ -33,6 +36,7 @@ struct virtio_blk_config } geometry; /* block size of device (if VIRTIO_BLK_F_BLK_SIZE) */ __u32 blk_size; + __u8 identify[VIRTIO_BLK_ID_BYTES]; } __attribute__((packed)); /* These two define direction. */ -- cgit v0.10.2 From d9c7d394a8ebacb60097b192939ae9f15235225e Mon Sep 17 00:00:00 2001 From: Nikanth Karthikesan Date: Wed, 10 Jun 2009 12:57:06 -0700 Subject: block: prevent possible io_context->refcount overflow Currently io_context has an atomic_t(32-bit) as refcount. In the case of cfq, for each device against whcih a task does I/O, a reference to the io_context would be taken. And when there are multiple process sharing io_contexts(CLONE_IO) would also have a reference to the same io_context. Theoretically the possible maximum number of processes sharing the same io_context + the number of disks/cfq_data referring to the same io_context can overflow the 32-bit counter on a very high-end machine. Even though it is an improbable case, let us make it atomic_long_t. Signed-off-by: Nikanth Karthikesan Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe diff --git a/block/blk-ioc.c b/block/blk-ioc.c index 012f065..d4ed600 100644 --- a/block/blk-ioc.c +++ b/block/blk-ioc.c @@ -35,9 +35,9 @@ int put_io_context(struct io_context *ioc) if (ioc == NULL) return 1; - BUG_ON(atomic_read(&ioc->refcount) == 0); + BUG_ON(atomic_long_read(&ioc->refcount) == 0); - if (atomic_dec_and_test(&ioc->refcount)) { + if (atomic_long_dec_and_test(&ioc->refcount)) { rcu_read_lock(); if (ioc->aic && ioc->aic->dtor) ioc->aic->dtor(ioc->aic); @@ -90,7 +90,7 @@ struct io_context *alloc_io_context(gfp_t gfp_flags, int node) ret = kmem_cache_alloc_node(iocontext_cachep, gfp_flags, node); if (ret) { - atomic_set(&ret->refcount, 1); + atomic_long_set(&ret->refcount, 1); atomic_set(&ret->nr_tasks, 1); spin_lock_init(&ret->lock); ret->ioprio_changed = 0; @@ -151,7 +151,7 @@ struct io_context *get_io_context(gfp_t gfp_flags, int node) ret = current_io_context(gfp_flags, node); if (unlikely(!ret)) break; - } while (!atomic_inc_not_zero(&ret->refcount)); + } while (!atomic_long_inc_not_zero(&ret->refcount)); return ret; } @@ -163,8 +163,8 @@ void copy_io_context(struct io_context **pdst, struct io_context **psrc) struct io_context *dst = *pdst; if (src) { - BUG_ON(atomic_read(&src->refcount) == 0); - atomic_inc(&src->refcount); + BUG_ON(atomic_long_read(&src->refcount) == 0); + atomic_long_inc(&src->refcount); put_io_context(dst); *pdst = src; } diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 99ac430..ef2f72d 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -1282,7 +1282,7 @@ static void cfq_dispatch_request(struct cfq_data *cfqd, struct cfq_queue *cfqq) if (!cfqd->active_cic) { struct cfq_io_context *cic = RQ_CIC(rq); - atomic_inc(&cic->ioc->refcount); + atomic_long_inc(&cic->ioc->refcount); cfqd->active_cic = cic; } } diff --git a/include/linux/iocontext.h b/include/linux/iocontext.h index 08b987b..dd05434 100644 --- a/include/linux/iocontext.h +++ b/include/linux/iocontext.h @@ -64,7 +64,7 @@ struct cfq_io_context { * and kmalloc'ed. These could be shared between processes. */ struct io_context { - atomic_t refcount; + atomic_long_t refcount; atomic_t nr_tasks; /* all the fields below are protected by this lock */ @@ -91,8 +91,8 @@ static inline struct io_context *ioc_task_link(struct io_context *ioc) * if ref count is zero, don't allow sharing (ioc is going away, it's * a race). */ - if (ioc && atomic_inc_not_zero(&ioc->refcount)) { - atomic_inc(&ioc->nr_tasks); + if (ioc && atomic_long_inc_not_zero(&ioc->refcount)) { + atomic_long_inc(&ioc->refcount); return ioc; } -- cgit v0.10.2 From 0e0c62123b517d2b3c26922342c0cc5bb63a93f8 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 10 Jun 2009 12:57:07 -0700 Subject: fs/bio.c: add missing __user annotation As reported by sparse: fs/bio.c:720:13: warning: incorrect type in assignment (different address spaces) fs/bio.c:720:13: expected char *iov_addr fs/bio.c:720:13: got void [noderef] * fs/bio.c:724:36: warning: incorrect type in argument 2 (different address spaces) fs/bio.c:724:36: expected void const [noderef] *from fs/bio.c:724:36: got char *iov_addr Signed-off-by: Michal Simek Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe diff --git a/fs/bio.c b/fs/bio.c index ab423a1..533266a 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -722,7 +722,7 @@ static int __bio_copy_iov(struct bio *bio, struct bio_vec *iovecs, while (bv_len && iov_idx < iov_count) { unsigned int bytes; - char *iov_addr; + char __user *iov_addr; bytes = min_t(unsigned int, iov[iov_idx].iov_len - iov_off, bv_len); -- cgit v0.10.2 From 1adbee50fd6fce5af4feb34d2db93cfe4d2066a4 Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Wed, 10 Jun 2009 12:57:08 -0700 Subject: ramdisk: remove long-deprecated "ramdisk=" boot-time parameter The "ramdisk" parameter was removed from the defunct rd.c file quite some time ago, in favour of the more specific "ramdisk_size" parameter so, for consistency, the same should be done here. Signed-off-by: Robert P. J. Day Acked-by: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe diff --git a/drivers/block/brd.c b/drivers/block/brd.c index 5f7e64b..4bf8705 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -407,12 +407,7 @@ static int __init ramdisk_size(char *str) rd_size = simple_strtol(str, NULL, 0); return 1; } -static int __init ramdisk_size2(char *str) -{ - return ramdisk_size(str); -} -__setup("ramdisk=", ramdisk_size); -__setup("ramdisk_size=", ramdisk_size2); +__setup("ramdisk_size=", ramdisk_size); #endif /* -- cgit v0.10.2 From 5e50b9ef975219304cc91d601530994861585bfe Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Wed, 10 Jun 2009 12:57:09 -0700 Subject: floppy: fix hibernation Based on Ingo Molnar's patch from 2006, this makes the floppy work after resume from hibernation, at least on my machine. This fix resets the floppy controller on resume. It was experimentally determined to bring the controller back to life - we don't really know why it works. floppy_init() does the same thing at boot/modprobe time. Signed-off-by: Ondrej Zary Cc: "Rafael J. Wysocki" Cc: Ingo Molnar Acked-by: Pavel Machek Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 90877fe..862b40c 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -4148,6 +4148,24 @@ static void floppy_device_release(struct device *dev) { } +static int floppy_resume(struct platform_device *dev) +{ + int fdc; + + for (fdc = 0; fdc < N_FDC; fdc++) + if (FDCS->address != -1) + user_reset_fdc(-1, FD_RESET_ALWAYS, 0); + + return 0; +} + +static struct platform_driver floppy_driver = { + .resume = floppy_resume, + .driver = { + .name = "floppy", + }, +}; + static struct platform_device floppy_device[N_DRIVE]; static struct kobject *floppy_find(dev_t dev, int *part, void *data) @@ -4196,10 +4214,14 @@ static int __init floppy_init(void) if (err) goto out_put_disk; + err = platform_driver_register(&floppy_driver); + if (err) + goto out_unreg_blkdev; + floppy_queue = blk_init_queue(do_fd_request, &floppy_lock); if (!floppy_queue) { err = -ENOMEM; - goto out_unreg_blkdev; + goto out_unreg_driver; } blk_queue_max_sectors(floppy_queue, 64); @@ -4346,6 +4368,8 @@ out_flush_work: out_unreg_region: blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256); blk_cleanup_queue(floppy_queue); +out_unreg_driver: + platform_driver_unregister(&floppy_driver); out_unreg_blkdev: unregister_blkdev(FLOPPY_MAJOR, "fd"); out_put_disk: @@ -4566,6 +4590,7 @@ static void __exit floppy_module_exit(void) blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256); unregister_blkdev(FLOPPY_MAJOR, "fd"); + platform_driver_unregister(&floppy_driver); for (drive = 0; drive < N_DRIVE; drive++) { del_timer_sync(&motor_off_timer[drive]); -- cgit v0.10.2 From b0fd271d5fba0b2d00888363f3869e3f9b26caa9 Mon Sep 17 00:00:00 2001 From: Kiyoshi Ueda Date: Thu, 11 Jun 2009 13:10:16 +0200 Subject: block: add request clone interface (v2) This patch adds the following 2 interfaces for request-stacking drivers: - blk_rq_prep_clone(struct request *clone, struct request *orig, struct bio_set *bs, gfp_t gfp_mask, int (*bio_ctr)(struct bio *, struct bio*, void *), void *data) * Clones bios in the original request to the clone request (bio_ctr is called for each cloned bios.) * Copies attributes of the original request to the clone request. The actual data parts (e.g. ->cmd, ->buffer, ->sense) are not copied. - blk_rq_unprep_clone(struct request *clone) * Frees cloned bios from the clone request. Request stacking drivers (e.g. request-based dm) need to make a clone request for a submitted request and dispatch it to other devices. To allocate request for the clone, request stacking drivers may not be able to use blk_get_request() because the allocation may be done in an irq-disabled context. So blk_rq_prep_clone() takes a request allocated by the caller as an argument. For each clone bio in the clone request, request stacking drivers should be able to set up their own completion handler. So blk_rq_prep_clone() takes a callback function which is called for each clone bio, and a pointer for private data which is passed to the callback. NOTE: blk_rq_prep_clone() doesn't copy any actual data of the original request. Pages are shared between original bios and cloned bios. So caller must not complete the original request before the clone request. Signed-off-by: Kiyoshi Ueda Signed-off-by: Jun'ichi Nomura Cc: Boaz Harrosh Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index 03c5a64..02a9252 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -2295,6 +2295,106 @@ int blk_lld_busy(struct request_queue *q) } EXPORT_SYMBOL_GPL(blk_lld_busy); +/** + * blk_rq_unprep_clone - Helper function to free all bios in a cloned request + * @rq: the clone request to be cleaned up + * + * Description: + * Free all bios in @rq for a cloned request. + */ +void blk_rq_unprep_clone(struct request *rq) +{ + struct bio *bio; + + while ((bio = rq->bio) != NULL) { + rq->bio = bio->bi_next; + + bio_put(bio); + } +} +EXPORT_SYMBOL_GPL(blk_rq_unprep_clone); + +/* + * Copy attributes of the original request to the clone request. + * The actual data parts (e.g. ->cmd, ->buffer, ->sense) are not copied. + */ +static void __blk_rq_prep_clone(struct request *dst, struct request *src) +{ + dst->cpu = src->cpu; + dst->cmd_flags = (rq_data_dir(src) | REQ_NOMERGE); + dst->cmd_type = src->cmd_type; + dst->__sector = blk_rq_pos(src); + dst->__data_len = blk_rq_bytes(src); + dst->nr_phys_segments = src->nr_phys_segments; + dst->ioprio = src->ioprio; + dst->extra_len = src->extra_len; +} + +/** + * blk_rq_prep_clone - Helper function to setup clone request + * @rq: the request to be setup + * @rq_src: original request to be cloned + * @bs: bio_set that bios for clone are allocated from + * @gfp_mask: memory allocation mask for bio + * @bio_ctr: setup function to be called for each clone bio. + * Returns %0 for success, non %0 for failure. + * @data: private data to be passed to @bio_ctr + * + * Description: + * Clones bios in @rq_src to @rq, and copies attributes of @rq_src to @rq. + * The actual data parts of @rq_src (e.g. ->cmd, ->buffer, ->sense) + * are not copied, and copying such parts is the caller's responsibility. + * Also, pages which the original bios are pointing to are not copied + * and the cloned bios just point same pages. + * So cloned bios must be completed before original bios, which means + * the caller must complete @rq before @rq_src. + */ +int blk_rq_prep_clone(struct request *rq, struct request *rq_src, + struct bio_set *bs, gfp_t gfp_mask, + int (*bio_ctr)(struct bio *, struct bio *, void *), + void *data) +{ + struct bio *bio, *bio_src; + + if (!bs) + bs = fs_bio_set; + + blk_rq_init(NULL, rq); + + __rq_for_each_bio(bio_src, rq_src) { + bio = bio_alloc_bioset(gfp_mask, bio_src->bi_max_vecs, bs); + if (!bio) + goto free_and_out; + + __bio_clone(bio, bio_src); + + if (bio_integrity(bio_src) && + bio_integrity_clone(bio, bio_src, gfp_mask)) + goto free_and_out; + + if (bio_ctr && bio_ctr(bio, bio_src, data)) + goto free_and_out; + + if (rq->bio) { + rq->biotail->bi_next = bio; + rq->biotail = bio; + } else + rq->bio = rq->biotail = bio; + } + + __blk_rq_prep_clone(rq, rq_src); + + return 0; + +free_and_out: + if (bio) + bio_free(bio, bs); + blk_rq_unprep_clone(rq); + + return -ENOMEM; +} +EXPORT_SYMBOL_GPL(blk_rq_prep_clone); + int kblockd_schedule_work(struct request_queue *q, struct work_struct *work) { return queue_work(kblockd_workqueue, work); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 5e740a1..ebdfde8 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -765,6 +765,11 @@ extern void blk_insert_request(struct request_queue *, struct request *, int, vo extern void blk_requeue_request(struct request_queue *, struct request *); extern int blk_rq_check_limits(struct request_queue *q, struct request *rq); extern int blk_lld_busy(struct request_queue *q); +extern int blk_rq_prep_clone(struct request *rq, struct request *rq_src, + struct bio_set *bs, gfp_t gfp_mask, + int (*bio_ctr)(struct bio *, struct bio *, void *), + void *data); +extern void blk_rq_unprep_clone(struct request *rq); extern int blk_insert_cloned_request(struct request_queue *q, struct request *rq); extern void blk_plug_device(struct request_queue *); -- cgit v0.10.2