Make the two block layer operations most frequently used (REQ_OP_READ and REQ_OP_WRITE) bypass the switch statements in the submission and response paths. Assume these two enums are 0 and 1 which allows a single comparison to select both of them. Check that assumption at driver start-up.
Signed-off-by: Douglas Gilbert <dgilb...@interlog.com> --- drivers/scsi/sd.c | 82 +++++++++++++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 27 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 4b1402633c36..9f047fd3c92d 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1227,6 +1227,14 @@ static int sd_init_command(struct scsi_cmnd *cmd) { struct request *rq = cmd->request; + /* + * Assumption that REQ_OP_READ and REQ_OP_WRITE are 0 and 1 is + * checked in init_sd(). The following "if" is done to dispatch + * REQ_OP_READ and REQ_OP_WRITE quickly. + */ + if (likely(req_op(rq) < 2)) + return sd_setup_read_write_cmnd(cmd); + switch (req_op(rq)) { case REQ_OP_DISCARD: switch (scsi_disk(rq->rq_disk)->provisioning_mode) { @@ -1247,9 +1255,6 @@ static int sd_init_command(struct scsi_cmnd *cmd) return sd_setup_write_same_cmnd(cmd); case REQ_OP_FLUSH: return sd_setup_flush_cmnd(cmd); - case REQ_OP_READ: - case REQ_OP_WRITE: - return sd_setup_read_write_cmnd(cmd); case REQ_OP_ZONE_REPORT: return sd_zbc_setup_report_cmnd(cmd); case REQ_OP_ZONE_RESET: @@ -1973,30 +1978,12 @@ static int sd_done(struct scsi_cmnd *SCpnt) int sense_valid = 0; int sense_deferred = 0; - switch (req_op(req)) { - case REQ_OP_DISCARD: - case REQ_OP_WRITE_ZEROES: - case REQ_OP_WRITE_SAME: - case REQ_OP_ZONE_RESET: - if (!result) { - good_bytes = blk_rq_bytes(req); - scsi_set_resid(SCpnt, 0); - } else { - good_bytes = 0; - scsi_set_resid(SCpnt, blk_rq_bytes(req)); - } - break; - case REQ_OP_ZONE_REPORT: - if (!result) { - good_bytes = scsi_bufflen(SCpnt) - - scsi_get_resid(SCpnt); - scsi_set_resid(SCpnt, 0); - } else { - good_bytes = 0; - scsi_set_resid(SCpnt, blk_rq_bytes(req)); - } - break; - default: + /* + * Assumption that REQ_OP_READ and REQ_OP_WRITE are 0 and 1 is + * checked in init_sd(). The following "if" is done to expedite + * REQ_OP_READ and REQ_OP_WRITE. + */ + if (likely(req_op(req) < 2)) { /* * In case of bogus fw or device, we could end up having * an unaligned partial completion. Check this here and force @@ -2011,6 +1998,36 @@ static int sd_done(struct scsi_cmnd *SCpnt) round_up(resid, sector_size)); scsi_set_resid(SCpnt, resid); } + } else { + switch (req_op(req)) { + case REQ_OP_DISCARD: + case REQ_OP_WRITE_ZEROES: + case REQ_OP_WRITE_SAME: + case REQ_OP_ZONE_RESET: + if (!result) { + good_bytes = blk_rq_bytes(req); + scsi_set_resid(SCpnt, 0); + } else { + good_bytes = 0; + scsi_set_resid(SCpnt, blk_rq_bytes(req)); + } + break; + case REQ_OP_ZONE_REPORT: + if (!result) { + good_bytes = scsi_bufflen(SCpnt) + - scsi_get_resid(SCpnt); + scsi_set_resid(SCpnt, 0); + } else { + good_bytes = 0; + scsi_set_resid(SCpnt, blk_rq_bytes(req)); + } + break; + default: + sd_printk(KERN_NOTICE, sdkp, "unexpected REQ_OP=%u\n", + (unsigned int)req_op(req)); + WARN_ON_ONCE(true); + break; + } } if (result) { @@ -3597,6 +3614,17 @@ static int __init init_sd(void) int majors = 0, i, err; SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n")); + /* + * The sd_init_command() and sd_done() assume REQ_OP_READ and + * REQ_OP_WRITE are 0 and 1 and will fail if they are not. If they + * are not, would prefer a compile failure but the preprocessor can't + * use enum constants. Place check here because only need to check + * early and once. + */ + if (REQ_OP_READ + REQ_OP_WRITE > 1) + pr_err("%s: REQ_OP_READ=%d REQ_OP_WRITE=%d %s.\n", __func__, + REQ_OP_READ, REQ_OP_WRITE, + "expected 0 and 1. Logic ERROR"); for (i = 0; i < SD_MAJORS; i++) { if (register_blkdev(sd_major(i), "sd") != 0) -- 2.17.1