On 5/19/23 10:12, John Garry wrote:
If only we could pass the actual scsi_cmnd sense buffer to the caller...
How about something like the totally untested patch below? Thanks, Bart. diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 7bb12deab70c..7ff8d5c263f0 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -379,15 +379,14 @@ static int ata_get_identity(struct ata_port *ap, struct scsi_device *sdev, int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg) { int rc = 0; - u8 sensebuf[SCSI_SENSE_BUFFERSIZE]; + u8 *sensebuf = NULL; u8 scsi_cmd[MAX_COMMAND_SIZE]; u8 args[4], *argbuf = NULL; int argsize = 0; struct scsi_sense_hdr sshdr; const struct scsi_exec_args exec_args = { .sshdr = &sshdr, - .sense = sensebuf, - .sense_len = sizeof(sensebuf), + .sense = &sensebuf, }; int cmd_result; @@ -397,7 +396,6 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg) if (copy_from_user(args, arg, sizeof(args))) return -EFAULT; - memset(sensebuf, 0, sizeof(sensebuf)); memset(scsi_cmd, 0, sizeof(scsi_cmd)); if (args[3]) { @@ -469,6 +467,7 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg) && copy_to_user(arg + sizeof(args), argbuf, argsize)) rc = -EFAULT; error: + scsi_free_sense_buffer(sensebuf); kfree(argbuf); return rc; } @@ -487,15 +486,14 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg) int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg) { int rc = 0; - u8 sensebuf[SCSI_SENSE_BUFFERSIZE]; + u8 *sensebuf = NULL; u8 scsi_cmd[MAX_COMMAND_SIZE]; u8 args[7]; struct scsi_sense_hdr sshdr; int cmd_result; const struct scsi_exec_args exec_args = { .sshdr = &sshdr, - .sense = sensebuf, - .sense_len = sizeof(sensebuf), + .sense = &sensebuf, }; if (arg == NULL) @@ -504,7 +502,6 @@ int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg) if (copy_from_user(args, arg, sizeof(args))) return -EFAULT; - memset(sensebuf, 0, sizeof(sensebuf)); memset(scsi_cmd, 0, sizeof(scsi_cmd)); scsi_cmd[0] = ATA_16; scsi_cmd[1] = (3 << 1); /* Non-data */ @@ -557,6 +554,7 @@ int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg) } error: + scsi_free_sense_buffer(sensebuf); return rc; } diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 6bc1a9380e69..8197023e9077 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -210,9 +210,6 @@ int scsi_execute_cmd(struct scsi_device *sdev, const unsigned char *cmd, if (!args) args = &default_args; - else if (WARN_ON_ONCE(args->sense && - args->sense_len != SCSI_SENSE_BUFFERSIZE)) - return -EINVAL; req = scsi_alloc_request(sdev->request_queue, opf, args->req_flags); if (IS_ERR(req)) @@ -248,8 +245,10 @@ int scsi_execute_cmd(struct scsi_device *sdev, const unsigned char *cmd, if (args->resid) *args->resid = scmd->resid_len; - if (args->sense) - memcpy(args->sense, scmd->sense_buffer, SCSI_SENSE_BUFFERSIZE); + if (args->sense) { + *args->sense = scmd->sense_buffer; + scmd->sense_buffer = NULL; + } if (args->sshdr) scsi_normalize_sense(scmd->sense_buffer, scmd->sense_len, args->sshdr); @@ -1825,6 +1824,12 @@ static int scsi_mq_init_request(struct blk_mq_tag_set *set, struct request *rq, return ret; } +void scsi_free_sense_buffer(u8 *sense_buffer) +{ + kmem_cache_free(scsi_sense_cache, sense_buffer); +} +EXPORT_SYMBOL_GPL(scsi_free_sense_buffer); + static void scsi_mq_exit_request(struct blk_mq_tag_set *set, struct request *rq, unsigned int hctx_idx) { diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h index ec093594ba53..7c37ef11c71a 100644 --- a/include/scsi/scsi.h +++ b/include/scsi/scsi.h @@ -217,4 +217,6 @@ static inline bool scsi_status_is_good(int status) (status == SAM_STAT_COMMAND_TERMINATED)); } +void scsi_free_sense_buffer(u8 *sense_buffer); + #endif /* _SCSI_SCSI_H */ diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index f10a008e5bfa..9f713fcb150e 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -460,8 +460,7 @@ extern void scsi_sanitize_inquiry_string(unsigned char *s, int len); /* Optional arguments to scsi_execute_cmd */ struct scsi_exec_args { - unsigned char *sense; /* sense buffer */ - unsigned int sense_len; /* sense buffer len */ + unsigned char **sense; /* sense buffer */ struct scsi_sense_hdr *sshdr; /* decoded sense header */ blk_mq_req_flags_t req_flags; /* BLK_MQ_REQ flags */ int scmd_flags; /* SCMD flags */