xref: /aosp_15_r20/external/crosvm/devices/src/virtio/vhost/user/device/block.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2021 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 mod sys;
6 
7 use anyhow::Context;
8 use cros_async::Executor;
9 use serde::Deserialize;
10 use serde::Serialize;
11 pub use sys::start_device as run_block_device;
12 pub use sys::Options;
13 use vm_memory::GuestMemory;
14 use vmm_vhost::message::*;
15 
16 use crate::virtio;
17 use crate::virtio::block::asynchronous::BlockAsync;
18 use crate::virtio::vhost::user::device::handler::DeviceRequestHandler;
19 use crate::virtio::vhost::user::device::handler::VhostUserDevice;
20 use crate::virtio::vhost::user::device::VhostUserDeviceBuilder;
21 use crate::virtio::VirtioDevice;
22 
23 const NUM_QUEUES: u16 = 16;
24 
25 struct BlockBackend {
26     inner: Box<BlockAsync>,
27 
28     avail_features: u64,
29 }
30 
31 #[derive(Serialize, Deserialize)]
32 struct BlockBackendSnapshot {
33     // `avail_features` don't need to be snapshotted, but they are
34     // to be used to make sure that the proper features are used on `restore`.
35     avail_features: u64,
36 }
37 
38 impl VhostUserDeviceBuilder for BlockAsync {
build(self: Box<Self>, _ex: &Executor) -> anyhow::Result<Box<dyn vmm_vhost::Backend>>39     fn build(self: Box<Self>, _ex: &Executor) -> anyhow::Result<Box<dyn vmm_vhost::Backend>> {
40         let avail_features = self.features() | 1 << VHOST_USER_F_PROTOCOL_FEATURES;
41         let backend = BlockBackend {
42             inner: self,
43             avail_features,
44         };
45         let handler = DeviceRequestHandler::new(backend);
46         Ok(Box::new(handler))
47     }
48 }
49 
50 impl VhostUserDevice for BlockBackend {
max_queue_num(&self) -> usize51     fn max_queue_num(&self) -> usize {
52         NUM_QUEUES as usize
53     }
54 
features(&self) -> u6455     fn features(&self) -> u64 {
56         self.avail_features
57     }
58 
protocol_features(&self) -> VhostUserProtocolFeatures59     fn protocol_features(&self) -> VhostUserProtocolFeatures {
60         VhostUserProtocolFeatures::CONFIG
61             | VhostUserProtocolFeatures::MQ
62             | VhostUserProtocolFeatures::BACKEND_REQ
63             | VhostUserProtocolFeatures::DEVICE_STATE
64     }
65 
read_config(&self, offset: u64, data: &mut [u8])66     fn read_config(&self, offset: u64, data: &mut [u8]) {
67         self.inner.read_config(offset, data)
68     }
69 
reset(&mut self)70     fn reset(&mut self) {
71         if let Err(e) = self.inner.reset() {
72             base::error!("reset failed: {:#}", e);
73         }
74     }
75 
start_queue( &mut self, idx: usize, queue: virtio::Queue, mem: GuestMemory, ) -> anyhow::Result<()>76     fn start_queue(
77         &mut self,
78         idx: usize,
79         queue: virtio::Queue,
80         mem: GuestMemory,
81     ) -> anyhow::Result<()> {
82         self.inner.start_queue(idx, queue, mem)
83     }
84 
stop_queue(&mut self, idx: usize) -> anyhow::Result<virtio::Queue>85     fn stop_queue(&mut self, idx: usize) -> anyhow::Result<virtio::Queue> {
86         self.inner.stop_queue(idx)
87     }
88 
enter_suspended_state(&mut self) -> anyhow::Result<()>89     fn enter_suspended_state(&mut self) -> anyhow::Result<()> {
90         // TODO: This assumes that `reset` only stops workers which might not be true in the
91         // future. Consider moving the `reset` code into a `stop_all_workers` method or, maybe,
92         // make `stop_queue` implicitly stop a worker thread when there is no active queue.
93         self.inner.reset()?;
94         Ok(())
95     }
96 
snapshot(&mut self) -> anyhow::Result<serde_json::Value>97     fn snapshot(&mut self) -> anyhow::Result<serde_json::Value> {
98         // The queue states are being snapshotted in the device handler.
99         serde_json::to_value(BlockBackendSnapshot {
100             avail_features: self.avail_features,
101         })
102         .context("Failed to serialize BlockBackendSnapshot")
103     }
104 
restore(&mut self, data: serde_json::Value) -> anyhow::Result<()>105     fn restore(&mut self, data: serde_json::Value) -> anyhow::Result<()> {
106         let block_backend_snapshot: BlockBackendSnapshot =
107             serde_json::from_value(data).context("Failed to deserialize BlockBackendSnapshot")?;
108         anyhow::ensure!(
109             self.avail_features == block_backend_snapshot.avail_features,
110             "Vhost user block restored avail_features do not match. Live: {:?}, snapshot: {:?}",
111             self.avail_features,
112             block_backend_snapshot.avail_features,
113         );
114         Ok(())
115     }
116 }
117