Skip to content

Commit 6f9c738

Browse files
committed
feat: added vhost-user to device manager save/restore paths
Even though we don't support creation of snapshots with vhost-user-block device we add it to the restoration path for future use. Signed-off-by: Egor Lazarchuk <[email protected]>
1 parent 3195c87 commit 6f9c738

File tree

7 files changed

+127
-52
lines changed

7 files changed

+127
-52
lines changed

src/vmm/src/device_manager/mmio.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -396,14 +396,18 @@ impl MMIODeviceManager {
396396
}
397397
}
398398
TYPE_BLOCK => {
399-
let block = virtio.as_mut_any().downcast_mut::<VirtioBlock>().unwrap();
400-
// If device is activated, kick the block queue(s) to make up for any
401-
// pending or in-flight epoll events we may have not captured in snapshot.
402-
// No need to kick Ratelimiters because they are restored 'unblocked' so
403-
// any inflight `timer_fd` events can be safely discarded.
404-
if block.is_activated() {
405-
info!("kick block {}.", id);
406-
block.process_virtio_queues();
399+
// We only care about kicking virtio block.
400+
// If we need to kick vhost-user-block we can do nothing.
401+
if let Some(block) = virtio.as_mut_any().downcast_mut::<VirtioBlock>() {
402+
// If device is activated, kick the block queue(s) to make up for any
403+
// pending or in-flight epoll events we may have not captured in
404+
// snapshot. No need to kick Ratelimiters
405+
// because they are restored 'unblocked' so
406+
// any inflight `timer_fd` events can be safely discarded.
407+
if block.is_activated() {
408+
info!("kick block {}.", id);
409+
block.process_virtio_queues();
410+
}
407411
}
408412
}
409413
TYPE_NET => {

src/vmm/src/device_manager/persist.rs

Lines changed: 87 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::sync::{Arc, Mutex};
88

99
use event_manager::{MutEventSubscriber, SubscriberOps};
1010
use kvm_ioctls::VmFd;
11-
use log::error;
11+
use log::{error, warn};
1212
use snapshot::Persist;
1313
use versionize::{VersionMap, Versionize, VersionizeError, VersionizeResult};
1414
use versionize_derive::Versionize;
@@ -30,12 +30,17 @@ use crate::devices::virtio::rng::persist::{
3030
EntropyConstructorArgs, EntropyPersistError as EntropyError, EntropyState,
3131
};
3232
use crate::devices::virtio::rng::Entropy;
33+
use crate::devices::virtio::vhost_user_block::device::VhostUserBlock;
34+
use crate::devices::virtio::vhost_user_block::persist::{
35+
VhostUserBlockConstructorArgs, VhostUserBlockState,
36+
};
3337
use crate::devices::virtio::vsock::persist::{
3438
VsockConstructorArgs, VsockState, VsockUdsConstructorArgs,
3539
};
3640
use crate::devices::virtio::vsock::{Vsock, VsockError, VsockUnixBackend, VsockUnixBackendError};
3741
use crate::devices::virtio::{
38-
MmioTransport, VirtioDevice, TYPE_BALLOON, TYPE_BLOCK, TYPE_NET, TYPE_RNG, TYPE_VSOCK,
42+
MmioTransport, VhostUserBlockError, VirtioDevice, TYPE_BALLOON, TYPE_BLOCK, TYPE_NET, TYPE_RNG,
43+
TYPE_VSOCK,
3944
};
4045
#[cfg(target_arch = "aarch64")]
4146
use crate::logger;
@@ -49,7 +54,8 @@ use crate::EventManager;
4954
#[derive(Debug, derive_more::From)]
5055
pub enum DevicePersistError {
5156
Balloon(BalloonError),
52-
Block(VirtioBlockError),
57+
VirtioBlock(VirtioBlockError),
58+
VhostUserBlock(VhostUserBlockError),
5359
DeviceManager(super::mmio::MmioError),
5460
MmioTransport,
5561
#[cfg(target_arch = "aarch64")]
@@ -75,10 +81,10 @@ pub struct ConnectedBalloonState {
7581
pub device_info: MMIODeviceInfo,
7682
}
7783

78-
/// Holds the state of a block device connected to the MMIO space.
84+
/// Holds the state of a virtio block device connected to the MMIO space.
7985
// NOTICE: Any changes to this structure require a snapshot version bump.
8086
#[derive(Debug, Clone, Versionize)]
81-
pub struct ConnectedBlockState {
87+
pub struct ConnectedVirtioBlockState {
8288
/// Device identifier.
8389
pub device_id: String,
8490
/// Device state.
@@ -89,6 +95,20 @@ pub struct ConnectedBlockState {
8995
pub device_info: MMIODeviceInfo,
9096
}
9197

98+
/// Holds the state of a vhost-user block device connected to the MMIO space.
99+
// NOTICE: Any changes to this structure require a snapshot version bump.
100+
#[derive(Debug, Clone, Versionize)]
101+
pub struct ConnectedVhostUserBlockState {
102+
/// Device identifier.
103+
pub device_id: String,
104+
/// Device state.
105+
pub device_state: VhostUserBlockState,
106+
/// Mmio transport state.
107+
pub transport_state: MmioTransportState,
108+
/// VmmResources.
109+
pub device_info: MMIODeviceInfo,
110+
}
111+
92112
/// Holds the state of a net device connected to the MMIO space.
93113
// NOTICE: Any changes to this structure require a snapshot version bump.
94114
#[derive(Debug, Clone, Versionize)]
@@ -174,8 +194,11 @@ pub struct DeviceStates {
174194
#[cfg(target_arch = "aarch64")]
175195
// State of legacy devices in MMIO space.
176196
pub legacy_devices: Vec<ConnectedLegacyState>,
177-
/// Block device states.
178-
pub block_devices: Vec<ConnectedBlockState>,
197+
/// Virtio block device states.
198+
pub virtio_block_devices: Vec<ConnectedVirtioBlockState>,
199+
/// Vhost-user block device states.
200+
#[version(start = 5, de_fn = "de_vhost_user_block")]
201+
pub vhost_user_block_devices: Vec<ConnectedVhostUserBlockState>,
179202
/// Net device states.
180203
pub net_devices: Vec<ConnectedNetState>,
181204
/// Vsock device state.
@@ -195,13 +218,23 @@ pub struct DeviceStates {
195218
/// from a snapshot.
196219
#[derive(Debug)]
197220
pub enum SharedDeviceType {
198-
Block(Arc<Mutex<VirtioBlock>>),
221+
VirtioBlock(Arc<Mutex<VirtioBlock>>),
222+
VhostUserBlock(Arc<Mutex<VhostUserBlock>>),
199223
Network(Arc<Mutex<Net>>),
200224
Balloon(Arc<Mutex<Balloon>>),
201225
Vsock(Arc<Mutex<Vsock<VsockUnixBackend>>>),
202226
Entropy(Arc<Mutex<Entropy>>),
203227
}
204228

229+
impl DeviceStates {
230+
fn de_vhost_user_block(&mut self, source_version: u16) -> VersionizeResult<()> {
231+
if source_version < 5 {
232+
self.vhost_user_block_devices = vec![];
233+
}
234+
235+
Ok(())
236+
}
237+
}
205238
pub struct MMIODevManagerConstructorArgs<'a> {
206239
pub mem: GuestMemoryMmap,
207240
pub vm: &'a VmFd,
@@ -229,16 +262,7 @@ impl<'a> Persist<'a> for MMIODeviceManager {
229262
type Error = DevicePersistError;
230263

231264
fn save(&self) -> Self::State {
232-
let mut states = DeviceStates {
233-
balloon_device: None,
234-
block_devices: Vec::new(),
235-
net_devices: Vec::new(),
236-
vsock_device: None,
237-
#[cfg(target_arch = "aarch64")]
238-
legacy_devices: Vec::new(),
239-
mmds_version: None,
240-
entropy_device: None,
241-
};
265+
let mut states = DeviceStates::default();
242266
let _: Result<(), ()> = self.for_each_device(|devtype, devid, device_info, bus_dev| {
243267
if *devtype == crate::arch::DeviceType::BootTimer {
244268
// No need to save BootTimer state.
@@ -279,18 +303,22 @@ impl<'a> Persist<'a> for MMIODeviceManager {
279303
device_info: device_info.clone(),
280304
});
281305
}
306+
// Both virtio-block and vhost-user-block share same device type.
282307
TYPE_BLOCK => {
283-
let block = locked_device
284-
.as_mut_any()
285-
.downcast_mut::<VirtioBlock>()
286-
.unwrap();
287-
block.prepare_save();
288-
states.block_devices.push(ConnectedBlockState {
289-
device_id: devid.clone(),
290-
device_state: block.save(),
291-
transport_state,
292-
device_info: device_info.clone(),
293-
});
308+
if let Some(block) = locked_device.as_mut_any().downcast_mut::<VirtioBlock>() {
309+
block.prepare_save();
310+
states.virtio_block_devices.push(ConnectedVirtioBlockState {
311+
device_id: devid.clone(),
312+
device_state: block.save(),
313+
transport_state,
314+
device_info: device_info.clone(),
315+
})
316+
} else {
317+
warn!(
318+
"Skipping vhost-user-block device. VhostUserBlock does not support \
319+
snapshotting yet"
320+
);
321+
}
294322
}
295323
TYPE_NET => {
296324
let net = locked_device.as_any().downcast_ref::<Net>().unwrap();
@@ -477,23 +505,44 @@ impl<'a> Persist<'a> for MMIODeviceManager {
477505
)?;
478506
}
479507

480-
for block_state in &state.block_devices {
508+
for virtio_block_state in &state.virtio_block_devices {
481509
let device = Arc::new(Mutex::new(VirtioBlock::restore(
482510
VirtioBlockConstructorArgs { mem: mem.clone() },
483-
&block_state.device_state,
511+
&virtio_block_state.device_state,
512+
)?));
513+
514+
(constructor_args.for_each_restored_device)(
515+
constructor_args.vm_resources,
516+
SharedDeviceType::VirtioBlock(device.clone()),
517+
);
518+
519+
restore_helper(
520+
device.clone(),
521+
device,
522+
&virtio_block_state.device_id,
523+
&virtio_block_state.transport_state,
524+
&virtio_block_state.device_info,
525+
constructor_args.event_manager,
526+
)?;
527+
}
528+
529+
for vhost_user_block_state in &state.vhost_user_block_devices {
530+
let device = Arc::new(Mutex::new(VhostUserBlock::restore(
531+
VhostUserBlockConstructorArgs { mem: mem.clone() },
532+
&vhost_user_block_state.device_state,
484533
)?));
485534

486535
(constructor_args.for_each_restored_device)(
487536
constructor_args.vm_resources,
488-
SharedDeviceType::Block(device.clone()),
537+
SharedDeviceType::VhostUserBlock(device.clone()),
489538
);
490539

491540
restore_helper(
492541
device.clone(),
493542
device,
494-
&block_state.device_id,
495-
&block_state.transport_state,
496-
&block_state.device_info,
543+
&vhost_user_block_state.device_id,
544+
&vhost_user_block_state.transport_state,
545+
&vhost_user_block_state.device_info,
497546
constructor_args.event_manager,
498547
)?;
499548
}
@@ -619,8 +668,8 @@ mod tests {
619668
}
620669
}
621670

622-
impl PartialEq for ConnectedBlockState {
623-
fn eq(&self, other: &ConnectedBlockState) -> bool {
671+
impl PartialEq for ConnectedVirtioBlockState {
672+
fn eq(&self, other: &ConnectedVirtioBlockState) -> bool {
624673
// Actual device state equality is checked by the device's tests.
625674
self.transport_state == other.transport_state && self.device_info == other.device_info
626675
}
@@ -643,7 +692,7 @@ mod tests {
643692
impl PartialEq for DeviceStates {
644693
fn eq(&self, other: &DeviceStates) -> bool {
645694
self.balloon_device == other.balloon_device
646-
&& self.block_devices == other.block_devices
695+
&& self.virtio_block_devices == other.virtio_block_devices
647696
&& self.net_devices == other.net_devices
648697
&& self.vsock_device == other.vsock_device
649698
}

src/vmm/src/persist.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,7 @@ mod tests {
650650

651651
// Only checking that all devices are saved, actual device state
652652
// is tested by that device's tests.
653-
assert_eq!(states.block_devices.len(), 1);
653+
assert_eq!(states.virtio_block_devices.len(), 1);
654654
assert_eq!(states.net_devices.len(), 1);
655655
assert!(states.vsock_device.is_some());
656656
assert!(states.balloon_device.is_some());

src/vmm/src/resources.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,12 @@ impl VmResources {
204204
/// restoring from a snapshot).
205205
pub fn update_from_restored_device(&mut self, device: SharedDeviceType) {
206206
match device {
207-
SharedDeviceType::Block(block) => {
208-
self.block.add_device(block);
207+
SharedDeviceType::VirtioBlock(block) => {
208+
self.block.add_virtio_device(block);
209+
}
210+
211+
SharedDeviceType::VhostUserBlock(block) => {
212+
self.block.add_vhost_user_device(block);
209213
}
210214

211215
SharedDeviceType::Network(network) => {

src/vmm/src/version_map.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ lazy_static! {
8686
version_map.new_version();
8787

8888
version_map.set_type_version(VirtioDeviceState::type_id(), 2);
89+
version_map.set_type_version(DeviceStates::type_id(), 5);
8990

9091
version_map
9192
};

src/vmm/src/vmm_config/drive.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ impl BlockBuilder {
125125
}
126126

127127
/// Inserts an existing block device.
128-
pub fn add_device(&mut self, block_device: Arc<Mutex<VirtioBlock>>) {
128+
pub fn add_virtio_device(&mut self, block_device: Arc<Mutex<VirtioBlock>>) {
129129
if block_device.lock().expect("Poisoned lock").is_root_device() {
130130
self.devices
131131
.push_front(BlockDeviceType::VirtioBlock(block_device));
@@ -135,6 +135,17 @@ impl BlockBuilder {
135135
}
136136
}
137137

138+
/// Inserts an existing block device.
139+
pub fn add_vhost_user_device(&mut self, block_device: Arc<Mutex<VhostUserBlock>>) {
140+
if block_device.lock().expect("Poisoned lock").root_device {
141+
self.devices
142+
.push_front(BlockDeviceType::VhostUserBlock(block_device));
143+
} else {
144+
self.devices
145+
.push_back(BlockDeviceType::VhostUserBlock(block_device));
146+
}
147+
}
148+
138149
/// Inserts a `Block` in the block devices list using the specified configuration.
139150
/// If a block with the same id already exists, it will overwrite it.
140151
/// Inserting a secondary root block device will fail.
@@ -633,7 +644,7 @@ mod tests {
633644

634645
let block = VirtioBlock::new(config).unwrap();
635646

636-
block_devs.add_device(Arc::new(Mutex::new(block)));
647+
block_devs.add_virtio_device(Arc::new(Mutex::new(block)));
637648
assert_eq!(block_devs.devices.len(), 1);
638649
match block_devs.devices.pop_back().unwrap() {
639650
BlockDeviceType::VirtioBlock(ref b) => assert_eq!(b.lock().unwrap().id(), block_id),

src/vmm/tests/integration_tests.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,13 @@ fn verify_create_snapshot(is_diff: bool) -> (TempFile, TempFile) {
223223

224224
// Verify deserialized data.
225225
// The default vmm has no devices and one vCPU.
226-
assert_eq!(restored_microvm_state.device_states.block_devices.len(), 0);
226+
assert_eq!(
227+
restored_microvm_state
228+
.device_states
229+
.virtio_block_devices
230+
.len(),
231+
0
232+
);
227233
assert_eq!(restored_microvm_state.device_states.net_devices.len(), 0);
228234
assert!(restored_microvm_state.device_states.vsock_device.is_none());
229235
assert_eq!(restored_microvm_state.vcpu_states.len(), 1);

0 commit comments

Comments
 (0)