From: Yingjie Wang The BSG io_uring end-I/O callback returns RQ_END_IO_NONE, so task work still owns the completed request and its tag. Task work then copies READ bounce data and optional sense data to userspace. A fault on the same one-tag device deadlocks nested I/O behind the retained request. Snapshot the result, residual, and sense bytes into local storage, then free the request before either userspace copy. A current-mainline BSG INQUIRY into a nonresident mapping of the same /dev/sr0 queue previously stuck in scsi_bsg_uring_task_cb -> blk_rq_unmap_user -> filemap_fault. The fixed kernel completed 20/20 repetitions and left no blocked I/O or hung-task report. Fixes: 7b6d3255e7f8 ("scsi: bsg: add io_uring passthrough handler") Cc: stable@vger.kernel.org Assisted-by: LLM Signed-off-by: Yingjie Wang --- drivers/scsi/scsi_bsg.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/scsi_bsg.c b/drivers/scsi/scsi_bsg.c index f95dc5da7480..341142dda71d 100644 --- a/drivers/scsi/scsi_bsg.c +++ b/drivers/scsi/scsi_bsg.c @@ -35,32 +35,37 @@ static void scsi_bsg_uring_task_cb(struct io_tw_req tw_req, io_tw_token_t tw) struct scsi_bsg_uring_cmd_pdu *pdu = scsi_bsg_uring_cmd_pdu(ioucmd); struct request *rq = pdu->req; struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq); + u8 sense_buffer[SCSI_SENSE_BUFFERSIZE]; + u32 scsi_result = scmd->result; + u32 resid_len = scmd->resid_len; u64 res2; int ret = 0; u8 driver_status = 0; u8 sense_len_wr = 0; - if (pdu->bio) - blk_rq_unmap_user(pdu->bio); - - if (scsi_status_is_check_condition(scmd->result)) { + if (scsi_status_is_check_condition(scsi_result)) { driver_status = DRIVER_SENSE; if (pdu->response_addr) sense_len_wr = min_t(unsigned int, pdu->max_response_len, scmd->sense_len); } + if (sense_len_wr) + memcpy(sense_buffer, scmd->sense_buffer, sense_len_wr); + + blk_mq_free_request(rq); + if (pdu->bio) + blk_rq_unmap_user(pdu->bio); if (sense_len_wr) { - if (copy_to_user(uptr64(pdu->response_addr), scmd->sense_buffer, + if (copy_to_user(uptr64(pdu->response_addr), sense_buffer, sense_len_wr)) ret = -EFAULT; } - res2 = bsg_scsi_res2_build(status_byte(scmd->result), driver_status, - host_byte(scmd->result), sense_len_wr, - scmd->resid_len); + res2 = bsg_scsi_res2_build(status_byte(scsi_result), + driver_status, host_byte(scsi_result), + sense_len_wr, resid_len); - blk_mq_free_request(rq); io_uring_cmd_done32(ioucmd, ret, res2, IO_URING_CMD_TASK_WORK_ISSUE_FLAGS); } -- 2.43.0