master
rs 478 lines 14.7 KB
Raw
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::prelude::*;
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 ToMigrationState for util::timer::Timer {
144 type Migrated = i64;
145
146 fn snapshot_migration_state(&self, target: &mut i64) -> Result<(), InvalidError> {
147 // SAFETY: as_ptr() is unsafe to ensure that the caller reasons about
148 // the pinning of the data inside the Opaque<>. Here all we do is
149 // access a field.
150 *target = self.expire_time_ns().unwrap_or(-1);
151 Ok(())
152 }
153
154 fn restore_migrated_state_mut(
155 &mut self,
156 source: Self::Migrated,
157 version_id: u8,
158 ) -> Result<(), InvalidError> {
159 self.restore_migrated_state(source, version_id)
160 }
161 }
162
163 impl<T: ToMigrationState, const N: usize> ToMigrationState for [T; N]
164 where
165 [T::Migrated; N]: Default,
166 {
167 type Migrated = [T::Migrated; N];
168
169 fn snapshot_migration_state(&self, target: &mut Self::Migrated) -> Result<(), InvalidError> {
170 for (item, target_item) in self.iter().zip(target.iter_mut()) {
171 item.snapshot_migration_state(target_item)?;
172 }
173 Ok(())
174 }
175
176 fn restore_migrated_state_mut(
177 &mut self,
178 source: Self::Migrated,
179 version_id: u8,
180 ) -> Result<(), InvalidError> {
181 for (item, source_item) in self.iter_mut().zip(source) {
182 item.restore_migrated_state_mut(source_item, version_id)?;
183 }
184 Ok(())
185 }
186 }
187
188 impl<T: ToMigrationState> ToMigrationState for Mutex<T> {
189 type Migrated = T::Migrated;
190
191 fn snapshot_migration_state(&self, target: &mut Self::Migrated) -> Result<(), InvalidError> {
192 self.lock().unwrap().snapshot_migration_state(target)
193 }
194
195 fn restore_migrated_state_mut(
196 &mut self,
197 source: Self::Migrated,
198 version_id: u8,
199 ) -> Result<(), InvalidError> {
200 self.get_mut()
201 .unwrap()
202 .restore_migrated_state_mut(source, version_id)
203 }
204 }
205
206 impl<T: ToMigrationState> ToMigrationState for BqlRefCell<T> {
207 type Migrated = T::Migrated;
208
209 fn snapshot_migration_state(&self, target: &mut Self::Migrated) -> Result<(), InvalidError> {
210 self.borrow().snapshot_migration_state(target)
211 }
212
213 fn restore_migrated_state_mut(
214 &mut self,
215 source: Self::Migrated,
216 version_id: u8,
217 ) -> Result<(), InvalidError> {
218 self.get_mut()
219 .restore_migrated_state_mut(source, version_id)
220 }
221 }
222
223 /// Extension trait for types that support migration state restoration
224 /// through interior mutability.
225 ///
226 /// This trait extends [`ToMigrationState`] for types that can restore
227 /// their state without requiring mutable access. While user structs
228 /// will generally use `ToMigrationState`, the device will have multiple
229 /// references and therefore the device struct has to employ an interior
230 /// mutability wrapper like [`Mutex`] or [`BqlRefCell`].
231 ///
232 /// Anything that implements this trait can in turn be used within
233 /// [`Migratable<T>`], which makes no assumptions on how to achieve mutable
234 /// access to the runtime state.
235 ///
236 /// # Examples
237 ///
238 /// ```
239 /// use std::sync::Mutex;
240 ///
241 /// use migration::ToMigrationStateShared;
242 ///
243 /// let device_state = Mutex::new(42);
244 /// // Can restore without &mut access
245 /// device_state.restore_migrated_state(100, 1).unwrap();
246 /// assert_eq!(*device_state.lock().unwrap(), 100);
247 /// ```
248 pub trait ToMigrationStateShared: ToMigrationState {
249 /// Restores state from a migrated representation to an interior-mutable
250 /// object. Similar to `restore_migrated_state_mut`, but requires a
251 /// shared reference; therefore it can be used to restore a device's
252 /// state even though devices have multiple references to them.
253 fn restore_migrated_state(
254 &self,
255 source: Self::Migrated,
256 version_id: u8,
257 ) -> Result<(), InvalidError>;
258 }
259
260 impl ToMigrationStateShared for util::timer::Timer {
261 fn restore_migrated_state(&self, source: i64, _version_id: u8) -> Result<(), InvalidError> {
262 if source >= 0 {
263 self.modify_ns(source as u64);
264 } else {
265 self.delete();
266 }
267 Ok(())
268 }
269 }
270
271 impl<T: ToMigrationStateShared, const N: usize> ToMigrationStateShared for [T; N]
272 where
273 [T::Migrated; N]: Default,
274 {
275 fn restore_migrated_state(
276 &self,
277 source: Self::Migrated,
278 version_id: u8,
279 ) -> Result<(), InvalidError> {
280 for (item, source_item) in self.iter().zip(source) {
281 item.restore_migrated_state(source_item, version_id)?;
282 }
283 Ok(())
284 }
285 }
286
287 // Arc requires the contained object to be interior-mutable
288 impl<T: ToMigrationStateShared> ToMigrationState for Arc<T> {
289 type Migrated = T::Migrated;
290
291 fn snapshot_migration_state(&self, target: &mut Self::Migrated) -> Result<(), InvalidError> {
292 (**self).snapshot_migration_state(target)
293 }
294
295 fn restore_migrated_state_mut(
296 &mut self,
297 source: Self::Migrated,
298 version_id: u8,
299 ) -> Result<(), InvalidError> {
300 (**self).restore_migrated_state(source, version_id)
301 }
302 }
303
304 impl<T: ToMigrationStateShared> ToMigrationStateShared for Arc<T> {
305 fn restore_migrated_state(
306 &self,
307 source: Self::Migrated,
308 version_id: u8,
309 ) -> Result<(), InvalidError> {
310 (**self).restore_migrated_state(source, version_id)
311 }
312 }
313
314 // Interior-mutable types. Note how they only require ToMigrationState for
315 // the inner type!
316
317 impl<T: ToMigrationState> ToMigrationStateShared for Mutex<T> {
318 fn restore_migrated_state(
319 &self,
320 source: Self::Migrated,
321 version_id: u8,
322 ) -> Result<(), InvalidError> {
323 self.lock()
324 .unwrap()
325 .restore_migrated_state_mut(source, version_id)
326 }
327 }
328
329 impl<T: ToMigrationState> ToMigrationStateShared for BqlRefCell<T> {
330 fn restore_migrated_state(
331 &self,
332 source: Self::Migrated,
333 version_id: u8,
334 ) -> Result<(), InvalidError> {
335 self.borrow_mut()
336 .restore_migrated_state_mut(source, version_id)
337 }
338 }
339
340 /// A wrapper that enables QEMU migration for types with shared state.
341 ///
342 /// `Migratable<T>` provides a bridge between Rust types that use interior
343 /// mutability (like `Mutex<T>`) and QEMU's C-based migration infrastructure.
344 /// It manages the lifecycle of migration state and provides automatic
345 /// conversion between runtime and migration representations.
346 ///
347 /// ```
348 /// # use std::sync::Mutex;
349 /// # use migration::{Migratable, ToMigrationState, VMState, VMStateField};
350 ///
351 /// #[derive(ToMigrationState)]
352 /// pub struct DeviceRegs {
353 /// status: u32,
354 /// }
355 /// # unsafe impl VMState for DeviceRegsMigration {
356 /// # const BASE: VMStateField = ::common::Zeroable::ZERO;
357 /// # }
358 ///
359 /// pub struct SomeDevice {
360 /// // ...
361 /// registers: Migratable<Mutex<DeviceRegs>>,
362 /// }
363 /// ```
364 #[repr(C)]
365 pub struct Migratable<T: ToMigrationStateShared> {
366 /// Pointer to migration state, valid only during migration operations.
367 /// C vmstate does not support NULL pointers, so no `Option<Box<>>`.
368 migration_state: BqlCell<*mut T::Migrated>,
369
370 /// The runtime state that can be accessed during normal operation
371 runtime_state: T,
372 }
373
374 // SAFETY: the migration_state asserts via `BqlCell` that the BQL is taken.
375 unsafe impl<T: ToMigrationStateShared + Sync> Sync for Migratable<T> {}
376
377 impl<T: ToMigrationStateShared> std::ops::Deref for Migratable<T> {
378 type Target = T;
379
380 fn deref(&self) -> &Self::Target {
381 &self.runtime_state
382 }
383 }
384
385 impl<T: ToMigrationStateShared> std::ops::DerefMut for Migratable<T> {
386 fn deref_mut(&mut self) -> &mut Self::Target {
387 &mut self.runtime_state
388 }
389 }
390
391 impl<T: ToMigrationStateShared> Migratable<T> {
392 /// Creates a new `Migratable` wrapper around the given runtime state.
393 ///
394 /// # Returns
395 /// A new `Migratable` instance ready for use and migration
396 pub fn new(runtime_state: T) -> Self {
397 Self {
398 migration_state: BqlCell::new(ptr::null_mut()),
399 runtime_state,
400 }
401 }
402
403 fn pre_save(&self) -> Result<(), InvalidError> {
404 let state = self.runtime_state.to_migration_state()?;
405 self.migration_state.set(Box::into_raw(state));
406 Ok(())
407 }
408
409 fn post_save(&self) {
410 let _ = unsafe { Box::from_raw(self.migration_state.replace(ptr::null_mut())) };
411 }
412
413 fn pre_load(&self) -> Result<(), InvalidError> {
414 self.migration_state
415 .set(Box::into_raw(Box::<T::Migrated>::default()));
416 Ok(())
417 }
418
419 fn post_load(&self, version_id: u8) -> Result<(), InvalidError> {
420 let state = unsafe { Box::from_raw(self.migration_state.replace(ptr::null_mut())) };
421 self.runtime_state
422 .restore_migrated_state(*state, version_id)
423 }
424 }
425
426 impl<T: ToMigrationStateShared + fmt::Debug> fmt::Debug for Migratable<T>
427 where
428 T::Migrated: fmt::Debug,
429 {
430 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
431 let mut struct_f = f.debug_struct("Migratable");
432 struct_f.field("runtime_state", &self.runtime_state);
433
434 let state = NonNull::new(self.migration_state.get()).map(|x| unsafe { x.as_ref() });
435 struct_f.field("migration_state", &state);
436 struct_f.finish()
437 }
438 }
439
440 impl<T: ToMigrationStateShared + Default> Default for Migratable<T> {
441 fn default() -> Self {
442 Self::new(T::default())
443 }
444 }
445
446 impl<T: 'static + ToMigrationStateShared> Migratable<T> {
447 const FIELD: bindings::VMStateField = vmstate_of!(Self, migration_state);
448
449 const FIELDS: &[bindings::VMStateField] = vmstate_fields_ref! {
450 Migratable::<T>::FIELD
451 };
452
453 // All Migratable<T> instances share the same name. This is fine because
454 // Migratable<T> is always a field within a VMSD. The parent VMSD has the
455 // different name to distinguish child Migratable<T>.
456 const VMSD: &'static bindings::VMStateDescription = VMStateDescriptionBuilder::<Self>::new()
457 .name(c"migratable-wrapper")
458 .version_id(1)
459 .minimum_version_id(1)
460 .pre_save(&Self::pre_save)
461 .pre_load(&Self::pre_load)
462 .post_save(&Self::post_save)
463 .post_load(&Self::post_load)
464 .fields(Self::FIELDS)
465 .build()
466 .as_ref();
467 }
468
469 unsafe impl<T: 'static + ToMigrationStateShared> VMState for Migratable<T> {
470 const BASE: bindings::VMStateField = {
471 bindings::VMStateField {
472 vmsd: addr_of!(*Self::VMSD),
473 size: size_of::<Self>(),
474 flags: bindings::VMStateFlags::VMS_STRUCT,
475 ..Zeroable::ZERO
476 }
477 };
478 }