scsi: drop the initiator's state when the nexus is lost - #4258
Open
Robert Nowotny (bitranox) wants to merge 1 commit into
Open
scsi: drop the initiator's state when the nexus is lost#4258Robert Nowotny (bitranox) wants to merge 1 commit into
Robert Nowotny (bitranox) wants to merge 1 commit into
Conversation
State scoped to the I_T nexus outlives it. PREVENT ALLOW MEDIUM REMOVAL, pending sense data and a queued medium-change event all live on the device, and storvsp's close() never reaches the SCSI layer, so they carry into whatever initiator comes next: a reopened channel, or a new guest after a machine reset, which closes every open channel on the way down. What that costs depends on the command. A new initiator's first REQUEST SENSE can be answered with the previous initiator's sense, and a medium-change event queued for an initiator that is gone is delivered to the new one; neither needs the new initiator to do anything to invite it. The tray lock is the same defect but easier to mask, and measuring it says so: a guest that locks the door itself before ejecting, as the Linux sr driver does while probing, never observes the stale bit. One that ejects without having locked is refused with MEDIUM_REMOVAL_PREVENTED by a decision it never made. AsyncScsiDisk gains clear_nexus_state, defaulting to nothing so a device holding no nexus-scoped state needs no change. SimpleScsiDvd clears the prevent/persistent pair, the pending medium event and its sense slot; SimpleScsiDisk clears its sense slot; AtapiScsiDisk clears its own slot in front of the device's and forwards. storvsp calls it when the primary channel closes, beside the protocol reset that is already there for the same reason. What deliberately does NOT reset: the tray and the media. An ejected tray stays ejected, as it would on real hardware. Nor do persistent reservations, which a bus reset is not supposed to clear. The capacity latch on SimpleScsiDisk stays too, since re-arming it would raise a spurious unit attention at the next initiator's first command. Two tests, both verified to fail against the unfixed code. The first locks the tray, requires the eject to be refused, clears the nexus and requires the same command to succeed - the refusal is the control, without which a pass would only show that ejecting works. The second checks sense clears while the tray state survives, and its command ORDER is load-bearing: a successful command empties the sense slot on its way out, so written with the eject last it passed against a clear_nexus_state mutated to do nothing.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes a SCSI correctness issue where initiator-scoped state (I_T nexus state) could outlive the initiator in the storvsp transport, causing the next initiator/guest to inherit stale sense data, queued medium-change events, and a PREVENT ALLOW MEDIUM REMOVAL tray lock.
Changes:
- Add
AsyncScsiDisk::clear_nexus_state()(default no-op) and implement it for key SCSI device types to clear initiator-scoped state. - Invoke nexus-state clearing from storvsp when the primary channel closes (the point where the I_T nexus is effectively lost).
- Add regression tests validating that tray lock and sense data do not survive nexus loss while device-scoped tray/media state does.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| vm/devices/storage/storvsp/src/lib.rs | Clears per-initiator device state when the primary channel closes (nexus loss). |
| vm/devices/storage/scsidisk/src/scsidvd/mod.rs | Implements nexus-state clearing for DVD and adds regression tests for tray-lock and sense behavior. |
| vm/devices/storage/scsidisk/src/lib.rs | Implements nexus-state clearing for disks (clears pending sense, preserves capacity latch behavior). |
| vm/devices/storage/scsidisk/src/atapi_scsi.rs | Clears both wrapper and inner sense slots on nexus loss for ATAPI wrapper devices. |
| vm/devices/storage/scsi_core/src/lib.rs | Extends AsyncScsiDisk with a default clear_nexus_state() API and documentation. |
Suppressed comments (1)
vm/devices/storage/scsidisk/src/scsidvd/mod.rs:2688
size_ofisn’t in scope here; this will fail to compile unless it’s fully-qualified or imported in this module. Usingcore::mem::size_ofkeeps it self-contained.
data[..size_of::<scsi::StartStop>()].copy_from_slice(cdb.as_bytes());
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
State scoped to the I_T nexus outlives it. PREVENT ALLOW MEDIUM REMOVAL, pending sense data and a queued medium-change event all live on the device, and storvsp's
close()never reaches the SCSI layer, so they carry into whatever initiator comes next: a reopened channel, or a new guest after a machine reset, which closes every open channel on the way down.What that costs depends on the command. A new initiator's first REQUEST SENSE can be answered with the previous initiator's sense, and a medium-change event queued for an initiator that is gone is delivered to the new one; neither needs the new initiator to do anything to invite it. The tray lock is the same defect but easier to mask, and measuring it says so: a guest that locks the door itself before ejecting, as the Linux sr driver does while probing, never observes the stale bit. One that ejects without having locked is refused with MEDIUM_REMOVAL_PREVENTED by a decision it never made.
AsyncScsiDiskgainsclear_nexus_state, defaulting to nothing so a device holding no nexus-scoped state needs no change.SimpleScsiDvdclears the prevent/persistent pair, the pending medium event and its sense slot;SimpleScsiDiskclears its sense slot;AtapiScsiDiskclears its own slot in front of the device's and forwards. storvsp calls it when the primary channel closes, beside the protocol reset that is already there for the same reason.Deliberately not reset: the tray and the media, so an ejected tray stays ejected as it would on real hardware; persistent reservations, which a bus reset is not supposed to clear; and the capacity latch on
SimpleScsiDisk, since re-arming it would raise a spurious unit attention at the next initiator's first command.Two tests, both verified to fail against the unfixed code. The first locks the tray, requires the eject to be refused, clears the nexus and requires the same command to succeed; the refusal is the control, without which a pass would only show that ejecting works at all. The second checks that sense clears while the tray state survives, and its command order is load-bearing: a successful command empties the sense slot on its way out, so written with the eject last it passed against a
clear_nexus_statemutated to do nothing.