migration: Add error-parameterized function variants in VMSD struct

- We need to have good error reporting in the callbacks in
  VMStateDescription struct. Specifically pre_save, pre_load
  and post_load callbacks.
- It is not possible to change these functions everywhere in one
  patch, therefore, we introduce a duplicate set of callbacks
  with Error object passed to them.
- So, in this commit, we implement 'errp' variants of these callbacks,
  introducing an explicit Error object parameter.
- This is a functional step towards transitioning the entire codebase
  to the new error-parameterized functions.
- Deliberately called in mutual exclusion from their counterparts,
  to prevent conflicts during the transition.
- New impls should preferentally use 'errp' variants of
  these methods, and existing impls incrementally converted.
  The variants without 'errp' are intended to be removed
  once all usage is converted.

Reviewed-by: Fabiano Rosas <farosas@suse.de>
Signed-off-by: Arun Menon <armenon@redhat.com>
Tested-by: Fabiano Rosas <farosas@suse.de>
Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
Link: https://lore.kernel.org/r/20250918-propagate_tpm_error-v14-26-36f11a6fb9d3@redhat.com
Signed-off-by: Peter Xu <peterx@redhat.com>
This commit is contained in:
Arun Menon
2025-09-18 20:53:43 +05:30
committed by Peter Xu
parent 6f9fc6f501
commit 40de712a89
3 changed files with 61 additions and 3 deletions

View File

@@ -444,6 +444,25 @@ The functions to do that are inside a vmstate definition, and are called:
This function is called after we save the state of one device
(even upon failure, unless the call to pre_save returned an error).
Following are the errp variants of these functions.
- ``int (*pre_load_errp)(void *opaque, Error **errp);``
This function is called before we load the state of one device.
- ``int (*post_load_errp)(void *opaque, int version_id, Error **errp);``
This function is called after we load the state of one device.
- ``int (*pre_save_errp)(void *opaque, Error **errp);``
This function is called before we save the state of one device.
New impls should preferentally use 'errp' variants of these
methods and existing impls incrementally converted.
The variants without 'errp' are intended to be removed
once all usage is converted.
Example: You can look at hpet.c, that uses the first three functions
to massage the state that is transferred.

View File

@@ -200,14 +200,28 @@ struct VMStateDescription {
* exclusive. For this reason, also early_setup VMSDs are migrated in a
* QEMU_VM_SECTION_FULL section, while save_setup() data is migrated in
* a QEMU_VM_SECTION_START section.
*
* There are duplicate impls of the post/pre save/load hooks.
* New impls should preferentally use 'errp' variants of these
* methods and existing impls incrementally converted.
* The variants without 'errp' are intended to be removed
* once all usage is converted.
*
* For the errp variants,
* Returns: 0 on success,
* <0 on error where -value is an error number from errno.h
*/
bool early_setup;
int version_id;
int minimum_version_id;
MigrationPriority priority;
int (*pre_load)(void *opaque);
int (*pre_load_errp)(void *opaque, Error **errp);
int (*post_load)(void *opaque, int version_id);
int (*post_load_errp)(void *opaque, int version_id, Error **errp);
int (*pre_save)(void *opaque);
int (*pre_save_errp)(void *opaque, Error **errp);
int (*post_save)(void *opaque);
bool (*needed)(void *opaque);
bool (*dev_unplug_pending)(void *opaque);

View File

@@ -134,6 +134,7 @@ static void vmstate_handle_alloc(void *ptr, const VMStateField *field,
int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
void *opaque, int version_id, Error **errp)
{
ERRP_GUARD();
const VMStateField *field = vmsd->fields;
int ret = 0;
@@ -152,7 +153,16 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
trace_vmstate_load_state_end(vmsd->name, "too old", -EINVAL);
return -EINVAL;
}
if (vmsd->pre_load) {
if (vmsd->pre_load_errp) {
ret = vmsd->pre_load_errp(opaque, errp);
if (ret < 0) {
error_prepend(errp, "pre load hook failed for: '%s', "
"version_id: %d, minimum version_id: %d, "
"ret: %d: ", vmsd->name, vmsd->version_id,
vmsd->minimum_version_id, ret);
return ret;
}
} else if (vmsd->pre_load) {
ret = vmsd->pre_load(opaque);
if (ret) {
error_setg(errp, "pre load hook failed for: '%s', "
@@ -245,7 +255,14 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
qemu_file_set_error(f, ret);
return ret;
}
if (vmsd->post_load) {
if (vmsd->post_load_errp) {
ret = vmsd->post_load_errp(opaque, version_id, errp);
if (ret < 0) {
error_prepend(errp, "post load hook failed for: %s, version_id: "
"%d, minimum_version: %d, ret: %d: ", vmsd->name,
vmsd->version_id, vmsd->minimum_version_id, ret);
}
} else if (vmsd->post_load) {
ret = vmsd->post_load(opaque, version_id);
if (ret < 0) {
error_setg(errp,
@@ -414,12 +431,20 @@ int vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
void *opaque, JSONWriter *vmdesc, int version_id, Error **errp)
{
ERRP_GUARD();
int ret = 0;
const VMStateField *field = vmsd->fields;
trace_vmstate_save_state_top(vmsd->name);
if (vmsd->pre_save) {
if (vmsd->pre_save_errp) {
ret = vmsd->pre_save_errp(opaque, errp);
trace_vmstate_save_state_pre_save_res(vmsd->name, ret);
if (ret < 0) {
error_prepend(errp, "pre-save for %s failed, ret: %d: ",
vmsd->name, ret);
}
} else if (vmsd->pre_save) {
ret = vmsd->pre_save(opaque);
trace_vmstate_save_state_pre_save_res(vmsd->name, ret);
if (ret) {