All other handlers now have _errp() variants. Should we go this way
for .post_save()? Actually it's rather strange, when the vmstate do
successful preparations in .pre_save(), then successfully save all
sections and subsections, end then fail when all the state is
successfully transferred to the target.
Happily, we have only three .post_save() realizations, all always
successful. Let's make this a rule.
Also note, that we call .post_save() in two places, and handle
its (theoretical) failure inconsistently. Fix that too.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
Reviewed-by: Peter Xu <peterx@redhat.com>
Reviewed-by: Zhao Liu <zhao1.liu@intel.com> #rust
Link: https://lore.kernel.org/qemu-devel/20260304212303.667141-4-vsementsov@yandex-team.ru
Signed-off-by: Fabiano Rosas <farosas@suse.de>
This function is called before we save the state of one device.
-- ``int (*post_save)(void *opaque);``
+- ``void (*post_save)(void *opaque);``
This function is called after we save the state of one device
(even upon failure, unless the call to pre_save returned an error).
return 0;
}
-static int spapr_pci_post_save(void *opaque)
+static void spapr_pci_post_save(void *opaque)
{
SpaprPhbState *sphb = opaque;
g_free(sphb->msi_devs);
sphb->msi_devs = NULL;
sphb->msi_devs_num = 0;
- return 0;
}
static int spapr_pci_post_load(void *opaque, int version_id)
bool (*post_load_errp)(void *opaque, int version_id, Error **errp);
int (*pre_save)(void *opaque);
bool (*pre_save_errp)(void *opaque, Error **errp);
- int (*post_save)(void *opaque);
+
+ /*
+ * Unless .pre_save() fails, .post_save() is called after saving
+ * fields and subsections. It should not fail because at this
+ * point the state has potentially already been transferred.
+ */
+ void (*post_save)(void *opaque);
bool (*needed)(void *opaque);
bool (*dev_unplug_pending)(void *opaque);
return 0;
}
-static int configuration_post_save(void *opaque)
+static void configuration_post_save(void *opaque)
{
SaveState *state = opaque;
g_free(state->capabilities);
state->capabilities = NULL;
state->caps_count = 0;
- return 0;
}
static int configuration_pre_load(void *opaque)
if (ret) {
error_prepend(errp, "Save of field %s/%s failed: ",
vmsd->name, field->name);
- if (vmsd->post_save) {
- vmsd->post_save(opaque);
- }
- return ret;
+ goto out;
}
/* Compressed arrays only care about the first element */
ret = vmstate_subsection_save(f, vmsd, opaque, vmdesc, errp);
+out:
if (vmsd->post_save) {
- int ps_ret = vmsd->post_save(opaque);
- if (!ret && ps_ret) {
- ret = ps_ret;
- error_setg(errp, "post-save failed: %s", vmsd->name);
- }
+ vmsd->post_save(opaque);
}
return ret;
}
Ok(())
}
- fn post_save(&self) -> Result<(), InvalidError> {
- let state = unsafe { Box::from_raw(self.migration_state.replace(ptr::null_mut())) };
- drop(state);
- Ok(())
+ fn post_save(&self) {
+ let _ = unsafe { Box::from_raw(self.migration_state.replace(ptr::null_mut())) };
}
fn pre_load(&self) -> Result<(), InvalidError> {
into_neg_errno(result)
}
+unsafe extern "C" fn vmstate_post_save_cb<T, F: for<'a> FnCall<(&'a T,), ()>>(opaque: *mut c_void) {
+ // SAFETY: the function is used in T's implementation of VMState.
+ F::call((unsafe { &*(opaque.cast::<T>()) },));
+}
+
unsafe extern "C" fn vmstate_post_load_cb<
T,
F: for<'a> FnCall<(&'a T, u8), Result<(), impl Into<Errno>>>,
}
#[must_use]
- pub const fn post_save<F: for<'a> FnCall<(&'a T,), Result<(), impl Into<Errno>>>>(
- mut self,
- _f: &F,
- ) -> Self {
+ pub const fn post_save<F: for<'a> FnCall<(&'a T,), ()>>(mut self, _f: &F) -> Self {
self.0.post_save = if F::IS_SOME {
- Some(vmstate_no_version_cb::<T, F>)
+ Some(vmstate_post_save_cb::<T, F>)
} else {
None
};
return 0;
}
-static int cpu_post_save(void *opaque)
+static void cpu_post_save(void *opaque)
{
ARMCPU *cpu = opaque;
cpu->cpreg_vmstate_indexes = NULL;
cpu->cpreg_vmstate_values = NULL;
-
- return 0;
}
static int cpu_pre_load(void *opaque)