devices/virtio/vhost_user_backend/
block.rs1mod sys;
6
7use anyhow::Context;
8use cros_async::Executor;
9use serde::Deserialize;
10use serde::Serialize;
11use snapshot::AnySnapshot;
12pub use sys::start_device as run_block_device;
13pub use sys::Options;
14use vm_memory::GuestMemory;
15use vmm_vhost::message::*;
16
17use crate::virtio;
18use crate::virtio::block::asynchronous::BlockAsync;
19use crate::virtio::vhost_user_backend::handler::DeviceRequestHandler;
20use crate::virtio::vhost_user_backend::handler::VhostUserDevice;
21use crate::virtio::vhost_user_backend::VhostUserDeviceBuilder;
22use crate::virtio::VirtioDevice;
23
24const NUM_QUEUES: u16 = 16;
25
26struct BlockBackend {
27 inner: Box<BlockAsync>,
28
29 avail_features: u64,
30}
31
32#[derive(Serialize, Deserialize)]
33struct BlockBackendSnapshot {
34 avail_features: u64,
37}
38
39impl VhostUserDeviceBuilder for BlockAsync {
40 fn build(self: Box<Self>, _ex: &Executor) -> anyhow::Result<Box<dyn vmm_vhost::Backend>> {
41 let avail_features = self.features() | 1 << VHOST_USER_F_PROTOCOL_FEATURES;
42 let backend = BlockBackend {
43 inner: self,
44 avail_features,
45 };
46 let handler = DeviceRequestHandler::new(backend);
47 Ok(Box::new(handler))
48 }
49}
50
51impl VhostUserDevice for BlockBackend {
52 fn max_queue_num(&self) -> usize {
53 NUM_QUEUES as usize
54 }
55
56 fn features(&self) -> u64 {
57 self.avail_features
58 }
59
60 fn protocol_features(&self) -> VhostUserProtocolFeatures {
61 VhostUserProtocolFeatures::CONFIG
62 | VhostUserProtocolFeatures::MQ
63 | VhostUserProtocolFeatures::BACKEND_REQ
64 | VhostUserProtocolFeatures::DEVICE_STATE
65 }
66
67 fn read_config(&self, offset: u64, data: &mut [u8]) {
68 self.inner.read_config(offset, data)
69 }
70
71 fn reset(&mut self) {
72 if let Err(e) = self.inner.reset() {
73 base::error!("reset failed: {:#}", e);
74 }
75 }
76
77 fn start_queue(
78 &mut self,
79 idx: usize,
80 queue: virtio::Queue,
81 mem: GuestMemory,
82 ) -> anyhow::Result<()> {
83 self.inner.start_queue(idx, queue, mem)
84 }
85
86 fn stop_queue(&mut self, idx: usize) -> anyhow::Result<virtio::Queue> {
87 self.inner.stop_queue(idx)
88 }
89
90 fn enter_suspended_state(&mut self) -> anyhow::Result<()> {
91 self.inner.reset()?;
95 Ok(())
96 }
97
98 fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
99 AnySnapshot::to_any(BlockBackendSnapshot {
101 avail_features: self.avail_features,
102 })
103 .context("Failed to serialize BlockBackendSnapshot")
104 }
105
106 fn restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
107 let block_backend_snapshot: BlockBackendSnapshot =
108 AnySnapshot::from_any(data).context("Failed to deserialize BlockBackendSnapshot")?;
109 anyhow::ensure!(
110 self.avail_features == block_backend_snapshot.avail_features,
111 "Vhost user block restored avail_features do not match. Live: {:?}, snapshot: {:?}",
112 self.avail_features,
113 block_backend_snapshot.avail_features,
114 );
115 Ok(())
116 }
117}