Skip to content

Commit 236328a

Browse files
committed
fix: snapshot: disallow snapshots with vhost-user devices
Previously we were incorrectly allow snapshots to be created even with vhost-user devices by simply ignoring them. Now we correctly return an error if we detect vhost-user devices. Signed-off-by: Egor Lazarchuk <yegorlz@amazon.co.uk>
1 parent 53b382a commit 236328a

3 files changed

Lines changed: 46 additions & 19 deletions

File tree

src/vmm/src/device_manager/persist.rs

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ use crate::devices::virtio::vsock::persist::{
3737
VsockConstructorArgs, VsockState, VsockUdsConstructorArgs,
3838
};
3939
use crate::devices::virtio::vsock::{Vsock, VsockUnixBackend};
40-
use crate::logger::warn;
4140
use crate::mmds::data_store::MmdsVersion;
4241
use crate::resources::VmResources;
4342
use crate::snapshot::Persist;
@@ -256,20 +255,17 @@ impl<'a> Persist<'a> for MMIODeviceManager {
256255
// Both virtio-block and vhost-user-block share same device type.
257256
VirtioDeviceType::Block => {
258257
let block = locked_device.as_mut_any().downcast_mut::<Block>().unwrap();
259-
if block.is_vhost_user() {
260-
warn!(
261-
"Skipping vhost-user-block device. VhostUserBlock does not support \
262-
snapshotting yet"
263-
);
264-
} else {
265-
let device_state = block.save();
266-
states.block_devices.push(VirtioDeviceState {
267-
device_id,
268-
device_state,
269-
transport_state,
270-
device_info,
271-
});
272-
}
258+
assert!(
259+
!block.is_vhost_user(),
260+
"vhost-user-block does not support snapshotting yet"
261+
);
262+
let device_state = block.save();
263+
states.block_devices.push(VirtioDeviceState {
264+
device_id,
265+
device_state,
266+
transport_state,
267+
device_info,
268+
});
273269
}
274270
VirtioDeviceType::Net => {
275271
let net = locked_device.as_mut_any().downcast_mut::<Net>().unwrap();

src/vmm/src/lib.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,20 @@ impl Vmm {
449449
}
450450
}
451451

452+
/// Check if the VM can be snapshotted
453+
pub fn can_snapshot(&self) -> bool {
454+
let mut has_vhost_user_devices = false;
455+
self.device_manager
456+
.for_each_virtio_device(|device_type, device| {
457+
if let VirtioDeviceType::Block = device_type
458+
&& let Some(b) = device.as_any().downcast_ref::<Block>()
459+
{
460+
has_vhost_user_devices |= b.is_vhost_user();
461+
}
462+
});
463+
!has_vhost_user_devices
464+
}
465+
452466
/// Starts the microVM vcpus.
453467
///
454468
/// # Errors
@@ -555,7 +569,12 @@ impl Vmm {
555569

556570
/// Saves the state of a paused Microvm.
557571
pub fn save_state(&mut self, vm_info: &VmInfo) -> Result<MicrovmState, MicrovmStateError> {
558-
use self::MicrovmStateError::SaveVmState;
572+
if !self.can_snapshot() {
573+
return Err(MicrovmStateError::NotAllowed(
574+
"Devices without snapshot support are present".into(),
575+
));
576+
}
577+
559578
// We need to save device state before saving KVM state.
560579
// Some devices, (at the time of writing this comment block device with async engine)
561580
// might modify the VirtIO transport and send an interrupt to the guest. If we save KVM
@@ -567,13 +586,17 @@ impl Vmm {
567586
let vm_state = {
568587
#[cfg(target_arch = "x86_64")]
569588
{
570-
self.vm.save_state().map_err(SaveVmState)?
589+
self.vm
590+
.save_state()
591+
.map_err(MicrovmStateError::SaveVmState)?
571592
}
572593
#[cfg(target_arch = "aarch64")]
573594
{
574595
let mpidrs = construct_kvm_mpidrs(&vcpu_states);
575596

576-
self.vm.save_state(&mpidrs).map_err(SaveVmState)?
597+
self.vm
598+
.save_state(&mpidrs)
599+
.map_err(MicrovmStateError::SaveVmState)?
577600
}
578601
};
579602

tests/integration_tests/functional/test_drive_vhost_user.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ def _check_drives(test_microvm, assert_dict, keys_array):
8888
def test_vhost_user_block(uvm_vhost_user_booted_ro):
8989
"""
9090
This test simply tries to boot a VM with
91-
vhost-user-block as a root device.
91+
vhost-user-block as a root device and then
92+
tries to snapshot it.
9293
"""
9394

9495
vm = uvm_vhost_user_booted_ro
@@ -105,6 +106,13 @@ def test_vhost_user_block(uvm_vhost_user_booted_ro):
105106
_check_drives(vm, assert_dict, assert_dict.keys())
106107
vhost_user_block_metrics.validate(vm)
107108

109+
with pytest.raises(
110+
RuntimeError, match="Devices without snapshot support are present"
111+
):
112+
vm.api.snapshot_create.put(
113+
mem_file_path="memfile", snapshot_path="statefile", snapshot_type="Full"
114+
)
115+
108116

109117
def test_vhost_user_block_read_write(uvm_vhost_user_booted_rw):
110118
"""

0 commit comments

Comments
 (0)