1
0

scsi: scsi_debug: Abort SCSI commands via an internal command

Add a .queue_reserved_command() implementation and call it from the code
path that aborts SCSI commands. This ensures that the code for
allocating a pseudo SCSI device and also the code for allocating and
processing reserved commands gets triggered while running blktests.

Most of the code in this patch is a modified version of code from John
Garry. See also
https://lore.kernel.org/linux-scsi/75018e17-4dea-4e1b-8c92-7a224a1e13b9@oracle.com/

Reviewed-by: John Garry <john.g.garry@oracle.com>
Suggested-by: John Garry <john.g.garry@oracle.com>
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Link: https://patch.msgid.link/20251031204029.2883185-8-bvanassche@acm.org
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Bart Van Assche
2025-10-31 13:39:15 -07:00
committed by Martin K. Petersen
parent a2ab4e3328
commit 581ca49035

View File

@@ -6752,20 +6752,59 @@ static bool scsi_debug_stop_cmnd(struct scsi_cmnd *cmnd)
return false;
}
struct sdebug_abort_cmd {
u32 unique_tag;
};
enum sdebug_internal_cmd_type {
SCSI_DEBUG_ABORT_CMD,
};
struct sdebug_internal_cmd {
enum sdebug_internal_cmd_type type;
union {
struct sdebug_abort_cmd abort_cmd;
};
};
union sdebug_priv {
struct sdebug_scsi_cmd cmd;
struct sdebug_internal_cmd internal_cmd;
};
/*
* Called from scsi_debug_abort() only, which is for timed-out cmd.
* Abort SCSI command @cmnd. Only called from scsi_debug_abort(). Although
* it would be possible to call scsi_debug_stop_cmnd() directly, an internal
* command is allocated and submitted to trigger the reserved command
* infrastructure.
*/
static bool scsi_debug_abort_cmnd(struct scsi_cmnd *cmnd)
{
struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmnd);
unsigned long flags;
bool res;
struct Scsi_Host *shost = cmnd->device->host;
struct request *rq = scsi_cmd_to_rq(cmnd);
u32 unique_tag = blk_mq_unique_tag(rq);
struct sdebug_internal_cmd *internal_cmd;
struct scsi_cmnd *abort_cmd;
struct request *abort_rq;
blk_status_t res;
spin_lock_irqsave(&sdsc->lock, flags);
res = scsi_debug_stop_cmnd(cmnd);
spin_unlock_irqrestore(&sdsc->lock, flags);
return res;
abort_cmd = scsi_get_internal_cmd(shost->pseudo_sdev, DMA_NONE,
BLK_MQ_REQ_RESERVED);
if (!abort_cmd)
return false;
internal_cmd = scsi_cmd_priv(abort_cmd);
*internal_cmd = (struct sdebug_internal_cmd) {
.type = SCSI_DEBUG_ABORT_CMD,
.abort_cmd = {
.unique_tag = unique_tag,
},
};
abort_rq = scsi_cmd_to_rq(abort_cmd);
abort_rq->timeout = secs_to_jiffies(3);
res = blk_execute_rq(abort_rq, true);
scsi_put_internal_cmd(abort_cmd);
return res == BLK_STS_OK;
}
/*
@@ -9220,6 +9259,56 @@ out_handle:
return ret;
}
/* Process @scp, a request to abort a SCSI command by tag. */
static void scsi_debug_abort_cmd(struct Scsi_Host *shost, struct scsi_cmnd *scp)
{
struct sdebug_internal_cmd *internal_cmd = scsi_cmd_priv(scp);
struct sdebug_abort_cmd *abort_cmd = &internal_cmd->abort_cmd;
const u32 unique_tag = abort_cmd->unique_tag;
struct scsi_cmnd *to_be_aborted_scmd =
scsi_host_find_tag(shost, unique_tag);
struct sdebug_scsi_cmd *to_be_aborted_sdsc =
scsi_cmd_priv(to_be_aborted_scmd);
bool res = false;
if (!to_be_aborted_scmd) {
pr_err("%s: command with tag %#x not found\n", __func__,
unique_tag);
return;
}
scoped_guard(spinlock_irqsave, &to_be_aborted_sdsc->lock)
res = scsi_debug_stop_cmnd(to_be_aborted_scmd);
if (res)
pr_info("%s: aborted command with tag %#x\n",
__func__, unique_tag);
else
pr_err("%s: failed to abort command with tag %#x\n",
__func__, unique_tag);
set_host_byte(scp, res ? DID_OK : DID_ERROR);
}
static int scsi_debug_process_reserved_command(struct Scsi_Host *shost,
struct scsi_cmnd *scp)
{
struct sdebug_internal_cmd *internal_cmd = scsi_cmd_priv(scp);
switch (internal_cmd->type) {
case SCSI_DEBUG_ABORT_CMD:
scsi_debug_abort_cmd(shost, scp);
break;
default:
WARN_ON_ONCE(true);
set_host_byte(scp, DID_ERROR);
break;
}
scsi_done(scp);
return 0;
}
static int scsi_debug_queuecommand(struct Scsi_Host *shost,
struct scsi_cmnd *scp)
{
@@ -9420,6 +9509,9 @@ static int sdebug_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmd);
struct sdebug_defer *sd_dp = &sdsc->sd_dp;
if (blk_mq_is_reserved_rq(scsi_cmd_to_rq(cmd)))
return 0;
spin_lock_init(&sdsc->lock);
hrtimer_setup(&sd_dp->hrt, sdebug_q_cmd_hrt_complete, CLOCK_MONOTONIC,
HRTIMER_MODE_REL_PINNED);
@@ -9439,6 +9531,7 @@ static const struct scsi_host_template sdebug_driver_template = {
.sdev_destroy = scsi_debug_sdev_destroy,
.ioctl = scsi_debug_ioctl,
.queuecommand = scsi_debug_queuecommand,
.queue_reserved_command = scsi_debug_process_reserved_command,
.change_queue_depth = sdebug_change_qdepth,
.map_queues = sdebug_map_queues,
.mq_poll = sdebug_blk_mq_poll,
@@ -9448,6 +9541,7 @@ static const struct scsi_host_template sdebug_driver_template = {
.eh_bus_reset_handler = scsi_debug_bus_reset,
.eh_host_reset_handler = scsi_debug_host_reset,
.can_queue = SDEBUG_CANQUEUE,
.nr_reserved_cmds = 1,
.this_id = 7,
.sg_tablesize = SG_MAX_SEGMENTS,
.cmd_per_lun = DEF_CMD_PER_LUN,
@@ -9456,7 +9550,7 @@ static const struct scsi_host_template sdebug_driver_template = {
.module = THIS_MODULE,
.skip_settle_delay = 1,
.track_queue_depth = 1,
.cmd_size = sizeof(struct sdebug_scsi_cmd),
.cmd_size = sizeof(union sdebug_priv),
.init_cmd_priv = sdebug_init_cmd_priv,
.target_alloc = sdebug_target_alloc,
.target_destroy = sdebug_target_destroy,