Skip to content

Conversation

@ser-io
Copy link
Member

@ser-io ser-io commented Dec 15, 2025

Port virtio media reference device simple_device as a vhost user implementation.

First iteration of simple_device/src/simple_device.rs is the same as in virtio-media upstream https://github.com/chromeos/virtio-media/blob/main/device/src/devices/simple_device.rs.

cargo run --bin simple_device  -- --socket-path /tmp/simple_device.sock
cargo run --features "media" -- --log-level=debug run --cpus 4 --mem 4096 \
  --rwdisk /path/to/debian-12.img \
  --params "root=/dev/vda1" \
  --vhost-user media,socket=/tmp/simple_device.sock \
  /path/to/bzImage

v4l2-compliance -d0 -s

Bug: 445229097

@ser-io ser-io requested review from Databean and jemoreira December 15, 2025 22:34
@jemoreira
Copy link
Member

Port virtio media reference device simple_device as a vhost user implementation.

First iteration of simple_device/src/simple_device.rs is the same as in virtio-media upstream https://github.com/chromeos/virtio-media/blob/main/device/src/devices/simple_device.rs.

Why are you copying this code here instead of depending on it? Would it be possible to contribute changes upstream and only implement the cuttlefish-specific changes here?

@ser-io ser-io requested a review from adelva1984 December 18, 2025 19:05
@ser-io ser-io force-pushed the virtio-media-use-new-SHMEM branch from d42f8bd to db5b139 Compare January 22, 2026 22:14
@ser-io
Copy link
Member Author

ser-io commented Jan 22, 2026

Port virtio media reference device simple_device as a vhost user implementation.
First iteration of simple_device/src/simple_device.rs is the same as in virtio-media upstream https://github.com/chromeos/virtio-media/blob/main/device/src/devices/simple_device.rs.

Why are you copying this code here instead of depending on it? Would it be possible to contribute changes upstream and only implement the cuttlefish-specific changes here?

Removed the copy depending on the upstream implementation.

@ser-io ser-io force-pushed the virtio-media-use-new-SHMEM branch 3 times, most recently from 833efed to fadcf29 Compare January 24, 2026 00:20
serde = { version = "1.0", features = ["derive"] }
serde_json = "1"

[patch.crates-io]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll remove this once rust-vmm/vhost/pull/339 is merged in.

@ser-io ser-io force-pushed the virtio-media-use-new-SHMEM branch from fadcf29 to 8b2a123 Compare January 24, 2026 00:33
@ser-io ser-io requested review from Databean and jemoreira January 24, 2026 00:34
Run the device.

```
RUST_LOG=trace cargo run --bin simple_device -- --socket-path /tmp/simple_device.sock

or

RUST_LOG=trace bazel run simple_device:simple_device -- --socket-path /tmp/simple_device.sock
```

Run the VM.

```
cargo run -- --log-level=debug run --cpus 4 --mem 4096 \
  --rwdisk /path/to/debian-12.img \
  --params "root=/dev/vda1" \
  --vhost-user media,socket=/tmp/simple_device.sock \
  /path/to/bzImage

v4l2-compliance -d0 -s
```

Bug: 445229097
@ser-io ser-io force-pushed the virtio-media-use-new-SHMEM branch from 8b2a123 to 774f02d Compare January 29, 2026 18:05
}
});

handle.join().map_err(std::panic::resume_unwind).unwrap()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused by resume_unwind here, which is documented as

This is designed to be used in conjunction with catch_unwind to, for example, carry a panic across a layer of C code.

I don't see a catch_unwind in this PR, does it come out of one of the libraries?

thread::spawn's NOTES mentions catch_unwind but doesn't explicitly say the two should be used together.

Comment on lines +149 to +158
vhost_user_media_workspace_crates = use_extension("@rules_rust//crate_universe:extensions.bzl", "crate")
vhost_user_media_workspace_crates.from_cargo(
name = "vhost_user_media_workspace_crates",
cargo_config = "@//build_external/crosvm:crosvm.config.toml",
manifests = [
"//cuttlefish/host/commands/vhost_user_media:Cargo.toml",
],
host_tools = "@rust_host_tools_nightly",
)
use_repo(vhost_user_media_workspace_crates, "vhost_user_media_workspace_crates")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this go in a vhost_user_media.MODULE.bazel file in the vhost_user_media directory?

