mirror of
https://github.com/freemkv/libfreemkv.git
synced 2026-10-07 18:13:10 +00:00
Security - Remove the unsafe Vec::set_len over recycled sector buffers — UB reachable from safe code (GHSA-j8ww-f5fg-9pmh, low). Uses Vec::resize; pooling unchanged. CI / tooling - clippy on stable with the MSRV single-sourced from Cargo.toml; cargo-deny dependency-audit gate with first-party git sources allowed (#15); audience-based comment-guard (#17). Docs - README (keydb ownership, BD-J parser count), drive-access transport/reset notes, mux timeline module-doc links.
50 lines
2.1 KiB
Markdown
50 lines
2.1 KiB
Markdown
# Linux SCSI transport (`src/scsi/linux.rs`)
|
|
|
|
## Kernel error-handling ladder
|
|
|
|
No userspace abort, no fd close+reopen, no SG_SCSI_RESET escalation — the
|
|
kernel SCSI mid-layer's `scsi_eh.rst` ladder (ABORT TASK -> LUN RESET ->
|
|
BUS RESET -> HOST RESET) runs internally when `hdr.timeout` expires, and
|
|
by the time the ioctl returns the kernel has already done what it can.
|
|
|
|
## Why one synchronous ioctl
|
|
|
|
This matches established practice for optical/SCSI I/O: a single
|
|
synchronous ioctl with a bounded per-command timeout (commonly in the
|
|
8-60 s range), consistent with the Linux kernel default for SCSI block
|
|
devices (30 s `/sys/.../timeout`).
|
|
|
|
## History: the async design it replaced
|
|
|
|
Pre-0.13.20 we ran an async `write() + poll(1.5s) + close-on-timeout +
|
|
bg reopen` pattern. That abandoned slow-but-alive commands faster than
|
|
the drive could drain its internal queue, deepening the wedge
|
|
pattern on the LG BU40N. Reverted in 0.13.20.
|
|
|
|
## `execute()` details
|
|
|
|
One syscall: `ioctl(fd, SG_IO, &hdr)`. The kernel honors `hdr.timeout`
|
|
and runs its own ABORT TASK -> LUN RESET -> BUS RESET -> HOST RESET
|
|
escalation if the device times out (per `Documentation/scsi/scsi_eh.rst`).
|
|
By the time this returns, the kernel has done its recovery work.
|
|
|
|
Errors surfaced to the caller:
|
|
|
|
- ioctl returned -1 -> `Error::IoError` (kernel-level failure)
|
|
- `hdr.host_status` != 0 OR `(hdr.driver_status & ~DRIVER_SENSE)` != 0
|
|
-> `Error::ScsiError { status: 0xFF, sense_key: 0, asc: 0, ascq: 0 }`
|
|
(real transport-layer failure: kernel timeout, bridge wedge, bus error)
|
|
- `hdr.status` != 0 (typically `0x02` CHECK CONDITION) ->
|
|
`Error::ScsiError { status, sense_key, asc, ascq }` carrying the
|
|
drive's full SPC-4 sense triple. Callers route on
|
|
`is_medium_error()`, `is_unit_attention()`, etc.
|
|
|
|
SG's `DRIVER_SENSE` (0x08) bit indicates *sense data is attached* — it's
|
|
set on every CHECK CONDITION reply. It is **not** a transport failure;
|
|
pre-0.13.23 we conflated it with one and silently lost every
|
|
drive-reported error reason. The mask in the transport-error check is
|
|
the fix.
|
|
|
|
Caller's `data` buffer is mutated only on success; partial transfers
|
|
are reported via `bytes_transferred = data.len() - resid`.
|