Skip to content

scsi: a layered BlockNode interface for disk backends - #337

Open
belikh wants to merge 1 commit into
techomancer:mainfrom
irix7:upstream/blocknode
Open

belikh wants to merge 1 commit into
techomancer:mainfrom
irix7:upstream/blocknode

Conversation

@belikh

@belikh belikh commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Refs #336 (approved direction), #265, #279, #283.

What this changes

src/scsi.rs's DiskBackend enum is replaced by BlockNode in src/block_node.rs, with one implementation per backend:

backend node
raw file / ISO RawNode
raw .overlay COW CowNode
hard-disk CHD ChdNode
CD CHD ChdCdNode

The trait is byte-addressed (size, read, write, flush, discard, block_status, backing) and carries the divergence contract (dirty_count, is_cow, commit, rollback, overlay_paths, pending_sync). ScsiDevice holds Option<Box<dyn BlockNode>>; perform_read/perform_write translate LBA to bytes once. CowNode::write does the 512-byte read-modify-write for a partial sector; a raw discard zero-fills, a COW discard releases the range back to the backing. block_status describes a homogeneous run, so a caller can step offset += status.len across an allocation boundary.

"Dirty" has one meaning across formats: the node holds writes that are not yet part of its durable base. Raw reports exact dirty 512-byte sectors, a CHD diff reports a coarse 1/0. commit folds the layer into the base (raw in place, CHD by rebuilding from the merged view and reopening); rollback discards it and reverts reads to the base.

Migration

  • ScsiDevice::open stays the single constructor both controllers use (the seam from scsi: targets any controller can open, with the machine's identity #265), so the WD33C93A and AIC-7880 paths need no call-site change and the AIC keeps its CHD/COW support. It now builds nodes.
  • The GUI cow commit path uses CowNode; chd-extract uses ChdNode.
  • chd_disk gains ChdHd::sector_size and ChdCd::read_at; cow_disk exposes the sidecar helpers the node shares.
  • DiskBackend is deleted.

Preserved exactly

Not in this PR

Physical block devices, bulk DMA, the advisory-lock node (#90) and O2-specific follow-ups. The overlay export/import methods remain on the trait only because ScsiDevice already exposes them to the snapshot code; there are no snapshot format changes here. cow_disk::CowDisk also remains as a standalone, test-covered type now that SCSI no longer uses it; deleting the old API can be a follow-up if you want it gone.

Decisions I would like comment on

  • block_status is in this PR because the COW/commit contract is built on it (the issue left this open). It can be split out if you would rather land the rest first.
  • I kept ScsiDevice::open rather than inlining backend construction into each controller. It preserves scsi: targets any controller can open, with the machine's identity #265's "targets any controller can open" seam and means the AIC-7880 keeps full CHD/COW support instead of a raw-only shim. Say if you would rather have node construction at the controller.
  • export_overlay/import_overlay are on the trait to keep the existing snapshot hooks working without downcasting.

Tests

  • cargo test --workspace: 1366 passed, 0 failed, 25 ignored.
  • cargo test --workspace --features jitv2: 1848 passed, 0 failed, 31 ignored.
  • src/block_node.rs: 16 unit tests — raw round-trip and bounds, COW read-through/overlay/discard/no-backing, a block_status run straddling allocated and held sectors, partial-sector read-modify-write, CHD read/write, dirty-sidecar reopen, export/import, and commit/rollback through dyn BlockNode for both raw and CHD, plus CHD pending-sync and overlay paths. The fork's advisory-lock regression test is deliberately not included because that node is out of scope, so 16 of its 17.
  • scsi::tests: the three scsi: cut data-in replies to the allocation length #279/scsi: a REQUEST SENSE allocation length of 0 asks for 4 bytes #283 tests plus two new construction-path tests (direct and COW through the SCSI READ/WRITE path). chd_disk and cow_disk suites are unchanged and green.

Provenance

This is a port of the irix7/iris implementation by Jupiter Belic — commits df7f6c7, 1801c06 and d9c1953 — adapted to upstream's current ScsiIdentity/open seam. The later advisory-lock work (ab0be92) is not included.

Replace the DiskBackend enum with a BlockNode trait and one implementation
per backend: RawNode, CowNode, ChdNode and ChdCdNode. ScsiDevice now owns
Option<Box<dyn BlockNode>> and the storage commands are byte-addressed, so
no caller matches on a backend kind.

The contract gives "dirty" one meaning across formats: dirty_count is exact
overlay sectors for a raw image and a coarse 1/0 for a CHD diff; commit folds
the layer into the durable base; rollback discards it. Raw and COW nodes do
512-byte read-modify-write for partial writes, and block_status reports which
layer serves a byte range.

ScsiDevice::open remains the single constructor both the WD33C93A and the
AIC-7880 use; it now builds nodes, preserving CHD and COW support on both
controllers. ScsiIdentity, the allocation-length truncation from techomancer#279 and the
zero-length REQUEST SENSE rule from techomancer#283 are unchanged. The GUI commit path
and chd-extract use the nodes instead of matching the enum.

Ported from the irix7/iris implementation (df7f6c7, 1801c06, d9c1953),
reconciled with the ScsiIdentity/open seam from techomancer#265.

Refs techomancer#336, techomancer#265, techomancer#279, techomancer#283.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant