block: unlocked completion test patch Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
diff --git a/block/blk-softirq.c b/block/blk-softirq.c index ee9c216..ebe3e1c 100644 --- a/block/blk-softirq.c +++ b/block/blk-softirq.c
@@ -101,7 +101,7 @@ .notifier_call = blk_cpu_notify, }; -void __blk_complete_request(struct request *req) +void __blk_complete_request(struct request *req, int locked) { struct request_queue *q = req->q; unsigned long flags; @@ -133,8 +133,15 @@ * entries there, someone already raised the irq but it * hasn't run yet. */ - if (list->next == &req->csd.list) - raise_softirq_irqoff(BLOCK_SOFTIRQ); + if (list->next == &req->csd.list) { + if (locked) + raise_softirq_irqoff(BLOCK_SOFTIRQ); + else { + local_irq_restore(flags); + q->softirq_done_fn(req); + return; + } + } } else if (raise_blk_irq(ccpu, req)) goto do_local; @@ -157,10 +164,19 @@ if (unlikely(blk_should_fake_timeout(req->q))) return; if (!blk_mark_rq_complete(req)) - __blk_complete_request(req); + __blk_complete_request(req, 1); } EXPORT_SYMBOL(blk_complete_request); +void blk_complete_request_nolock(struct request *req) +{ + if (unlikely(blk_should_fake_timeout(req->q))) + return; + if (!blk_mark_rq_complete(req)) + __blk_complete_request(req, 0); +} +EXPORT_SYMBOL(blk_complete_request_nolock); + static __init int blk_softirq_init(void) { int i;
diff --git a/block/blk-timeout.c b/block/blk-timeout.c index 1ba7e0a..55ec995 100644 --- a/block/blk-timeout.c +++ b/block/blk-timeout.c
@@ -84,7 +84,7 @@ ret = q->rq_timed_out_fn(req); switch (ret) { case BLK_EH_HANDLED: - __blk_complete_request(req); + __blk_complete_request(req, 0); break; case BLK_EH_RESET_TIMER: blk_clear_rq_complete(req);
diff --git a/block/blk.h b/block/blk.h index 42e63e85..b97654a 100644 --- a/block/blk.h +++ b/block/blk.h
@@ -81,6 +81,8 @@ elv_call_deactivate_req_fn(q, rq); } +extern void __blk_complete_request(struct request *, int); + #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/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index d23aaaa..9129749 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c
@@ -2616,6 +2616,7 @@ cmd->result = SAM_STAT_GOOD; } + cmd->unlocked = 1; qc->scsidone(cmd); ata_qc_free(qc); }
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 7f1b266..5e968bc 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c
@@ -757,7 +757,10 @@ */ static void scsi_done(struct scsi_cmnd *cmd) { - blk_complete_request(cmd->request); + if (cmd->unlocked) + blk_complete_request_nolock(cmd->request); + else + blk_complete_request(cmd->request); } /* Move this to a header if it becomes more generally useful */
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 8436caf..e7b0e6f 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h
@@ -921,7 +921,7 @@ extern bool __blk_end_request_err(struct request *rq, int error); extern void blk_complete_request(struct request *); -extern void __blk_complete_request(struct request *); +extern void blk_complete_request_nolock(struct request *); extern void blk_abort_request(struct request *); extern void blk_abort_queue(struct request_queue *);
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index db2440f..860bb77 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h
@@ -75,6 +75,7 @@ int retries; int allowed; + int unlocked; unsigned char prot_op; unsigned char prot_type;