Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/devices/src/virtio/vhost_user_backend/block.rs
5394 views
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
use snapshot::AnySnapshot;
12
pub use sys::start_device as run_block_device;
13
pub use sys::Options;
14
use vm_memory::GuestMemory;
15
use vmm_vhost::message::*;
16
17
use crate::virtio;
18
use crate::virtio::block::asynchronous::BlockAsync;
19
use crate::virtio::vhost_user_backend::handler::DeviceRequestHandler;
20
use crate::virtio::vhost_user_backend::handler::VhostUserDevice;
21
use crate::virtio::vhost_user_backend::VhostUserDeviceBuilder;
22
use crate::virtio::VirtioDevice;
23
24
const NUM_QUEUES: u16 = 16;
25
26
struct BlockBackend {
27
inner: Box<BlockAsync>,
28
29
avail_features: u64,
30
}
31
32
#[derive(Serialize, Deserialize)]
33
struct BlockBackendSnapshot {
34
// `avail_features` don't need to be snapshotted, but they are
35
// to be used to make sure that the proper features are used on `restore`.
36
avail_features: u64,
37
}
38
39
impl 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
51
impl 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
// TODO: This assumes that `reset` only stops workers which might not be true in the
92
// future. Consider moving the `reset` code into a `stop_all_workers` method or, maybe,
93
// make `stop_queue` implicitly stop a worker thread when there is no active queue.
94
self.inner.reset()?;
95
Ok(())
96
}
97
98
fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
99
// The queue states are being snapshotted in the device handler.
100
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
}
118
119