From: Bart Van Assche bvanassche@acm.org
stable inclusion from stable-v5.10.206 commit f2d30198c0530b8da155697d8723e19ac72c15fe category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/I8ZD3X CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=v...
-------------------------
[ Upstream commit bf23e619039d360d503b7282d030daf2277a5d47 ]
Conditional statements are faster than indirect calls. Use a structure member to track the SCSI command submitter such that later patches can call scsi_done(scmd) instead of scmd->scsi_done(scmd).
The asymmetric behavior that scsi_send_eh_cmnd() sets the submission context to the SCSI error handler and that it does not restore the submission context to the SCSI core is retained.
Link: https://lore.kernel.org/r/20211007202923.2174984-2-bvanassche@acm.org Cc: Hannes Reinecke hare@suse.com Cc: Ming Lei ming.lei@redhat.com Cc: Christoph Hellwig hch@lst.de Reviewed-by: Benjamin Block bblock@linux.ibm.com Reviewed-by: Bean Huo beanhuo@micron.com Signed-off-by: Bart Van Assche bvanassche@acm.org Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Stable-dep-of: 066c5b46b6ea ("scsi: core: Always send batch on reset or error handling command") Signed-off-by: Sasha Levin sashal@kernel.org Signed-off-by: Li Lingfeng lilingfeng3@huawei.com Signed-off-by: Li Lingfeng lilingfeng3@huawei.com --- drivers/scsi/scsi_error.c | 17 ++++++----------- drivers/scsi/scsi_lib.c | 10 ++++++++++ drivers/scsi/scsi_priv.h | 1 + include/scsi/scsi_cmnd.h | 7 +++++++ 4 files changed, 24 insertions(+), 11 deletions(-)
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 89189b65e5eb..93374173b957 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -50,8 +50,6 @@
#include <asm/unaligned.h>
-static void scsi_eh_done(struct scsi_cmnd *scmd); - /* * These should *probably* be handled by the host itself. * Since it is allowed to sleep, it probably should. @@ -500,7 +498,8 @@ int scsi_check_sense(struct scsi_cmnd *scmd) /* handler does not care. Drop down to default handling */ }
- if (scmd->cmnd[0] == TEST_UNIT_READY && scmd->scsi_done != scsi_eh_done) + if (scmd->cmnd[0] == TEST_UNIT_READY && + scmd->submitter != SUBMITTED_BY_SCSI_ERROR_HANDLER) /* * nasty: for mid-layer issued TURs, we need to return the * actual sense data without any recovery attempt. For eh @@ -768,7 +767,7 @@ static int scsi_eh_completed_normally(struct scsi_cmnd *scmd) * scsi_eh_done - Completion function for error handling. * @scmd: Cmd that is done. */ -static void scsi_eh_done(struct scsi_cmnd *scmd) +void scsi_eh_done(struct scsi_cmnd *scmd) { struct completion *eh_action;
@@ -1068,7 +1067,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, shost->eh_action = &done;
scsi_log_send(scmd); - scmd->scsi_done = scsi_eh_done; + scmd->submitter = SUBMITTED_BY_SCSI_ERROR_HANDLER;
/* * Lock sdev->state_mutex to avoid that scsi_device_quiesce() can @@ -1095,6 +1094,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, if (rtn) { if (timeleft > stall_for) { scsi_eh_restore_cmnd(scmd, &ses); + timeleft -= stall_for; msleep(jiffies_to_msecs(stall_for)); goto retry; @@ -2322,11 +2322,6 @@ void scsi_report_device_reset(struct Scsi_Host *shost, int channel, int target) } EXPORT_SYMBOL(scsi_report_device_reset);
-static void -scsi_reset_provider_done_command(struct scsi_cmnd *scmd) -{ -} - /** * scsi_ioctl_reset: explicitly reset a host/bus/target/device * @dev: scsi_device to operate on @@ -2363,7 +2358,7 @@ scsi_ioctl_reset(struct scsi_device *dev, int __user *arg) scmd->request = rq; scmd->cmnd = scsi_req(rq)->cmd;
- scmd->scsi_done = scsi_reset_provider_done_command; + scmd->submitter = SUBMITTED_BY_SCSI_RESET_IOCTL; memset(&scmd->sdb, 0, sizeof(scmd->sdb));
scmd->cmd_len = 0; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index fe54afd5802e..a6b181c262a6 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1599,6 +1599,15 @@ static blk_status_t scsi_prepare_cmd(struct request *req)
static void scsi_mq_done(struct scsi_cmnd *cmd) { + switch (cmd->submitter) { + case SUBMITTED_BY_BLOCK_LAYER: + break; + case SUBMITTED_BY_SCSI_ERROR_HANDLER: + return scsi_eh_done(cmd); + case SUBMITTED_BY_SCSI_RESET_IOCTL: + return; + } + if (unlikely(blk_should_fake_timeout(scsi_cmd_to_rq(cmd)->q))) return; if (unlikely(test_and_set_bit(SCMD_STATE_COMPLETE, &cmd->state))) @@ -1688,6 +1697,7 @@ static blk_status_t scsi_queue_rq(struct blk_mq_hw_ctx *hctx,
scsi_set_resid(cmd, 0); memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); + cmd->submitter = SUBMITTED_BY_BLOCK_LAYER; cmd->scsi_done = scsi_mq_done;
blk_mq_start_request(req); diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 180636d54982..89992d8879ac 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -82,6 +82,7 @@ void scsi_eh_ready_devs(struct Scsi_Host *shost, int scsi_eh_get_sense(struct list_head *work_q, struct list_head *done_q); int scsi_noretry_cmd(struct scsi_cmnd *scmd); +void scsi_eh_done(struct scsi_cmnd *scmd);
/* scsi_lib.c */ extern int scsi_maybe_unblock_host(struct scsi_device *sdev); diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index 069ebedcbf26..31622b67324e 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h @@ -66,6 +66,12 @@ struct scsi_pointer { #define SCMD_STATE_COMPLETE 0 #define SCMD_STATE_INFLIGHT 1
+enum scsi_cmnd_submitter { + SUBMITTED_BY_BLOCK_LAYER = 0, + SUBMITTED_BY_SCSI_ERROR_HANDLER = 1, + SUBMITTED_BY_SCSI_RESET_IOCTL = 2, +} __packed; + struct scsi_cmnd { struct scsi_request req; struct scsi_device *device; @@ -89,6 +95,7 @@ struct scsi_cmnd { unsigned char prot_op; unsigned char prot_type; unsigned char prot_flags; + enum scsi_cmnd_submitter submitter;
unsigned short cmd_len; enum dma_data_direction sc_data_direction;