Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

scsi rebase #301

Merged
merged 13 commits into from
Jun 5, 2023
95 changes: 88 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ members = [
"crates/gpio",
"crates/i2c",
"crates/rng",
"crates/scsi",
"crates/vsock",
]
2 changes: 1 addition & 1 deletion coverage_config_x86_64.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"coverage_score": 67.6,
"coverage_score": 69.6,
"exclude_path": "",
"crate_features": ""
}
39 changes: 39 additions & 0 deletions crates/scsi/ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# vhost-user-scsi architecture

Rough outline of the different pieces and how they fit together:

## `scsi/mod.rs`

This defines the `Target` trait, which represents a SCSI target. The code in
this file is independent from:

- A particular SCSI implementation: Currently, we have one implementation of
`Target`, which emulates the SCSI commands itself; but future implementations
could provide pass-through to an iSCSI target or SCSI devices attached to the
host.
- A particular SCSI transport: Nothing in `src/scsi/*` knows anything about
virtio; this is helpful for maintainability, and also allows our SCSI
emulation code to be reusable as, for example, an iSCSI target. To this end,
the `Target` trait is generic over a `Read` and `Write` that it uses for SCSI
data transfer. This makes testing easy: we can just provide a `Vec<u8>` to
write into.

## `scsi/emulation/*.rs`

This is the SCSI emulation code, which forms the bulk of the crate. It provides
`EmulatedTarget`, an implementation of `Target`. `EmulatedTarget`, in turn,
looks at the LUN and delegates commands to an implementation of `LogicalUnit`.
In most cases, this will be `BlockDevice`; there's also `MissingLun`, which is
used for responding to commands to invalid LUNs.

Currently, there is no separation between commands defined in the SPC standard
(commands shared by all device types) and the SBC standard (block-device
specific commands). If we ever implemented another device type (CD/DVD seems
most likely), we'd want to separate those out.

As noted above, the emulation code knows nothing about virtio.

## `src/{main,virtio}.rs`

This code handles vhost-user, virtio, and virtio-scsi; it's the only part of
the crate that knows about these protocols.
3 changes: 3 additions & 0 deletions crates/scsi/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Upcoming Release

- First initial daemon implementation.
31 changes: 31 additions & 0 deletions crates/scsi/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[package]
name = "vhost-device-scsi"
version = "0.1.0"
authors = ["Gaelan Steele <[email protected]>", "Erik Schilling <[email protected]>"]
description = "vhost scsi backend device"
repository = "https://github.com/rust-vmm/vhost-device"
readme = "README.md"
keywords = ["scsi", "vhost", "virt", "backend"]
license = "Apache-2.0 OR BSD-3-Clause"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
clap = { version = "4.2", features = ["derive"] }
env_logger = "0.10"
epoll = "4.3"
log = "0.4"
num_enum = "0.5"
thiserror = "1.0"
vhost = { version = "0.7", features = ["vhost-user-slave"] }
vhost-user-backend = "0.9"
# until the scsi bindings hit a release, we have to use the commit that adds them as rev.
virtio-bindings = { git = "https://github.com/rust-vmm/vm-virtio", rev = "467c8ec99375a5f4e08b85b18257cd7e0bac1dc0" }
virtio-queue = "0.8"
vm-memory = "0.11"
vmm-sys-util = "0.11"

[dev-dependencies]
tempfile = "3.2.0"

Ablu marked this conversation as resolved.
Show resolved Hide resolved
48 changes: 48 additions & 0 deletions crates/scsi/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# vhost-user-scsi

This is a Rust implementation of a vhost-user-scsi daemon.

## Usage

Run the vhost-user-scsi daemon:

```
vhost-user-scsi -r --socket-path /tmp/vhost-user-scsi.sock /path/to/image.raw /path/to/second-image.raw ...
```

Run QEMU:

```
qemu-system-x86_64 ... \
-device vhost-user-scsi-pci,num_queues=1,param_change=off,chardev=vus \
-chardev socket,id=vus,path=/tmp/vhost-user-scsi.sock \
# must match total guest meory
-object memory-backend-memfd,id=mem,size=384M,share=on \
-numa node,memdev=mem
```

## Limitations

We are currently only supporting a single request queue and do not support
dynamic reconfiguration of LUN parameters (VIRTIO_SCSI_F_CHANGE).

## Features

This crate is a work-in-progress. Currently, it's possible to mount and read
up to 256 read-only raw disk images. Some features we might like to add
at some point, roughly ordered from sooner to later:

- Write support. This should just be a matter of implementing the WRITE
command, but there's a bit of complexity around writeback caching we
need to make sure we get right.
- Support more LUNs. virtio-scsi supports up to 16384 LUNs per target.
After 256, the LUN encoding format is different; it's nothing too
complicated, but I haven't gotten around to implementing it.
- Concurrency. Currently, we process SCSI commands one at a time. Eventually,
it'd be a good idea to use threads or some fancy async/io_uring stuff to
concurrently handle multiple commands. virtio-scsi also allows for multiple
request queues, allowing the guest to submit requests from multiple cores
in parallel; we should support that.
- iSCSI passthrough. This shouldn't be too bad, but it might be a good idea
to decide on a concurrency model (threads or async) before we spend too much
time here.
Loading