// Copyright 2025 Red Hat, Inc. // Author(s): Paolo Bonzini // SPDX-License-Identifier: GPL-2.0-or-later use std::{ fmt, mem::size_of, ptr::{self, addr_of, NonNull}, sync::{Arc, Mutex}, }; use bql::{BqlCell, BqlRefCell}; use common::Zeroable; use crate::{ bindings, vmstate_fields_ref, vmstate_of, InvalidError, VMState, VMStateDescriptionBuilder, }; /// Enables QEMU migration support even when a type is wrapped with /// synchronization primitives (like `Mutex`) that the C migration /// code cannot directly handle. The trait provides methods to /// extract essential state for migration and restore it after /// migration completes. /// /// On top of extracting data from synchronization wrappers during save /// and restoring it during load, it's also possible to use `ToMigrationState` /// to convert runtime representations to migration-safe formats. /// /// # Examples /// /// ``` /// use bql::BqlCell; /// use migration::{InvalidError, ToMigrationState, VMState}; /// # use migration::VMStateField; /// /// # #[derive(Debug, PartialEq, Eq)] /// struct DeviceState { /// counter: BqlCell, /// enabled: bool, /// } /// /// # #[derive(Debug)] /// #[derive(Default)] /// struct DeviceMigrationState { /// counter: u32, /// enabled: bool, /// } /// /// # unsafe impl VMState for DeviceMigrationState { /// # const BASE: VMStateField = ::common::Zeroable::ZERO; /// # } /// impl ToMigrationState for DeviceState { /// type Migrated = DeviceMigrationState; /// /// fn snapshot_migration_state( /// &self, /// target: &mut Self::Migrated, /// ) -> Result<(), InvalidError> { /// target.counter = self.counter.get(); /// target.enabled = self.enabled; /// Ok(()) /// } /// /// fn restore_migrated_state_mut( /// &mut self, /// source: Self::Migrated, /// _version_id: u8, /// ) -> Result<(), InvalidError> { /// self.counter.set(source.counter); /// self.enabled = source.enabled; /// Ok(()) /// } /// } /// # bql::start_test(); /// # let dev = DeviceState { counter: 10.into(), enabled: true }; /// # let mig = dev.to_migration_state().unwrap(); /// # assert!(matches!(*mig, DeviceMigrationState { counter: 10, enabled: true })); /// # let mut dev2 = DeviceState { counter: 42.into(), enabled: false }; /// # dev2.restore_migrated_state_mut(*mig, 1).unwrap(); /// # assert_eq!(dev2, dev); /// ``` /// /// More commonly, the trait is derived through the /// [`derive(ToMigrationState)`](qemu_macros::ToMigrationState) procedural /// macro. pub trait ToMigrationState { /// The type used to represent the migrated state. type Migrated: Default + VMState; /// Capture the current state into a migration-safe format, failing /// if the state cannot be migrated. fn snapshot_migration_state(&self, target: &mut Self::Migrated) -> Result<(), InvalidError>; /// Restores state from a migrated representation, failing if the /// state cannot be restored. fn restore_migrated_state_mut( &mut self, source: Self::Migrated, version_id: u8, ) -> Result<(), InvalidError>; /// Convenience method to combine allocation and state capture /// into a single operation. fn to_migration_state(&self) -> Result, InvalidError> { let mut migrated = Box::::default(); self.snapshot_migration_state(&mut migrated)?; Ok(migrated) } } // Implementations for primitive types. Do not use a blanket implementation // for all Copy types, because [T; N] is Copy if T is Copy; that would conflict // with the below implementation for arrays. macro_rules! impl_for_primitive { ($($t:ty),*) => { $( impl ToMigrationState for $t { type Migrated = Self; fn snapshot_migration_state( &self, target: &mut Self::Migrated, ) -> Result<(), InvalidError> { *target = *self; Ok(()) } fn restore_migrated_state_mut( &mut self, source: Self::Migrated, _version_id: u8, ) -> Result<(), InvalidError> { *self = source; Ok(()) } } )* }; } impl_for_primitive!(u8, u16, u32, u64, i8, i16, i32, i64, bool); impl ToMigrationState for [T; N] where [T::Migrated; N]: Default, { type Migrated = [T::Migrated; N]; fn snapshot_migration_state(&self, target: &mut Self::Migrated) -> Result<(), InvalidError> { for (item, target_item) in self.iter().zip(target.iter_mut()) { item.snapshot_migration_state(target_item)?; } Ok(()) } fn restore_migrated_state_mut( &mut self, source: Self::Migrated, version_id: u8, ) -> Result<(), InvalidError> { for (item, source_item) in self.iter_mut().zip(source) { item.restore_migrated_state_mut(source_item, version_id)?; } Ok(()) } } impl ToMigrationState for Mutex { type Migrated = T::Migrated; fn snapshot_migration_state(&self, target: &mut Self::Migrated) -> Result<(), InvalidError> { self.lock().unwrap().snapshot_migration_state(target) } fn restore_migrated_state_mut( &mut self, source: Self::Migrated, version_id: u8, ) -> Result<(), InvalidError> { self.get_mut() .unwrap() .restore_migrated_state_mut(source, version_id) } } impl ToMigrationState for BqlRefCell { type Migrated = T::Migrated; fn snapshot_migration_state(&self, target: &mut Self::Migrated) -> Result<(), InvalidError> { self.borrow().snapshot_migration_state(target) } fn restore_migrated_state_mut( &mut self, source: Self::Migrated, version_id: u8, ) -> Result<(), InvalidError> { self.get_mut() .restore_migrated_state_mut(source, version_id) } } /// Extension trait for types that support migration state restoration /// through interior mutability. /// /// This trait extends [`ToMigrationState`] for types that can restore /// their state without requiring mutable access. While user structs /// will generally use `ToMigrationState`, the device will have multiple /// references and therefore the device struct has to employ an interior /// mutability wrapper like [`Mutex`] or [`BqlRefCell`]. /// /// Anything that implements this trait can in turn be used within /// [`Migratable`], which makes no assumptions on how to achieve mutable /// access to the runtime state. /// /// # Examples /// /// ``` /// use std::sync::Mutex; /// /// use migration::ToMigrationStateShared; /// /// let device_state = Mutex::new(42); /// // Can restore without &mut access /// device_state.restore_migrated_state(100, 1).unwrap(); /// assert_eq!(*device_state.lock().unwrap(), 100); /// ``` pub trait ToMigrationStateShared: ToMigrationState { /// Restores state from a migrated representation to an interior-mutable /// object. Similar to `restore_migrated_state_mut`, but requires a /// shared reference; therefore it can be used to restore a device's /// state even though devices have multiple references to them. fn restore_migrated_state( &self, source: Self::Migrated, version_id: u8, ) -> Result<(), InvalidError>; } impl ToMigrationStateShared for [T; N] where [T::Migrated; N]: Default, { fn restore_migrated_state( &self, source: Self::Migrated, version_id: u8, ) -> Result<(), InvalidError> { for (item, source_item) in self.iter().zip(source) { item.restore_migrated_state(source_item, version_id)?; } Ok(()) } } // Arc requires the contained object to be interior-mutable impl ToMigrationState for Arc { type Migrated = T::Migrated; fn snapshot_migration_state(&self, target: &mut Self::Migrated) -> Result<(), InvalidError> { (**self).snapshot_migration_state(target) } fn restore_migrated_state_mut( &mut self, source: Self::Migrated, version_id: u8, ) -> Result<(), InvalidError> { (**self).restore_migrated_state(source, version_id) } } impl ToMigrationStateShared for Arc { fn restore_migrated_state( &self, source: Self::Migrated, version_id: u8, ) -> Result<(), InvalidError> { (**self).restore_migrated_state(source, version_id) } } // Interior-mutable types. Note how they only require ToMigrationState for // the inner type! impl ToMigrationStateShared for Mutex { fn restore_migrated_state( &self, source: Self::Migrated, version_id: u8, ) -> Result<(), InvalidError> { self.lock() .unwrap() .restore_migrated_state_mut(source, version_id) } } impl ToMigrationStateShared for BqlRefCell { fn restore_migrated_state( &self, source: Self::Migrated, version_id: u8, ) -> Result<(), InvalidError> { self.borrow_mut() .restore_migrated_state_mut(source, version_id) } } /// A wrapper that enables QEMU migration for types with shared state. /// /// `Migratable` provides a bridge between Rust types that use interior /// mutability (like `Mutex`) and QEMU's C-based migration infrastructure. /// It manages the lifecycle of migration state and provides automatic /// conversion between runtime and migration representations. /// /// ``` /// # use std::sync::Mutex; /// # use migration::{Migratable, ToMigrationState, VMState, VMStateField}; /// /// #[derive(ToMigrationState)] /// pub struct DeviceRegs { /// status: u32, /// } /// # unsafe impl VMState for DeviceRegsMigration { /// # const BASE: VMStateField = ::common::Zeroable::ZERO; /// # } /// /// pub struct SomeDevice { /// // ... /// registers: Migratable>, /// } /// ``` #[repr(C)] pub struct Migratable { /// Pointer to migration state, valid only during migration operations. /// C vmstate does not support NULL pointers, so no `Option>`. migration_state: BqlCell<*mut T::Migrated>, /// The runtime state that can be accessed during normal operation runtime_state: T, } impl std::ops::Deref for Migratable { type Target = T; fn deref(&self) -> &Self::Target { &self.runtime_state } } impl std::ops::DerefMut for Migratable { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.runtime_state } } impl Migratable { /// Creates a new `Migratable` wrapper around the given runtime state. /// /// # Returns /// A new `Migratable` instance ready for use and migration pub fn new(runtime_state: T) -> Self { Self { migration_state: BqlCell::new(ptr::null_mut()), runtime_state, } } fn pre_save(&self) -> Result<(), InvalidError> { let state = self.runtime_state.to_migration_state()?; self.migration_state.set(Box::into_raw(state)); Ok(()) } fn post_save(&self) -> Result<(), InvalidError> { let state = unsafe { Box::from_raw(self.migration_state.replace(ptr::null_mut())) }; drop(state); Ok(()) } fn pre_load(&self) -> Result<(), InvalidError> { self.migration_state .set(Box::into_raw(Box::::default())); Ok(()) } fn post_load(&self, version_id: u8) -> Result<(), InvalidError> { let state = unsafe { Box::from_raw(self.migration_state.replace(ptr::null_mut())) }; self.runtime_state .restore_migrated_state(*state, version_id) } } impl fmt::Debug for Migratable where T::Migrated: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut struct_f = f.debug_struct("Migratable"); struct_f.field("runtime_state", &self.runtime_state); let state = NonNull::new(self.migration_state.get()).map(|x| unsafe { x.as_ref() }); struct_f.field("migration_state", &state); struct_f.finish() } } impl Default for Migratable { fn default() -> Self { Self::new(T::default()) } } impl Migratable { const FIELD: bindings::VMStateField = vmstate_of!(Self, migration_state); const FIELDS: &[bindings::VMStateField] = vmstate_fields_ref! { Migratable::::FIELD }; const VMSD: &'static bindings::VMStateDescription = VMStateDescriptionBuilder::::new() .version_id(1) .minimum_version_id(1) .pre_save(&Self::pre_save) .pre_load(&Self::pre_load) .post_save(&Self::post_save) .post_load(&Self::post_load) .fields(Self::FIELDS) .build() .as_ref(); } unsafe impl VMState for Migratable { const BASE: bindings::VMStateField = { bindings::VMStateField { vmsd: addr_of!(*Self::VMSD), size: size_of::(), flags: bindings::VMStateFlags::VMS_STRUCT, ..Zeroable::ZERO } }; }