On 2018/08/06 13:51, Douglas Gilbert wrote:
> 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.

What about simply moving the REQ_OP_READ and REQ_OP_WRITE cases at the top of
the switch case list ? Since that gets (usually) compiled as a jump, the effect
should be the same, no ?

> 
> 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)
> 


-- 
Damien Le Moal
Western Digital Research

Reply via email to