pci: vfio: Probe migration v2 capabilities

Probe VFIO_DEVICE_FEATURE_MIGRATION during VfioCommon::new() and store
the result in a new migration_flags field so later migration phases can
gate state machine transitions.

The probe runs on every instantiation, including snapshot restore,
because migration capability is a property of the host kernel and its
variant driver rather than of any saved VM state.

migration_flags() is added to the internal Vfio trait with a default
implementation that returns Ok(None), meaning not migratable.
VfioDeviceWrapper overrides it to issue the kernel ioctl, while
vfio-user devices keep the default and are always treated as non
migratable.

Allow the VFIO_DEVICE_FEATURE ioctl in the VMM seccomp filter.

Signed-off-by: Saravanan D <saravanand@crusoe.ai>
This commit is contained in:
Saravanan D
2026-04-17 07:50:09 +00:00
committed by Bo Chen
parent f5344414e9
commit 41ffd04644
2 changed files with 37 additions and 1 deletions

View File

@@ -15,7 +15,7 @@ use anyhow::anyhow;
use byteorder::{ByteOrder, LittleEndian};
use hypervisor::HypervisorVmError;
use libc::{_SC_PAGESIZE, sysconf};
use log::{error, info};
use log::{debug, error, info};
use serde::{Deserialize, Serialize};
use thiserror::Error;
use vfio_bindings::bindings::vfio::*;
@@ -437,6 +437,10 @@ pub(crate) trait Vfio: Send + Sync {
fn unmask_irq(&self, _irq_index: u32) -> Result<(), VfioError> {
unimplemented!()
}
fn migration_flags(&self) -> Result<Option<u64>, VfioError> {
Ok(None)
}
}
struct VfioDeviceWrapper {
@@ -479,6 +483,12 @@ impl Vfio for VfioDeviceWrapper {
.unmask_irq(irq_index)
.map_err(VfioError::KernelVfio)
}
fn migration_flags(&self) -> Result<Option<u64>, VfioError> {
self.device
.query_migration_support()
.map_err(VfioError::KernelVfio)
}
}
#[derive(Serialize, Deserialize)]
@@ -503,6 +513,8 @@ pub(crate) struct VfioCommon {
pub(crate) patches: HashMap<usize, ConfigPatch>,
x_nv_gpudirect_clique: Option<u8>,
x_exclude_mmap_bars: Vec<u8>,
#[allow(dead_code)]
pub(crate) migration_flags: Option<u64>,
}
#[derive(Default)]
@@ -542,6 +554,27 @@ impl VfioCommon {
pci_configuration_state,
);
let migration_flags = match vfio_wrapper.migration_flags() {
Ok(Some(flags)) => {
info!(
"VFIO device {bdf} supports migration v2 (flags=0x{flags:x}, \
STOP_COPY={}, P2P={}, PRE_COPY={})",
flags & VFIO_MIGRATION_STOP_COPY as u64 != 0,
flags & VFIO_MIGRATION_P2P as u64 != 0,
flags & VFIO_MIGRATION_PRE_COPY as u64 != 0,
);
Some(flags)
}
Ok(None) => {
debug!("VFIO device {bdf} does not support migration v2");
None
}
Err(e) => {
debug!("VFIO device {bdf} migration probe failed, treating as non-migratable: {e}");
None
}
};
let mut vfio_common = VfioCommon {
mmio_regions: Vec::new(),
configuration,
@@ -556,6 +589,7 @@ impl VfioCommon {
patches: HashMap::new(),
x_nv_gpudirect_clique: config.x_nv_gpudirect_clique,
x_exclude_mmap_bars: config.x_exclude_mmap_bars,
migration_flags,
};
let state: Option<VfioCommonState> = snapshot

View File

@@ -86,6 +86,7 @@ const VFIO_DEVICE_RESET: u64 = 0x3b6f;
const VFIO_IOMMU_MAP_DMA: u64 = 0x3b71;
const VFIO_IOMMU_UNMAP_DMA: u64 = 0x3b72;
const VFIO_DEVICE_IOEVENTFD: u64 = 0x3b74;
const VFIO_DEVICE_FEATURE: u64 = 0x3b75;
// See include/uapi/linux/kvm.h in the kernel code.
#[cfg(feature = "kvm")]
@@ -381,6 +382,7 @@ fn create_vmm_ioctl_seccomp_rule_common(
and![Cond::new(1, ArgLen::Dword, Eq, VFIO_IOMMU_MAP_DMA)?],
and![Cond::new(1, ArgLen::Dword, Eq, VFIO_IOMMU_UNMAP_DMA)?],
and![Cond::new(1, ArgLen::Dword, Eq, VFIO_DEVICE_IOEVENTFD)?],
and![Cond::new(1, ArgLen::Dword, Eq, VFIO_DEVICE_FEATURE)?],
and![Cond::new(1, ArgLen::Dword, Eq, VHOST_GET_FEATURES())?],
and![Cond::new(1, ArgLen::Dword, Eq, VHOST_SET_FEATURES())?],
and![Cond::new(1, ArgLen::Dword, Eq, VHOST_SET_OWNER())?],