xref: /openbmc/qemu/rust/migration/src/migratable.rs (revision b2d86f1c5429979d9ecaf43a7973cc129da1b135)
1 // Copyright 2025 Red Hat, Inc.
2 // Author(s): Paolo Bonzini <pbonzini@redhat.com>
3 // SPDX-License-Identifier: GPL-2.0-or-later
4 
5 use std::{
6     fmt,
7     mem::size_of,
8     ptr::{self, addr_of, NonNull},
9     sync::{Arc, Mutex},
10 };
11 
12 use bql::{BqlCell, BqlRefCell};
13 use common::Zeroable;
14 
15 use crate::{
16     bindings, vmstate_fields_ref, vmstate_of, InvalidError, VMState, VMStateDescriptionBuilder,
17 };
18 
19 /// Enables QEMU migration support even when a type is wrapped with
20 /// synchronization primitives (like `Mutex`) that the C migration
21 /// code cannot directly handle. The trait provides methods to
22 /// extract essential state for migration and restore it after
23 /// migration completes.
24 ///
25 /// On top of extracting data from synchronization wrappers during save
26 /// and restoring it during load, it's also possible to use `ToMigrationState`
27 /// to convert runtime representations to migration-safe formats.
28 ///
29 /// # Examples
30 ///
31 /// ```
32 /// use bql::BqlCell;
33 /// use migration::{InvalidError, ToMigrationState, VMState};
34 /// # use migration::VMStateField;
35 ///
36 /// # #[derive(Debug, PartialEq, Eq)]
37 /// struct DeviceState {
38 ///     counter: BqlCell<u32>,
39 ///     enabled: bool,
40 /// }
41 ///
42 /// # #[derive(Debug)]
43 /// #[derive(Default)]
44 /// struct DeviceMigrationState {
45 ///     counter: u32,
46 ///     enabled: bool,
47 /// }
48 ///
49 /// # unsafe impl VMState for DeviceMigrationState {
50 /// #     const BASE: VMStateField = ::common::Zeroable::ZERO;
51 /// # }
52 /// impl ToMigrationState for DeviceState {
53 ///     type Migrated = DeviceMigrationState;
54 ///
55 ///     fn snapshot_migration_state(
56 ///         &self,
57 ///         target: &mut Self::Migrated,
58 ///     ) -> Result<(), InvalidError> {
59 ///         target.counter = self.counter.get();
60 ///         target.enabled = self.enabled;
61 ///         Ok(())
62 ///     }
63 ///
64 ///     fn restore_migrated_state_mut(
65 ///         &mut self,
66 ///         source: Self::Migrated,
67 ///         _version_id: u8,
68 ///     ) -> Result<(), InvalidError> {
69 ///         self.counter.set(source.counter);
70 ///         self.enabled = source.enabled;
71 ///         Ok(())
72 ///     }
73 /// }
74 /// # bql::start_test();
75 /// # let dev = DeviceState { counter: 10.into(), enabled: true };
76 /// # let mig = dev.to_migration_state().unwrap();
77 /// # assert!(matches!(*mig, DeviceMigrationState { counter: 10, enabled: true }));
78 /// # let mut dev2 = DeviceState { counter: 42.into(), enabled: false };
79 /// # dev2.restore_migrated_state_mut(*mig, 1).unwrap();
80 /// # assert_eq!(dev2, dev);
81 /// ```
82 ///
83 /// More commonly, the trait is derived through the
84 /// [`derive(ToMigrationState)`](qemu_macros::ToMigrationState) procedural
85 /// macro.
86 pub trait ToMigrationState {
87     /// The type used to represent the migrated state.
88     type Migrated: Default + VMState;
89 
90     /// Capture the current state into a migration-safe format, failing
91     /// if the state cannot be migrated.
92     fn snapshot_migration_state(&self, target: &mut Self::Migrated) -> Result<(), InvalidError>;
93 
94     /// Restores state from a migrated representation, failing if the
95     /// state cannot be restored.
96     fn restore_migrated_state_mut(
97         &mut self,
98         source: Self::Migrated,
99         version_id: u8,
100     ) -> Result<(), InvalidError>;
101 
102     /// Convenience method to combine allocation and state capture
103     /// into a single operation.
104     fn to_migration_state(&self) -> Result<Box<Self::Migrated>, InvalidError> {
105         let mut migrated = Box::<Self::Migrated>::default();
106         self.snapshot_migration_state(&mut migrated)?;
107         Ok(migrated)
108     }
109 }
110 
111 // Implementations for primitive types.  Do not use a blanket implementation
112 // for all Copy types, because [T; N] is Copy if T is Copy; that would conflict
113 // with the below implementation for arrays.
114 macro_rules! impl_for_primitive {
115     ($($t:ty),*) => {
116         $(
117             impl ToMigrationState for $t {
118                 type Migrated = Self;
119 
120                 fn snapshot_migration_state(
121                     &self,
122                     target: &mut Self::Migrated,
123                 ) -> Result<(), InvalidError> {
124                     *target = *self;
125                     Ok(())
126                 }
127 
128                 fn restore_migrated_state_mut(
129                     &mut self,
130                     source: Self::Migrated,
131                     _version_id: u8,
132                 ) -> Result<(), InvalidError> {
133                     *self = source;
134                     Ok(())
135                 }
136             }
137         )*
138     };
139 }
140 
141 impl_for_primitive!(u8, u16, u32, u64, i8, i16, i32, i64, bool);
142 
143 impl<T: ToMigrationState, const N: usize> ToMigrationState for [T; N]
144 where
145     [T::Migrated; N]: Default,
146 {
147     type Migrated = [T::Migrated; N];
148 
149     fn snapshot_migration_state(&self, target: &mut Self::Migrated) -> Result<(), InvalidError> {
150         for (item, target_item) in self.iter().zip(target.iter_mut()) {
151             item.snapshot_migration_state(target_item)?;
152         }
153         Ok(())
154     }
155 
156     fn restore_migrated_state_mut(
157         &mut self,
158         source: Self::Migrated,
159         version_id: u8,
160     ) -> Result<(), InvalidError> {
161         for (item, source_item) in self.iter_mut().zip(source) {
162             item.restore_migrated_state_mut(source_item, version_id)?;
163         }
164         Ok(())
165     }
166 }
167 
168 impl<T: ToMigrationState> ToMigrationState for Mutex<T> {
169     type Migrated = T::Migrated;
170 
171     fn snapshot_migration_state(&self, target: &mut Self::Migrated) -> Result<(), InvalidError> {
172         self.lock().unwrap().snapshot_migration_state(target)
173     }
174 
175     fn restore_migrated_state_mut(
176         &mut self,
177         source: Self::Migrated,
178         version_id: u8,
179     ) -> Result<(), InvalidError> {
180         self.get_mut()
181             .unwrap()
182             .restore_migrated_state_mut(source, version_id)
183     }
184 }
185 
186 impl<T: ToMigrationState> ToMigrationState for BqlRefCell<T> {
187     type Migrated = T::Migrated;
188 
189     fn snapshot_migration_state(&self, target: &mut Self::Migrated) -> Result<(), InvalidError> {
190         self.borrow().snapshot_migration_state(target)
191     }
192 
193     fn restore_migrated_state_mut(
194         &mut self,
195         source: Self::Migrated,
196         version_id: u8,
197     ) -> Result<(), InvalidError> {
198         self.get_mut()
199             .restore_migrated_state_mut(source, version_id)
200     }
201 }
202 
203 /// Extension trait for types that support migration state restoration
204 /// through interior mutability.
205 ///
206 /// This trait extends [`ToMigrationState`] for types that can restore
207 /// their state without requiring mutable access. While user structs
208 /// will generally use `ToMigrationState`, the device will have multiple
209 /// references and therefore the device struct has to employ an interior
210 /// mutability wrapper like [`Mutex`] or [`BqlRefCell`].
211 ///
212 /// Anything that implements this trait can in turn be used within
213 /// [`Migratable<T>`], which makes no assumptions on how to achieve mutable
214 /// access to the runtime state.
215 ///
216 /// # Examples
217 ///
218 /// ```
219 /// use std::sync::Mutex;
220 ///
221 /// use migration::ToMigrationStateShared;
222 ///
223 /// let device_state = Mutex::new(42);
224 /// // Can restore without &mut access
225 /// device_state.restore_migrated_state(100, 1).unwrap();
226 /// assert_eq!(*device_state.lock().unwrap(), 100);
227 /// ```
228 pub trait ToMigrationStateShared: ToMigrationState {
229     /// Restores state from a migrated representation to an interior-mutable
230     /// object.  Similar to `restore_migrated_state_mut`, but requires a
231     /// shared reference; therefore it can be used to restore a device's
232     /// state even though devices have multiple references to them.
233     fn restore_migrated_state(
234         &self,
235         source: Self::Migrated,
236         version_id: u8,
237     ) -> Result<(), InvalidError>;
238 }
239 
240 impl<T: ToMigrationStateShared, const N: usize> ToMigrationStateShared for [T; N]
241 where
242     [T::Migrated; N]: Default,
243 {
244     fn restore_migrated_state(
245         &self,
246         source: Self::Migrated,
247         version_id: u8,
248     ) -> Result<(), InvalidError> {
249         for (item, source_item) in self.iter().zip(source) {
250             item.restore_migrated_state(source_item, version_id)?;
251         }
252         Ok(())
253     }
254 }
255 
256 // Arc requires the contained object to be interior-mutable
257 impl<T: ToMigrationStateShared> ToMigrationState for Arc<T> {
258     type Migrated = T::Migrated;
259 
260     fn snapshot_migration_state(&self, target: &mut Self::Migrated) -> Result<(), InvalidError> {
261         (**self).snapshot_migration_state(target)
262     }
263 
264     fn restore_migrated_state_mut(
265         &mut self,
266         source: Self::Migrated,
267         version_id: u8,
268     ) -> Result<(), InvalidError> {
269         (**self).restore_migrated_state(source, version_id)
270     }
271 }
272 
273 impl<T: ToMigrationStateShared> ToMigrationStateShared for Arc<T> {
274     fn restore_migrated_state(
275         &self,
276         source: Self::Migrated,
277         version_id: u8,
278     ) -> Result<(), InvalidError> {
279         (**self).restore_migrated_state(source, version_id)
280     }
281 }
282 
283 // Interior-mutable types.  Note how they only require ToMigrationState for
284 // the inner type!
285 
286 impl<T: ToMigrationState> ToMigrationStateShared for Mutex<T> {
287     fn restore_migrated_state(
288         &self,
289         source: Self::Migrated,
290         version_id: u8,
291     ) -> Result<(), InvalidError> {
292         self.lock()
293             .unwrap()
294             .restore_migrated_state_mut(source, version_id)
295     }
296 }
297 
298 impl<T: ToMigrationState> ToMigrationStateShared for BqlRefCell<T> {
299     fn restore_migrated_state(
300         &self,
301         source: Self::Migrated,
302         version_id: u8,
303     ) -> Result<(), InvalidError> {
304         self.borrow_mut()
305             .restore_migrated_state_mut(source, version_id)
306     }
307 }
308 
309 /// A wrapper that enables QEMU migration for types with shared state.
310 ///
311 /// `Migratable<T>` provides a bridge between Rust types that use interior
312 /// mutability (like `Mutex<T>`) and QEMU's C-based migration infrastructure.
313 /// It manages the lifecycle of migration state and provides automatic
314 /// conversion between runtime and migration representations.
315 ///
316 /// ```
317 /// # use std::sync::Mutex;
318 /// # use migration::{Migratable, ToMigrationState, VMState, VMStateField};
319 ///
320 /// #[derive(ToMigrationState)]
321 /// pub struct DeviceRegs {
322 ///     status: u32,
323 /// }
324 /// # unsafe impl VMState for DeviceRegsMigration {
325 /// #     const BASE: VMStateField = ::common::Zeroable::ZERO;
326 /// # }
327 ///
328 /// pub struct SomeDevice {
329 ///     // ...
330 ///     registers: Migratable<Mutex<DeviceRegs>>,
331 /// }
332 /// ```
333 #[repr(C)]
334 pub struct Migratable<T: ToMigrationStateShared> {
335     /// Pointer to migration state, valid only during migration operations.
336     /// C vmstate does not support NULL pointers, so no `Option<Box<>>`.
337     migration_state: BqlCell<*mut T::Migrated>,
338 
339     /// The runtime state that can be accessed during normal operation
340     runtime_state: T,
341 }
342 
343 impl<T: ToMigrationStateShared> std::ops::Deref for Migratable<T> {
344     type Target = T;
345 
346     fn deref(&self) -> &Self::Target {
347         &self.runtime_state
348     }
349 }
350 
351 impl<T: ToMigrationStateShared> std::ops::DerefMut for Migratable<T> {
352     fn deref_mut(&mut self) -> &mut Self::Target {
353         &mut self.runtime_state
354     }
355 }
356 
357 impl<T: ToMigrationStateShared> Migratable<T> {
358     /// Creates a new `Migratable` wrapper around the given runtime state.
359     ///
360     /// # Returns
361     /// A new `Migratable` instance ready for use and migration
362     pub fn new(runtime_state: T) -> Self {
363         Self {
364             migration_state: BqlCell::new(ptr::null_mut()),
365             runtime_state,
366         }
367     }
368 
369     fn pre_save(&self) -> Result<(), InvalidError> {
370         let state = self.runtime_state.to_migration_state()?;
371         self.migration_state.set(Box::into_raw(state));
372         Ok(())
373     }
374 
375     fn post_save(&self) -> Result<(), InvalidError> {
376         let state = unsafe { Box::from_raw(self.migration_state.replace(ptr::null_mut())) };
377         drop(state);
378         Ok(())
379     }
380 
381     fn pre_load(&self) -> Result<(), InvalidError> {
382         self.migration_state
383             .set(Box::into_raw(Box::<T::Migrated>::default()));
384         Ok(())
385     }
386 
387     fn post_load(&self, version_id: u8) -> Result<(), InvalidError> {
388         let state = unsafe { Box::from_raw(self.migration_state.replace(ptr::null_mut())) };
389         self.runtime_state
390             .restore_migrated_state(*state, version_id)
391     }
392 }
393 
394 impl<T: ToMigrationStateShared + fmt::Debug> fmt::Debug for Migratable<T>
395 where
396     T::Migrated: fmt::Debug,
397 {
398     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
399         let mut struct_f = f.debug_struct("Migratable");
400         struct_f.field("runtime_state", &self.runtime_state);
401 
402         let state = NonNull::new(self.migration_state.get()).map(|x| unsafe { x.as_ref() });
403         struct_f.field("migration_state", &state);
404         struct_f.finish()
405     }
406 }
407 
408 impl<T: ToMigrationStateShared + Default> Default for Migratable<T> {
409     fn default() -> Self {
410         Self::new(T::default())
411     }
412 }
413 
414 impl<T: 'static + ToMigrationStateShared> Migratable<T> {
415     const FIELD: bindings::VMStateField = vmstate_of!(Self, migration_state);
416 
417     const FIELDS: &[bindings::VMStateField] = vmstate_fields_ref! {
418         Migratable::<T>::FIELD
419     };
420 
421     const VMSD: &'static bindings::VMStateDescription = VMStateDescriptionBuilder::<Self>::new()
422         .version_id(1)
423         .minimum_version_id(1)
424         .pre_save(&Self::pre_save)
425         .pre_load(&Self::pre_load)
426         .post_save(&Self::post_save)
427         .post_load(&Self::post_load)
428         .fields(Self::FIELDS)
429         .build()
430         .as_ref();
431 }
432 
433 unsafe impl<T: 'static + ToMigrationStateShared> VMState for Migratable<T> {
434     const BASE: bindings::VMStateField = {
435         bindings::VMStateField {
436             vmsd: addr_of!(*Self::VMSD),
437             size: size_of::<Self>(),
438             flags: bindings::VMStateFlags::VMS_STRUCT,
439             ..Zeroable::ZERO
440         }
441     };
442 }
443