Copy link
Member

@Databean Databean left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of the comments apply in multiple places, like reducing map_err usage in favor of automatic conversion with From.

#[error("Failed to handle unknown event")]
HandleEventUnknown,
#[error("Descriptor chain error")]
DescriptorChainError(virtio_queue::Error),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A feature of thiserror is that this can be written as

DescriptorChainError(#[from] virtio_queue::Error),

This automatically creates From<DescriptorChainError> implementation for VhuMediaBackendError. ? will automatically invoke From conversions, meaning that other uses can be simplified:

vring
    .get_mut()
    .add_used(head_index, writer.bytes_written() as u32)
    .map_err(|e| VhuMediaBackendError::DescriptorChainError(e))?;

becomes

vring
    .get_mut()
    .add_used(head_index, writer.bytes_written() as u32)?;

}

fn queues_per_thread(&self) -> Vec<u64> {
return vec![3];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this can be vec![3] (no return or semicolon) as Rust will use the final expression in a function as a return value.

| VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits()
}

fn protocol_features(&self) -> vhost::vhost_user::message::VhostUserProtocolFeatures {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: vhost::vhost_user::message::VhostUserProtocolFeatures has a use statement, it doesn't need a full path.

if requests.is_empty() {
return Err(VhuMediaBackendError::DescriptorUnavailable);
}
for desc_chain in requests.clone() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does requests need to be clone()d here? It doesn't look like it is used anywhere else.

Comment on lines +210 to +216
if let Err(e) = match event {
V4l2Event::DequeueBuffer(e) => WriteToDescriptorChain::write_obj(&mut writer, e),
V4l2Event::Error(e) => WriteToDescriptorChain::write_obj(&mut writer, e),
V4l2Event::Event(e) => WriteToDescriptorChain::write_obj(&mut writer, e),
} {
return Err(VhuMediaBackendError::Io(e));
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be written as

match event {
  V4l2Event::DequeueBuffer(e) | V4l2Event::Error(e) | V4l2Event::Event(e) => WriteToDescriptorChain::write_obj(&mut writer, e)?,
}

From the reference

Multiple match patterns may be joined with the | operator. Each pattern will be tested in left-to-right sequence until a successful match is found.

Every binding in each | separated pattern must appear in all of the patterns in the arm.

Every binding of the same name must have the same type, and have the same binding mode.

The ? operator will automatically use the From<std::io::Error> conversion defind fro VhuMediaBackendError.

}
}
unknown_cmd => {
error!("unknown virtio media command: {}", unknown_cmd);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

error! supports standard Rust format strings, which can use variable names inline, i.e.

error!("unknown virtio media command: {unknown_cmd}");

error!("device new session error: {}", e);
writer
.write_err_response(e)
.map_err(|e| VhuMediaBackendError::Io(e))?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VhuMediaBackendError::Io defines a From<io::Error> implementation, so this could be collapsed to

writer.write_err_response(e)?;

using automatic From conversion in the ? operator.

Comment on lines +129 to +132
let mut flags = VhostUserMMapFlags::empty();
if rw {
flags |= VhostUserMMapFlags::WRITABLE;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: An alternative to making this variable mut is to use an if expression:

let flags = if rw { VhostUserMMapFlags::empty() } else { VhostUserMMapFlags::WRITABLE };

use vhost::vhost_user::message::VhostUserProtocolFeatures;
use vhost::vhost_user::message::VhostUserShMemConfig;
use vhost::vhost_user::message::VhostUserVirtioFeatures;
use vhost_user_backend::{VhostUserBackendMut, VringRwLock, VringT};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of using the combined use x::{y, z} syntax more?

It supports multiple levels of nesting, e.g.

use std::{collections::HashMap, convert, io, os::{fd::BorrowedFd, unix::io::AsRawFd}};
...
use log::{error, info};
...

It's even possible to combine everything into a single use statement:

use {
  std::collection::HashMap,
  ...
  libc::{_SC_PAGESIZE, sysconf},
  log::{error, info},
};

The style guide also has some opinions, though they don't seem like strict rules.

DescriptorUnavailable,
}

impl convert::From<VhuMediaBackendError> for io::Error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: since the 2021 edition, std::convert::From is in the prelude, so it doesn't have to be imported and can be referenced as From.

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.

3 participants