mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Bart Van Assche <bvanassche@acm.org>
To: Wang Yingjie <x-professor@outlook.com>
Cc: "James.Bottomley@HansenPartnership.com"
	<James.Bottomley@HansenPartnership.com>,
	"mkp@kernel.org" <mkp@kernel.org>,
	"yangxiuwei@kylinos.cn" <yangxiuwei@kylinos.cn>,
	"axboe@kernel.dk" <axboe@kernel.dk>,
	"linux-scsi@vger.kernel.org" <linux-scsi@vger.kernel.org>,
	"io-uring@vger.kernel.org" <io-uring@vger.kernel.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH 0/6] scsi: make SG_IO user copyback failure-safe
Date: Mon, 19 Oct 2026 14:11:20 -0700	[thread overview]
Message-ID: <7a2dfdd0-812c-470a-9b31-402dc601f05c@acm.org> (raw)
In-Reply-To: <20261019.scsi-copyback.9d2bf936038d@outlook.com>

[-- Attachment #1: Type: text/plain, Size: 1039 bytes --]


On 10/18/26 11:32 PM, Wang Yingjie wrote:
>> Has it been considered to disable SG_IO
>> for one-tag devices instead of complicating the SG_IO implementation?
> 
> My concern with disabling SG_IO is that it would also reject working
> passthrough commands on those devices. For example, smartctl uses SG_IO
> on block devices for SCSI/SAT commands. The lifetime changes preserve that
> interface by saving the request-backed completion data, freeing the
> completed request, and then doing the potentially faulting user copies.
> That does require extra storage for the completion results and sense data.
> 
> Separately, patches 4/6 and 6/6 fix lost data-copyback errors and do not
> depend on the queue depth. I can split those out if that helps review.

Since I don't have the time right now to do an in-depth review, please
take a look at the attached LLM-generated review. One way to view the
attached markdown file is by using the Linux "glow" command. The review
comes from an LLM that is not yet publicly available.

Thanks,

Bart.

[-- Attachment #2: review.md --]
[-- Type: text/markdown, Size: 10424 bytes --]

Here is a technical review of Wang Yingjie's series (`[PATCH 0/6] scsi: make SG_IO user copyback failure-safe`) and his follow-up reply (`20261019.scsi-copyback.9d2bf936038d@outlook.com`).

---

### 1. Architectural Assessment & Evaluation of Yingjie's Reply

1. **Disabling `SG_IO` on `.can_queue == 1` devices is not viable:**
   - Yingjie's examples are accurate: [`usb_stor_host_template`](file:///usr/local/google/home/bvanassche/software/linux-kernel/drivers/usb/storage/scsiglue.c#L632) sets `.can_queue = 1` (covering all non-UAS USB flash drives, USB external HDD/SSD bridges, and USB optical drives), and `ATA_SUBBASE_SHT` in [`include/linux/libata.h`](file:///usr/local/google/home/bvanassche/software/linux-kernel/include/linux/libata.h#L1488-L1492) sets `.can_queue = ATA_DEF_QUEUE` (`1`) for PATA/BMDMA hosts such as `ata_piix` (plus `sbp2`, `ppa`, `imm`, etc.).
   - Disabling `SG_IO` (or `CDROMREADAUDIO`) on those queues would break `smartctl -d sat`, `hdparm`, `udisks2`, `fwupd`, `sg3_utils`, and optical media burning/ripping tools (`growisofs`, `cdrecord`/`wodim`, `cdparanoia`, `VLC`).

2. **The deadlock is not specific to `.can_queue == 1` queues:**
   - Holding a `blk-mq` driver tag across a faulting user copy creates a general lock/resource inversion:
     $$\text{blk-mq tag} \;\longrightarrow\; \text{user page fault / folio lock} \;\longrightarrow\; \text{nested same-queue I/O} \;\longrightarrow\; \text{blk-mq tag}$$
   - On a queue with `can_queue = K`, $K$ concurrent passthrough completions faulting onto nonresident mappings on the same device exhaust all $K$ tags and deadlock identically (as Yingjie himself demonstrated with queue depth 2 in his parallel NVMe series `cover.1792118770.git.x-professor@outlook.com`). `.can_queue = 1` simply reduces the concurrency needed from $K$ threads to 1.
   - Releasing `rq` before `blk_rq_unmap_user()` is sound from a lifetime perspective: `blk_rq_map_user*()` allocates BIOs independently from `fs_bio_set` via [`blk_rq_map_bio_alloc()`](file:///usr/local/google/home/bvanassche/software/linux-kernel/block/blk-map.c#L45-L57), and both [`sg_rq_end_io()`](file:///usr/local/google/home/bvanassche/software/linux-kernel/drivers/scsi/sg.c#L1374-L1382) (since commit `7568615c1054`) and [`nvme_uring_cmd_end_io()`](file:///usr/local/google/home/bvanassche/software/linux-kernel/drivers/nvme/host/ioctl.c#L447-L479) (`RQ_END_IO_FREE`) already rely on freeing `rq` before `blk_rq_unmap_user()`.

3. **Build / Checkpatch / Stack Frame Sanity:**
   - All 6 patches apply cleanly on `0fcb05b72344`, pass `scripts/checkpatch.pl --strict`, compile cleanly with `W=1 C=1` (zero compiler or sparse warnings), and keep stack frames small (`120` bytes on x86_64 for `sg_io()`, `scsi_bsg_sg_io_fn()`, and `scsi_bsg_uring_task_cb()`).

---

### 2. Substantive Issues Found in the Patches

#### Issue 1 (Major — Patch 5/6): `scsi_bsg_uring_cmd_done()` still pins `rq` across `io_uring` `task_work` (`RQ_END_IO_NONE`)
In [`drivers/scsi/scsi_bsg.c`](file:///usr/local/google/home/bvanassche/software/linux-kernel/drivers/scsi/scsi_bsg.c#L68-L76), [`scsi_bsg_uring_cmd_done()`](file:///usr/local/google/home/bvanassche/software/linux-kernel/drivers/scsi/scsi_bsg.c#L68-L76) returns `RQ_END_IO_NONE` and defers `blk_mq_free_request(rq)` to [`scsi_bsg_uring_task_cb()`](file:///usr/local/google/home/bvanassche/software/linux-kernel/drivers/scsi/scsi_bsg.c#L32-L66). Patch 5/6 only moves `blk_mq_free_request(rq)` a few lines earlier inside `scsi_bsg_uring_task_cb()`, which leaves the request and its `blk-mq` tag pinned across the entire async boundary between `end_io` and `task_work`:

- **Still deadlocks with `IORING_SETUP_DEFER_TASKRUN`:** Under `IORING_SETUP_DEFER_TASKRUN` (standard modern `liburing` usage), [`io_req_local_work_add()`](file:///usr/local/google/home/bvanassche/software/linux-kernel/io_uring/tw.c#L151-L206) pushes the item onto `ctx->work_list` without scheduling signal `task_work`; `scsi_bsg_uring_task_cb()` **does not run until userspace explicitly calls `io_uring_enter(IORING_ENTER_GETEVENTS)`**. If the ring task submits 1 BSG command on a 1-tag queue (or `can_queue` commands on *any* queue) and then touches a nonresident `mmap()` page or calls `pread()` on that same device before calling `io_uring_enter(GETEVENTS)`, it **still deadlocks in `D` state in `blk_mq_get_tag()`** even with Patch 5/6 applied.
- **Un-reaped CQEs starve the entire queue:** Even without `DEFER_TASKRUN`, if a task submits `can_queue` BSG `uring_cmd`s and sleeps (`poll()`/`futex()`) without reaping CQEs after I/O finishes, every tag on the device remains pinned, hanging `disk_events`, writeback, and all other processes in `blk_mq_get_tag()` — the exact bug fixed for `/dev/sg*` in commit `7568615c1054` (*"sg: fix unkillable I/O wait deadlock with scsi-mq"*).
- **Better fix (matching [`nvme_uring_cmd_end_io()`](file:///usr/local/google/home/bvanassche/software/linux-kernel/drivers/nvme/host/ioctl.c#L447-L479) and [`sg_rq_end_io()`](file:///usr/local/google/home/bvanassche/software/linux-kernel/drivers/scsi/sg.c#L1374-L1382)):** Snapshot completion state into `struct scsi_bsg_uring_cmd_pdu` inside `scsi_bsg_uring_cmd_done()` *before* calling `io_uring_cmd_do_in_task_lazy()`, and **`return RQ_END_IO_FREE;`**:
  - `pdu->req` is no longer needed, and `max_response_len` is read in `end_io` while `res2` is read in `task_cb`, so `bio` (8B) + `response_addr` (8B) + `union { u32 max_response_len; u64 res2; }` (8B) + `u8 *sense_buf` (8B) = **32 bytes**, fitting within `ioucmd->pdu[32]`.
  - Allocating `sense_buf` (`min_t(u32, cmd->max_response_len, SCSI_SENSE_BUFFERSIZE)`) in [`scsi_bsg_uring_cmd()`](file:///usr/local/google/home/bvanassche/software/linux-kernel/drivers/scsi/scsi_bsg.c#L163-L165) only when `cmd->response && cmd->max_response_len` avoids both `GFP_ATOMIC` failure in IRQ context and the 96-byte stack array in `scsi_bsg_uring_task_cb()`.

#### Issue 2 (Bug — Patch 5/6): `scsi_bsg_uring_task_cb()` reports non-zero `sense_len_wr` in CQE `res2` on `copy_to_user()` failure and omits `sizeof(sense_buffer)` bound
In Patch 5/6 (`scsi_bsg_uring_task_cb()`):
```c
	if (sense_len_wr) {
		if (copy_to_user(uptr64(pdu->response_addr), sense_buffer,
				 sense_len_wr))
			ret = -EFAULT;
	}

	res2 = bsg_scsi_res2_build(status_byte(scsi_result),
				   driver_status, host_byte(scsi_result),
				   sense_len_wr, resid_len);
```
1. Per [`include/uapi/linux/bsg.h`](file:///usr/local/google/home/bvanassche/software/linux-kernel/include/uapi/linux/bsg.h#L108), `res2` bits `[24..31]` are `sense_len_wr` (*"bytes of sense data written to response buffer"*). Both [`scsi_complete_sghdr_rq()`](file:///usr/local/google/home/bvanassche/software/linux-kernel/drivers/scsi/scsi_ioctl.c#L411-L420) (`hdr->sb_len_wr = 0`) and [`scsi_bsg_sg_io_fn()`](file:///usr/local/google/home/bvanassche/software/linux-kernel/drivers/scsi/scsi_bsg.c#L258-L269) (`hdr->response_len = 0`) report `0` bytes written when `copy_to_user()` fails, whereas `scsi_bsg_uring_task_cb()` leaves `sense_len_wr` non-zero. It should zero `sense_len_wr` when `copy_to_user()` fails.
2. Patches 1/6 and 3/6 explicitly bound `sense_len` with `sizeof(sense_buffer)`, whereas Patch 5/6 computes `sense_len_wr = min_t(unsigned int, pdu->max_response_len, scmd->sense_len)` without clamping to `sizeof(sense_buffer)` before `memcpy(sense_buffer, scmd->sense_buffer, sense_len_wr)`.

#### Issue 3 (Missed Call Sites): Same deadlock exists in `sg_scsi_ioctl()` (same file!) and `bsg_transport_sg_io_fn()`
1. Immediately below [`sg_io()`](file:///usr/local/google/home/bvanassche/software/linux-kernel/drivers/scsi/scsi_ioctl.c#L429-L495) in [`drivers/scsi/scsi_ioctl.c`](file:///usr/local/google/home/bvanassche/software/linux-kernel/drivers/scsi/scsi_ioctl.c#L612-L633), [`sg_scsi_ioctl()`](file:///usr/local/google/home/bvanassche/software/linux-kernel/drivers/scsi/scsi_ioctl.c#L523-L634) (`SCSI_IOCTL_SEND_COMMAND`) calls `copy_to_user(sic->data, scmd->sense_buffer, ...)` and `copy_to_user(sic->data, buffer, out_len)` **before** `blk_mq_free_request(rq)`. If `sic->data` faults onto a mapping backed by the same 1-tag queue (e.g. `sic` crossing a resident/nonresident page boundary or reclaimed during I/O), it deadlocks identically.
2. [`bsg_transport_sg_io_fn()`](file:///usr/local/google/home/bvanassche/software/linux-kernel/block/bsg-lib.c#L115-L149) in [`block/bsg-lib.c`](file:///usr/local/google/home/bvanassche/software/linux-kernel/block/bsg-lib.c#L138-L149) likewise runs `copy_to_user()` and `blk_rq_unmap_user()` before `blk_mq_free_request()` and ignores `blk_rq_unmap_user()` errors.

#### Issue 4 (Metadata / Stable Backporting): Bogus `Fixes:` tags in Patches 1/6–4/6
- **Patches 1/6 & 2/6** cite `Fixes: 31151ba2cef1 ("fix mismerge in ll_rw_blk.c")`, an August 2005 merge commit touching `drivers/block/ll_rw_blk.c` — 9 years before fixed `scsi-mq` tag pools existed and 16 years before [`sr_read_cdda_bpc()`](file:///usr/local/google/home/bvanassche/software/linux-kernel/drivers/scsi/sr.c#L928-L976) (`ba51bdafaafc`, v5.15) and [`sg_io()`](file:///usr/local/google/home/bvanassche/software/linux-kernel/drivers/scsi/scsi_ioctl.c#L429-L495) (`f2542a3be327`, v5.15) existed in `drivers/scsi/`.
- **Patches 3/6 & 4/6** cite `Fixes: 10e8855b9451 ("bsg: add SG_IO to SG v4")` (`block/bsg.c`, 2006), whereas [`scsi_bsg_sg_io_fn()`](file:///usr/local/google/home/bvanassche/software/linux-kernel/drivers/scsi/scsi_bsg.c#L196-L281) in `drivers/scsi/scsi_bsg.c` was created in `78011042684d` / `75ca56409e5b` (v5.15).

#### Issue 5 (Series Organization & Minor Type Consistency)
- **Splitting / ordering:** Accepting Yingjie's offer to split (or place first in the series) Patches 4/6 and 6/6 makes sense: lost data-copyback `-EFAULT` reporting is unconditional and independent of queue depth, so having those self-contained fixes first simplifies review and backporting.
- **Type consistency:** [`scmd->result`](file:///usr/local/google/home/bvanassche/software/linux-kernel/include/scsi/scsi_cmnd.h#L143) is `int` and [`scmd->sense_len`](file:///usr/local/google/home/bvanassche/software/linux-kernel/include/scsi/scsi_cmnd.h#L118) is `unsigned`, yet Patch 1/6 uses `int result` / `unsigned int sense_len` while Patches 3/6 and 5/6 use `u32 scsi_result` / `u8 sense_len`. Using `int` for `result` consistently across all three functions is cleaner.

      reply	other threads:[~2026-10-19 21:11 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-18 15:41 Wang Yingjie
2026-10-18 15:41 ` [PATCH 1/6] scsi: core: release SG_IO request before copying to userspace Wang Yingjie
2026-10-18 15:41 ` [PATCH 2/6] scsi: sr: release CDDA " Wang Yingjie
2026-10-19 20:33   ` Bart Van Assche
2026-10-18 15:41 ` [PATCH 3/6] scsi: bsg: release synchronous request before user copyback Wang Yingjie
2026-10-18 15:41 ` [PATCH 4/6] scsi: bsg: report synchronous data copyback failures Wang Yingjie
2026-10-18 15:41 ` [PATCH 5/6] scsi: bsg: release io_uring request before user copyback Wang Yingjie
2026-10-18 15:41 ` [PATCH 6/6] scsi: bsg: report io_uring data copyback failures Wang Yingjie
2026-10-18 16:41 ` [PATCH 0/6] scsi: make SG_IO user copyback failure-safe Bart Van Assche
2026-10-19  6:32   ` Wang Yingjie
2026-10-19 21:11     ` Bart Van Assche [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=7a2dfdd0-812c-470a-9b31-402dc601f05c@acm.org \
    --to=bvanassche@acm.org \
    --cc=James.Bottomley@HansenPartnership.com \
    --cc=axboe@kernel.dk \
    --cc=io-uring@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-scsi@vger.kernel.org \
    --cc=mkp@kernel.org \
    --cc=x-professor@outlook.com \
    --cc=yangxiuwei@kylinos.cn \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®