[PATCH v2 1/6] scsi: core: release SG_IO request before user copyback

From: Yingjie Wang

Date: Mon Oct 26 2026 - 04:32:40 EST


From: Yingjie Wang <x-professor@xxxxxxxxxxx>

The block-device SG_IO path retains its completed request while copying
sense data and unmapping the user data buffer. Either operation can fault.
If the fault needs I/O from the same queue and completed requests retain
the available tags, the nested I/O cannot make progress.

Fill the kernel-resident output header and save the bounded sense data
before releasing the request. Then perform the user copies and unmap the
original BIO chain, preserving the existing sense-copy error precedence.
The saved mapping owns its BIO references independently of the request.

The fixed request pool was introduced by scsi-mq; the later move of this
ioctl implementation into drivers/scsi did not introduce the dependency.

Fixes: d285203cf647 ("scsi: add support for a blk-mq based I/O path.")
Link: https://lore.kernel.org/r/20261022.scsi-copyback-review.31b8d6a70f4c@xxxxxxxxxxx
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Yingjie Wang <x-professor@xxxxxxxxxxx>
---
drivers/scsi/scsi_ioctl.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
index 122403ec3ab8d..68e84705634c9 100644
--- a/drivers/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -393,6 +393,8 @@ static int scsi_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr,
struct bio *bio)
{
struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq);
+ u8 sense_buffer[SCSI_SENSE_BUFFERSIZE];
+ unsigned int sense_len = 0;
int r, ret = 0;

/*
@@ -412,10 +414,16 @@ static int scsi_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr,
hdr->sb_len_wr = 0;

if (scmd->sense_len && hdr->sbp) {
- int len = min((unsigned int) hdr->mx_sb_len, scmd->sense_len);
+ sense_len = min3(hdr->mx_sb_len, scmd->sense_len,
+ sizeof(sense_buffer));
+ memcpy(sense_buffer, scmd->sense_buffer, sense_len);
+ }
+
+ blk_mq_free_request(rq);

- if (!copy_to_user(hdr->sbp, scmd->sense_buffer, len))
- hdr->sb_len_wr = len;
+ if (sense_len) {
+ if (!copy_to_user(hdr->sbp, sense_buffer, sense_len))
+ hdr->sb_len_wr = sense_len;
else
ret = -EFAULT;
}
@@ -488,7 +496,7 @@ static int sg_io(struct scsi_device *sdev, struct sg_io_hdr *hdr,

hdr->duration = jiffies_to_msecs(jiffies - start_time);

- ret = scsi_complete_sghdr_rq(rq, hdr, bio);
+ return scsi_complete_sghdr_rq(rq, hdr, bio);

out_put_request:
blk_mq_free_request(rq);
--
2.43.0