* [PATCH v6 00/24] migration: propagate vTPM errors using Error objects
@ 2025-07-21 11:29 Arun Menon
2025-07-21 11:29 ` [PATCH v6 01/24] migration: push Error **errp into vmstate_subsection_load() Arun Menon
` (23 more replies)
0 siblings, 24 replies; 55+ messages in thread
From: Arun Menon @ 2025-07-21 11:29 UTC (permalink / raw)
To: qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato, Arun Menon,
Daniel P. Berrangé, Stefan Berger
Hello,
Currently, when a migration of a VM with an encrypted vTPM
fails on the destination host (e.g., due to a mismatch in secret values),
the error message displayed on the source host is generic and unhelpful.
For example, a typical error looks like this:
"operation failed: job 'migration out' failed: Sibling indicated error 1.
operation failed: job 'migration in' failed: load of migration failed:
Input/output error"
This message does not provide any specific indication of a vTPM failure.
Such generic errors are logged using error_report(), which prints to
the console/monitor but does not make the detailed error accessible via
the QMP query-migrate command.
This series addresses the issue, by ensuring that specific TPM error
messages are propagated via the QEMU Error object.
To make this possible,
- A set of functions in the call stack is changed
to incorporate an Error object as an additional parameter.
- Also, the TPM backend makes use of a new hook called post_load_errp()
that explicitly passes an Error object.
It is organized as follows,
- Patches 1-21 focuses on pushing Error object into the functions
that are important in the call stack where TPM errors are observed.
We still need to make changes in rest of the functions in savevm.c
such that they also incorporate the errp object for propagating errors.
- Patch 22 introduces the new variants of the hooks in VMStateDescription
structure. These hooks should be used in future implementations.
- Patch 23 focuses on changing the TPM backend such that the errors are
set in the Error object.
While this series focuses specifically on TPM error reporting during
live migration, it lays the groundwork for broader improvements.
A lot of methods in savevm.c that previously returned an integer now capture
errors in the Error object, enabling other modules to adopt the
post_load_errp hook in the future.
One such change previously attempted:
https://lists.gnu.org/archive/html/qemu-devel/2021-02/msg01727.html
Resolves: https://issues.redhat.com/browse/RHEL-82826
Signed-off-by: Arun Menon <armenon@redhat.com>
---
Changes in v6:
- Incorporated review comments from Daniel and Akihiko, related to few
semantic errors and improve error logging.
- Add one more patch that removes NULL checks after calling
qemu_file_get_return_path() because it does not fail.
- Link to v5: https://lore.kernel.org/qemu-devel/20250717-propagate_tpm_error-v5-0-1f406f88ee65@redhat.com
Changes in v5:
- Solve a bug that set errp even though it was not NULL, pointed out by Fabiano in v4.
- Link to v4: https://lore.kernel.org/qemu-devel/20250716-propagate_tpm_error-v4-0-7141902077c0@redhat.com
Changes in v4:
- Split the patches into smaller ones based on functions. Pass NULL in the
caller until errp is made available. Every function that has an
Error **errp object passed to it, ensures that it sets the errp object
in case of failure.
- A few more functions within loadvm_process_command() now handle errors using
the errp object. I've converted these for consistency, taking Daniel's
patches (link above) as a reference.
- Along with the post_load_errp() hook, other duplicate hooks are also introduced.
This will enable us to migrate to the newer versions eventually.
- Fix some semantic errors, like using error_propagate_prepend() in places where
we need to preserve existing behaviour of accumulating the error in local_err
and then propagating it to errp. This can be refactored in a later commit.
- Add more information in commit messages explaining the changes.
- Link to v3: https://lore.kernel.org/qemu-devel/20250702-propagate_tpm_error-v3-0-986d94540528@redhat.com
Changes in v3:
- Split the 2nd patch into 2. Introducing post_load_with_error() hook
has been separated from using it in the backends TPM module. This is
so that it can be acknowledged.
- Link to v2: https://lore.kernel.org/qemu-devel/20250627-propagate_tpm_error-v2-0-85990c89da29@redhat.com
Changes in v2:
- Combine the first two changes into one, focusing on passing the
Error object (errp) consistently through functions involved in
loading the VM's state. Other functions are not yet changed.
- As suggested in the review comment, add null checks for errp
before adding error messages, preventing crashes.
We also now correctly set errors when post-copy migration fails.
- In process_incoming_migration_co(), switch to error_prepend
instead of error_setg. This means we now null-check local_err in
the "fail" section before using it, preventing dereferencing issues.
- Link to v1: https://lore.kernel.org/qemu-devel/20250624-propagate_tpm_error-v1-0-2171487a593d@redhat.com
---
Arun Menon (24):
migration: push Error **errp into vmstate_subsection_load()
migration: push Error **errp into vmstate_load_state()
migration: push Error **errp into qemu_loadvm_state_header()
migration: push Error **errp into vmstate_load()
migration: push Error **errp into qemu_loadvm_section_start_full()
migration: push Error **errp into qemu_loadvm_section_part_end()
migration: Update qemu_file_get_return_path() docs and remove dead checks
migration: push Error **errp into loadvm_process_command()
migration: push Error **errp into loadvm_handle_cmd_packaged()
migration: push Error **errp into ram_postcopy_incoming_init()
migration: push Error **errp into loadvm_postcopy_handle_advise()
migration: push Error **errp into loadvm_postcopy_handle_listen()
migration: push Error **errp into loadvm_postcopy_handle_run()
migration: push Error **errp into loadvm_postcopy_ram_handle_discard()
migration: make loadvm_postcopy_handle_resume() void
migration: push Error **errp into loadvm_handle_recv_bitmap()
migration: push Error **errp into loadvm_process_enable_colo()
migration: push Error **errp into loadvm_postcopy_handle_switchover_start()
migration: push Error **errp into qemu_loadvm_state_main()
migration: push Error **errp into qemu_loadvm_state()
migration: push Error **errp into qemu_load_device_state()
migration: Capture error in postcopy_ram_listen_thread()
migration: Add error-parameterized function variants in VMSD struct
backends/tpm: Propagate vTPM error on migration failure
backends/tpm/tpm_emulator.c | 39 +++---
hw/display/virtio-gpu.c | 2 +-
hw/pci/pci.c | 2 +-
hw/s390x/virtio-ccw.c | 2 +-
hw/scsi/spapr_vscsi.c | 2 +-
hw/vfio/pci.c | 2 +-
hw/virtio/virtio-mmio.c | 2 +-
hw/virtio/virtio-pci.c | 2 +-
hw/virtio/virtio.c | 4 +-
include/migration/colo.h | 2 +-
include/migration/vmstate.h | 13 +-
migration/colo.c | 12 +-
migration/cpr.c | 4 +-
migration/migration.c | 31 ++---
migration/postcopy-ram.c | 9 +-
migration/postcopy-ram.h | 2 +-
migration/qemu-file.c | 1 -
migration/ram.c | 14 +-
migration/ram.h | 4 +-
migration/savevm.c | 309 +++++++++++++++++++++++++-------------------
migration/savevm.h | 7 +-
migration/vmstate-types.c | 10 +-
migration/vmstate.c | 94 ++++++++++----
tests/unit/test-vmstate.c | 18 +--
ui/vdagent.c | 2 +-
25 files changed, 342 insertions(+), 247 deletions(-)
---
base-commit: f96b157ebb93f94cd56ebbc99bc20982b8fd86ef
change-id: 20250624-propagate_tpm_error-bf4ae6c23d30
Best regards,
--
Arun Menon <armenon@redhat.com>
^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH v6 01/24] migration: push Error **errp into vmstate_subsection_load()
2025-07-21 11:29 [PATCH v6 00/24] migration: propagate vTPM errors using Error objects Arun Menon
@ 2025-07-21 11:29 ` Arun Menon
2025-07-21 12:10 ` Akihiko Odaki
2025-07-21 11:29 ` [PATCH v6 02/24] migration: push Error **errp into vmstate_load_state() Arun Menon
` (22 subsequent siblings)
23 siblings, 1 reply; 55+ messages in thread
From: Arun Menon @ 2025-07-21 11:29 UTC (permalink / raw)
To: qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato, Arun Menon
This is an incremental step in converting vmstate loading
code to report error via Error objects instead of directly
printing it to console/monitor.
It is ensured that vmstate_subsection_load() must report an error
in errp, in case of failure.
Signed-off-by: Arun Menon <armenon@redhat.com>
---
migration/vmstate.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/migration/vmstate.c b/migration/vmstate.c
index 5feaa3244d259874f03048326b2497e7db32e47c..129b19d7603a0ddf8ab6e946e41c1c4d773d1fa8 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -25,7 +25,7 @@ static int vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
void *opaque, JSONWriter *vmdesc,
Error **errp);
static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
- void *opaque);
+ void *opaque, Error **errp);
/* Whether this field should exist for either save or load the VM? */
static bool
@@ -225,7 +225,7 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
field++;
}
assert(field->flags == VMS_END);
- ret = vmstate_subsection_load(f, vmsd, opaque);
+ ret = vmstate_subsection_load(f, vmsd, opaque, NULL);
if (ret != 0) {
qemu_file_set_error(f, ret);
return ret;
@@ -566,7 +566,7 @@ vmstate_get_subsection(const VMStateDescription * const *sub,
}
static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
- void *opaque)
+ void *opaque, Error **errp)
{
trace_vmstate_subsection_load(vmsd->name);
@@ -598,6 +598,8 @@ static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
sub_vmsd = vmstate_get_subsection(vmsd->subsections, idstr);
if (sub_vmsd == NULL) {
trace_vmstate_subsection_load_bad(vmsd->name, idstr, "(lookup)");
+ error_setg(errp, "VM subsection '%s' in '%s' does not exist",
+ idstr, vmsd->name);
return -ENOENT;
}
qemu_file_skip(f, 1); /* subsection */
@@ -608,6 +610,8 @@ static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
ret = vmstate_load_state(f, sub_vmsd, opaque, version_id);
if (ret) {
trace_vmstate_subsection_load_bad(vmsd->name, idstr, "(child)");
+ error_setg(errp, "Loading VM subsection '%s' in '%s' failed : %d",
+ idstr, vmsd->name, ret);
return ret;
}
}
--
2.50.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v6 02/24] migration: push Error **errp into vmstate_load_state()
2025-07-21 11:29 [PATCH v6 00/24] migration: propagate vTPM errors using Error objects Arun Menon
2025-07-21 11:29 ` [PATCH v6 01/24] migration: push Error **errp into vmstate_subsection_load() Arun Menon
@ 2025-07-21 11:29 ` Arun Menon
2025-07-21 12:24 ` Akihiko Odaki
2025-07-21 12:30 ` Marc-André Lureau
2025-07-21 11:29 ` [PATCH v6 03/24] migration: push Error **errp into qemu_loadvm_state_header() Arun Menon
` (21 subsequent siblings)
23 siblings, 2 replies; 55+ messages in thread
From: Arun Menon @ 2025-07-21 11:29 UTC (permalink / raw)
To: qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato, Arun Menon
This is an incremental step in converting vmstate loading
code to report error via Error objects instead of directly
printing it to console/monitor.
It is ensured that vmstate_load_state() must report an error
in errp, in case of failure.
Signed-off-by: Arun Menon <armenon@redhat.com>
---
hw/display/virtio-gpu.c | 2 +-
hw/pci/pci.c | 2 +-
hw/s390x/virtio-ccw.c | 2 +-
hw/scsi/spapr_vscsi.c | 2 +-
hw/vfio/pci.c | 2 +-
hw/virtio/virtio-mmio.c | 2 +-
hw/virtio/virtio-pci.c | 2 +-
hw/virtio/virtio.c | 4 ++--
include/migration/vmstate.h | 2 +-
migration/cpr.c | 4 ++--
migration/savevm.c | 6 ++++--
migration/vmstate-types.c | 10 +++++-----
migration/vmstate.c | 45 ++++++++++++++++++++++++++++-----------------
tests/unit/test-vmstate.c | 18 +++++++++---------
ui/vdagent.c | 2 +-
15 files changed, 59 insertions(+), 46 deletions(-)
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 0a1a625b0ea6cf26cb0d799171a57ed3d3ab2442..5d2ca8d8b864350133a674802d7316abd379591c 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -1343,7 +1343,7 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
}
/* load & apply scanout state */
- vmstate_load_state(f, &vmstate_virtio_gpu_scanouts, g, 1);
+ vmstate_load_state(f, &vmstate_virtio_gpu_scanouts, g, 1, NULL);
return 0;
}
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index c70b5ceebaf1f2b10768bd030526cbb518da2b8d..2ab5d30bb3c319ac1c7bfc9a2acf6a2b38082066 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -934,7 +934,7 @@ void pci_device_save(PCIDevice *s, QEMUFile *f)
int pci_device_load(PCIDevice *s, QEMUFile *f)
{
int ret;
- ret = vmstate_load_state(f, &vmstate_pci_device, s, s->version_id);
+ ret = vmstate_load_state(f, &vmstate_pci_device, s, s->version_id, NULL);
/* Restore the interrupt status bit. */
pci_update_irq_status(s);
return ret;
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index d2f85b39f30f7fc82e0c600144c0a958e1269b2c..2f6feff2b0a22d7d7f6aecfd7e7870d8362f1a73 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -1136,7 +1136,7 @@ static void virtio_ccw_save_config(DeviceState *d, QEMUFile *f)
static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f)
{
VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
- return vmstate_load_state(f, &vmstate_virtio_ccw_dev, dev, 1);
+ return vmstate_load_state(f, &vmstate_virtio_ccw_dev, dev, 1, NULL);
}
static void virtio_ccw_pre_plugged(DeviceState *d, Error **errp)
diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c
index 20f70fb2729de78b9636a6b8c869695dab4f8902..573fdea668536b464bca11f001e9e0288e781493 100644
--- a/hw/scsi/spapr_vscsi.c
+++ b/hw/scsi/spapr_vscsi.c
@@ -648,7 +648,7 @@ static void *vscsi_load_request(QEMUFile *f, SCSIRequest *sreq)
assert(!req->active);
memset(req, 0, sizeof(*req));
- rc = vmstate_load_state(f, &vmstate_spapr_vscsi_req, req, 1);
+ rc = vmstate_load_state(f, &vmstate_spapr_vscsi_req, req, 1, NULL);
if (rc) {
fprintf(stderr, "VSCSI: failed loading request tag#%u\n", sreq->tag);
return NULL;
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index be05002b9819fafa45cf2fb4d2a0acdc475c558c..f8ce4a40dbe4c070a0d6c111051051ee97542719 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -2797,7 +2797,7 @@ static int vfio_pci_load_config(VFIODevice *vbasedev, QEMUFile *f)
old_addr[bar] = pdev->io_regions[bar].addr;
}
- ret = vmstate_load_state(f, &vmstate_vfio_pci_config, vdev, 1);
+ ret = vmstate_load_state(f, &vmstate_vfio_pci_config, vdev, 1, NULL);
if (ret) {
return ret;
}
diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c
index 532c67107ba1d2978a76cf49f9cdc1de1dea3e11..9058b1563462d4464dcba799643a583c93fb5683 100644
--- a/hw/virtio/virtio-mmio.c
+++ b/hw/virtio/virtio-mmio.c
@@ -619,7 +619,7 @@ static int virtio_mmio_load_extra_state(DeviceState *opaque, QEMUFile *f)
{
VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
- return vmstate_load_state(f, &vmstate_virtio_mmio, proxy, 1);
+ return vmstate_load_state(f, &vmstate_virtio_mmio, proxy, 1, NULL);
}
static bool virtio_mmio_has_extra_state(DeviceState *opaque)
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 767216d795998708f5716a23ae16c79cd90ff489..f8b52a611e56c22d844fd4cae3619da4f2686d03 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -161,7 +161,7 @@ static int virtio_pci_load_extra_state(DeviceState *d, QEMUFile *f)
{
VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
- return vmstate_load_state(f, &vmstate_virtio_pci, proxy, 1);
+ return vmstate_load_state(f, &vmstate_virtio_pci, proxy, 1, NULL);
}
static void virtio_pci_save_queue(DeviceState *d, int n, QEMUFile *f)
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 2ab1d20769495ea39445b87e3673b076ad172510..d5698b062a1e95437f6113f41136e90ae06f1974 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -3317,14 +3317,14 @@ virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
}
if (vdc->vmsd) {
- ret = vmstate_load_state(f, vdc->vmsd, vdev, version_id);
+ ret = vmstate_load_state(f, vdc->vmsd, vdev, version_id, NULL);
if (ret) {
return ret;
}
}
/* Subsections */
- ret = vmstate_load_state(f, &vmstate_virtio, vdev, 1);
+ ret = vmstate_load_state(f, &vmstate_virtio, vdev, 1, NULL);
if (ret) {
return ret;
}
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 1ff7bd9ac425ba67cd5ca7ad97bcf570f9e19abe..056781b1c21e737583f081594d9f88b32adfd674 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -1196,7 +1196,7 @@ extern const VMStateInfo vmstate_info_qlist;
}
int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
- void *opaque, int version_id);
+ void *opaque, int version_id, Error **errp);
int vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
void *opaque, JSONWriter *vmdesc);
int vmstate_save_state_with_err(QEMUFile *f, const VMStateDescription *vmsd,
diff --git a/migration/cpr.c b/migration/cpr.c
index 42ad0b0d500e5de57faf0c6517e216b2d1c0cacf..74fac9521717ec568d14dabcbcb574b19fc1da67 100644
--- a/migration/cpr.c
+++ b/migration/cpr.c
@@ -233,9 +233,9 @@ int cpr_state_load(MigrationChannel *channel, Error **errp)
return -ENOTSUP;
}
- ret = vmstate_load_state(f, &vmstate_cpr_state, &cpr_state, 1);
+ ret = vmstate_load_state(f, &vmstate_cpr_state, &cpr_state, 1, errp);
if (ret) {
- error_setg(errp, "vmstate_load_state error %d", ret);
+ error_prepend(errp, "vmstate_load_state error %d ", ret);
qemu_fclose(f);
return ret;
}
diff --git a/migration/savevm.c b/migration/savevm.c
index fabbeb296ae987d0c06ba6dafda63720205fecfd..ab947620f724874f325fb9fb59bef50b7c16fb51 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -969,7 +969,8 @@ static int vmstate_load(QEMUFile *f, SaveStateEntry *se)
if (!se->vmsd) { /* Old style */
return se->ops->load_state(f, se->opaque, se->load_version_id);
}
- return vmstate_load_state(f, se->vmsd, se->opaque, se->load_version_id);
+ return vmstate_load_state(f, se->vmsd, se->opaque, se->load_version_id,
+ NULL);
}
static void vmstate_save_old_style(QEMUFile *f, SaveStateEntry *se,
@@ -2839,7 +2840,8 @@ static int qemu_loadvm_state_header(QEMUFile *f)
error_report("Configuration section missing");
return -EINVAL;
}
- ret = vmstate_load_state(f, &vmstate_configuration, &savevm_state, 0);
+ ret = vmstate_load_state(f, &vmstate_configuration, &savevm_state, 0,
+ NULL);
if (ret) {
return ret;
diff --git a/migration/vmstate-types.c b/migration/vmstate-types.c
index 741a588b7e18c6d37724b08a0101edc8bc74a0a5..1c5b76e1dd198030847971bc35637867c9d54fc0 100644
--- a/migration/vmstate-types.c
+++ b/migration/vmstate-types.c
@@ -549,7 +549,7 @@ static int get_tmp(QEMUFile *f, void *pv, size_t size,
/* Writes the parent field which is at the start of the tmp */
*(void **)tmp = pv;
- ret = vmstate_load_state(f, vmsd, tmp, version_id);
+ ret = vmstate_load_state(f, vmsd, tmp, version_id, NULL);
g_free(tmp);
return ret;
}
@@ -649,7 +649,7 @@ static int get_qtailq(QEMUFile *f, void *pv, size_t unused_size,
while (qemu_get_byte(f)) {
elm = g_malloc(size);
- ret = vmstate_load_state(f, vmsd, elm, version_id);
+ ret = vmstate_load_state(f, vmsd, elm, version_id, NULL);
if (ret) {
return ret;
}
@@ -803,7 +803,7 @@ static int get_gtree(QEMUFile *f, void *pv, size_t unused_size,
key = (void *)(uintptr_t)qemu_get_be64(f);
} else {
key = g_malloc0(key_size);
- ret = vmstate_load_state(f, key_vmsd, key, version_id);
+ ret = vmstate_load_state(f, key_vmsd, key, version_id, NULL);
if (ret) {
error_report("%s : failed to load %s (%d)",
field->name, key_vmsd->name, ret);
@@ -811,7 +811,7 @@ static int get_gtree(QEMUFile *f, void *pv, size_t unused_size,
}
}
val = g_malloc0(val_size);
- ret = vmstate_load_state(f, val_vmsd, val, version_id);
+ ret = vmstate_load_state(f, val_vmsd, val, version_id, NULL);
if (ret) {
error_report("%s : failed to load %s (%d)",
field->name, val_vmsd->name, ret);
@@ -892,7 +892,7 @@ static int get_qlist(QEMUFile *f, void *pv, size_t unused_size,
while (qemu_get_byte(f)) {
elm = g_malloc(size);
- ret = vmstate_load_state(f, vmsd, elm, version_id);
+ ret = vmstate_load_state(f, vmsd, elm, version_id, NULL);
if (ret) {
error_report("%s: failed to load %s (%d)", field->name,
vmsd->name, ret);
diff --git a/migration/vmstate.c b/migration/vmstate.c
index 129b19d7603a0ddf8ab6e946e41c1c4d773d1fa8..288b57e1ed778cce21247b64d5e97dfef41ad586 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -132,29 +132,33 @@ static void vmstate_handle_alloc(void *ptr, const VMStateField *field,
}
int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
- void *opaque, int version_id)
+ void *opaque, int version_id, Error **errp)
{
const VMStateField *field = vmsd->fields;
int ret = 0;
trace_vmstate_load_state(vmsd->name, version_id);
if (version_id > vmsd->version_id) {
- error_report("%s: incoming version_id %d is too new "
- "for local version_id %d",
- vmsd->name, version_id, vmsd->version_id);
+ error_setg(errp, "%s: incoming version_id %d is too new "
+ "for local version_id %d",
+ vmsd->name, version_id, vmsd->version_id);
trace_vmstate_load_state_end(vmsd->name, "too new", -EINVAL);
return -EINVAL;
}
if (version_id < vmsd->minimum_version_id) {
- error_report("%s: incoming version_id %d is too old "
- "for local minimum version_id %d",
- vmsd->name, version_id, vmsd->minimum_version_id);
+ error_setg(errp, "%s: incoming version_id %d is too old "
+ "for local minimum version_id %d",
+ vmsd->name, version_id, vmsd->minimum_version_id);
trace_vmstate_load_state_end(vmsd->name, "too old", -EINVAL);
return -EINVAL;
}
if (vmsd->pre_load) {
ret = vmsd->pre_load(opaque);
if (ret) {
+ error_setg(errp, "VM pre load failed for: '%s', "
+ "version_id: '%d', minimum version_id: '%d', ret: %d",
+ vmsd->name, vmsd->version_id, vmsd->minimum_version_id,
+ ret);
return ret;
}
}
@@ -192,10 +196,12 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
if (inner_field->flags & VMS_STRUCT) {
ret = vmstate_load_state(f, inner_field->vmsd, curr_elem,
- inner_field->vmsd->version_id);
+ inner_field->vmsd->version_id,
+ errp);
} else if (inner_field->flags & VMS_VSTRUCT) {
ret = vmstate_load_state(f, inner_field->vmsd, curr_elem,
- inner_field->struct_version_id);
+ inner_field->struct_version_id,
+ errp);
} else {
ret = inner_field->info->get(f, curr_elem, size,
inner_field);
@@ -211,27 +217,32 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
}
if (ret < 0) {
qemu_file_set_error(f, ret);
- error_report("Failed to load %s:%s", vmsd->name,
- field->name);
+ error_prepend(errp, "Failed to load %s:%s version_id: %d ",
+ vmsd->name, field->name, vmsd->version_id);
trace_vmstate_load_field_error(field->name, ret);
return ret;
}
}
} else if (field->flags & VMS_MUST_EXIST) {
- error_report("Input validation failed: %s/%s",
- vmsd->name, field->name);
+ error_setg(errp, "Input validation failed: %s/%s version_id: %d",
+ vmsd->name, field->name, vmsd->version_id);
return -1;
}
field++;
}
assert(field->flags == VMS_END);
- ret = vmstate_subsection_load(f, vmsd, opaque, NULL);
+ ret = vmstate_subsection_load(f, vmsd, opaque, errp);
if (ret != 0) {
qemu_file_set_error(f, ret);
return ret;
}
if (vmsd->post_load) {
ret = vmsd->post_load(opaque, version_id);
+ if (ret < 0) {
+ error_setg(errp, "VM Post load failed for: %s, version_id: %d,"
+ "minimum_version: %d, ret: %d", vmsd->name,
+ vmsd->version_id, vmsd->minimum_version_id, ret);
+ }
}
trace_vmstate_load_state_end(vmsd->name, "end", ret);
return ret;
@@ -607,11 +618,11 @@ static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
qemu_file_skip(f, len); /* idstr */
version_id = qemu_get_be32(f);
- ret = vmstate_load_state(f, sub_vmsd, opaque, version_id);
+ ret = vmstate_load_state(f, sub_vmsd, opaque, version_id, errp);
if (ret) {
trace_vmstate_subsection_load_bad(vmsd->name, idstr, "(child)");
- error_setg(errp, "Loading VM subsection '%s' in '%s' failed : %d",
- idstr, vmsd->name, ret);
+ error_prepend(errp, "Loading VM subsection '%s'"
+ "in '%s' failed : %d ", idstr, vmsd->name, ret);
return ret;
}
}
diff --git a/tests/unit/test-vmstate.c b/tests/unit/test-vmstate.c
index 63f28f26f45691a70936d33e7341d16477a3471f..ca5e0ba1e3e5e2bb0a1ce39143a292f2c6f9420a 100644
--- a/tests/unit/test-vmstate.c
+++ b/tests/unit/test-vmstate.c
@@ -114,7 +114,7 @@ static int load_vmstate_one(const VMStateDescription *desc, void *obj,
qemu_fclose(f);
f = open_test_file(false);
- ret = vmstate_load_state(f, desc, obj, version);
+ ret = vmstate_load_state(f, desc, obj, version, NULL);
if (ret) {
g_assert(qemu_file_get_error(f));
} else{
@@ -365,7 +365,7 @@ static void test_load_v1(void)
QEMUFile *loading = open_test_file(false);
TestStruct obj = { .b = 200, .e = 500, .f = 600 };
- vmstate_load_state(loading, &vmstate_versioned, &obj, 1);
+ vmstate_load_state(loading, &vmstate_versioned, &obj, 1, NULL);
g_assert(!qemu_file_get_error(loading));
g_assert_cmpint(obj.a, ==, 10);
g_assert_cmpint(obj.b, ==, 200);
@@ -391,7 +391,7 @@ static void test_load_v2(void)
QEMUFile *loading = open_test_file(false);
TestStruct obj;
- vmstate_load_state(loading, &vmstate_versioned, &obj, 2);
+ vmstate_load_state(loading, &vmstate_versioned, &obj, 2, NULL);
g_assert_cmpint(obj.a, ==, 10);
g_assert_cmpint(obj.b, ==, 20);
g_assert_cmpint(obj.c, ==, 30);
@@ -480,7 +480,7 @@ static void test_load_noskip(void)
QEMUFile *loading = open_test_file(false);
TestStruct obj = { .skip_c_e = false };
- vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
+ vmstate_load_state(loading, &vmstate_skipping, &obj, 2, NULL);
g_assert(!qemu_file_get_error(loading));
g_assert_cmpint(obj.a, ==, 10);
g_assert_cmpint(obj.b, ==, 20);
@@ -504,7 +504,7 @@ static void test_load_skip(void)
QEMUFile *loading = open_test_file(false);
TestStruct obj = { .skip_c_e = true, .c = 300, .e = 500 };
- vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
+ vmstate_load_state(loading, &vmstate_skipping, &obj, 2, NULL);
g_assert(!qemu_file_get_error(loading));
g_assert_cmpint(obj.a, ==, 10);
g_assert_cmpint(obj.b, ==, 20);
@@ -773,7 +773,7 @@ static void test_load_q(void)
TestQtailq tgt;
QTAILQ_INIT(&tgt.q);
- vmstate_load_state(fload, &vmstate_q, &tgt, 1);
+ vmstate_load_state(fload, &vmstate_q, &tgt, 1, NULL);
char eof = qemu_get_byte(fload);
g_assert(!qemu_file_get_error(fload));
g_assert_cmpint(tgt.i16, ==, obj_q.i16);
@@ -1127,7 +1127,7 @@ static void test_gtree_load_domain(void)
fload = open_test_file(false);
- vmstate_load_state(fload, &vmstate_domain, dest_domain, 1);
+ vmstate_load_state(fload, &vmstate_domain, dest_domain, 1, NULL);
eof = qemu_get_byte(fload);
g_assert(!qemu_file_get_error(fload));
g_assert_cmpint(orig_domain->id, ==, dest_domain->id);
@@ -1241,7 +1241,7 @@ static void test_gtree_load_iommu(void)
qemu_fclose(fsave);
fload = open_test_file(false);
- vmstate_load_state(fload, &vmstate_iommu, dest_iommu, 1);
+ vmstate_load_state(fload, &vmstate_iommu, dest_iommu, 1, NULL);
eof = qemu_get_byte(fload);
g_assert(!qemu_file_get_error(fload));
g_assert_cmpint(orig_iommu->id, ==, dest_iommu->id);
@@ -1376,7 +1376,7 @@ static void test_load_qlist(void)
qemu_fclose(fsave);
fload = open_test_file(false);
- vmstate_load_state(fload, &vmstate_container, dest_container, 1);
+ vmstate_load_state(fload, &vmstate_container, dest_container, 1, NULL);
eof = qemu_get_byte(fload);
g_assert(!qemu_file_get_error(fload));
g_assert_cmpint(eof, ==, QEMU_VM_EOF);
diff --git a/ui/vdagent.c b/ui/vdagent.c
index c0746fe5b168fdc7aeb4866de2ba0c3387566649..83457dee0767433ad0778b37b41b9c673a0e1860 100644
--- a/ui/vdagent.c
+++ b/ui/vdagent.c
@@ -1008,7 +1008,7 @@ static int get_cbinfo(QEMUFile *f, void *pv, size_t size,
vdagent_clipboard_peer_register(vd);
- ret = vmstate_load_state(f, &vmstate_cbinfo_array, &cbinfo, 0);
+ ret = vmstate_load_state(f, &vmstate_cbinfo_array, &cbinfo, 0, NULL);
if (ret) {
return ret;
}
--
2.50.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v6 03/24] migration: push Error **errp into qemu_loadvm_state_header()
2025-07-21 11:29 [PATCH v6 00/24] migration: propagate vTPM errors using Error objects Arun Menon
2025-07-21 11:29 ` [PATCH v6 01/24] migration: push Error **errp into vmstate_subsection_load() Arun Menon
2025-07-21 11:29 ` [PATCH v6 02/24] migration: push Error **errp into vmstate_load_state() Arun Menon
@ 2025-07-21 11:29 ` Arun Menon
2025-07-21 12:34 ` Marc-André Lureau
2025-07-21 11:29 ` [PATCH v6 04/24] migration: push Error **errp into vmstate_load() Arun Menon
` (20 subsequent siblings)
23 siblings, 1 reply; 55+ messages in thread
From: Arun Menon @ 2025-07-21 11:29 UTC (permalink / raw)
To: qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato, Arun Menon
This is an incremental step in converting vmstate loading
code to report error via Error objects instead of directly
printing it to console/monitor.
It is ensured that qemu_loadvm_state_header() must report an error
in errp, in case of failure.
Signed-off-by: Arun Menon <armenon@redhat.com>
---
migration/savevm.c | 25 ++++++++++++++++---------
1 file changed, 16 insertions(+), 9 deletions(-)
diff --git a/migration/savevm.c b/migration/savevm.c
index ab947620f724874f325fb9fb59bef50b7c16fb51..162fb05933fae5993eeef107811f97cb08726ac3 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2814,35 +2814,42 @@ qemu_loadvm_section_part_end(QEMUFile *f, uint8_t type)
return 0;
}
-static int qemu_loadvm_state_header(QEMUFile *f)
+static int qemu_loadvm_state_header(QEMUFile *f, Error **errp)
{
unsigned int v;
int ret;
v = qemu_get_be32(f);
if (v != QEMU_VM_FILE_MAGIC) {
- error_report("Not a migration stream");
+ error_setg(errp, "Not a migration stream, "
+ "magic: %x != %x", v, QEMU_VM_FILE_MAGIC);
return -EINVAL;
}
v = qemu_get_be32(f);
if (v == QEMU_VM_FILE_VERSION_COMPAT) {
- error_report("SaveVM v2 format is obsolete and don't work anymore");
+ error_setg(errp, "SaveVM v2 format is obsolete and no"
+ "longer supported, file version %x != %x",
+ v, QEMU_VM_FILE_VERSION_COMPAT);
+
return -ENOTSUP;
}
if (v != QEMU_VM_FILE_VERSION) {
- error_report("Unsupported migration stream version");
+ error_setg(errp, "Unsupported migration stream "
+ "version, file version %x != %x", v, QEMU_VM_FILE_VERSION);
return -ENOTSUP;
}
if (migrate_get_current()->send_configuration) {
- if (qemu_get_byte(f) != QEMU_VM_CONFIGURATION) {
- error_report("Configuration section missing");
+ v = qemu_get_byte(f);
+ if (v != QEMU_VM_CONFIGURATION) {
+ error_setg(errp, "Configuration section missing,"
+ "%x != %x", v, QEMU_VM_CONFIGURATION);
return -EINVAL;
}
- ret = vmstate_load_state(f, &vmstate_configuration, &savevm_state, 0,
- NULL);
+ ret = vmstate_load_state(f, &vmstate_configuration, &savevm_state, 0,
+ errp);
if (ret) {
return ret;
}
@@ -3119,7 +3126,7 @@ int qemu_loadvm_state(QEMUFile *f)
qemu_loadvm_thread_pool_create(mis);
- ret = qemu_loadvm_state_header(f);
+ ret = qemu_loadvm_state_header(f, NULL);
if (ret) {
return ret;
}
--
2.50.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v6 04/24] migration: push Error **errp into vmstate_load()
2025-07-21 11:29 [PATCH v6 00/24] migration: propagate vTPM errors using Error objects Arun Menon
` (2 preceding siblings ...)
2025-07-21 11:29 ` [PATCH v6 03/24] migration: push Error **errp into qemu_loadvm_state_header() Arun Menon
@ 2025-07-21 11:29 ` Arun Menon
2025-07-21 11:29 ` [PATCH v6 05/24] migration: push Error **errp into qemu_loadvm_section_start_full() Arun Menon
` (19 subsequent siblings)
23 siblings, 0 replies; 55+ messages in thread
From: Arun Menon @ 2025-07-21 11:29 UTC (permalink / raw)
To: qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato, Arun Menon
This is an incremental step in converting vmstate loading
code to report error via Error objects instead of directly
printing it to console/monitor.
It is ensured that vmstate_load() must report an error
in errp, in case of failure.
Signed-off-by: Arun Menon <armenon@redhat.com>
---
migration/savevm.c | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/migration/savevm.c b/migration/savevm.c
index 162fb05933fae5993eeef107811f97cb08726ac3..5fe896545a5407393b1bc5126ee977f11b1fc626 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -963,14 +963,20 @@ void vmstate_unregister(VMStateIf *obj, const VMStateDescription *vmsd,
}
}
-static int vmstate_load(QEMUFile *f, SaveStateEntry *se)
+static int vmstate_load(QEMUFile *f, SaveStateEntry *se, Error **errp)
{
+ int ret;
trace_vmstate_load(se->idstr, se->vmsd ? se->vmsd->name : "(old)");
if (!se->vmsd) { /* Old style */
- return se->ops->load_state(f, se->opaque, se->load_version_id);
+ ret = se->ops->load_state(f, se->opaque, se->load_version_id);
+ if (ret < 0) {
+ error_setg(errp, "Failed to load version_id: '%d' of VM, "
+ "ret: '%d'", se->load_version_id, ret);
+ }
+ return ret;
}
return vmstate_load_state(f, se->vmsd, se->opaque, se->load_version_id,
- NULL);
+ errp);
}
static void vmstate_save_old_style(QEMUFile *f, SaveStateEntry *se,
@@ -2741,7 +2747,7 @@ qemu_loadvm_section_start_full(QEMUFile *f, uint8_t type)
start_ts = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
}
- ret = vmstate_load(f, se);
+ ret = vmstate_load(f, se, NULL);
if (ret < 0) {
error_report("error while loading state for instance 0x%"PRIx32" of"
" device '%s'", instance_id, idstr);
@@ -2794,7 +2800,7 @@ qemu_loadvm_section_part_end(QEMUFile *f, uint8_t type)
start_ts = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
}
- ret = vmstate_load(f, se);
+ ret = vmstate_load(f, se, NULL);
if (ret < 0) {
error_report("error while loading state section id %d(%s)",
section_id, se->idstr);
--
2.50.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v6 05/24] migration: push Error **errp into qemu_loadvm_section_start_full()
2025-07-21 11:29 [PATCH v6 00/24] migration: propagate vTPM errors using Error objects Arun Menon
` (3 preceding siblings ...)
2025-07-21 11:29 ` [PATCH v6 04/24] migration: push Error **errp into vmstate_load() Arun Menon
@ 2025-07-21 11:29 ` Arun Menon
2025-07-21 11:29 ` [PATCH v6 06/24] migration: push Error **errp into qemu_loadvm_section_part_end() Arun Menon
` (18 subsequent siblings)
23 siblings, 0 replies; 55+ messages in thread
From: Arun Menon @ 2025-07-21 11:29 UTC (permalink / raw)
To: qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato, Arun Menon
This is an incremental step in converting vmstate loading
code to report error via Error objects instead of directly
printing it to console/monitor.
It is ensured that qemu_loadvm_section_start_full() must report an error
in errp, in case of failure.
Signed-off-by: Arun Menon <armenon@redhat.com>
---
migration/savevm.c | 35 +++++++++++++++++++----------------
1 file changed, 19 insertions(+), 16 deletions(-)
diff --git a/migration/savevm.c b/migration/savevm.c
index 5fe896545a5407393b1bc5126ee977f11b1fc626..96c1a029953230586d4dd48097467d3fdc3e3d39 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2690,7 +2690,7 @@ static bool check_section_footer(QEMUFile *f, SaveStateEntry *se)
}
static int
-qemu_loadvm_section_start_full(QEMUFile *f, uint8_t type)
+qemu_loadvm_section_start_full(QEMUFile *f, uint8_t type, Error **errp)
{
bool trace_downtime = (type == QEMU_VM_SECTION_FULL);
uint32_t instance_id, version_id, section_id;
@@ -2702,8 +2702,8 @@ qemu_loadvm_section_start_full(QEMUFile *f, uint8_t type)
/* Read section start */
section_id = qemu_get_be32(f);
if (!qemu_get_counted_string(f, idstr)) {
- error_report("Unable to read ID string for section %u",
- section_id);
+ error_setg(errp, "Unable to read ID string for section %u",
+ section_id);
return -EINVAL;
}
instance_id = qemu_get_be32(f);
@@ -2711,8 +2711,7 @@ qemu_loadvm_section_start_full(QEMUFile *f, uint8_t type)
ret = qemu_file_get_error(f);
if (ret) {
- error_report("%s: Failed to read instance/version ID: %d",
- __func__, ret);
+ error_setg(errp, "Failed to read instance/version ID: %d", ret);
return ret;
}
@@ -2721,17 +2720,17 @@ qemu_loadvm_section_start_full(QEMUFile *f, uint8_t type)
/* Find savevm section */
se = find_se(idstr, instance_id);
if (se == NULL) {
- error_report("Unknown savevm section or instance '%s' %"PRIu32". "
- "Make sure that your current VM setup matches your "
- "saved VM setup, including any hotplugged devices",
- idstr, instance_id);
+ error_setg(errp, "Unknown savevm section or instance '%s' %"PRIu32". "
+ "Make sure that your current VM setup matches your "
+ "saved VM setup, including any hotplugged devices",
+ idstr, instance_id);
return -EINVAL;
}
/* Validate version */
if (version_id > se->version_id) {
- error_report("savevm: unsupported version %d for '%s' v%d",
- version_id, idstr, se->version_id);
+ error_setg(errp, "savevm: unsupported version %d for '%s' v%d",
+ version_id, idstr, se->version_id);
return -EINVAL;
}
se->load_version_id = version_id;
@@ -2739,7 +2738,7 @@ qemu_loadvm_section_start_full(QEMUFile *f, uint8_t type)
/* Validate if it is a device's state */
if (xen_enabled() && se->is_ram) {
- error_report("loadvm: %s RAM loading not allowed on Xen", idstr);
+ error_setg(errp, "loadvm: %s RAM loading not allowed on Xen", idstr);
return -EINVAL;
}
@@ -2747,10 +2746,11 @@ qemu_loadvm_section_start_full(QEMUFile *f, uint8_t type)
start_ts = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
}
- ret = vmstate_load(f, se, NULL);
+ ret = vmstate_load(f, se, errp);
if (ret < 0) {
- error_report("error while loading state for instance 0x%"PRIx32" of"
- " device '%s'", instance_id, idstr);
+ error_prepend(errp, "error while loading state for"
+ " instance 0x%"PRIx32" of"
+ " device '%s' ", instance_id, idstr);
return ret;
}
@@ -2761,6 +2761,9 @@ qemu_loadvm_section_start_full(QEMUFile *f, uint8_t type)
}
if (!check_section_footer(f, se)) {
+ error_setg(errp, "Reading footer section of instance "
+ "0x%"PRIx32" of device '%s' for version_id:'%d' failed",
+ instance_id, idstr, version_id);
return -EINVAL;
}
@@ -3061,7 +3064,7 @@ retry:
switch (section_type) {
case QEMU_VM_SECTION_START:
case QEMU_VM_SECTION_FULL:
- ret = qemu_loadvm_section_start_full(f, section_type);
+ ret = qemu_loadvm_section_start_full(f, section_type, NULL);
if (ret < 0) {
goto out;
}
--
2.50.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v6 06/24] migration: push Error **errp into qemu_loadvm_section_part_end()
2025-07-21 11:29 [PATCH v6 00/24] migration: propagate vTPM errors using Error objects Arun Menon
` (4 preceding siblings ...)
2025-07-21 11:29 ` [PATCH v6 05/24] migration: push Error **errp into qemu_loadvm_section_start_full() Arun Menon
@ 2025-07-21 11:29 ` Arun Menon
2025-07-21 11:29 ` [PATCH v6 07/24] migration: Update qemu_file_get_return_path() docs and remove dead checks Arun Menon
` (17 subsequent siblings)
23 siblings, 0 replies; 55+ messages in thread
From: Arun Menon @ 2025-07-21 11:29 UTC (permalink / raw)
To: qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato, Arun Menon
This is an incremental step in converting vmstate loading
code to report error via Error objects instead of directly
printing it to console/monitor.
It is ensured that qemu_loadvm_section_part_end() must report an error
in errp, in case of failure.
Signed-off-by: Arun Menon <armenon@redhat.com>
---
migration/savevm.c | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/migration/savevm.c b/migration/savevm.c
index 96c1a029953230586d4dd48097467d3fdc3e3d39..bef2236799945ed63124b3a41559ca4ab02e094e 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2771,7 +2771,7 @@ qemu_loadvm_section_start_full(QEMUFile *f, uint8_t type, Error **errp)
}
static int
-qemu_loadvm_section_part_end(QEMUFile *f, uint8_t type)
+qemu_loadvm_section_part_end(QEMUFile *f, uint8_t type, Error **errp)
{
bool trace_downtime = (type == QEMU_VM_SECTION_END);
int64_t start_ts, end_ts;
@@ -2783,8 +2783,7 @@ qemu_loadvm_section_part_end(QEMUFile *f, uint8_t type)
ret = qemu_file_get_error(f);
if (ret) {
- error_report("%s: Failed to read section ID: %d",
- __func__, ret);
+ error_setg(errp, "Failed to read section ID: %d", ret);
return ret;
}
@@ -2795,7 +2794,7 @@ qemu_loadvm_section_part_end(QEMUFile *f, uint8_t type)
}
}
if (se == NULL) {
- error_report("Unknown savevm section %d", section_id);
+ error_setg(errp, "Unknown savevm section %d", section_id);
return -EINVAL;
}
@@ -2803,10 +2802,10 @@ qemu_loadvm_section_part_end(QEMUFile *f, uint8_t type)
start_ts = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
}
- ret = vmstate_load(f, se, NULL);
+ ret = vmstate_load(f, se, errp);
if (ret < 0) {
- error_report("error while loading state section id %d(%s)",
- section_id, se->idstr);
+ error_prepend(errp, "error while loading state section id %d(%s) ",
+ section_id, se->idstr);
return ret;
}
@@ -2817,6 +2816,8 @@ qemu_loadvm_section_part_end(QEMUFile *f, uint8_t type)
}
if (!check_section_footer(f, se)) {
+ error_setg(errp, "Check section footer error, section_id: '%d'",
+ section_id);
return -EINVAL;
}
@@ -3071,7 +3072,7 @@ retry:
break;
case QEMU_VM_SECTION_PART:
case QEMU_VM_SECTION_END:
- ret = qemu_loadvm_section_part_end(f, section_type);
+ ret = qemu_loadvm_section_part_end(f, section_type, NULL);
if (ret < 0) {
goto out;
}
--
2.50.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v6 07/24] migration: Update qemu_file_get_return_path() docs and remove dead checks
2025-07-21 11:29 [PATCH v6 00/24] migration: propagate vTPM errors using Error objects Arun Menon
` (5 preceding siblings ...)
2025-07-21 11:29 ` [PATCH v6 06/24] migration: push Error **errp into qemu_loadvm_section_part_end() Arun Menon
@ 2025-07-21 11:29 ` Arun Menon
2025-07-21 12:24 ` Daniel P. Berrangé
2025-07-21 11:29 ` [PATCH v6 08/24] migration: push Error **errp into loadvm_process_command() Arun Menon
` (16 subsequent siblings)
23 siblings, 1 reply; 55+ messages in thread
From: Arun Menon @ 2025-07-21 11:29 UTC (permalink / raw)
To: qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato, Arun Menon
The documentation of qemu_file_get_return_path() states that it can
return NULL on failure. However, a review of the current implementation
reveals that it is guaranteed that it will always succeed and will never
return NULL.
As a result, the NULL checks post calling the function become redundant.
This commit updates the documentation for the function and removes all
NULL checks throughout the migration code.
Signed-off-by: Arun Menon <armenon@redhat.com>
---
migration/colo.c | 4 ----
migration/migration.c | 12 ++----------
migration/qemu-file.c | 1 -
migration/savevm.c | 4 ----
4 files changed, 2 insertions(+), 19 deletions(-)
diff --git a/migration/colo.c b/migration/colo.c
index e0f713c837f5da25d67afbd02ceb6c54024ca3af..981bd4bf9ced8b45b4c5d494acae119a174ee974 100644
--- a/migration/colo.c
+++ b/migration/colo.c
@@ -849,10 +849,6 @@ static void *colo_process_incoming_thread(void *opaque)
failover_init_state();
mis->to_src_file = qemu_file_get_return_path(mis->from_src_file);
- if (!mis->to_src_file) {
- error_report("COLO incoming thread: Open QEMUFile to_src_file failed");
- goto out;
- }
/*
* Note: the communication between Primary side and Secondary side
* should be sequential, we set the fd to unblocked in migration incoming
diff --git a/migration/migration.c b/migration/migration.c
index 10c216d25dec01f206eacad2edd24d21f00e614c..b3bccaeaee806abd01595863f6475057049b0688 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -2646,12 +2646,9 @@ out:
return NULL;
}
-static int open_return_path_on_source(MigrationState *ms)
+static void open_return_path_on_source(MigrationState *ms)
{
ms->rp_state.from_dst_file = qemu_file_get_return_path(ms->to_dst_file);
- if (!ms->rp_state.from_dst_file) {
- return -1;
- }
trace_open_return_path_on_source();
@@ -2660,8 +2657,6 @@ static int open_return_path_on_source(MigrationState *ms)
ms->rp_state.rp_thread_created = true;
trace_open_return_path_on_source_continue();
-
- return 0;
}
/* Return true if error detected, or false otherwise */
@@ -4010,10 +4005,7 @@ void migration_connect(MigrationState *s, Error *error_in)
* QEMU uses the return path.
*/
if (migrate_postcopy_ram() || migrate_return_path()) {
- if (open_return_path_on_source(s)) {
- error_setg(&local_err, "Unable to open return-path for postcopy");
- goto fail;
- }
+ open_return_path_on_source(s);
}
/*
diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index b6ac190034f777dbde0da1598483a892089d7538..f9ccee9a1091ecbd37e6b7d2081a4446442b544d 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -125,7 +125,6 @@ static QEMUFile *qemu_file_new_impl(QIOChannel *ioc, bool is_writable)
/*
* Result: QEMUFile* for a 'return path' for comms in the opposite direction
- * NULL if not available
*/
QEMUFile *qemu_file_get_return_path(QEMUFile *f)
{
diff --git a/migration/savevm.c b/migration/savevm.c
index bef2236799945ed63124b3a41559ca4ab02e094e..96af7b412f2ed43468f4bcac8b833cda223f8321 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2583,10 +2583,6 @@ static int loadvm_process_command(QEMUFile *f)
return 0;
}
mis->to_src_file = qemu_file_get_return_path(f);
- if (!mis->to_src_file) {
- error_report("CMD_OPEN_RETURN_PATH failed");
- return -1;
- }
/*
* Switchover ack is enabled but no device uses it, so send an ACK to
--
2.50.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v6 08/24] migration: push Error **errp into loadvm_process_command()
2025-07-21 11:29 [PATCH v6 00/24] migration: propagate vTPM errors using Error objects Arun Menon
` (6 preceding siblings ...)
2025-07-21 11:29 ` [PATCH v6 07/24] migration: Update qemu_file_get_return_path() docs and remove dead checks Arun Menon
@ 2025-07-21 11:29 ` Arun Menon
2025-07-21 12:38 ` Akihiko Odaki
2025-07-21 11:29 ` [PATCH v6 09/24] migration: push Error **errp into loadvm_handle_cmd_packaged() Arun Menon
` (15 subsequent siblings)
23 siblings, 1 reply; 55+ messages in thread
From: Arun Menon @ 2025-07-21 11:29 UTC (permalink / raw)
To: qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato, Arun Menon
This is an incremental step in converting vmstate loading
code to report error via Error objects instead of directly
printing it to console/monitor.
It is ensured that loadvm_process_command() must report an error
in errp, in case of failure.
Signed-off-by: Arun Menon <armenon@redhat.com>
---
migration/savevm.c | 87 +++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 66 insertions(+), 21 deletions(-)
diff --git a/migration/savevm.c b/migration/savevm.c
index 96af7b412f2ed43468f4bcac8b833cda223f8321..d8feb9e1599d019636cd400ee7ebe594df27bd1d 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2546,12 +2546,13 @@ static int loadvm_postcopy_handle_switchover_start(void)
* LOADVM_QUIT All good, but exit the loop
* <0 Error
*/
-static int loadvm_process_command(QEMUFile *f)
+static int loadvm_process_command(QEMUFile *f, Error **errp)
{
MigrationIncomingState *mis = migration_incoming_get_current();
uint16_t cmd;
uint16_t len;
uint32_t tmp32;
+ int ret;
cmd = qemu_get_be16(f);
len = qemu_get_be16(f);
@@ -2562,16 +2563,16 @@ static int loadvm_process_command(QEMUFile *f)
}
if (cmd >= MIG_CMD_MAX || cmd == MIG_CMD_INVALID) {
- error_report("MIG_CMD 0x%x unknown (len 0x%x)", cmd, len);
+ error_setg(errp, "MIG_CMD 0x%x unknown (len 0x%x)", cmd, len);
return -EINVAL;
}
trace_loadvm_process_command(mig_cmd_args[cmd].name, len);
if (mig_cmd_args[cmd].len != -1 && mig_cmd_args[cmd].len != len) {
- error_report("%s received with bad length - expecting %zu, got %d",
- mig_cmd_args[cmd].name,
- (size_t)mig_cmd_args[cmd].len, len);
+ error_setg(errp, "%s received with bad length - expecting %zu, got %d",
+ mig_cmd_args[cmd].name,
+ (size_t)mig_cmd_args[cmd].len, len);
return -ERANGE;
}
@@ -2590,11 +2591,10 @@ static int loadvm_process_command(QEMUFile *f)
* been created.
*/
if (migrate_switchover_ack() && !mis->switchover_ack_pending_num) {
- int ret = migrate_send_rp_switchover_ack(mis);
+ ret = migrate_send_rp_switchover_ack(mis);
if (ret) {
- error_report(
- "Could not send switchover ack RP MSG, err %d (%s)", ret,
- strerror(-ret));
+ error_setg(errp, "Could not send switchover ack "
+ "RP MSG, err %d (%s)", ret, strerror(-ret));
return ret;
}
}
@@ -2604,39 +2604,84 @@ static int loadvm_process_command(QEMUFile *f)
tmp32 = qemu_get_be32(f);
trace_loadvm_process_command_ping(tmp32);
if (!mis->to_src_file) {
- error_report("CMD_PING (0x%x) received with no return path",
- tmp32);
+ error_setg(errp, "CMD_PING (0x%x) received with no return path",
+ tmp32);
return -1;
}
migrate_send_rp_pong(mis, tmp32);
break;
case MIG_CMD_PACKAGED:
- return loadvm_handle_cmd_packaged(mis);
+ ret = loadvm_handle_cmd_packaged(mis);
+ if (ret < 0) {
+ error_setg(errp, "Failed to load device state command: %d", ret);
+ return -1;
+ }
+ return ret;
case MIG_CMD_POSTCOPY_ADVISE:
- return loadvm_postcopy_handle_advise(mis, len);
+ ret = loadvm_postcopy_handle_advise(mis, len);
+ if (ret < 0) {
+ error_setg(errp, "Failed to load device state command: %d", ret);
+ return -1;
+ }
+ return ret;
case MIG_CMD_POSTCOPY_LISTEN:
- return loadvm_postcopy_handle_listen(mis);
+ ret = loadvm_postcopy_handle_listen(mis);
+ if (ret < 0) {
+ error_setg(errp, "Failed to load device state command: %d", ret);
+ return -1;
+ }
+ return ret;
case MIG_CMD_POSTCOPY_RUN:
- return loadvm_postcopy_handle_run(mis);
+ ret = loadvm_postcopy_handle_run(mis);
+ if (ret < 0) {
+ error_setg(errp, "Failed to load device state command: %d", ret);
+ return -1;
+ }
+ return ret;
case MIG_CMD_POSTCOPY_RAM_DISCARD:
- return loadvm_postcopy_ram_handle_discard(mis, len);
+ ret = loadvm_postcopy_ram_handle_discard(mis, len);
+ if (ret < 0) {
+ error_setg(errp, "Failed to load device state command: %d", ret);
+ return -1;
+ }
+ return ret;
case MIG_CMD_POSTCOPY_RESUME:
- return loadvm_postcopy_handle_resume(mis);
+ ret = loadvm_postcopy_handle_resume(mis);
+ if (ret < 0) {
+ error_setg(errp, "Failed to load device state command: %d", ret);
+ return -1;
+ }
+ return ret;
case MIG_CMD_RECV_BITMAP:
- return loadvm_handle_recv_bitmap(mis, len);
+ ret = loadvm_handle_recv_bitmap(mis, len);
+ if (ret < 0) {
+ error_setg(errp, "Failed to load device state command: %d", ret);
+ return -1;
+ }
+ return ret;
case MIG_CMD_ENABLE_COLO:
- return loadvm_process_enable_colo(mis);
+ ret = loadvm_process_enable_colo(mis);
+ if (ret < 0) {
+ error_setg(errp, "Failed to load device state command: %d", ret);
+ return -1;
+ }
+ return ret;
case MIG_CMD_SWITCHOVER_START:
- return loadvm_postcopy_handle_switchover_start();
+ ret = loadvm_postcopy_handle_switchover_start();
+ if (ret < 0) {
+ error_setg(errp, "Failed to load device state command: %d", ret);
+ return -1;
+ }
+ return ret;
}
return 0;
@@ -3074,7 +3119,7 @@ retry:
}
break;
case QEMU_VM_COMMAND:
- ret = loadvm_process_command(f);
+ ret = loadvm_process_command(f, NULL);
trace_qemu_loadvm_state_section_command(ret);
if ((ret < 0) || (ret == LOADVM_QUIT)) {
goto out;
--
2.50.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v6 09/24] migration: push Error **errp into loadvm_handle_cmd_packaged()
2025-07-21 11:29 [PATCH v6 00/24] migration: propagate vTPM errors using Error objects Arun Menon
` (7 preceding siblings ...)
2025-07-21 11:29 ` [PATCH v6 08/24] migration: push Error **errp into loadvm_process_command() Arun Menon
@ 2025-07-21 11:29 ` Arun Menon
2025-07-21 11:29 ` [PATCH v6 10/24] migration: push Error **errp into ram_postcopy_incoming_init() Arun Menon
` (14 subsequent siblings)
23 siblings, 0 replies; 55+ messages in thread
From: Arun Menon @ 2025-07-21 11:29 UTC (permalink / raw)
To: qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato, Arun Menon,
Daniel P. Berrangé
This is an incremental step in converting vmstate loading
code to report error via Error objects instead of directly
printing it to console/monitor.
It is ensured that loadvm_handle_cmd_packaged() must report an error
in errp, in case of failure.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Arun Menon <armenon@redhat.com>
---
migration/savevm.c | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/migration/savevm.c b/migration/savevm.c
index d8feb9e1599d019636cd400ee7ebe594df27bd1d..3ade91d2f757f94bc6c0242a38c6e750a9252f96 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2405,7 +2405,7 @@ static int loadvm_postcopy_handle_resume(MigrationIncomingState *mis)
* Returns: Negative values on error
*
*/
-static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis)
+static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis, Error **errp)
{
int ret;
size_t length;
@@ -2415,7 +2415,7 @@ static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis)
trace_loadvm_handle_cmd_packaged(length);
if (length > MAX_VM_CMD_PACKAGED_SIZE) {
- error_report("Unreasonably large packaged state: %zu", length);
+ error_setg(errp, "Unreasonably large packaged state: %zu", length);
return -1;
}
@@ -2426,8 +2426,8 @@ static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis)
length);
if (ret != length) {
object_unref(OBJECT(bioc));
- error_report("CMD_PACKAGED: Buffer receive fail ret=%d length=%zu",
- ret, length);
+ error_setg(errp, "CMD_PACKAGED: Buffer receive fail ret=%d length=%zu",
+ ret, length);
return (ret < 0) ? ret : -EAGAIN;
}
bioc->usage += length;
@@ -2457,6 +2457,9 @@ static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis)
} while (1);
ret = qemu_loadvm_state_main(packf, mis);
+ if (ret < 0) {
+ error_setg(errp, "VM state load failed: %d", ret);
+ }
trace_loadvm_handle_cmd_packaged_main(ret);
qemu_fclose(packf);
object_unref(OBJECT(bioc));
@@ -2612,12 +2615,7 @@ static int loadvm_process_command(QEMUFile *f, Error **errp)
break;
case MIG_CMD_PACKAGED:
- ret = loadvm_handle_cmd_packaged(mis);
- if (ret < 0) {
- error_setg(errp, "Failed to load device state command: %d", ret);
- return -1;
- }
- return ret;
+ return loadvm_handle_cmd_packaged(mis, errp);
case MIG_CMD_POSTCOPY_ADVISE:
ret = loadvm_postcopy_handle_advise(mis, len);
--
2.50.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v6 10/24] migration: push Error **errp into ram_postcopy_incoming_init()
2025-07-21 11:29 [PATCH v6 00/24] migration: propagate vTPM errors using Error objects Arun Menon
` (8 preceding siblings ...)
2025-07-21 11:29 ` [PATCH v6 09/24] migration: push Error **errp into loadvm_handle_cmd_packaged() Arun Menon
@ 2025-07-21 11:29 ` Arun Menon
2025-07-21 11:29 ` [PATCH v6 11/24] migration: push Error **errp into loadvm_postcopy_handle_advise() Arun Menon
` (13 subsequent siblings)
23 siblings, 0 replies; 55+ messages in thread
From: Arun Menon @ 2025-07-21 11:29 UTC (permalink / raw)
To: qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato, Arun Menon
This is an incremental step in converting vmstate loading
code to report error via Error objects instead of directly
printing it to console/monitor.
It is ensured that ram_postcopy_incoming_init() must report an error
in errp, in case of failure.
Signed-off-by: Arun Menon <armenon@redhat.com>
---
migration/postcopy-ram.c | 9 ++++++---
migration/postcopy-ram.h | 2 +-
migration/ram.c | 6 +++---
migration/ram.h | 2 +-
migration/savevm.c | 2 +-
5 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c
index 45af9a361e8eacaad0fb217a5da2c5004416c1da..05617e5fbcad62226a54fe17d9f7d9a316baf1e4 100644
--- a/migration/postcopy-ram.c
+++ b/migration/postcopy-ram.c
@@ -681,6 +681,7 @@ out:
*/
static int init_range(RAMBlock *rb, void *opaque)
{
+ Error **errp = opaque;
const char *block_name = qemu_ram_get_idstr(rb);
void *host_addr = qemu_ram_get_host_addr(rb);
ram_addr_t offset = qemu_ram_get_offset(rb);
@@ -701,6 +702,8 @@ static int init_range(RAMBlock *rb, void *opaque)
* (Precopy will just overwrite this data, so doesn't need the discard)
*/
if (ram_discard_range(block_name, 0, length)) {
+ error_setg(errp, "failed to discard RAM block %s len=%zu",
+ block_name, length);
return -1;
}
@@ -749,9 +752,9 @@ static int cleanup_range(RAMBlock *rb, void *opaque)
* postcopy later; must be called prior to any precopy.
* called from arch_init's similarly named ram_postcopy_incoming_init
*/
-int postcopy_ram_incoming_init(MigrationIncomingState *mis)
+int postcopy_ram_incoming_init(MigrationIncomingState *mis, Error **errp)
{
- if (foreach_not_ignored_block(init_range, NULL)) {
+ if (foreach_not_ignored_block(init_range, errp)) {
return -1;
}
@@ -1703,7 +1706,7 @@ bool postcopy_ram_supported_by_host(MigrationIncomingState *mis, Error **errp)
return false;
}
-int postcopy_ram_incoming_init(MigrationIncomingState *mis)
+int postcopy_ram_incoming_init(MigrationIncomingState *mis, Error **errp)
{
error_report("postcopy_ram_incoming_init: No OS support");
return -1;
diff --git a/migration/postcopy-ram.h b/migration/postcopy-ram.h
index 3852141d7e37ab18bada4b46c137fef0969d0070..ca19433b246893fa5105bcebffb442c58a9a4f48 100644
--- a/migration/postcopy-ram.h
+++ b/migration/postcopy-ram.h
@@ -30,7 +30,7 @@ int postcopy_ram_incoming_setup(MigrationIncomingState *mis);
* postcopy later; must be called prior to any precopy.
* called from ram.c's similarly named ram_postcopy_incoming_init
*/
-int postcopy_ram_incoming_init(MigrationIncomingState *mis);
+int postcopy_ram_incoming_init(MigrationIncomingState *mis, Error **errp);
/*
* At the end of a migration where postcopy_ram_incoming_init was called.
diff --git a/migration/ram.c b/migration/ram.c
index 7208bc114fb5c366740db380ee6956a91b3871a0..8223183132dc0f558f45fbae3f4f832845730bd3 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -3708,7 +3708,7 @@ static int ram_load_cleanup(void *opaque)
/**
* ram_postcopy_incoming_init: allocate postcopy data structures
*
- * Returns 0 for success and negative if there was one error
+ * Returns 0 for success and -1 if there was one error
*
* @mis: current migration incoming state
*
@@ -3716,9 +3716,9 @@ static int ram_load_cleanup(void *opaque)
* postcopy-ram. postcopy-ram's similarly names
* postcopy_ram_incoming_init does the work.
*/
-int ram_postcopy_incoming_init(MigrationIncomingState *mis)
+int ram_postcopy_incoming_init(MigrationIncomingState *mis, Error **errp)
{
- return postcopy_ram_incoming_init(mis);
+ return postcopy_ram_incoming_init(mis, errp);
}
/**
diff --git a/migration/ram.h b/migration/ram.h
index 921c39a2c5c45bc2344be80854c46e4c10c09aeb..275709a99187f9429ccb4111e05281ec268ba0db 100644
--- a/migration/ram.h
+++ b/migration/ram.h
@@ -86,7 +86,7 @@ void ram_postcopy_migrated_memory_release(MigrationState *ms);
void ram_postcopy_send_discard_bitmap(MigrationState *ms);
/* For incoming postcopy discard */
int ram_discard_range(const char *block_name, uint64_t start, size_t length);
-int ram_postcopy_incoming_init(MigrationIncomingState *mis);
+int ram_postcopy_incoming_init(MigrationIncomingState *mis, Error **errp);
int ram_load_postcopy(QEMUFile *f, int channel);
void ram_handle_zero(void *host, uint64_t size);
diff --git a/migration/savevm.c b/migration/savevm.c
index 3ade91d2f757f94bc6c0242a38c6e750a9252f96..6b8c78bfb9bde2a8e7500b0342cd386b0d12db97 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -1989,7 +1989,7 @@ static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis,
return -1;
}
- if (ram_postcopy_incoming_init(mis)) {
+ if (ram_postcopy_incoming_init(mis, NULL) < 0) {
return -1;
}
--
2.50.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v6 11/24] migration: push Error **errp into loadvm_postcopy_handle_advise()
2025-07-21 11:29 [PATCH v6 00/24] migration: propagate vTPM errors using Error objects Arun Menon
` (9 preceding siblings ...)
2025-07-21 11:29 ` [PATCH v6 10/24] migration: push Error **errp into ram_postcopy_incoming_init() Arun Menon
@ 2025-07-21 11:29 ` Arun Menon
2025-07-21 12:43 ` Akihiko Odaki
2025-07-21 11:29 ` [PATCH v6 12/24] migration: push Error **errp into loadvm_postcopy_handle_listen() Arun Menon
` (12 subsequent siblings)
23 siblings, 1 reply; 55+ messages in thread
From: Arun Menon @ 2025-07-21 11:29 UTC (permalink / raw)
To: qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato, Arun Menon,
Daniel P. Berrangé
This is an incremental step in converting vmstate loading
code to report error via Error objects instead of directly
printing it to console/monitor.
It is ensured that loadvm_postcopy_handle_advise() must report an error
in errp, in case of failure.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Arun Menon <armenon@redhat.com>
---
migration/savevm.c | 39 +++++++++++++++++----------------------
1 file changed, 17 insertions(+), 22 deletions(-)
diff --git a/migration/savevm.c b/migration/savevm.c
index 6b8c78bfb9bde2a8e7500b0342cd386b0d12db97..4a3db9498678a19597257e683029cd3f6c8d1a65 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -1912,39 +1912,39 @@ enum LoadVMExitCodes {
* quickly.
*/
static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis,
- uint16_t len)
+ uint16_t len, Error **errp)
{
PostcopyState ps = postcopy_state_set(POSTCOPY_INCOMING_ADVISE);
uint64_t remote_pagesize_summary, local_pagesize_summary, remote_tps;
size_t page_size = qemu_target_page_size();
- Error *local_err = NULL;
trace_loadvm_postcopy_handle_advise();
if (ps != POSTCOPY_INCOMING_NONE) {
- error_report("CMD_POSTCOPY_ADVISE in wrong postcopy state (%d)", ps);
+ error_setg(errp, "CMD_POSTCOPY_ADVISE in wrong postcopy "
+ "state (%d)", ps);
return -1;
}
switch (len) {
case 0:
if (migrate_postcopy_ram()) {
- error_report("RAM postcopy is enabled but have 0 byte advise");
+ error_setg(errp, "RAM postcopy is enabled but have 0 byte advise");
return -EINVAL;
}
return 0;
case 8 + 8:
if (!migrate_postcopy_ram()) {
- error_report("RAM postcopy is disabled but have 16 byte advise");
+ error_setg(errp, "RAM postcopy is disabled but have 16 "
+ "byte advise");
return -EINVAL;
}
break;
default:
- error_report("CMD_POSTCOPY_ADVISE invalid length (%d)", len);
+ error_setg(errp, "CMD_POSTCOPY_ADVISE invalid length (%d)", len);
return -EINVAL;
}
- if (!postcopy_ram_supported_by_host(mis, &local_err)) {
- error_report_err(local_err);
+ if (!postcopy_ram_supported_by_host(mis, errp)) {
postcopy_state_set(POSTCOPY_INCOMING_NONE);
return -1;
}
@@ -1967,9 +1967,9 @@ static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis,
* also fails when passed to an older qemu that doesn't
* do huge pages.
*/
- error_report("Postcopy needs matching RAM page sizes (s=%" PRIx64
- " d=%" PRIx64 ")",
- remote_pagesize_summary, local_pagesize_summary);
+ error_setg(errp, "Postcopy needs matching RAM "
+ "page sizes (s=%" PRIx64 " d=%" PRIx64 ")",
+ remote_pagesize_summary, local_pagesize_summary);
return -1;
}
@@ -1979,17 +1979,17 @@ static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis,
* Again, some differences could be dealt with, but for now keep it
* simple.
*/
- error_report("Postcopy needs matching target page sizes (s=%d d=%zd)",
- (int)remote_tps, page_size);
+ error_setg(errp, "Postcopy needs matching target "
+ "page sizes (s=%d d=%zd)", (int)remote_tps, page_size);
return -1;
}
- if (postcopy_notify(POSTCOPY_NOTIFY_INBOUND_ADVISE, &local_err)) {
- error_report_err(local_err);
+ if (postcopy_notify(POSTCOPY_NOTIFY_INBOUND_ADVISE, errp)) {
return -1;
}
- if (ram_postcopy_incoming_init(mis, NULL) < 0) {
+ if (ram_postcopy_incoming_init(mis, errp) < 0) {
+ error_prepend(errp, "PostCopy RAM incoming init failed ");
return -1;
}
@@ -2618,12 +2618,7 @@ static int loadvm_process_command(QEMUFile *f, Error **errp)
return loadvm_handle_cmd_packaged(mis, errp);
case MIG_CMD_POSTCOPY_ADVISE:
- ret = loadvm_postcopy_handle_advise(mis, len);
- if (ret < 0) {
- error_setg(errp, "Failed to load device state command: %d", ret);
- return -1;
- }
- return ret;
+ return loadvm_postcopy_handle_advise(mis, len, errp);
case MIG_CMD_POSTCOPY_LISTEN:
ret = loadvm_postcopy_handle_listen(mis);
--
2.50.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v6 12/24] migration: push Error **errp into loadvm_postcopy_handle_listen()
2025-07-21 11:29 [PATCH v6 00/24] migration: propagate vTPM errors using Error objects Arun Menon
` (10 preceding siblings ...)
2025-07-21 11:29 ` [PATCH v6 11/24] migration: push Error **errp into loadvm_postcopy_handle_advise() Arun Menon
@ 2025-07-21 11:29 ` Arun Menon
2025-07-21 11:29 ` [PATCH v6 13/24] migration: push Error **errp into loadvm_postcopy_handle_run() Arun Menon
` (11 subsequent siblings)
23 siblings, 0 replies; 55+ messages in thread
From: Arun Menon @ 2025-07-21 11:29 UTC (permalink / raw)
To: qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato, Arun Menon,
Daniel P. Berrangé
This is an incremental step in converting vmstate loading
code to report error via Error objects instead of directly
printing it to console/monitor.
It is ensured that loadvm_postcopy_handle_listen() must report an error
in errp, in case of failure.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Arun Menon <armenon@redhat.com>
---
migration/savevm.c | 18 +++++++-----------
1 file changed, 7 insertions(+), 11 deletions(-)
diff --git a/migration/savevm.c b/migration/savevm.c
index 4a3db9498678a19597257e683029cd3f6c8d1a65..09d12dbcf59e2dedd529224f70003e6e673442ff 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2179,15 +2179,16 @@ static void *postcopy_ram_listen_thread(void *opaque)
}
/* After this message we must be able to immediately receive postcopy data */
-static int loadvm_postcopy_handle_listen(MigrationIncomingState *mis)
+static int loadvm_postcopy_handle_listen(MigrationIncomingState *mis,
+ Error **errp)
{
PostcopyState ps = postcopy_state_set(POSTCOPY_INCOMING_LISTENING);
- Error *local_err = NULL;
trace_loadvm_postcopy_handle_listen("enter");
if (ps != POSTCOPY_INCOMING_ADVISE && ps != POSTCOPY_INCOMING_DISCARD) {
- error_report("CMD_POSTCOPY_LISTEN in wrong postcopy state (%d)", ps);
+ error_setg(errp, "CMD_POSTCOPY_LISTEN in wrong postcopy "
+ "state (%d)", ps);
return -1;
}
if (ps == POSTCOPY_INCOMING_ADVISE) {
@@ -2210,14 +2211,14 @@ static int loadvm_postcopy_handle_listen(MigrationIncomingState *mis)
if (migrate_postcopy_ram()) {
if (postcopy_ram_incoming_setup(mis)) {
postcopy_ram_incoming_cleanup(mis);
+ error_setg(errp, "Failed to setup incoming postcopy RAM blocks");
return -1;
}
}
trace_loadvm_postcopy_handle_listen("after uffd");
- if (postcopy_notify(POSTCOPY_NOTIFY_INBOUND_LISTEN, &local_err)) {
- error_report_err(local_err);
+ if (postcopy_notify(POSTCOPY_NOTIFY_INBOUND_LISTEN, errp)) {
return -1;
}
@@ -2621,12 +2622,7 @@ static int loadvm_process_command(QEMUFile *f, Error **errp)
return loadvm_postcopy_handle_advise(mis, len, errp);
case MIG_CMD_POSTCOPY_LISTEN:
- ret = loadvm_postcopy_handle_listen(mis);
- if (ret < 0) {
- error_setg(errp, "Failed to load device state command: %d", ret);
- return -1;
- }
- return ret;
+ return loadvm_postcopy_handle_listen(mis, errp);
case MIG_CMD_POSTCOPY_RUN:
ret = loadvm_postcopy_handle_run(mis);
--
2.50.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v6 13/24] migration: push Error **errp into loadvm_postcopy_handle_run()
2025-07-21 11:29 [PATCH v6 00/24] migration: propagate vTPM errors using Error objects Arun Menon
` (11 preceding siblings ...)
2025-07-21 11:29 ` [PATCH v6 12/24] migration: push Error **errp into loadvm_postcopy_handle_listen() Arun Menon
@ 2025-07-21 11:29 ` Arun Menon
2025-07-21 11:29 ` [PATCH v6 14/24] migration: push Error **errp into loadvm_postcopy_ram_handle_discard() Arun Menon
` (10 subsequent siblings)
23 siblings, 0 replies; 55+ messages in thread
From: Arun Menon @ 2025-07-21 11:29 UTC (permalink / raw)
To: qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato, Arun Menon,
Daniel P. Berrangé
This is an incremental step in converting vmstate loading
code to report error via Error objects instead of directly
printing it to console/monitor.
It is ensured that loadvm_postcopy_handle_run() must report an error
in errp, in case of failure.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Arun Menon <armenon@redhat.com>
---
migration/savevm.c | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/migration/savevm.c b/migration/savevm.c
index 09d12dbcf59e2dedd529224f70003e6e673442ff..856ec984e1ab09f5fddfd30eeb59e73a4c981697 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2271,13 +2271,14 @@ static void loadvm_postcopy_handle_run_bh(void *opaque)
}
/* After all discards we can start running and asking for pages */
-static int loadvm_postcopy_handle_run(MigrationIncomingState *mis)
+static int loadvm_postcopy_handle_run(MigrationIncomingState *mis, Error **errp)
{
PostcopyState ps = postcopy_state_get();
trace_loadvm_postcopy_handle_run();
if (ps != POSTCOPY_INCOMING_LISTENING) {
- error_report("CMD_POSTCOPY_RUN in wrong postcopy state (%d)", ps);
+ error_setg(errp, "CMD_POSTCOPY_RUN in wrong postcopy "
+ "state (%d)", ps);
return -1;
}
@@ -2625,12 +2626,7 @@ static int loadvm_process_command(QEMUFile *f, Error **errp)
return loadvm_postcopy_handle_listen(mis, errp);
case MIG_CMD_POSTCOPY_RUN:
- ret = loadvm_postcopy_handle_run(mis);
- if (ret < 0) {
- error_setg(errp, "Failed to load device state command: %d", ret);
- return -1;
- }
- return ret;
+ return loadvm_postcopy_handle_run(mis, errp);
case MIG_CMD_POSTCOPY_RAM_DISCARD:
ret = loadvm_postcopy_ram_handle_discard(mis, len);
--
2.50.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v6 14/24] migration: push Error **errp into loadvm_postcopy_ram_handle_discard()
2025-07-21 11:29 [PATCH v6 00/24] migration: propagate vTPM errors using Error objects Arun Menon
` (12 preceding siblings ...)
2025-07-21 11:29 ` [PATCH v6 13/24] migration: push Error **errp into loadvm_postcopy_handle_run() Arun Menon
@ 2025-07-21 11:29 ` Arun Menon
2025-07-21 11:29 ` [PATCH v6 15/24] migration: make loadvm_postcopy_handle_resume() void Arun Menon
` (9 subsequent siblings)
23 siblings, 0 replies; 55+ messages in thread
From: Arun Menon @ 2025-07-21 11:29 UTC (permalink / raw)
To: qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato, Arun Menon
This is an incremental step in converting vmstate loading
code to report error via Error objects instead of directly
printing it to console/monitor.
It is ensured that loadvm_postcopy_ram_handle_discard() must report an error
in errp, in case of failure.
Signed-off-by: Arun Menon <armenon@redhat.com>
---
migration/savevm.c | 26 ++++++++++++--------------
1 file changed, 12 insertions(+), 14 deletions(-)
diff --git a/migration/savevm.c b/migration/savevm.c
index 856ec984e1ab09f5fddfd30eeb59e73a4c981697..e472f79d5d5c4fb4410a28cbf43c298be028f4b4 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2002,7 +2002,7 @@ static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis,
* There can be 0..many of these messages, each encoding multiple pages.
*/
static int loadvm_postcopy_ram_handle_discard(MigrationIncomingState *mis,
- uint16_t len)
+ uint16_t len, Error **errp)
{
int tmp;
char ramid[256];
@@ -2015,6 +2015,7 @@ static int loadvm_postcopy_ram_handle_discard(MigrationIncomingState *mis,
/* 1st discard */
tmp = postcopy_ram_prepare_discard(mis);
if (tmp) {
+ error_setg(errp, "Failed to prepare for RAM discard: %d", tmp);
return tmp;
}
break;
@@ -2024,8 +2025,8 @@ static int loadvm_postcopy_ram_handle_discard(MigrationIncomingState *mis,
break;
default:
- error_report("CMD_POSTCOPY_RAM_DISCARD in wrong postcopy state (%d)",
- ps);
+ error_setg(errp, "CMD_POSTCOPY_RAM_DISCARD in wrong "
+ "postcopy state (%d)", ps);
return -1;
}
/* We're expecting a
@@ -2034,29 +2035,30 @@ static int loadvm_postcopy_ram_handle_discard(MigrationIncomingState *mis,
* then at least 1 16 byte chunk
*/
if (len < (1 + 1 + 1 + 1 + 2 * 8)) {
- error_report("CMD_POSTCOPY_RAM_DISCARD invalid length (%d)", len);
+ error_setg(errp, "CMD_POSTCOPY_RAM_DISCARD invalid length (%d)", len);
return -1;
}
tmp = qemu_get_byte(mis->from_src_file);
if (tmp != postcopy_ram_discard_version) {
- error_report("CMD_POSTCOPY_RAM_DISCARD invalid version (%d)", tmp);
+ error_setg(errp, "CMD_POSTCOPY_RAM_DISCARD invalid version (%d)", tmp);
return -1;
}
if (!qemu_get_counted_string(mis->from_src_file, ramid)) {
- error_report("CMD_POSTCOPY_RAM_DISCARD Failed to read RAMBlock ID");
+ error_setg(errp, "CMD_POSTCOPY_RAM_DISCARD Failed to read "
+ "RAMBlock ID");
return -1;
}
tmp = qemu_get_byte(mis->from_src_file);
if (tmp != 0) {
- error_report("CMD_POSTCOPY_RAM_DISCARD missing nil (%d)", tmp);
+ error_setg(errp, "CMD_POSTCOPY_RAM_DISCARD missing nil (%d)", tmp);
return -1;
}
len -= 3 + strlen(ramid);
if (len % 16) {
- error_report("CMD_POSTCOPY_RAM_DISCARD invalid length (%d)", len);
+ error_setg(errp, "CMD_POSTCOPY_RAM_DISCARD invalid length (%d)", len);
return -1;
}
trace_loadvm_postcopy_ram_handle_discard_header(ramid, len);
@@ -2068,6 +2070,7 @@ static int loadvm_postcopy_ram_handle_discard(MigrationIncomingState *mis,
len -= 16;
int ret = ram_discard_range(ramid, start_addr, block_length);
if (ret) {
+ error_setg(errp, "Failed to discard RAM range %s: %d", ramid, ret);
return ret;
}
}
@@ -2629,12 +2632,7 @@ static int loadvm_process_command(QEMUFile *f, Error **errp)
return loadvm_postcopy_handle_run(mis, errp);
case MIG_CMD_POSTCOPY_RAM_DISCARD:
- ret = loadvm_postcopy_ram_handle_discard(mis, len);
- if (ret < 0) {
- error_setg(errp, "Failed to load device state command: %d", ret);
- return -1;
- }
- return ret;
+ return loadvm_postcopy_ram_handle_discard(mis, len, errp);
case MIG_CMD_POSTCOPY_RESUME:
ret = loadvm_postcopy_handle_resume(mis);
--
2.50.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v6 15/24] migration: make loadvm_postcopy_handle_resume() void
2025-07-21 11:29 [PATCH v6 00/24] migration: propagate vTPM errors using Error objects Arun Menon
` (13 preceding siblings ...)
2025-07-21 11:29 ` [PATCH v6 14/24] migration: push Error **errp into loadvm_postcopy_ram_handle_discard() Arun Menon
@ 2025-07-21 11:29 ` Arun Menon
2025-07-21 12:46 ` Akihiko Odaki
2025-07-21 11:29 ` [PATCH v6 16/24] migration: push Error **errp into loadvm_handle_recv_bitmap() Arun Menon
` (8 subsequent siblings)
23 siblings, 1 reply; 55+ messages in thread
From: Arun Menon @ 2025-07-21 11:29 UTC (permalink / raw)
To: qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato, Arun Menon,
Daniel P. Berrangé
This is an incremental step in converting vmstate loading
code to report error via Error objects instead of directly
printing it to console/monitor.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Arun Menon <armenon@redhat.com>
---
migration/savevm.c | 16 +++++-----------
1 file changed, 5 insertions(+), 11 deletions(-)
diff --git a/migration/savevm.c b/migration/savevm.c
index e472f79d5d5c4fb4410a28cbf43c298be028f4b4..6887877f2f8648f66e34bdb1cc3ca6dc7514f9df 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2339,12 +2339,12 @@ static void migrate_send_rp_req_pages_pending(MigrationIncomingState *mis)
}
}
-static int loadvm_postcopy_handle_resume(MigrationIncomingState *mis)
+static void loadvm_postcopy_handle_resume(MigrationIncomingState *mis)
{
if (mis->state != MIGRATION_STATUS_POSTCOPY_RECOVER) {
- error_report("%s: illegal resume received", __func__);
+ warn_report("%s: illegal resume received", __func__);
/* Don't fail the load, only for this. */
- return 0;
+ return;
}
/*
@@ -2396,8 +2396,6 @@ static int loadvm_postcopy_handle_resume(MigrationIncomingState *mis)
/* Kick the fast ram load thread too */
qemu_sem_post(&mis->postcopy_pause_sem_fast_load);
}
-
- return 0;
}
/**
@@ -2635,12 +2633,8 @@ static int loadvm_process_command(QEMUFile *f, Error **errp)
return loadvm_postcopy_ram_handle_discard(mis, len, errp);
case MIG_CMD_POSTCOPY_RESUME:
- ret = loadvm_postcopy_handle_resume(mis);
- if (ret < 0) {
- error_setg(errp, "Failed to load device state command: %d", ret);
- return -1;
- }
- return ret;
+ loadvm_postcopy_handle_resume(mis);
+ return 0;
case MIG_CMD_RECV_BITMAP:
ret = loadvm_handle_recv_bitmap(mis, len);
--
2.50.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v6 16/24] migration: push Error **errp into loadvm_handle_recv_bitmap()
2025-07-21 11:29 [PATCH v6 00/24] migration: propagate vTPM errors using Error objects Arun Menon
` (14 preceding siblings ...)
2025-07-21 11:29 ` [PATCH v6 15/24] migration: make loadvm_postcopy_handle_resume() void Arun Menon
@ 2025-07-21 11:29 ` Arun Menon
2025-07-21 11:29 ` [PATCH v6 17/24] migration: push Error **errp into loadvm_process_enable_colo() Arun Menon
` (7 subsequent siblings)
23 siblings, 0 replies; 55+ messages in thread
From: Arun Menon @ 2025-07-21 11:29 UTC (permalink / raw)
To: qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato, Arun Menon,
Daniel P. Berrangé
This is an incremental step in converting vmstate loading
code to report error via Error objects instead of directly
printing it to console/monitor.
It is ensured that loadvm_handle_recv_bitmap() must report an error
in errp, in case of failure.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Arun Menon <armenon@redhat.com>
---
migration/savevm.c | 22 ++++++++++------------
1 file changed, 10 insertions(+), 12 deletions(-)
diff --git a/migration/savevm.c b/migration/savevm.c
index 6887877f2f8648f66e34bdb1cc3ca6dc7514f9df..011f4032d582e64b112313e783e0cbf98822292d 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2477,32 +2477,35 @@ static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis, Error **errp)
* len (1 byte) + ramblock_name (<255 bytes)
*/
static int loadvm_handle_recv_bitmap(MigrationIncomingState *mis,
- uint16_t len)
+ uint16_t len, Error **errp)
{
QEMUFile *file = mis->from_src_file;
RAMBlock *rb;
char block_name[256];
size_t cnt;
+ int ret;
cnt = qemu_get_counted_string(file, block_name);
if (!cnt) {
- error_report("%s: failed to read block name", __func__);
+ error_setg(errp, "failed to read block name: %s", block_name);
return -EINVAL;
}
/* Validate before using the data */
- if (qemu_file_get_error(file)) {
- return qemu_file_get_error(file);
+ ret = qemu_file_get_error(file);
+ if (ret < 0) {
+ error_setg(errp, "migration stream has error: %d", ret);
+ return ret;
}
if (len != cnt + 1) {
- error_report("%s: invalid payload length (%d)", __func__, len);
+ error_setg(errp, "invalid payload length (%d)", len);
return -EINVAL;
}
rb = qemu_ram_block_by_name(block_name);
if (!rb) {
- error_report("%s: block '%s' not found", __func__, block_name);
+ error_setg(errp, "block '%s' not found", block_name);
return -EINVAL;
}
@@ -2637,12 +2640,7 @@ static int loadvm_process_command(QEMUFile *f, Error **errp)
return 0;
case MIG_CMD_RECV_BITMAP:
- ret = loadvm_handle_recv_bitmap(mis, len);
- if (ret < 0) {
- error_setg(errp, "Failed to load device state command: %d", ret);
- return -1;
- }
- return ret;
+ return loadvm_handle_recv_bitmap(mis, len, errp);
case MIG_CMD_ENABLE_COLO:
ret = loadvm_process_enable_colo(mis);
--
2.50.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v6 17/24] migration: push Error **errp into loadvm_process_enable_colo()
2025-07-21 11:29 [PATCH v6 00/24] migration: propagate vTPM errors using Error objects Arun Menon
` (15 preceding siblings ...)
2025-07-21 11:29 ` [PATCH v6 16/24] migration: push Error **errp into loadvm_handle_recv_bitmap() Arun Menon
@ 2025-07-21 11:29 ` Arun Menon
2025-07-21 11:29 ` [PATCH v6 18/24] migration: push Error **errp into loadvm_postcopy_handle_switchover_start() Arun Menon
` (6 subsequent siblings)
23 siblings, 0 replies; 55+ messages in thread
From: Arun Menon @ 2025-07-21 11:29 UTC (permalink / raw)
To: qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato, Arun Menon
This is an incremental step in converting vmstate loading
code to report error via Error objects instead of directly
printing it to console/monitor.
It is ensured that loadvm_process_enable_colo() must report an error
in errp, in case of failure.
Signed-off-by: Arun Menon <armenon@redhat.com>
---
include/migration/colo.h | 2 +-
migration/migration.c | 12 ++++++------
migration/ram.c | 8 ++++----
migration/ram.h | 2 +-
migration/savevm.c | 26 +++++++++++++-------------
5 files changed, 25 insertions(+), 25 deletions(-)
diff --git a/include/migration/colo.h b/include/migration/colo.h
index 43222ef5ae6adc3f7d8aa6a48bef79af33d09208..d4fe422e4d335d3bef4f860f56400fcd73287a0e 100644
--- a/include/migration/colo.h
+++ b/include/migration/colo.h
@@ -25,7 +25,7 @@ void migrate_start_colo_process(MigrationState *s);
bool migration_in_colo_state(void);
/* loadvm */
-int migration_incoming_enable_colo(void);
+int migration_incoming_enable_colo(Error **errp);
void migration_incoming_disable_colo(void);
bool migration_incoming_colo_enabled(void);
bool migration_incoming_in_colo_state(void);
diff --git a/migration/migration.c b/migration/migration.c
index b3bccaeaee806abd01595863f6475057049b0688..d748a02712dc4ebc2de6b0488fb199c92c4d4079 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -623,22 +623,22 @@ void migration_incoming_disable_colo(void)
migration_colo_enabled = false;
}
-int migration_incoming_enable_colo(void)
+int migration_incoming_enable_colo(Error **errp)
{
#ifndef CONFIG_REPLICATION
- error_report("ENABLE_COLO command come in migration stream, but the "
- "replication module is not built in");
+ error_setg(errp, "ENABLE_COLO command come in migration stream, but the "
+ "replication module is not built in");
return -ENOTSUP;
#endif
if (!migrate_colo()) {
- error_report("ENABLE_COLO command come in migration stream, but x-colo "
- "capability is not set");
+ error_setg(errp, "ENABLE_COLO command come in migration stream"
+ ", but x-colo capability is not set");
return -EINVAL;
}
if (ram_block_discard_disable(true)) {
- error_report("COLO: cannot disable RAM discard");
+ error_setg(errp, "COLO: cannot disable RAM discard");
return -EBUSY;
}
migration_colo_enabled = true;
diff --git a/migration/ram.c b/migration/ram.c
index 8223183132dc0f558f45fbae3f4f832845730bd3..607c979cc15a3d321e5e3e380ac7613d80d86fc9 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -3576,7 +3576,7 @@ static void colo_init_ram_state(void)
* memory of the secondary VM, it is need to hold the global lock
* to call this helper.
*/
-int colo_init_ram_cache(void)
+int colo_init_ram_cache(Error **errp)
{
RAMBlock *block;
@@ -3585,9 +3585,9 @@ int colo_init_ram_cache(void)
block->colo_cache = qemu_anon_ram_alloc(block->used_length,
NULL, false, false);
if (!block->colo_cache) {
- error_report("%s: Can't alloc memory for COLO cache of block %s,"
- "size 0x" RAM_ADDR_FMT, __func__, block->idstr,
- block->used_length);
+ error_setg(errp, "%s: Can't alloc memory for COLO cache of "
+ "block %s, size 0x" RAM_ADDR_FMT, __func__,
+ block->idstr, block->used_length);
RAMBLOCK_FOREACH_NOT_IGNORED(block) {
if (block->colo_cache) {
qemu_anon_ram_free(block->colo_cache, block->used_length);
diff --git a/migration/ram.h b/migration/ram.h
index 275709a99187f9429ccb4111e05281ec268ba0db..24cd0bf585762cfa1e86834dc03c6baeea2f0627 100644
--- a/migration/ram.h
+++ b/migration/ram.h
@@ -109,7 +109,7 @@ void ramblock_set_file_bmap_atomic(RAMBlock *block, ram_addr_t offset,
bool set);
/* ram cache */
-int colo_init_ram_cache(void);
+int colo_init_ram_cache(Error **errp);
void colo_flush_ram_cache(void);
void colo_release_ram_cache(void);
void colo_incoming_start_dirty_log(void);
diff --git a/migration/savevm.c b/migration/savevm.c
index 011f4032d582e64b112313e783e0cbf98822292d..49eb629a8dcd909274e78ecb2f31eb10f57c5425 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2516,15 +2516,20 @@ static int loadvm_handle_recv_bitmap(MigrationIncomingState *mis,
return 0;
}
-static int loadvm_process_enable_colo(MigrationIncomingState *mis)
+static int loadvm_process_enable_colo(MigrationIncomingState *mis,
+ Error **errp)
{
- int ret = migration_incoming_enable_colo();
+ int ret;
- if (!ret) {
- ret = colo_init_ram_cache();
- if (ret) {
- migration_incoming_disable_colo();
- }
+ ret = migration_incoming_enable_colo(errp);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = colo_init_ram_cache(errp);
+ if (ret) {
+ error_prepend(errp, "failed to init colo RAM cache: %d", ret);
+ migration_incoming_disable_colo();
}
return ret;
}
@@ -2643,12 +2648,7 @@ static int loadvm_process_command(QEMUFile *f, Error **errp)
return loadvm_handle_recv_bitmap(mis, len, errp);
case MIG_CMD_ENABLE_COLO:
- ret = loadvm_process_enable_colo(mis);
- if (ret < 0) {
- error_setg(errp, "Failed to load device state command: %d", ret);
- return -1;
- }
- return ret;
+ return loadvm_process_enable_colo(mis, errp);
case MIG_CMD_SWITCHOVER_START:
ret = loadvm_postcopy_handle_switchover_start();
--
2.50.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v6 18/24] migration: push Error **errp into loadvm_postcopy_handle_switchover_start()
2025-07-21 11:29 [PATCH v6 00/24] migration: propagate vTPM errors using Error objects Arun Menon
` (16 preceding siblings ...)
2025-07-21 11:29 ` [PATCH v6 17/24] migration: push Error **errp into loadvm_process_enable_colo() Arun Menon
@ 2025-07-21 11:29 ` Arun Menon
2025-07-21 11:29 ` [PATCH v6 19/24] migration: push Error **errp into qemu_loadvm_state_main() Arun Menon
` (5 subsequent siblings)
23 siblings, 0 replies; 55+ messages in thread
From: Arun Menon @ 2025-07-21 11:29 UTC (permalink / raw)
To: qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato, Arun Menon,
Daniel P. Berrangé
This is an incremental step in converting vmstate loading code to report
error via Error objects instead of directly printing it to console/monitor.
It is ensured that loadvm_postcopy_handle_switchover_start() must report
an error in errp, in case of failure.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Arun Menon <armenon@redhat.com>
---
migration/savevm.c | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/migration/savevm.c b/migration/savevm.c
index 49eb629a8dcd909274e78ecb2f31eb10f57c5425..679abf7c668ea7990da10ca8caba09fbb7bdd2ea 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2534,7 +2534,7 @@ static int loadvm_process_enable_colo(MigrationIncomingState *mis,
return ret;
}
-static int loadvm_postcopy_handle_switchover_start(void)
+static int loadvm_postcopy_handle_switchover_start(Error **errp)
{
SaveStateEntry *se;
@@ -2547,6 +2547,7 @@ static int loadvm_postcopy_handle_switchover_start(void)
ret = se->ops->switchover_start(se->opaque);
if (ret < 0) {
+ error_setg(errp, "Switchover start failed: %d", ret);
return ret;
}
}
@@ -2651,12 +2652,7 @@ static int loadvm_process_command(QEMUFile *f, Error **errp)
return loadvm_process_enable_colo(mis, errp);
case MIG_CMD_SWITCHOVER_START:
- ret = loadvm_postcopy_handle_switchover_start();
- if (ret < 0) {
- error_setg(errp, "Failed to load device state command: %d", ret);
- return -1;
- }
- return ret;
+ return loadvm_postcopy_handle_switchover_start(errp);
}
return 0;
--
2.50.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v6 19/24] migration: push Error **errp into qemu_loadvm_state_main()
2025-07-21 11:29 [PATCH v6 00/24] migration: propagate vTPM errors using Error objects Arun Menon
` (17 preceding siblings ...)
2025-07-21 11:29 ` [PATCH v6 18/24] migration: push Error **errp into loadvm_postcopy_handle_switchover_start() Arun Menon
@ 2025-07-21 11:29 ` Arun Menon
2025-07-21 11:29 ` [PATCH v6 20/24] migration: push Error **errp into qemu_loadvm_state() Arun Menon
` (4 subsequent siblings)
23 siblings, 0 replies; 55+ messages in thread
From: Arun Menon @ 2025-07-21 11:29 UTC (permalink / raw)
To: qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato, Arun Menon,
Daniel P. Berrangé
This is an incremental step in converting vmstate loading
code to report error via Error objects instead of directly
printing it to console/monitor.
It is ensured that qemu_loadvm_state_main() must report an error
in errp, in case of failure.
loadvm_process_command also sets the errp object explicitly.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Arun Menon <armenon@redhat.com>
---
migration/colo.c | 4 ++--
migration/savevm.c | 25 ++++++++++++++-----------
migration/savevm.h | 3 ++-
3 files changed, 18 insertions(+), 14 deletions(-)
diff --git a/migration/colo.c b/migration/colo.c
index 981bd4bf9ced8b45b4c5d494acae119a174ee974..03edf870e2bc9c724fc27e26e7ba54a40c13399e 100644
--- a/migration/colo.c
+++ b/migration/colo.c
@@ -686,11 +686,11 @@ static void colo_incoming_process_checkpoint(MigrationIncomingState *mis,
bql_lock();
cpu_synchronize_all_states();
- ret = qemu_loadvm_state_main(mis->from_src_file, mis);
+ ret = qemu_loadvm_state_main(mis->from_src_file, mis, errp);
bql_unlock();
if (ret < 0) {
- error_setg(errp, "Load VM's live state (ram) error");
+ error_prepend(errp, "Load VM's live state (ram) error");
return;
}
diff --git a/migration/savevm.c b/migration/savevm.c
index 679abf7c668ea7990da10ca8caba09fbb7bdd2ea..ba146f91427f2a36880aadeb16b11ab2b7df099a 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2108,7 +2108,7 @@ static void *postcopy_ram_listen_thread(void *opaque)
qemu_file_set_blocking(f, true);
/* TODO: sanity check that only postcopiable data will be loaded here */
- load_res = qemu_loadvm_state_main(f, mis);
+ load_res = qemu_loadvm_state_main(f, mis, NULL);
/*
* This is tricky, but, mis->from_src_file can change after it
@@ -2459,9 +2459,9 @@ static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis, Error **errp)
qemu_coroutine_yield();
} while (1);
- ret = qemu_loadvm_state_main(packf, mis);
+ ret = qemu_loadvm_state_main(packf, mis, errp);
if (ret < 0) {
- error_setg(errp, "VM state load failed: %d", ret);
+ error_prepend(errp, "Loading VM state failed: %d ", ret);
}
trace_loadvm_handle_cmd_packaged_main(ret);
qemu_fclose(packf);
@@ -3059,7 +3059,8 @@ static bool postcopy_pause_incoming(MigrationIncomingState *mis)
return true;
}
-int qemu_loadvm_state_main(QEMUFile *f, MigrationIncomingState *mis)
+int qemu_loadvm_state_main(QEMUFile *f, MigrationIncomingState *mis,
+ Error **errp)
{
uint8_t section_type;
int ret = 0;
@@ -3068,8 +3069,10 @@ retry:
while (true) {
section_type = qemu_get_byte(f);
- ret = qemu_file_get_error_obj_any(f, mis->postcopy_qemufile_dst, NULL);
+ ret = qemu_file_get_error_obj_any(f, mis->postcopy_qemufile_dst, errp);
if (ret) {
+ error_prepend(errp, "Failed to load device state section ID : %d ",
+ ret);
break;
}
@@ -3077,20 +3080,20 @@ retry:
switch (section_type) {
case QEMU_VM_SECTION_START:
case QEMU_VM_SECTION_FULL:
- ret = qemu_loadvm_section_start_full(f, section_type, NULL);
+ ret = qemu_loadvm_section_start_full(f, section_type, errp);
if (ret < 0) {
goto out;
}
break;
case QEMU_VM_SECTION_PART:
case QEMU_VM_SECTION_END:
- ret = qemu_loadvm_section_part_end(f, section_type, NULL);
+ ret = qemu_loadvm_section_part_end(f, section_type, errp);
if (ret < 0) {
goto out;
}
break;
case QEMU_VM_COMMAND:
- ret = loadvm_process_command(f, NULL);
+ ret = loadvm_process_command(f, errp);
trace_qemu_loadvm_state_section_command(ret);
if ((ret < 0) || (ret == LOADVM_QUIT)) {
goto out;
@@ -3100,7 +3103,7 @@ retry:
/* This is the end of migration */
goto out;
default:
- error_report("Unknown savevm section type %d", section_type);
+ error_setg(errp, "Unknown savevm section type %d", section_type);
ret = -EINVAL;
goto out;
}
@@ -3164,7 +3167,7 @@ int qemu_loadvm_state(QEMUFile *f)
cpu_synchronize_all_pre_loadvm();
- ret = qemu_loadvm_state_main(f, mis);
+ ret = qemu_loadvm_state_main(f, mis, NULL);
qemu_event_set(&mis->main_thread_load_event);
trace_qemu_loadvm_state_post_main(ret);
@@ -3238,7 +3241,7 @@ int qemu_load_device_state(QEMUFile *f)
int ret;
/* Load QEMU_VM_SECTION_FULL section */
- ret = qemu_loadvm_state_main(f, mis);
+ ret = qemu_loadvm_state_main(f, mis, NULL);
if (ret < 0) {
error_report("Failed to load device state: %d", ret);
return ret;
diff --git a/migration/savevm.h b/migration/savevm.h
index 2d5e9c716686f06720325e82fe90c75335ced1de..fd7419e6ff90062970ed246b3ea71e6d49a6e372 100644
--- a/migration/savevm.h
+++ b/migration/savevm.h
@@ -66,7 +66,8 @@ int qemu_save_device_state(QEMUFile *f);
int qemu_loadvm_state(QEMUFile *f);
void qemu_loadvm_state_cleanup(MigrationIncomingState *mis);
-int qemu_loadvm_state_main(QEMUFile *f, MigrationIncomingState *mis);
+int qemu_loadvm_state_main(QEMUFile *f, MigrationIncomingState *mis,
+ Error **errp);
int qemu_load_device_state(QEMUFile *f);
int qemu_loadvm_approve_switchover(void);
int qemu_savevm_state_complete_precopy_non_iterable(QEMUFile *f,
--
2.50.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v6 20/24] migration: push Error **errp into qemu_loadvm_state()
2025-07-21 11:29 [PATCH v6 00/24] migration: propagate vTPM errors using Error objects Arun Menon
` (18 preceding siblings ...)
2025-07-21 11:29 ` [PATCH v6 19/24] migration: push Error **errp into qemu_loadvm_state_main() Arun Menon
@ 2025-07-21 11:29 ` Arun Menon
2025-07-21 13:01 ` Akihiko Odaki
2025-07-21 11:29 ` [PATCH v6 21/24] migration: push Error **errp into qemu_load_device_state() Arun Menon
` (3 subsequent siblings)
23 siblings, 1 reply; 55+ messages in thread
From: Arun Menon @ 2025-07-21 11:29 UTC (permalink / raw)
To: qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato, Arun Menon
This is an incremental step in converting vmstate loading
code to report error via Error objects instead of directly
printing it to console/monitor.
It is ensured that qemu_loadvm_state() must report an error
in errp, in case of failure.
Signed-off-by: Arun Menon <armenon@redhat.com>
---
migration/migration.c | 5 +++--
migration/savevm.c | 25 +++++++++++++------------
migration/savevm.h | 2 +-
3 files changed, 17 insertions(+), 15 deletions(-)
diff --git a/migration/migration.c b/migration/migration.c
index d748a02712dc4ebc2de6b0488fb199c92c4d4079..09fadf36dbbbd2f68df1e4cafbf3a51b18531978 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -881,7 +881,7 @@ process_incoming_migration_co(void *opaque)
MIGRATION_STATUS_ACTIVE);
mis->loadvm_co = qemu_coroutine_self();
- ret = qemu_loadvm_state(mis->from_src_file);
+ ret = qemu_loadvm_state(mis->from_src_file, &local_err);
mis->loadvm_co = NULL;
trace_vmstate_downtime_checkpoint("dst-precopy-loadvm-completed");
@@ -908,7 +908,8 @@ process_incoming_migration_co(void *opaque)
}
if (ret < 0) {
- error_setg(&local_err, "load of migration failed: %s", strerror(-ret));
+ error_prepend(&local_err, "load of migration failed: %s ",
+ strerror(-ret));
goto fail;
}
diff --git a/migration/savevm.c b/migration/savevm.c
index ba146f91427f2a36880aadeb16b11ab2b7df099a..1261e81c86f836e6b5a155ba1880b5823a779567 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -3137,27 +3137,24 @@ out:
return ret;
}
-int qemu_loadvm_state(QEMUFile *f)
+int qemu_loadvm_state(QEMUFile *f, Error **errp)
{
MigrationState *s = migrate_get_current();
MigrationIncomingState *mis = migration_incoming_get_current();
- Error *local_err = NULL;
int ret;
- if (qemu_savevm_state_blocked(&local_err)) {
- error_report_err(local_err);
+ if (qemu_savevm_state_blocked(errp)) {
return -EINVAL;
}
qemu_loadvm_thread_pool_create(mis);
- ret = qemu_loadvm_state_header(f, NULL);
+ ret = qemu_loadvm_state_header(f, errp);
if (ret) {
return ret;
}
- if (qemu_loadvm_state_setup(f, &local_err) != 0) {
- error_report_err(local_err);
+ if (qemu_loadvm_state_setup(f, errp) != 0) {
return -EINVAL;
}
@@ -3167,7 +3164,7 @@ int qemu_loadvm_state(QEMUFile *f)
cpu_synchronize_all_pre_loadvm();
- ret = qemu_loadvm_state_main(f, mis, NULL);
+ ret = qemu_loadvm_state_main(f, mis, errp);
qemu_event_set(&mis->main_thread_load_event);
trace_qemu_loadvm_state_post_main(ret);
@@ -3185,8 +3182,12 @@ int qemu_loadvm_state(QEMUFile *f)
if (migrate_has_error(migrate_get_current()) ||
!qemu_loadvm_thread_pool_wait(s, mis)) {
ret = -EINVAL;
+ error_setg(errp, "Error while loading vmstate : %d", ret);
} else {
ret = qemu_file_get_error(f);
+ if (ret < 0) {
+ error_setg(errp, "Error while loading vmstate : %d", ret);
+ }
}
}
/*
@@ -3472,10 +3473,10 @@ void qmp_xen_load_devices_state(const char *filename, Error **errp)
f = qemu_file_new_input(QIO_CHANNEL(ioc));
object_unref(OBJECT(ioc));
- ret = qemu_loadvm_state(f);
+ ret = qemu_loadvm_state(f, errp);
qemu_fclose(f);
if (ret < 0) {
- error_setg(errp, "loading Xen device state failed");
+ error_prepend(errp, "loading Xen device state failed ");
}
migration_incoming_state_destroy();
}
@@ -3546,13 +3547,13 @@ bool load_snapshot(const char *name, const char *vmstate,
ret = -EINVAL;
goto err_drain;
}
- ret = qemu_loadvm_state(f);
+ ret = qemu_loadvm_state(f, errp);
migration_incoming_state_destroy();
bdrv_drain_all_end();
if (ret < 0) {
- error_setg(errp, "Error %d while loading VM state", ret);
+ error_prepend(errp, "Error %d while loading VM state ", ret);
return false;
}
diff --git a/migration/savevm.h b/migration/savevm.h
index fd7419e6ff90062970ed246b3ea71e6d49a6e372..a6df5198f3fe1a39fc0e6ce3e79cf7a5d8e032db 100644
--- a/migration/savevm.h
+++ b/migration/savevm.h
@@ -64,7 +64,7 @@ void qemu_savevm_send_colo_enable(QEMUFile *f);
void qemu_savevm_live_state(QEMUFile *f);
int qemu_save_device_state(QEMUFile *f);
-int qemu_loadvm_state(QEMUFile *f);
+int qemu_loadvm_state(QEMUFile *f, Error **errp);
void qemu_loadvm_state_cleanup(MigrationIncomingState *mis);
int qemu_loadvm_state_main(QEMUFile *f, MigrationIncomingState *mis,
Error **errp);
--
2.50.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v6 21/24] migration: push Error **errp into qemu_load_device_state()
2025-07-21 11:29 [PATCH v6 00/24] migration: propagate vTPM errors using Error objects Arun Menon
` (19 preceding siblings ...)
2025-07-21 11:29 ` [PATCH v6 20/24] migration: push Error **errp into qemu_loadvm_state() Arun Menon
@ 2025-07-21 11:29 ` Arun Menon
2025-07-21 11:29 ` [PATCH v6 22/24] migration: Capture error in postcopy_ram_listen_thread() Arun Menon
` (2 subsequent siblings)
23 siblings, 0 replies; 55+ messages in thread
From: Arun Menon @ 2025-07-21 11:29 UTC (permalink / raw)
To: qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato, Arun Menon
This is an incremental step in converting vmstate loading
code to report error via Error objects instead of directly
printing it to console/monitor.
It is ensured that qemu_load_device_state() must report an error
in errp, in case of failure.
Signed-off-by: Arun Menon <armenon@redhat.com>
---
migration/colo.c | 4 ++--
migration/savevm.c | 6 +++---
migration/savevm.h | 2 +-
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/migration/colo.c b/migration/colo.c
index 03edf870e2bc9c724fc27e26e7ba54a40c13399e..650f7b61d92693eeace475f221a37cfa81331b97 100644
--- a/migration/colo.c
+++ b/migration/colo.c
@@ -729,9 +729,9 @@ static void colo_incoming_process_checkpoint(MigrationIncomingState *mis,
bql_lock();
vmstate_loading = true;
colo_flush_ram_cache();
- ret = qemu_load_device_state(fb);
+ ret = qemu_load_device_state(fb, errp);
if (ret < 0) {
- error_setg(errp, "COLO: load device state failed");
+ error_prepend(errp, "COLO: load device state failed ");
vmstate_loading = false;
bql_unlock();
return;
diff --git a/migration/savevm.c b/migration/savevm.c
index 1261e81c86f836e6b5a155ba1880b5823a779567..b90505595091da27d3cf92984eb256f137fb9d36 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -3236,15 +3236,15 @@ int qemu_loadvm_state(QEMUFile *f, Error **errp)
return ret;
}
-int qemu_load_device_state(QEMUFile *f)
+int qemu_load_device_state(QEMUFile *f, Error **errp)
{
MigrationIncomingState *mis = migration_incoming_get_current();
int ret;
/* Load QEMU_VM_SECTION_FULL section */
- ret = qemu_loadvm_state_main(f, mis, NULL);
+ ret = qemu_loadvm_state_main(f, mis, errp);
if (ret < 0) {
- error_report("Failed to load device state: %d", ret);
+ error_prepend(errp, "Failed to load device state: %d ", ret);
return ret;
}
diff --git a/migration/savevm.h b/migration/savevm.h
index a6df5198f3fe1a39fc0e6ce3e79cf7a5d8e032db..c337e3e3d111a7f28a57b90f61e8f70b71803d4e 100644
--- a/migration/savevm.h
+++ b/migration/savevm.h
@@ -68,7 +68,7 @@ int qemu_loadvm_state(QEMUFile *f, Error **errp);
void qemu_loadvm_state_cleanup(MigrationIncomingState *mis);
int qemu_loadvm_state_main(QEMUFile *f, MigrationIncomingState *mis,
Error **errp);
-int qemu_load_device_state(QEMUFile *f);
+int qemu_load_device_state(QEMUFile *f, Error **errp);
int qemu_loadvm_approve_switchover(void);
int qemu_savevm_state_complete_precopy_non_iterable(QEMUFile *f,
bool in_postcopy);
--
2.50.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v6 22/24] migration: Capture error in postcopy_ram_listen_thread()
2025-07-21 11:29 [PATCH v6 00/24] migration: propagate vTPM errors using Error objects Arun Menon
` (20 preceding siblings ...)
2025-07-21 11:29 ` [PATCH v6 21/24] migration: push Error **errp into qemu_load_device_state() Arun Menon
@ 2025-07-21 11:29 ` Arun Menon
2025-07-21 11:29 ` [PATCH v6 23/24] migration: Add error-parameterized function variants in VMSD struct Arun Menon
2025-07-21 11:29 ` [PATCH v6 24/24] backends/tpm: Propagate vTPM error on migration failure Arun Menon
23 siblings, 0 replies; 55+ messages in thread
From: Arun Menon @ 2025-07-21 11:29 UTC (permalink / raw)
To: qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato, Arun Menon
This is an incremental step in converting vmstate loading
code to report error via Error objects instead of directly
printing it to console/monitor.
postcopy_ram_listen_thread() calls qemu_loadvm_state_main()
to load the vm, and in case of a failure, it should set the error
in the migration object.
When postcopy live migration runs, the device states are loaded by
both the qemu coroutine process_incoming_migration_co() and the
postcopy_ram_listen_thread(). Therefore, it is important that the
coroutine also reports the error in case of failure, with
error_report_err(). Otherwise, the source qemu will not display
any errors before going into the postcopy pause state.
Signed-off-by: Arun Menon <armenon@redhat.com>
---
migration/migration.c | 2 +-
migration/savevm.c | 10 ++++++++--
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/migration/migration.c b/migration/migration.c
index 09fadf36dbbbd2f68df1e4cafbf3a51b18531978..8acbed207440fe4a2dfe303f97cfd83b40457db0 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -925,7 +925,7 @@ fail:
migrate_set_state(&mis->state, MIGRATION_STATUS_ACTIVE,
MIGRATION_STATUS_FAILED);
migrate_set_error(s, local_err);
- error_free(local_err);
+ error_report_err(local_err);
migration_incoming_state_destroy();
diff --git a/migration/savevm.c b/migration/savevm.c
index b90505595091da27d3cf92984eb256f137fb9d36..55cda4566ac2f8c72fe5fa2f8df8475e175ee717 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2092,6 +2092,7 @@ static void *postcopy_ram_listen_thread(void *opaque)
QEMUFile *f = mis->from_src_file;
int load_res;
MigrationState *migr = migrate_get_current();
+ Error *local_err = NULL;
object_ref(OBJECT(migr));
@@ -2108,7 +2109,7 @@ static void *postcopy_ram_listen_thread(void *opaque)
qemu_file_set_blocking(f, true);
/* TODO: sanity check that only postcopiable data will be loaded here */
- load_res = qemu_loadvm_state_main(f, mis, NULL);
+ load_res = qemu_loadvm_state_main(f, mis, &local_err);
/*
* This is tricky, but, mis->from_src_file can change after it
@@ -2134,7 +2135,12 @@ static void *postcopy_ram_listen_thread(void *opaque)
__func__, load_res);
load_res = 0; /* prevent further exit() */
} else {
- error_report("%s: loadvm failed: %d", __func__, load_res);
+ if (local_err != NULL) {
+ error_prepend(&local_err, "loadvm failed during postcopy: %d",
+ load_res);
+ migrate_set_error(migr, local_err);
+ error_report_err(local_err);
+ }
migrate_set_state(&mis->state, MIGRATION_STATUS_POSTCOPY_ACTIVE,
MIGRATION_STATUS_FAILED);
}
--
2.50.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v6 23/24] migration: Add error-parameterized function variants in VMSD struct
2025-07-21 11:29 [PATCH v6 00/24] migration: propagate vTPM errors using Error objects Arun Menon
` (21 preceding siblings ...)
2025-07-21 11:29 ` [PATCH v6 22/24] migration: Capture error in postcopy_ram_listen_thread() Arun Menon
@ 2025-07-21 11:29 ` Arun Menon
2025-07-21 13:14 ` Akihiko Odaki
2025-07-21 13:32 ` Daniel P. Berrangé
2025-07-21 11:29 ` [PATCH v6 24/24] backends/tpm: Propagate vTPM error on migration failure Arun Menon
23 siblings, 2 replies; 55+ messages in thread
From: Arun Menon @ 2025-07-21 11:29 UTC (permalink / raw)
To: qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato, Arun Menon
- We need to have good error reporting in the callbacks in
VMStateDescription struct. Specifically pre_save, post_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.
Signed-off-by: Arun Menon <armenon@redhat.com>
---
include/migration/vmstate.h | 11 +++++++++++
migration/vmstate.c | 47 +++++++++++++++++++++++++++++++++++++++------
2 files changed, 52 insertions(+), 6 deletions(-)
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 056781b1c21e737583f081594d9f88b32adfd674..53fa72c1bbde399be02c88fc8745fdbb79bfd7c8 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -200,15 +200,26 @@ 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.
*/
+
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);
+ int (*post_save_errp)(void *opaque, Error **errp);
bool (*needed)(void *opaque);
bool (*dev_unplug_pending)(void *opaque);
diff --git a/migration/vmstate.c b/migration/vmstate.c
index 288b57e1ed778cce21247b64d5e97dfef41ad586..d96908d12ccffaef421e5d399a48e26cada2cb77 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -152,7 +152,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) {
+ error_prepend(errp, "VM pre load 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, "VM pre load failed for: '%s', "
@@ -236,10 +245,17 @@ 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, "VM Post load 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, "VM Post load failed for: %s, version_id: %d,"
+ error_setg(errp, "VM Post load failed for: %s, version_id: %d, "
"minimum_version: %d, ret: %d", vmsd->name,
vmsd->version_id, vmsd->minimum_version_id, ret);
}
@@ -410,11 +426,19 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
void *opaque, JSONWriter *vmdesc, int version_id, Error **errp)
{
int ret = 0;
+ Error *local_err = NULL;
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) {
+ error_prepend(errp, "pre-save failed: %s ", vmsd->name);
+ return ret;
+ }
+ } else if (vmsd->pre_save) {
ret = vmsd->pre_save(opaque);
trace_vmstate_save_state_pre_save_res(vmsd->name, ret);
if (ret) {
@@ -524,7 +548,12 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
if (ret) {
error_setg(errp, "Save of field %s/%s failed",
vmsd->name, field->name);
- if (vmsd->post_save) {
+ if (vmsd->post_save_errp) {
+ ret = vmsd->post_save_errp(opaque, &local_err);
+ if (ret < 0) {
+ error_propagate(errp, local_err);
+ }
+ } else if (vmsd->post_save) {
vmsd->post_save(opaque);
}
return ret;
@@ -552,7 +581,13 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
ret = vmstate_subsection_save(f, vmsd, opaque, vmdesc, errp);
- if (vmsd->post_save) {
+ if (vmsd->post_save_errp) {
+ int ps_ret = vmsd->post_save_errp(opaque, &local_err);
+ if (!ret && ps_ret) {
+ ret = ps_ret;
+ error_propagate(errp, local_err);
+ }
+ } else if (vmsd->post_save) {
int ps_ret = vmsd->post_save(opaque);
if (!ret && ps_ret) {
ret = ps_ret;
--
2.50.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v6 24/24] backends/tpm: Propagate vTPM error on migration failure
2025-07-21 11:29 [PATCH v6 00/24] migration: propagate vTPM errors using Error objects Arun Menon
` (22 preceding siblings ...)
2025-07-21 11:29 ` [PATCH v6 23/24] migration: Add error-parameterized function variants in VMSD struct Arun Menon
@ 2025-07-21 11:29 ` Arun Menon
23 siblings, 0 replies; 55+ messages in thread
From: Arun Menon @ 2025-07-21 11:29 UTC (permalink / raw)
To: qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato, Arun Menon,
Daniel P. Berrangé, Stefan Berger
- When migration of a VM with encrypted vTPM fails on the
destination host, (e.g., due to a mismatch in secret values),
the error message displayed on the source host is generic and unhelpful.
- For example, a typical error looks like this:
"operation failed: job 'migration out' failed: Sibling indicated error 1.
operation failed: job 'migration in' failed: load of migration failed:
Input/output error"
- Such generic errors are logged using error_report(), which prints to
the console/monitor but does not make the detailed error accessible via
the QMP query-migrate command.
- This change, along with the set of changes of passing errp Error object
to the VM state loading functions, help in addressing the issue.
We use the post_load_errp hook of VMStateDescription to propagate errors
by setting Error **errp objects in case of failure in the TPM backend.
- It can then be retrieved using QMP command:
{"execute" : "query-migrate"}
Buglink: https://issues.redhat.com/browse/RHEL-82826
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Arun Menon <armenon@redhat.com>
---
backends/tpm/tpm_emulator.c | 39 ++++++++++++++++++++-------------------
1 file changed, 20 insertions(+), 19 deletions(-)
diff --git a/backends/tpm/tpm_emulator.c b/backends/tpm/tpm_emulator.c
index 4a234ab2c0b19b2604bf0dd8cb5f4540c72a9438..9bf5927e8e1542cf2e4f2275783d32853d5f1473 100644
--- a/backends/tpm/tpm_emulator.c
+++ b/backends/tpm/tpm_emulator.c
@@ -819,7 +819,8 @@ static int tpm_emulator_get_state_blobs(TPMEmulator *tpm_emu)
static int tpm_emulator_set_state_blob(TPMEmulator *tpm_emu,
uint32_t type,
TPMSizedBuffer *tsb,
- uint32_t flags)
+ uint32_t flags,
+ Error **errp)
{
ssize_t n;
ptm_setstate pss;
@@ -838,17 +839,17 @@ static int tpm_emulator_set_state_blob(TPMEmulator *tpm_emu,
/* write the header only */
if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_STATEBLOB, &pss,
offsetof(ptm_setstate, u.req.data), 0, 0) < 0) {
- error_report("tpm-emulator: could not set state blob type %d : %s",
- type, strerror(errno));
+ error_setg(errp, "tpm-emulator: could not set state blob type %d : %s",
+ type, strerror(errno));
return -1;
}
/* now the body */
n = qemu_chr_fe_write_all(&tpm_emu->ctrl_chr, tsb->buffer, tsb->size);
if (n != tsb->size) {
- error_report("tpm-emulator: Writing the stateblob (type %d) "
- "failed; could not write %u bytes, but only %zd",
- type, tsb->size, n);
+ error_setg(errp, "tpm-emulator: Writing the stateblob (type %d) "
+ "failed; could not write %u bytes, but only %zd",
+ type, tsb->size, n);
return -1;
}
@@ -856,17 +857,17 @@ static int tpm_emulator_set_state_blob(TPMEmulator *tpm_emu,
n = qemu_chr_fe_read_all(&tpm_emu->ctrl_chr,
(uint8_t *)&pss, sizeof(pss.u.resp));
if (n != sizeof(pss.u.resp)) {
- error_report("tpm-emulator: Reading response from writing stateblob "
- "(type %d) failed; expected %zu bytes, got %zd", type,
- sizeof(pss.u.resp), n);
+ error_setg(errp, "tpm-emulator: Reading response from writing "
+ "stateblob (type %d) failed; expected %zu bytes, "
+ "got %zd", type, sizeof(pss.u.resp), n);
return -1;
}
tpm_result = be32_to_cpu(pss.u.resp.tpm_result);
if (tpm_result != 0) {
- error_report("tpm-emulator: Setting the stateblob (type %d) failed "
- "with a TPM error 0x%x %s", type, tpm_result,
- tpm_emulator_strerror(tpm_result));
+ error_setg(errp, "tpm-emulator: Setting the stateblob (type %d) "
+ "failed with a TPM error 0x%x %s", type, tpm_result,
+ tpm_emulator_strerror(tpm_result));
return -1;
}
@@ -880,7 +881,7 @@ static int tpm_emulator_set_state_blob(TPMEmulator *tpm_emu,
*
* Returns a negative errno code in case of error.
*/
-static int tpm_emulator_set_state_blobs(TPMBackend *tb)
+static int tpm_emulator_set_state_blobs(TPMBackend *tb, Error **errp)
{
TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
TPMBlobBuffers *state_blobs = &tpm_emu->state_blobs;
@@ -894,13 +895,13 @@ static int tpm_emulator_set_state_blobs(TPMBackend *tb)
if (tpm_emulator_set_state_blob(tpm_emu, PTM_BLOB_TYPE_PERMANENT,
&state_blobs->permanent,
- state_blobs->permanent_flags) < 0 ||
+ state_blobs->permanent_flags, errp) < 0 ||
tpm_emulator_set_state_blob(tpm_emu, PTM_BLOB_TYPE_VOLATILE,
&state_blobs->volatil,
- state_blobs->volatil_flags) < 0 ||
+ state_blobs->volatil_flags, errp) < 0 ||
tpm_emulator_set_state_blob(tpm_emu, PTM_BLOB_TYPE_SAVESTATE,
&state_blobs->savestate,
- state_blobs->savestate_flags) < 0) {
+ state_blobs->savestate_flags, errp) < 0) {
return -EIO;
}
@@ -948,12 +949,12 @@ static void tpm_emulator_vm_state_change(void *opaque, bool running,
*
* Returns negative errno codes in case of error.
*/
-static int tpm_emulator_post_load(void *opaque, int version_id)
+static int tpm_emulator_post_load(void *opaque, int version_id, Error **errp)
{
TPMBackend *tb = opaque;
int ret;
- ret = tpm_emulator_set_state_blobs(tb);
+ ret = tpm_emulator_set_state_blobs(tb, errp);
if (ret < 0) {
return ret;
}
@@ -969,7 +970,7 @@ static const VMStateDescription vmstate_tpm_emulator = {
.name = "tpm-emulator",
.version_id = 0,
.pre_save = tpm_emulator_pre_save,
- .post_load = tpm_emulator_post_load,
+ .post_load_errp = tpm_emulator_post_load,
.fields = (const VMStateField[]) {
VMSTATE_UINT32(state_blobs.permanent_flags, TPMEmulator),
VMSTATE_UINT32(state_blobs.permanent.size, TPMEmulator),
--
2.50.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [PATCH v6 01/24] migration: push Error **errp into vmstate_subsection_load()
2025-07-21 11:29 ` [PATCH v6 01/24] migration: push Error **errp into vmstate_subsection_load() Arun Menon
@ 2025-07-21 12:10 ` Akihiko Odaki
2025-07-25 7:09 ` Arun Menon
0 siblings, 1 reply; 55+ messages in thread
From: Akihiko Odaki @ 2025-07-21 12:10 UTC (permalink / raw)
To: Arun Menon, qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Dmitry Osipenko,
Matthew Rosato
On 2025/07/21 20:29, Arun Menon wrote:
> This is an incremental step in converting vmstate loading
> code to report error via Error objects instead of directly
> printing it to console/monitor.
> It is ensured that vmstate_subsection_load() must report an error
> in errp, in case of failure.
>
> Signed-off-by: Arun Menon <armenon@redhat.com>
> ---
> migration/vmstate.c | 10 +++++++---
> 1 file changed, 7 insertions(+), 3 deletions(-)
>
> diff --git a/migration/vmstate.c b/migration/vmstate.c
> index 5feaa3244d259874f03048326b2497e7db32e47c..129b19d7603a0ddf8ab6e946e41c1c4d773d1fa8 100644
> --- a/migration/vmstate.c
> +++ b/migration/vmstate.c
> @@ -25,7 +25,7 @@ static int vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
> void *opaque, JSONWriter *vmdesc,
> Error **errp);
> static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
> - void *opaque);
> + void *opaque, Error **errp);
>
> /* Whether this field should exist for either save or load the VM? */
> static bool
> @@ -225,7 +225,7 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
> field++;
> }
> assert(field->flags == VMS_END);
> - ret = vmstate_subsection_load(f, vmsd, opaque);
> + ret = vmstate_subsection_load(f, vmsd, opaque, NULL);
> if (ret != 0) {
> qemu_file_set_error(f, ret);
> return ret;
> @@ -566,7 +566,7 @@ vmstate_get_subsection(const VMStateDescription * const *sub,
> }
>
> static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
> - void *opaque)
> + void *opaque, Error **errp)
> {
> trace_vmstate_subsection_load(vmsd->name);
>
> @@ -598,6 +598,8 @@ static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
> sub_vmsd = vmstate_get_subsection(vmsd->subsections, idstr);
> if (sub_vmsd == NULL) {
> trace_vmstate_subsection_load_bad(vmsd->name, idstr, "(lookup)");
> + error_setg(errp, "VM subsection '%s' in '%s' does not exist",
There are two whitespaces before "in" but I think we only need one.
> + idstr, vmsd->name);
> return -ENOENT;
> }
> qemu_file_skip(f, 1); /* subsection */
> @@ -608,6 +610,8 @@ static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
> ret = vmstate_load_state(f, sub_vmsd, opaque, version_id);
> if (ret) {
> trace_vmstate_subsection_load_bad(vmsd->name, idstr, "(child)");
> + error_setg(errp, "Loading VM subsection '%s' in '%s' failed : %d",
> + idstr, vmsd->name, ret);
> return ret;
> }
> }
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 07/24] migration: Update qemu_file_get_return_path() docs and remove dead checks
2025-07-21 11:29 ` [PATCH v6 07/24] migration: Update qemu_file_get_return_path() docs and remove dead checks Arun Menon
@ 2025-07-21 12:24 ` Daniel P. Berrangé
0 siblings, 0 replies; 55+ messages in thread
From: Daniel P. Berrangé @ 2025-07-21 12:24 UTC (permalink / raw)
To: Arun Menon
Cc: qemu-devel, Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck,
Halil Pasic, Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato
On Mon, Jul 21, 2025 at 04:59:12PM +0530, Arun Menon wrote:
> The documentation of qemu_file_get_return_path() states that it can
> return NULL on failure. However, a review of the current implementation
> reveals that it is guaranteed that it will always succeed and will never
> return NULL.
>
> As a result, the NULL checks post calling the function become redundant.
> This commit updates the documentation for the function and removes all
> NULL checks throughout the migration code.
>
> Signed-off-by: Arun Menon <armenon@redhat.com>
> ---
> migration/colo.c | 4 ----
> migration/migration.c | 12 ++----------
> migration/qemu-file.c | 1 -
> migration/savevm.c | 4 ----
> 4 files changed, 2 insertions(+), 19 deletions(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
With regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 02/24] migration: push Error **errp into vmstate_load_state()
2025-07-21 11:29 ` [PATCH v6 02/24] migration: push Error **errp into vmstate_load_state() Arun Menon
@ 2025-07-21 12:24 ` Akihiko Odaki
2025-07-25 7:11 ` Arun Menon
2025-07-21 12:30 ` Marc-André Lureau
1 sibling, 1 reply; 55+ messages in thread
From: Akihiko Odaki @ 2025-07-21 12:24 UTC (permalink / raw)
To: Arun Menon, qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Dmitry Osipenko,
Matthew Rosato
On 2025/07/21 20:29, Arun Menon wrote:
> This is an incremental step in converting vmstate loading
> code to report error via Error objects instead of directly
> printing it to console/monitor.
> It is ensured that vmstate_load_state() must report an error
> in errp, in case of failure.
>
> Signed-off-by: Arun Menon <armenon@redhat.com>
> ---
> hw/display/virtio-gpu.c | 2 +-
> hw/pci/pci.c | 2 +-
> hw/s390x/virtio-ccw.c | 2 +-
> hw/scsi/spapr_vscsi.c | 2 +-
> hw/vfio/pci.c | 2 +-
> hw/virtio/virtio-mmio.c | 2 +-
> hw/virtio/virtio-pci.c | 2 +-
> hw/virtio/virtio.c | 4 ++--
> include/migration/vmstate.h | 2 +-
> migration/cpr.c | 4 ++--
> migration/savevm.c | 6 ++++--
> migration/vmstate-types.c | 10 +++++-----
> migration/vmstate.c | 45 ++++++++++++++++++++++++++++-----------------
> tests/unit/test-vmstate.c | 18 +++++++++---------
> ui/vdagent.c | 2 +-
> 15 files changed, 59 insertions(+), 46 deletions(-)
>
> diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
> index 0a1a625b0ea6cf26cb0d799171a57ed3d3ab2442..5d2ca8d8b864350133a674802d7316abd379591c 100644
> --- a/hw/display/virtio-gpu.c
> +++ b/hw/display/virtio-gpu.c
> @@ -1343,7 +1343,7 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
> }
>
> /* load & apply scanout state */
> - vmstate_load_state(f, &vmstate_virtio_gpu_scanouts, g, 1);
> + vmstate_load_state(f, &vmstate_virtio_gpu_scanouts, g, 1, NULL);
>
> return 0;
> }
> diff --git a/hw/pci/pci.c b/hw/pci/pci.c
> index c70b5ceebaf1f2b10768bd030526cbb518da2b8d..2ab5d30bb3c319ac1c7bfc9a2acf6a2b38082066 100644
> --- a/hw/pci/pci.c
> +++ b/hw/pci/pci.c
> @@ -934,7 +934,7 @@ void pci_device_save(PCIDevice *s, QEMUFile *f)
> int pci_device_load(PCIDevice *s, QEMUFile *f)
> {
> int ret;
> - ret = vmstate_load_state(f, &vmstate_pci_device, s, s->version_id);
> + ret = vmstate_load_state(f, &vmstate_pci_device, s, s->version_id, NULL);
> /* Restore the interrupt status bit. */
> pci_update_irq_status(s);
> return ret;
> diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
> index d2f85b39f30f7fc82e0c600144c0a958e1269b2c..2f6feff2b0a22d7d7f6aecfd7e7870d8362f1a73 100644
> --- a/hw/s390x/virtio-ccw.c
> +++ b/hw/s390x/virtio-ccw.c
> @@ -1136,7 +1136,7 @@ static void virtio_ccw_save_config(DeviceState *d, QEMUFile *f)
> static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f)
> {
> VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
> - return vmstate_load_state(f, &vmstate_virtio_ccw_dev, dev, 1);
> + return vmstate_load_state(f, &vmstate_virtio_ccw_dev, dev, 1, NULL);
> }
>
> static void virtio_ccw_pre_plugged(DeviceState *d, Error **errp)
> diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c
> index 20f70fb2729de78b9636a6b8c869695dab4f8902..573fdea668536b464bca11f001e9e0288e781493 100644
> --- a/hw/scsi/spapr_vscsi.c
> +++ b/hw/scsi/spapr_vscsi.c
> @@ -648,7 +648,7 @@ static void *vscsi_load_request(QEMUFile *f, SCSIRequest *sreq)
> assert(!req->active);
>
> memset(req, 0, sizeof(*req));
> - rc = vmstate_load_state(f, &vmstate_spapr_vscsi_req, req, 1);
> + rc = vmstate_load_state(f, &vmstate_spapr_vscsi_req, req, 1, NULL);
> if (rc) {
> fprintf(stderr, "VSCSI: failed loading request tag#%u\n", sreq->tag);
> return NULL;
> diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
> index be05002b9819fafa45cf2fb4d2a0acdc475c558c..f8ce4a40dbe4c070a0d6c111051051ee97542719 100644
> --- a/hw/vfio/pci.c
> +++ b/hw/vfio/pci.c
> @@ -2797,7 +2797,7 @@ static int vfio_pci_load_config(VFIODevice *vbasedev, QEMUFile *f)
> old_addr[bar] = pdev->io_regions[bar].addr;
> }
>
> - ret = vmstate_load_state(f, &vmstate_vfio_pci_config, vdev, 1);
> + ret = vmstate_load_state(f, &vmstate_vfio_pci_config, vdev, 1, NULL);
> if (ret) {
> return ret;
> }
> diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c
> index 532c67107ba1d2978a76cf49f9cdc1de1dea3e11..9058b1563462d4464dcba799643a583c93fb5683 100644
> --- a/hw/virtio/virtio-mmio.c
> +++ b/hw/virtio/virtio-mmio.c
> @@ -619,7 +619,7 @@ static int virtio_mmio_load_extra_state(DeviceState *opaque, QEMUFile *f)
> {
> VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
>
> - return vmstate_load_state(f, &vmstate_virtio_mmio, proxy, 1);
> + return vmstate_load_state(f, &vmstate_virtio_mmio, proxy, 1, NULL);
> }
>
> static bool virtio_mmio_has_extra_state(DeviceState *opaque)
> diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
> index 767216d795998708f5716a23ae16c79cd90ff489..f8b52a611e56c22d844fd4cae3619da4f2686d03 100644
> --- a/hw/virtio/virtio-pci.c
> +++ b/hw/virtio/virtio-pci.c
> @@ -161,7 +161,7 @@ static int virtio_pci_load_extra_state(DeviceState *d, QEMUFile *f)
> {
> VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
>
> - return vmstate_load_state(f, &vmstate_virtio_pci, proxy, 1);
> + return vmstate_load_state(f, &vmstate_virtio_pci, proxy, 1, NULL);
> }
>
> static void virtio_pci_save_queue(DeviceState *d, int n, QEMUFile *f)
> diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
> index 2ab1d20769495ea39445b87e3673b076ad172510..d5698b062a1e95437f6113f41136e90ae06f1974 100644
> --- a/hw/virtio/virtio.c
> +++ b/hw/virtio/virtio.c
> @@ -3317,14 +3317,14 @@ virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
> }
>
> if (vdc->vmsd) {
> - ret = vmstate_load_state(f, vdc->vmsd, vdev, version_id);
> + ret = vmstate_load_state(f, vdc->vmsd, vdev, version_id, NULL);
> if (ret) {
> return ret;
> }
> }
>
> /* Subsections */
> - ret = vmstate_load_state(f, &vmstate_virtio, vdev, 1);
> + ret = vmstate_load_state(f, &vmstate_virtio, vdev, 1, NULL);
> if (ret) {
> return ret;
> }
> diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
> index 1ff7bd9ac425ba67cd5ca7ad97bcf570f9e19abe..056781b1c21e737583f081594d9f88b32adfd674 100644
> --- a/include/migration/vmstate.h
> +++ b/include/migration/vmstate.h
> @@ -1196,7 +1196,7 @@ extern const VMStateInfo vmstate_info_qlist;
> }
>
> int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
> - void *opaque, int version_id);
> + void *opaque, int version_id, Error **errp);
> int vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
> void *opaque, JSONWriter *vmdesc);
> int vmstate_save_state_with_err(QEMUFile *f, const VMStateDescription *vmsd,
> diff --git a/migration/cpr.c b/migration/cpr.c
> index 42ad0b0d500e5de57faf0c6517e216b2d1c0cacf..74fac9521717ec568d14dabcbcb574b19fc1da67 100644
> --- a/migration/cpr.c
> +++ b/migration/cpr.c
> @@ -233,9 +233,9 @@ int cpr_state_load(MigrationChannel *channel, Error **errp)
> return -ENOTSUP;
> }
>
> - ret = vmstate_load_state(f, &vmstate_cpr_state, &cpr_state, 1);
> + ret = vmstate_load_state(f, &vmstate_cpr_state, &cpr_state, 1, errp);
> if (ret) {
> - error_setg(errp, "vmstate_load_state error %d", ret);
> + error_prepend(errp, "vmstate_load_state error %d ", ret);
> qemu_fclose(f);
> return ret;
> }
> diff --git a/migration/savevm.c b/migration/savevm.c
> index fabbeb296ae987d0c06ba6dafda63720205fecfd..ab947620f724874f325fb9fb59bef50b7c16fb51 100644
> --- a/migration/savevm.c
> +++ b/migration/savevm.c
> @@ -969,7 +969,8 @@ static int vmstate_load(QEMUFile *f, SaveStateEntry *se)
> if (!se->vmsd) { /* Old style */
> return se->ops->load_state(f, se->opaque, se->load_version_id);
> }
> - return vmstate_load_state(f, se->vmsd, se->opaque, se->load_version_id);
> + return vmstate_load_state(f, se->vmsd, se->opaque, se->load_version_id,
> + NULL);
> }
>
> static void vmstate_save_old_style(QEMUFile *f, SaveStateEntry *se,
> @@ -2839,7 +2840,8 @@ static int qemu_loadvm_state_header(QEMUFile *f)
> error_report("Configuration section missing");
> return -EINVAL;
> }
> - ret = vmstate_load_state(f, &vmstate_configuration, &savevm_state, 0);
> + ret = vmstate_load_state(f, &vmstate_configuration, &savevm_state, 0,
> + NULL);
>
> if (ret) {
> return ret;
> diff --git a/migration/vmstate-types.c b/migration/vmstate-types.c
> index 741a588b7e18c6d37724b08a0101edc8bc74a0a5..1c5b76e1dd198030847971bc35637867c9d54fc0 100644
> --- a/migration/vmstate-types.c
> +++ b/migration/vmstate-types.c
> @@ -549,7 +549,7 @@ static int get_tmp(QEMUFile *f, void *pv, size_t size,
>
> /* Writes the parent field which is at the start of the tmp */
> *(void **)tmp = pv;
> - ret = vmstate_load_state(f, vmsd, tmp, version_id);
> + ret = vmstate_load_state(f, vmsd, tmp, version_id, NULL);
> g_free(tmp);
> return ret;
> }
> @@ -649,7 +649,7 @@ static int get_qtailq(QEMUFile *f, void *pv, size_t unused_size,
>
> while (qemu_get_byte(f)) {
> elm = g_malloc(size);
> - ret = vmstate_load_state(f, vmsd, elm, version_id);
> + ret = vmstate_load_state(f, vmsd, elm, version_id, NULL);
> if (ret) {
> return ret;
> }
> @@ -803,7 +803,7 @@ static int get_gtree(QEMUFile *f, void *pv, size_t unused_size,
> key = (void *)(uintptr_t)qemu_get_be64(f);
> } else {
> key = g_malloc0(key_size);
> - ret = vmstate_load_state(f, key_vmsd, key, version_id);
> + ret = vmstate_load_state(f, key_vmsd, key, version_id, NULL);
> if (ret) {
> error_report("%s : failed to load %s (%d)",
> field->name, key_vmsd->name, ret);
> @@ -811,7 +811,7 @@ static int get_gtree(QEMUFile *f, void *pv, size_t unused_size,
> }
> }
> val = g_malloc0(val_size);
> - ret = vmstate_load_state(f, val_vmsd, val, version_id);
> + ret = vmstate_load_state(f, val_vmsd, val, version_id, NULL);
> if (ret) {
> error_report("%s : failed to load %s (%d)",
> field->name, val_vmsd->name, ret);
> @@ -892,7 +892,7 @@ static int get_qlist(QEMUFile *f, void *pv, size_t unused_size,
>
> while (qemu_get_byte(f)) {
> elm = g_malloc(size);
> - ret = vmstate_load_state(f, vmsd, elm, version_id);
> + ret = vmstate_load_state(f, vmsd, elm, version_id, NULL);
> if (ret) {
> error_report("%s: failed to load %s (%d)", field->name,
> vmsd->name, ret);
> diff --git a/migration/vmstate.c b/migration/vmstate.c
> index 129b19d7603a0ddf8ab6e946e41c1c4d773d1fa8..288b57e1ed778cce21247b64d5e97dfef41ad586 100644
> --- a/migration/vmstate.c
> +++ b/migration/vmstate.c
> @@ -132,29 +132,33 @@ static void vmstate_handle_alloc(void *ptr, const VMStateField *field,
> }
>
> int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
> - void *opaque, int version_id)
> + void *opaque, int version_id, Error **errp)
> {
> const VMStateField *field = vmsd->fields;
> int ret = 0;
>
> trace_vmstate_load_state(vmsd->name, version_id);
> if (version_id > vmsd->version_id) {
> - error_report("%s: incoming version_id %d is too new "
> - "for local version_id %d",
> - vmsd->name, version_id, vmsd->version_id);
> + error_setg(errp, "%s: incoming version_id %d is too new "
> + "for local version_id %d",
> + vmsd->name, version_id, vmsd->version_id);
> trace_vmstate_load_state_end(vmsd->name, "too new", -EINVAL);
> return -EINVAL;
> }
> if (version_id < vmsd->minimum_version_id) {
> - error_report("%s: incoming version_id %d is too old "
> - "for local minimum version_id %d",
> - vmsd->name, version_id, vmsd->minimum_version_id);
> + error_setg(errp, "%s: incoming version_id %d is too old "
> + "for local minimum version_id %d",
> + vmsd->name, version_id, vmsd->minimum_version_id);
> trace_vmstate_load_state_end(vmsd->name, "too old", -EINVAL);
> return -EINVAL;
> }
> if (vmsd->pre_load) {
> ret = vmsd->pre_load(opaque);
> if (ret) {
> + error_setg(errp, "VM pre load failed for: '%s', "
> + "version_id: '%d', minimum version_id: '%d', ret: %d",
> + vmsd->name, vmsd->version_id, vmsd->minimum_version_id,
> + ret);
> return ret;
> }
> }
> @@ -192,10 +196,12 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
>
> if (inner_field->flags & VMS_STRUCT) {
> ret = vmstate_load_state(f, inner_field->vmsd, curr_elem,
> - inner_field->vmsd->version_id);
> + inner_field->vmsd->version_id,
> + errp);
> } else if (inner_field->flags & VMS_VSTRUCT) {
> ret = vmstate_load_state(f, inner_field->vmsd, curr_elem,
> - inner_field->struct_version_id);
> + inner_field->struct_version_id,
> + errp);
> } else {
> ret = inner_field->info->get(f, curr_elem, size,
> inner_field);
> @@ -211,27 +217,32 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
> }
> if (ret < 0) {
> qemu_file_set_error(f, ret);
> - error_report("Failed to load %s:%s", vmsd->name,
> - field->name);
> + error_prepend(errp, "Failed to load %s:%s version_id: %d ",
> + vmsd->name, field->name, vmsd->version_id);
> trace_vmstate_load_field_error(field->name, ret);
> return ret;
> }
> }
> } else if (field->flags & VMS_MUST_EXIST) {
> - error_report("Input validation failed: %s/%s",
> - vmsd->name, field->name);
> + error_setg(errp, "Input validation failed: %s/%s version_id: %d",
> + vmsd->name, field->name, vmsd->version_id);
> return -1;
> }
> field++;
> }
> assert(field->flags == VMS_END);
> - ret = vmstate_subsection_load(f, vmsd, opaque, NULL);
> + ret = vmstate_subsection_load(f, vmsd, opaque, errp);
> if (ret != 0) {
> qemu_file_set_error(f, ret);
> return ret;
> }
> if (vmsd->post_load) {
> ret = vmsd->post_load(opaque, version_id);
> + if (ret < 0) {
> + error_setg(errp, "VM Post load failed for: %s, version_id: %d,"
> + "minimum_version: %d, ret: %d", vmsd->name,
This error message lacks a whitespace between "," and "minimum_version".
By the way, I prefer not to have line breaks in string literals to ease
code search.
While QEMU's coding style guide says nothing about the length limit for
a line with a string literal, scripts/checkpatch.pl make an exemption
for such a line.
scripts/checkpatch.pl came from Linux, and Linux's coding style guide says:
> However, never break user-visible strings such as printk messages
> because that breaks the ability to grep for them.
https://www.kernel.org/doc/html/v6.15/process/coding-style.html#breaking-long-lines-and-strings
While we don't have to follow Linux's style, I think this particular
statement makes sense for QEMU too.
> + vmsd->version_id, vmsd->minimum_version_id, ret);
> + }
> }
> trace_vmstate_load_state_end(vmsd->name, "end", ret);
> return ret;
> @@ -607,11 +618,11 @@ static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
> qemu_file_skip(f, len); /* idstr */
> version_id = qemu_get_be32(f);
>
> - ret = vmstate_load_state(f, sub_vmsd, opaque, version_id);
> + ret = vmstate_load_state(f, sub_vmsd, opaque, version_id, errp);
> if (ret) {
> trace_vmstate_subsection_load_bad(vmsd->name, idstr, "(child)");
> - error_setg(errp, "Loading VM subsection '%s' in '%s' failed : %d",
> - idstr, vmsd->name, ret);
> + error_prepend(errp, "Loading VM subsection '%s'"
> + "in '%s' failed : %d ", idstr, vmsd->name, ret);
> return ret;
> }
> }
> diff --git a/tests/unit/test-vmstate.c b/tests/unit/test-vmstate.c
> index 63f28f26f45691a70936d33e7341d16477a3471f..ca5e0ba1e3e5e2bb0a1ce39143a292f2c6f9420a 100644
> --- a/tests/unit/test-vmstate.c
> +++ b/tests/unit/test-vmstate.c
> @@ -114,7 +114,7 @@ static int load_vmstate_one(const VMStateDescription *desc, void *obj,
> qemu_fclose(f);
>
> f = open_test_file(false);
> - ret = vmstate_load_state(f, desc, obj, version);
> + ret = vmstate_load_state(f, desc, obj, version, NULL);
> if (ret) {
> g_assert(qemu_file_get_error(f));
> } else{
> @@ -365,7 +365,7 @@ static void test_load_v1(void)
>
> QEMUFile *loading = open_test_file(false);
> TestStruct obj = { .b = 200, .e = 500, .f = 600 };
> - vmstate_load_state(loading, &vmstate_versioned, &obj, 1);
> + vmstate_load_state(loading, &vmstate_versioned, &obj, 1, NULL);
> g_assert(!qemu_file_get_error(loading));
> g_assert_cmpint(obj.a, ==, 10);
> g_assert_cmpint(obj.b, ==, 200);
> @@ -391,7 +391,7 @@ static void test_load_v2(void)
>
> QEMUFile *loading = open_test_file(false);
> TestStruct obj;
> - vmstate_load_state(loading, &vmstate_versioned, &obj, 2);
> + vmstate_load_state(loading, &vmstate_versioned, &obj, 2, NULL);
> g_assert_cmpint(obj.a, ==, 10);
> g_assert_cmpint(obj.b, ==, 20);
> g_assert_cmpint(obj.c, ==, 30);
> @@ -480,7 +480,7 @@ static void test_load_noskip(void)
>
> QEMUFile *loading = open_test_file(false);
> TestStruct obj = { .skip_c_e = false };
> - vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
> + vmstate_load_state(loading, &vmstate_skipping, &obj, 2, NULL);
> g_assert(!qemu_file_get_error(loading));
> g_assert_cmpint(obj.a, ==, 10);
> g_assert_cmpint(obj.b, ==, 20);
> @@ -504,7 +504,7 @@ static void test_load_skip(void)
>
> QEMUFile *loading = open_test_file(false);
> TestStruct obj = { .skip_c_e = true, .c = 300, .e = 500 };
> - vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
> + vmstate_load_state(loading, &vmstate_skipping, &obj, 2, NULL);
> g_assert(!qemu_file_get_error(loading));
> g_assert_cmpint(obj.a, ==, 10);
> g_assert_cmpint(obj.b, ==, 20);
> @@ -773,7 +773,7 @@ static void test_load_q(void)
> TestQtailq tgt;
>
> QTAILQ_INIT(&tgt.q);
> - vmstate_load_state(fload, &vmstate_q, &tgt, 1);
> + vmstate_load_state(fload, &vmstate_q, &tgt, 1, NULL);
> char eof = qemu_get_byte(fload);
> g_assert(!qemu_file_get_error(fload));
> g_assert_cmpint(tgt.i16, ==, obj_q.i16);
> @@ -1127,7 +1127,7 @@ static void test_gtree_load_domain(void)
>
> fload = open_test_file(false);
>
> - vmstate_load_state(fload, &vmstate_domain, dest_domain, 1);
> + vmstate_load_state(fload, &vmstate_domain, dest_domain, 1, NULL);
> eof = qemu_get_byte(fload);
> g_assert(!qemu_file_get_error(fload));
> g_assert_cmpint(orig_domain->id, ==, dest_domain->id);
> @@ -1241,7 +1241,7 @@ static void test_gtree_load_iommu(void)
> qemu_fclose(fsave);
>
> fload = open_test_file(false);
> - vmstate_load_state(fload, &vmstate_iommu, dest_iommu, 1);
> + vmstate_load_state(fload, &vmstate_iommu, dest_iommu, 1, NULL);
> eof = qemu_get_byte(fload);
> g_assert(!qemu_file_get_error(fload));
> g_assert_cmpint(orig_iommu->id, ==, dest_iommu->id);
> @@ -1376,7 +1376,7 @@ static void test_load_qlist(void)
> qemu_fclose(fsave);
>
> fload = open_test_file(false);
> - vmstate_load_state(fload, &vmstate_container, dest_container, 1);
> + vmstate_load_state(fload, &vmstate_container, dest_container, 1, NULL);
> eof = qemu_get_byte(fload);
> g_assert(!qemu_file_get_error(fload));
> g_assert_cmpint(eof, ==, QEMU_VM_EOF);
> diff --git a/ui/vdagent.c b/ui/vdagent.c
> index c0746fe5b168fdc7aeb4866de2ba0c3387566649..83457dee0767433ad0778b37b41b9c673a0e1860 100644
> --- a/ui/vdagent.c
> +++ b/ui/vdagent.c
> @@ -1008,7 +1008,7 @@ static int get_cbinfo(QEMUFile *f, void *pv, size_t size,
>
> vdagent_clipboard_peer_register(vd);
>
> - ret = vmstate_load_state(f, &vmstate_cbinfo_array, &cbinfo, 0);
> + ret = vmstate_load_state(f, &vmstate_cbinfo_array, &cbinfo, 0, NULL);
> if (ret) {
> return ret;
> }
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 02/24] migration: push Error **errp into vmstate_load_state()
2025-07-21 11:29 ` [PATCH v6 02/24] migration: push Error **errp into vmstate_load_state() Arun Menon
2025-07-21 12:24 ` Akihiko Odaki
@ 2025-07-21 12:30 ` Marc-André Lureau
2025-07-25 7:12 ` Arun Menon
1 sibling, 1 reply; 55+ messages in thread
From: Marc-André Lureau @ 2025-07-21 12:30 UTC (permalink / raw)
To: Arun Menon, Armbruster, Markus
Cc: qemu-devel, Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck,
Halil Pasic, Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Alex Bennée, Akihiko Odaki, Dmitry Osipenko, Matthew Rosato
[-- Attachment #1: Type: text/plain, Size: 21372 bytes --]
Hi
On Mon, Jul 21, 2025 at 3:35 PM Arun Menon <armenon@redhat.com> wrote:
> This is an incremental step in converting vmstate loading
> code to report error via Error objects instead of directly
> printing it to console/monitor.
> It is ensured that vmstate_load_state() must report an error
> in errp, in case of failure.
>
> Signed-off-by: Arun Menon <armenon@redhat.com>
> ---
> hw/display/virtio-gpu.c | 2 +-
> hw/pci/pci.c | 2 +-
> hw/s390x/virtio-ccw.c | 2 +-
> hw/scsi/spapr_vscsi.c | 2 +-
> hw/vfio/pci.c | 2 +-
> hw/virtio/virtio-mmio.c | 2 +-
> hw/virtio/virtio-pci.c | 2 +-
> hw/virtio/virtio.c | 4 ++--
> include/migration/vmstate.h | 2 +-
> migration/cpr.c | 4 ++--
> migration/savevm.c | 6 ++++--
> migration/vmstate-types.c | 10 +++++-----
> migration/vmstate.c | 45
> ++++++++++++++++++++++++++++-----------------
> tests/unit/test-vmstate.c | 18 +++++++++---------
> ui/vdagent.c | 2 +-
> 15 files changed, 59 insertions(+), 46 deletions(-)
>
> diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
> index
> 0a1a625b0ea6cf26cb0d799171a57ed3d3ab2442..5d2ca8d8b864350133a674802d7316abd379591c
> 100644
> --- a/hw/display/virtio-gpu.c
> +++ b/hw/display/virtio-gpu.c
> @@ -1343,7 +1343,7 @@ static int virtio_gpu_load(QEMUFile *f, void
> *opaque, size_t size,
> }
>
> /* load & apply scanout state */
> - vmstate_load_state(f, &vmstate_virtio_gpu_scanouts, g, 1);
> + vmstate_load_state(f, &vmstate_virtio_gpu_scanouts, g, 1, NULL);
>
> return 0;
> }
> diff --git a/hw/pci/pci.c b/hw/pci/pci.c
> index
> c70b5ceebaf1f2b10768bd030526cbb518da2b8d..2ab5d30bb3c319ac1c7bfc9a2acf6a2b38082066
> 100644
> --- a/hw/pci/pci.c
> +++ b/hw/pci/pci.c
> @@ -934,7 +934,7 @@ void pci_device_save(PCIDevice *s, QEMUFile *f)
> int pci_device_load(PCIDevice *s, QEMUFile *f)
> {
> int ret;
> - ret = vmstate_load_state(f, &vmstate_pci_device, s, s->version_id);
> + ret = vmstate_load_state(f, &vmstate_pci_device, s, s->version_id,
> NULL);
> /* Restore the interrupt status bit. */
> pci_update_irq_status(s);
> return ret;
> diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
> index
> d2f85b39f30f7fc82e0c600144c0a958e1269b2c..2f6feff2b0a22d7d7f6aecfd7e7870d8362f1a73
> 100644
> --- a/hw/s390x/virtio-ccw.c
> +++ b/hw/s390x/virtio-ccw.c
> @@ -1136,7 +1136,7 @@ static void virtio_ccw_save_config(DeviceState *d,
> QEMUFile *f)
> static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f)
> {
> VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
> - return vmstate_load_state(f, &vmstate_virtio_ccw_dev, dev, 1);
> + return vmstate_load_state(f, &vmstate_virtio_ccw_dev, dev, 1, NULL);
> }
>
> static void virtio_ccw_pre_plugged(DeviceState *d, Error **errp)
> diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c
> index
> 20f70fb2729de78b9636a6b8c869695dab4f8902..573fdea668536b464bca11f001e9e0288e781493
> 100644
> --- a/hw/scsi/spapr_vscsi.c
> +++ b/hw/scsi/spapr_vscsi.c
> @@ -648,7 +648,7 @@ static void *vscsi_load_request(QEMUFile *f,
> SCSIRequest *sreq)
> assert(!req->active);
>
> memset(req, 0, sizeof(*req));
> - rc = vmstate_load_state(f, &vmstate_spapr_vscsi_req, req, 1);
> + rc = vmstate_load_state(f, &vmstate_spapr_vscsi_req, req, 1, NULL);
> if (rc) {
> fprintf(stderr, "VSCSI: failed loading request tag#%u\n",
> sreq->tag);
> return NULL;
> diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
> index
> be05002b9819fafa45cf2fb4d2a0acdc475c558c..f8ce4a40dbe4c070a0d6c111051051ee97542719
> 100644
> --- a/hw/vfio/pci.c
> +++ b/hw/vfio/pci.c
> @@ -2797,7 +2797,7 @@ static int vfio_pci_load_config(VFIODevice
> *vbasedev, QEMUFile *f)
> old_addr[bar] = pdev->io_regions[bar].addr;
> }
>
> - ret = vmstate_load_state(f, &vmstate_vfio_pci_config, vdev, 1);
> + ret = vmstate_load_state(f, &vmstate_vfio_pci_config, vdev, 1, NULL);
> if (ret) {
> return ret;
> }
> diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c
> index
> 532c67107ba1d2978a76cf49f9cdc1de1dea3e11..9058b1563462d4464dcba799643a583c93fb5683
> 100644
> --- a/hw/virtio/virtio-mmio.c
> +++ b/hw/virtio/virtio-mmio.c
> @@ -619,7 +619,7 @@ static int virtio_mmio_load_extra_state(DeviceState
> *opaque, QEMUFile *f)
> {
> VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
>
> - return vmstate_load_state(f, &vmstate_virtio_mmio, proxy, 1);
> + return vmstate_load_state(f, &vmstate_virtio_mmio, proxy, 1, NULL);
> }
>
> static bool virtio_mmio_has_extra_state(DeviceState *opaque)
> diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
> index
> 767216d795998708f5716a23ae16c79cd90ff489..f8b52a611e56c22d844fd4cae3619da4f2686d03
> 100644
> --- a/hw/virtio/virtio-pci.c
> +++ b/hw/virtio/virtio-pci.c
> @@ -161,7 +161,7 @@ static int virtio_pci_load_extra_state(DeviceState *d,
> QEMUFile *f)
> {
> VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
>
> - return vmstate_load_state(f, &vmstate_virtio_pci, proxy, 1);
> + return vmstate_load_state(f, &vmstate_virtio_pci, proxy, 1, NULL);
> }
>
> static void virtio_pci_save_queue(DeviceState *d, int n, QEMUFile *f)
> diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
> index
> 2ab1d20769495ea39445b87e3673b076ad172510..d5698b062a1e95437f6113f41136e90ae06f1974
> 100644
> --- a/hw/virtio/virtio.c
> +++ b/hw/virtio/virtio.c
> @@ -3317,14 +3317,14 @@ virtio_load(VirtIODevice *vdev, QEMUFile *f, int
> version_id)
> }
>
> if (vdc->vmsd) {
> - ret = vmstate_load_state(f, vdc->vmsd, vdev, version_id);
> + ret = vmstate_load_state(f, vdc->vmsd, vdev, version_id, NULL);
> if (ret) {
> return ret;
> }
> }
>
> /* Subsections */
> - ret = vmstate_load_state(f, &vmstate_virtio, vdev, 1);
> + ret = vmstate_load_state(f, &vmstate_virtio, vdev, 1, NULL);
> if (ret) {
> return ret;
> }
> diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
> index
> 1ff7bd9ac425ba67cd5ca7ad97bcf570f9e19abe..056781b1c21e737583f081594d9f88b32adfd674
> 100644
> --- a/include/migration/vmstate.h
> +++ b/include/migration/vmstate.h
> @@ -1196,7 +1196,7 @@ extern const VMStateInfo vmstate_info_qlist;
> }
>
> int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
> - void *opaque, int version_id);
> + void *opaque, int version_id, Error **errp);
> int vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
> void *opaque, JSONWriter *vmdesc);
> int vmstate_save_state_with_err(QEMUFile *f, const VMStateDescription
> *vmsd,
> diff --git a/migration/cpr.c b/migration/cpr.c
> index
> 42ad0b0d500e5de57faf0c6517e216b2d1c0cacf..74fac9521717ec568d14dabcbcb574b19fc1da67
> 100644
> --- a/migration/cpr.c
> +++ b/migration/cpr.c
> @@ -233,9 +233,9 @@ int cpr_state_load(MigrationChannel *channel, Error
> **errp)
> return -ENOTSUP;
> }
>
> - ret = vmstate_load_state(f, &vmstate_cpr_state, &cpr_state, 1);
> + ret = vmstate_load_state(f, &vmstate_cpr_state, &cpr_state, 1, errp);
> if (ret) {
> - error_setg(errp, "vmstate_load_state error %d", ret);
> + error_prepend(errp, "vmstate_load_state error %d ", ret);
>
Although it's not enforced, I think it's recommended to end the
error_prepend() string with ": ", not just a space.
> qemu_fclose(f);
> return ret;
> }
> diff --git a/migration/savevm.c b/migration/savevm.c
> index
> fabbeb296ae987d0c06ba6dafda63720205fecfd..ab947620f724874f325fb9fb59bef50b7c16fb51
> 100644
> --- a/migration/savevm.c
> +++ b/migration/savevm.c
> @@ -969,7 +969,8 @@ static int vmstate_load(QEMUFile *f, SaveStateEntry
> *se)
> if (!se->vmsd) { /* Old style */
> return se->ops->load_state(f, se->opaque, se->load_version_id);
> }
> - return vmstate_load_state(f, se->vmsd, se->opaque,
> se->load_version_id);
> + return vmstate_load_state(f, se->vmsd, se->opaque,
> se->load_version_id,
> + NULL);
> }
>
> static void vmstate_save_old_style(QEMUFile *f, SaveStateEntry *se,
> @@ -2839,7 +2840,8 @@ static int qemu_loadvm_state_header(QEMUFile *f)
> error_report("Configuration section missing");
> return -EINVAL;
> }
> - ret = vmstate_load_state(f, &vmstate_configuration,
> &savevm_state, 0);
> + ret = vmstate_load_state(f, &vmstate_configuration,
> &savevm_state, 0,
> + NULL);
>
> if (ret) {
> return ret;
> diff --git a/migration/vmstate-types.c b/migration/vmstate-types.c
> index
> 741a588b7e18c6d37724b08a0101edc8bc74a0a5..1c5b76e1dd198030847971bc35637867c9d54fc0
> 100644
> --- a/migration/vmstate-types.c
> +++ b/migration/vmstate-types.c
> @@ -549,7 +549,7 @@ static int get_tmp(QEMUFile *f, void *pv, size_t size,
>
> /* Writes the parent field which is at the start of the tmp */
> *(void **)tmp = pv;
> - ret = vmstate_load_state(f, vmsd, tmp, version_id);
> + ret = vmstate_load_state(f, vmsd, tmp, version_id, NULL);
> g_free(tmp);
> return ret;
> }
> @@ -649,7 +649,7 @@ static int get_qtailq(QEMUFile *f, void *pv, size_t
> unused_size,
>
> while (qemu_get_byte(f)) {
> elm = g_malloc(size);
> - ret = vmstate_load_state(f, vmsd, elm, version_id);
> + ret = vmstate_load_state(f, vmsd, elm, version_id, NULL);
> if (ret) {
> return ret;
> }
> @@ -803,7 +803,7 @@ static int get_gtree(QEMUFile *f, void *pv, size_t
> unused_size,
> key = (void *)(uintptr_t)qemu_get_be64(f);
> } else {
> key = g_malloc0(key_size);
> - ret = vmstate_load_state(f, key_vmsd, key, version_id);
> + ret = vmstate_load_state(f, key_vmsd, key, version_id, NULL);
> if (ret) {
> error_report("%s : failed to load %s (%d)",
> field->name, key_vmsd->name, ret);
> @@ -811,7 +811,7 @@ static int get_gtree(QEMUFile *f, void *pv, size_t
> unused_size,
> }
> }
> val = g_malloc0(val_size);
> - ret = vmstate_load_state(f, val_vmsd, val, version_id);
> + ret = vmstate_load_state(f, val_vmsd, val, version_id, NULL);
> if (ret) {
> error_report("%s : failed to load %s (%d)",
> field->name, val_vmsd->name, ret);
> @@ -892,7 +892,7 @@ static int get_qlist(QEMUFile *f, void *pv, size_t
> unused_size,
>
> while (qemu_get_byte(f)) {
> elm = g_malloc(size);
> - ret = vmstate_load_state(f, vmsd, elm, version_id);
> + ret = vmstate_load_state(f, vmsd, elm, version_id, NULL);
> if (ret) {
> error_report("%s: failed to load %s (%d)", field->name,
> vmsd->name, ret);
> diff --git a/migration/vmstate.c b/migration/vmstate.c
> index
> 129b19d7603a0ddf8ab6e946e41c1c4d773d1fa8..288b57e1ed778cce21247b64d5e97dfef41ad586
> 100644
> --- a/migration/vmstate.c
> +++ b/migration/vmstate.c
> @@ -132,29 +132,33 @@ static void vmstate_handle_alloc(void *ptr, const
> VMStateField *field,
> }
>
> int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
> - void *opaque, int version_id)
> + void *opaque, int version_id, Error **errp)
> {
> const VMStateField *field = vmsd->fields;
> int ret = 0;
>
> trace_vmstate_load_state(vmsd->name, version_id);
> if (version_id > vmsd->version_id) {
> - error_report("%s: incoming version_id %d is too new "
> - "for local version_id %d",
> - vmsd->name, version_id, vmsd->version_id);
> + error_setg(errp, "%s: incoming version_id %d is too new "
> + "for local version_id %d",
> + vmsd->name, version_id, vmsd->version_id);
> trace_vmstate_load_state_end(vmsd->name, "too new", -EINVAL);
> return -EINVAL;
> }
> if (version_id < vmsd->minimum_version_id) {
> - error_report("%s: incoming version_id %d is too old "
> - "for local minimum version_id %d",
> - vmsd->name, version_id, vmsd->minimum_version_id);
> + error_setg(errp, "%s: incoming version_id %d is too old "
> + "for local minimum version_id %d",
> + vmsd->name, version_id, vmsd->minimum_version_id);
> trace_vmstate_load_state_end(vmsd->name, "too old", -EINVAL);
> return -EINVAL;
> }
> if (vmsd->pre_load) {
> ret = vmsd->pre_load(opaque);
> if (ret) {
> + error_setg(errp, "VM pre load failed for: '%s', "
> + "version_id: '%d', minimum version_id: '%d', ret:
> %d",
> + vmsd->name, vmsd->version_id,
> vmsd->minimum_version_id,
> + ret);
> return ret;
> }
> }
> @@ -192,10 +196,12 @@ int vmstate_load_state(QEMUFile *f, const
> VMStateDescription *vmsd,
>
> if (inner_field->flags & VMS_STRUCT) {
> ret = vmstate_load_state(f, inner_field->vmsd,
> curr_elem,
> -
> inner_field->vmsd->version_id);
> +
> inner_field->vmsd->version_id,
> + errp);
> } else if (inner_field->flags & VMS_VSTRUCT) {
> ret = vmstate_load_state(f, inner_field->vmsd,
> curr_elem,
> -
> inner_field->struct_version_id);
> +
> inner_field->struct_version_id,
> + errp);
> } else {
> ret = inner_field->info->get(f, curr_elem, size,
> inner_field);
> @@ -211,27 +217,32 @@ int vmstate_load_state(QEMUFile *f, const
> VMStateDescription *vmsd,
> }
> if (ret < 0) {
> qemu_file_set_error(f, ret);
> - error_report("Failed to load %s:%s", vmsd->name,
> - field->name);
> + error_prepend(errp, "Failed to load %s:%s version_id:
> %d ",
> + vmsd->name, field->name,
> vmsd->version_id);
> trace_vmstate_load_field_error(field->name, ret);
> return ret;
> }
> }
> } else if (field->flags & VMS_MUST_EXIST) {
> - error_report("Input validation failed: %s/%s",
> - vmsd->name, field->name);
> + error_setg(errp, "Input validation failed: %s/%s version_id:
> %d",
> + vmsd->name, field->name, vmsd->version_id);
> return -1;
> }
> field++;
> }
> assert(field->flags == VMS_END);
> - ret = vmstate_subsection_load(f, vmsd, opaque, NULL);
> + ret = vmstate_subsection_load(f, vmsd, opaque, errp);
> if (ret != 0) {
> qemu_file_set_error(f, ret);
> return ret;
> }
> if (vmsd->post_load) {
> ret = vmsd->post_load(opaque, version_id);
> + if (ret < 0) {
> + error_setg(errp, "VM Post load failed for: %s, version_id:
> %d,"
> + "minimum_version: %d, ret: %d", vmsd->name,
> + vmsd->version_id, vmsd->minimum_version_id, ret);
> + }
> }
> trace_vmstate_load_state_end(vmsd->name, "end", ret);
> return ret;
> @@ -607,11 +618,11 @@ static int vmstate_subsection_load(QEMUFile *f,
> const VMStateDescription *vmsd,
> qemu_file_skip(f, len); /* idstr */
> version_id = qemu_get_be32(f);
>
> - ret = vmstate_load_state(f, sub_vmsd, opaque, version_id);
> + ret = vmstate_load_state(f, sub_vmsd, opaque, version_id, errp);
> if (ret) {
> trace_vmstate_subsection_load_bad(vmsd->name, idstr,
> "(child)");
> - error_setg(errp, "Loading VM subsection '%s' in '%s' failed :
> %d",
> - idstr, vmsd->name, ret);
> + error_prepend(errp, "Loading VM subsection '%s'"
> + "in '%s' failed : %d ", idstr, vmsd->name, ret);
> return ret;
> }
> }
> diff --git a/tests/unit/test-vmstate.c b/tests/unit/test-vmstate.c
> index
> 63f28f26f45691a70936d33e7341d16477a3471f..ca5e0ba1e3e5e2bb0a1ce39143a292f2c6f9420a
> 100644
> --- a/tests/unit/test-vmstate.c
> +++ b/tests/unit/test-vmstate.c
> @@ -114,7 +114,7 @@ static int load_vmstate_one(const VMStateDescription
> *desc, void *obj,
> qemu_fclose(f);
>
> f = open_test_file(false);
> - ret = vmstate_load_state(f, desc, obj, version);
> + ret = vmstate_load_state(f, desc, obj, version, NULL);
> if (ret) {
> g_assert(qemu_file_get_error(f));
> } else{
> @@ -365,7 +365,7 @@ static void test_load_v1(void)
>
> QEMUFile *loading = open_test_file(false);
> TestStruct obj = { .b = 200, .e = 500, .f = 600 };
> - vmstate_load_state(loading, &vmstate_versioned, &obj, 1);
> + vmstate_load_state(loading, &vmstate_versioned, &obj, 1, NULL);
> g_assert(!qemu_file_get_error(loading));
> g_assert_cmpint(obj.a, ==, 10);
> g_assert_cmpint(obj.b, ==, 200);
> @@ -391,7 +391,7 @@ static void test_load_v2(void)
>
> QEMUFile *loading = open_test_file(false);
> TestStruct obj;
> - vmstate_load_state(loading, &vmstate_versioned, &obj, 2);
> + vmstate_load_state(loading, &vmstate_versioned, &obj, 2, NULL);
> g_assert_cmpint(obj.a, ==, 10);
> g_assert_cmpint(obj.b, ==, 20);
> g_assert_cmpint(obj.c, ==, 30);
> @@ -480,7 +480,7 @@ static void test_load_noskip(void)
>
> QEMUFile *loading = open_test_file(false);
> TestStruct obj = { .skip_c_e = false };
> - vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
> + vmstate_load_state(loading, &vmstate_skipping, &obj, 2, NULL);
> g_assert(!qemu_file_get_error(loading));
> g_assert_cmpint(obj.a, ==, 10);
> g_assert_cmpint(obj.b, ==, 20);
> @@ -504,7 +504,7 @@ static void test_load_skip(void)
>
> QEMUFile *loading = open_test_file(false);
> TestStruct obj = { .skip_c_e = true, .c = 300, .e = 500 };
> - vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
> + vmstate_load_state(loading, &vmstate_skipping, &obj, 2, NULL);
> g_assert(!qemu_file_get_error(loading));
> g_assert_cmpint(obj.a, ==, 10);
> g_assert_cmpint(obj.b, ==, 20);
> @@ -773,7 +773,7 @@ static void test_load_q(void)
> TestQtailq tgt;
>
> QTAILQ_INIT(&tgt.q);
> - vmstate_load_state(fload, &vmstate_q, &tgt, 1);
> + vmstate_load_state(fload, &vmstate_q, &tgt, 1, NULL);
> char eof = qemu_get_byte(fload);
> g_assert(!qemu_file_get_error(fload));
> g_assert_cmpint(tgt.i16, ==, obj_q.i16);
> @@ -1127,7 +1127,7 @@ static void test_gtree_load_domain(void)
>
> fload = open_test_file(false);
>
> - vmstate_load_state(fload, &vmstate_domain, dest_domain, 1);
> + vmstate_load_state(fload, &vmstate_domain, dest_domain, 1, NULL);
> eof = qemu_get_byte(fload);
> g_assert(!qemu_file_get_error(fload));
> g_assert_cmpint(orig_domain->id, ==, dest_domain->id);
> @@ -1241,7 +1241,7 @@ static void test_gtree_load_iommu(void)
> qemu_fclose(fsave);
>
> fload = open_test_file(false);
> - vmstate_load_state(fload, &vmstate_iommu, dest_iommu, 1);
> + vmstate_load_state(fload, &vmstate_iommu, dest_iommu, 1, NULL);
> eof = qemu_get_byte(fload);
> g_assert(!qemu_file_get_error(fload));
> g_assert_cmpint(orig_iommu->id, ==, dest_iommu->id);
> @@ -1376,7 +1376,7 @@ static void test_load_qlist(void)
> qemu_fclose(fsave);
>
> fload = open_test_file(false);
> - vmstate_load_state(fload, &vmstate_container, dest_container, 1);
> + vmstate_load_state(fload, &vmstate_container, dest_container, 1,
> NULL);
> eof = qemu_get_byte(fload);
> g_assert(!qemu_file_get_error(fload));
> g_assert_cmpint(eof, ==, QEMU_VM_EOF);
> diff --git a/ui/vdagent.c b/ui/vdagent.c
> index
> c0746fe5b168fdc7aeb4866de2ba0c3387566649..83457dee0767433ad0778b37b41b9c673a0e1860
> 100644
> --- a/ui/vdagent.c
> +++ b/ui/vdagent.c
> @@ -1008,7 +1008,7 @@ static int get_cbinfo(QEMUFile *f, void *pv, size_t
> size,
>
> vdagent_clipboard_peer_register(vd);
>
> - ret = vmstate_load_state(f, &vmstate_cbinfo_array, &cbinfo, 0);
> + ret = vmstate_load_state(f, &vmstate_cbinfo_array, &cbinfo, 0, NULL);
> if (ret) {
> return ret;
> }
>
> --
> 2.50.0
>
>
[-- Attachment #2: Type: text/html, Size: 25305 bytes --]
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 03/24] migration: push Error **errp into qemu_loadvm_state_header()
2025-07-21 11:29 ` [PATCH v6 03/24] migration: push Error **errp into qemu_loadvm_state_header() Arun Menon
@ 2025-07-21 12:34 ` Marc-André Lureau
2025-07-25 7:12 ` Arun Menon
0 siblings, 1 reply; 55+ messages in thread
From: Marc-André Lureau @ 2025-07-21 12:34 UTC (permalink / raw)
To: Arun Menon
Cc: qemu-devel, Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck,
Halil Pasic, Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Alex Bennée, Akihiko Odaki, Dmitry Osipenko, Matthew Rosato
[-- Attachment #1: Type: text/plain, Size: 3185 bytes --]
Hi
On Mon, Jul 21, 2025 at 3:30 PM Arun Menon <armenon@redhat.com> wrote:
> This is an incremental step in converting vmstate loading
> code to report error via Error objects instead of directly
> printing it to console/monitor.
> It is ensured that qemu_loadvm_state_header() must report an error
> in errp, in case of failure.
>
> Signed-off-by: Arun Menon <armenon@redhat.com>
> ---
> migration/savevm.c | 25 ++++++++++++++++---------
> 1 file changed, 16 insertions(+), 9 deletions(-)
>
> diff --git a/migration/savevm.c b/migration/savevm.c
> index
> ab947620f724874f325fb9fb59bef50b7c16fb51..162fb05933fae5993eeef107811f97cb08726ac3
> 100644
> --- a/migration/savevm.c
> +++ b/migration/savevm.c
> @@ -2814,35 +2814,42 @@ qemu_loadvm_section_part_end(QEMUFile *f, uint8_t
> type)
> return 0;
> }
>
> -static int qemu_loadvm_state_header(QEMUFile *f)
> +static int qemu_loadvm_state_header(QEMUFile *f, Error **errp)
> {
> unsigned int v;
> int ret;
>
> v = qemu_get_be32(f);
> if (v != QEMU_VM_FILE_MAGIC) {
> - error_report("Not a migration stream");
> + error_setg(errp, "Not a migration stream, "
> + "magic: %x != %x", v, QEMU_VM_FILE_MAGIC);
> return -EINVAL;
> }
>
> v = qemu_get_be32(f);
> if (v == QEMU_VM_FILE_VERSION_COMPAT) {
> - error_report("SaveVM v2 format is obsolete and don't work
> anymore");
> + error_setg(errp, "SaveVM v2 format is obsolete and no"
> + "longer supported, file version %x != %x",
>
As Akihiko said in patch 2 review, better "not to have line breaks in
string literals" .. here, there is a missing space now.
+ v, QEMU_VM_FILE_VERSION_COMPAT);
> +
> return -ENOTSUP;
> }
> if (v != QEMU_VM_FILE_VERSION) {
> - error_report("Unsupported migration stream version");
> + error_setg(errp, "Unsupported migration stream "
> + "version, file version %x != %x", v,
> QEMU_VM_FILE_VERSION);
> return -ENOTSUP;
> }
>
> if (migrate_get_current()->send_configuration) {
> - if (qemu_get_byte(f) != QEMU_VM_CONFIGURATION) {
> - error_report("Configuration section missing");
> + v = qemu_get_byte(f);
> + if (v != QEMU_VM_CONFIGURATION) {
> + error_setg(errp, "Configuration section missing,"
>
here too
> + "%x != %x", v, QEMU_VM_CONFIGURATION);
> return -EINVAL;
> }
> - ret = vmstate_load_state(f, &vmstate_configuration,
> &savevm_state, 0,
> - NULL);
>
> + ret = vmstate_load_state(f, &vmstate_configuration,
> &savevm_state, 0,
> + errp);
> if (ret) {
> return ret;
> }
> @@ -3119,7 +3126,7 @@ int qemu_loadvm_state(QEMUFile *f)
>
> qemu_loadvm_thread_pool_create(mis);
>
> - ret = qemu_loadvm_state_header(f);
> + ret = qemu_loadvm_state_header(f, NULL);
> if (ret) {
> return ret;
> }
>
> --
> 2.50.0
>
>
[-- Attachment #2: Type: text/html, Size: 4436 bytes --]
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 08/24] migration: push Error **errp into loadvm_process_command()
2025-07-21 11:29 ` [PATCH v6 08/24] migration: push Error **errp into loadvm_process_command() Arun Menon
@ 2025-07-21 12:38 ` Akihiko Odaki
2025-07-25 7:13 ` Arun Menon
0 siblings, 1 reply; 55+ messages in thread
From: Akihiko Odaki @ 2025-07-21 12:38 UTC (permalink / raw)
To: Arun Menon, qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Dmitry Osipenko,
Matthew Rosato
On 2025/07/21 20:29, Arun Menon wrote:
> This is an incremental step in converting vmstate loading
> code to report error via Error objects instead of directly
> printing it to console/monitor.
> It is ensured that loadvm_process_command() must report an error
> in errp, in case of failure.
>
> Signed-off-by: Arun Menon <armenon@redhat.com>
> ---
> migration/savevm.c | 87 +++++++++++++++++++++++++++++++++++++++++-------------
> 1 file changed, 66 insertions(+), 21 deletions(-)
>
> diff --git a/migration/savevm.c b/migration/savevm.c
> index 96af7b412f2ed43468f4bcac8b833cda223f8321..d8feb9e1599d019636cd400ee7ebe594df27bd1d 100644
> --- a/migration/savevm.c
> +++ b/migration/savevm.c
> @@ -2546,12 +2546,13 @@ static int loadvm_postcopy_handle_switchover_start(void)
> * LOADVM_QUIT All good, but exit the loop
> * <0 Error
> */
> -static int loadvm_process_command(QEMUFile *f)
> +static int loadvm_process_command(QEMUFile *f, Error **errp)
> {
> MigrationIncomingState *mis = migration_incoming_get_current();
> uint16_t cmd;
> uint16_t len;
> uint32_t tmp32;
> + int ret;
>
> cmd = qemu_get_be16(f);
> len = qemu_get_be16(f);
> @@ -2562,16 +2563,16 @@ static int loadvm_process_command(QEMUFile *f)
> }
>
> if (cmd >= MIG_CMD_MAX || cmd == MIG_CMD_INVALID) {
> - error_report("MIG_CMD 0x%x unknown (len 0x%x)", cmd, len);
> + error_setg(errp, "MIG_CMD 0x%x unknown (len 0x%x)", cmd, len);
> return -EINVAL;
> }
>
> trace_loadvm_process_command(mig_cmd_args[cmd].name, len);
>
> if (mig_cmd_args[cmd].len != -1 && mig_cmd_args[cmd].len != len) {
> - error_report("%s received with bad length - expecting %zu, got %d",
> - mig_cmd_args[cmd].name,
> - (size_t)mig_cmd_args[cmd].len, len);
> + error_setg(errp, "%s received with bad length - expecting %zu, got %d",
> + mig_cmd_args[cmd].name,
> + (size_t)mig_cmd_args[cmd].len, len);
> return -ERANGE;
> }
>
> @@ -2590,11 +2591,10 @@ static int loadvm_process_command(QEMUFile *f)
> * been created.
> */
> if (migrate_switchover_ack() && !mis->switchover_ack_pending_num) {
> - int ret = migrate_send_rp_switchover_ack(mis);
> + ret = migrate_send_rp_switchover_ack(mis);
> if (ret) {
> - error_report(
> - "Could not send switchover ack RP MSG, err %d (%s)", ret,
> - strerror(-ret));
> + error_setg(errp, "Could not send switchover ack "
> + "RP MSG, err %d (%s)", ret, strerror(-ret));
> return ret;
> }
> }
> @@ -2604,39 +2604,84 @@ static int loadvm_process_command(QEMUFile *f)
> tmp32 = qemu_get_be32(f);
> trace_loadvm_process_command_ping(tmp32);
> if (!mis->to_src_file) {
> - error_report("CMD_PING (0x%x) received with no return path",
> - tmp32);
> + error_setg(errp, "CMD_PING (0x%x) received with no return path",
> + tmp32);
> return -1;
> }
> migrate_send_rp_pong(mis, tmp32);
> break;
>
> case MIG_CMD_PACKAGED:
> - return loadvm_handle_cmd_packaged(mis);
> + ret = loadvm_handle_cmd_packaged(mis);
> + if (ret < 0) {
> + error_setg(errp, "Failed to load device state command: %d", ret);
> + return -1;
This "return -1" is extraneous.
The error_setg() call is later replaced with "[PATCH v6 09/24]
migration: push Error **errp into loadvm_handle_cmd_packaged()", but
this "return -1" is simply removed in the patch. There is no need to add
it in the first place.
> + }
> + return ret;
>
> case MIG_CMD_POSTCOPY_ADVISE:
> - return loadvm_postcopy_handle_advise(mis, len);
> + ret = loadvm_postcopy_handle_advise(mis, len);
> + if (ret < 0) {
> + error_setg(errp, "Failed to load device state command: %d", ret);
> + return -1;
> + }
> + return ret;
>
> case MIG_CMD_POSTCOPY_LISTEN:
> - return loadvm_postcopy_handle_listen(mis);
> + ret = loadvm_postcopy_handle_listen(mis);
> + if (ret < 0) {
> + error_setg(errp, "Failed to load device state command: %d", ret);
> + return -1;
> + }
> + return ret;
>
> case MIG_CMD_POSTCOPY_RUN:
> - return loadvm_postcopy_handle_run(mis);
> + ret = loadvm_postcopy_handle_run(mis);
> + if (ret < 0) {
> + error_setg(errp, "Failed to load device state command: %d", ret);
> + return -1;
> + }
> + return ret;
>
> case MIG_CMD_POSTCOPY_RAM_DISCARD:
> - return loadvm_postcopy_ram_handle_discard(mis, len);
> + ret = loadvm_postcopy_ram_handle_discard(mis, len);
> + if (ret < 0) {
> + error_setg(errp, "Failed to load device state command: %d", ret);
> + return -1;
> + }
> + return ret;
>
> case MIG_CMD_POSTCOPY_RESUME:
> - return loadvm_postcopy_handle_resume(mis);
> + ret = loadvm_postcopy_handle_resume(mis);
> + if (ret < 0) {
> + error_setg(errp, "Failed to load device state command: %d", ret);
> + return -1;
> + }
> + return ret;
>
> case MIG_CMD_RECV_BITMAP:
> - return loadvm_handle_recv_bitmap(mis, len);
> + ret = loadvm_handle_recv_bitmap(mis, len);
> + if (ret < 0) {
> + error_setg(errp, "Failed to load device state command: %d", ret);
> + return -1;
> + }
> + return ret;
>
> case MIG_CMD_ENABLE_COLO:
> - return loadvm_process_enable_colo(mis);
> + ret = loadvm_process_enable_colo(mis);
> + if (ret < 0) {
> + error_setg(errp, "Failed to load device state command: %d", ret);
> + return -1;
> + }
> + return ret;
>
> case MIG_CMD_SWITCHOVER_START:
> - return loadvm_postcopy_handle_switchover_start();
> + ret = loadvm_postcopy_handle_switchover_start();
> + if (ret < 0) {
> + error_setg(errp, "Failed to load device state command: %d", ret);
> + return -1;
> + }
> + return ret;
> }
>
> return 0;
> @@ -3074,7 +3119,7 @@ retry:
> }
> break;
> case QEMU_VM_COMMAND:
> - ret = loadvm_process_command(f);
> + ret = loadvm_process_command(f, NULL);
> trace_qemu_loadvm_state_section_command(ret);
> if ((ret < 0) || (ret == LOADVM_QUIT)) {
> goto out;
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 11/24] migration: push Error **errp into loadvm_postcopy_handle_advise()
2025-07-21 11:29 ` [PATCH v6 11/24] migration: push Error **errp into loadvm_postcopy_handle_advise() Arun Menon
@ 2025-07-21 12:43 ` Akihiko Odaki
2025-07-25 7:14 ` Arun Menon
0 siblings, 1 reply; 55+ messages in thread
From: Akihiko Odaki @ 2025-07-21 12:43 UTC (permalink / raw)
To: Arun Menon, qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Dmitry Osipenko,
Matthew Rosato, Daniel P. Berrangé
On 2025/07/21 20:29, Arun Menon wrote:
> This is an incremental step in converting vmstate loading
> code to report error via Error objects instead of directly
> printing it to console/monitor.
> It is ensured that loadvm_postcopy_handle_advise() must report an error
> in errp, in case of failure.
>
> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
> Signed-off-by: Arun Menon <armenon@redhat.com>
> ---
> migration/savevm.c | 39 +++++++++++++++++----------------------
> 1 file changed, 17 insertions(+), 22 deletions(-)
>
> diff --git a/migration/savevm.c b/migration/savevm.c
> index 6b8c78bfb9bde2a8e7500b0342cd386b0d12db97..4a3db9498678a19597257e683029cd3f6c8d1a65 100644
> --- a/migration/savevm.c
> +++ b/migration/savevm.c
> @@ -1912,39 +1912,39 @@ enum LoadVMExitCodes {
> * quickly.
> */
> static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis,
> - uint16_t len)
> + uint16_t len, Error **errp)
> {
> PostcopyState ps = postcopy_state_set(POSTCOPY_INCOMING_ADVISE);
> uint64_t remote_pagesize_summary, local_pagesize_summary, remote_tps;
> size_t page_size = qemu_target_page_size();
> - Error *local_err = NULL;
>
> trace_loadvm_postcopy_handle_advise();
> if (ps != POSTCOPY_INCOMING_NONE) {
> - error_report("CMD_POSTCOPY_ADVISE in wrong postcopy state (%d)", ps);
> + error_setg(errp, "CMD_POSTCOPY_ADVISE in wrong postcopy "
> + "state (%d)", ps);
> return -1;
> }
>
> switch (len) {
> case 0:
> if (migrate_postcopy_ram()) {
> - error_report("RAM postcopy is enabled but have 0 byte advise");
> + error_setg(errp, "RAM postcopy is enabled but have 0 byte advise");
> return -EINVAL;
> }
> return 0;
> case 8 + 8:
> if (!migrate_postcopy_ram()) {
> - error_report("RAM postcopy is disabled but have 16 byte advise");
> + error_setg(errp, "RAM postcopy is disabled but have 16 "
> + "byte advise");
> return -EINVAL;
> }
> break;
> default:
> - error_report("CMD_POSTCOPY_ADVISE invalid length (%d)", len);
> + error_setg(errp, "CMD_POSTCOPY_ADVISE invalid length (%d)", len);
> return -EINVAL;
> }
>
> - if (!postcopy_ram_supported_by_host(mis, &local_err)) {
> - error_report_err(local_err);
> + if (!postcopy_ram_supported_by_host(mis, errp)) {
> postcopy_state_set(POSTCOPY_INCOMING_NONE);
> return -1;
> }
> @@ -1967,9 +1967,9 @@ static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis,
> * also fails when passed to an older qemu that doesn't
> * do huge pages.
> */
> - error_report("Postcopy needs matching RAM page sizes (s=%" PRIx64
> - " d=%" PRIx64 ")",
> - remote_pagesize_summary, local_pagesize_summary);
> + error_setg(errp, "Postcopy needs matching RAM "
> + "page sizes (s=%" PRIx64 " d=%" PRIx64 ")",
> + remote_pagesize_summary, local_pagesize_summary);
> return -1;
> }
>
> @@ -1979,17 +1979,17 @@ static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis,
> * Again, some differences could be dealt with, but for now keep it
> * simple.
> */
> - error_report("Postcopy needs matching target page sizes (s=%d d=%zd)",
> - (int)remote_tps, page_size);
> + error_setg(errp, "Postcopy needs matching target "
> + "page sizes (s=%d d=%zd)", (int)remote_tps, page_size);
> return -1;
> }
>
> - if (postcopy_notify(POSTCOPY_NOTIFY_INBOUND_ADVISE, &local_err)) {
> - error_report_err(local_err);
> + if (postcopy_notify(POSTCOPY_NOTIFY_INBOUND_ADVISE, errp)) {
> return -1;
> }
>
> - if (ram_postcopy_incoming_init(mis, NULL) < 0) {
> + if (ram_postcopy_incoming_init(mis, errp) < 0) {
> + error_prepend(errp, "PostCopy RAM incoming init failed ");
Nitpick: s/PostCopy/Postcopy/ for consistency with other error messages.
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 15/24] migration: make loadvm_postcopy_handle_resume() void
2025-07-21 11:29 ` [PATCH v6 15/24] migration: make loadvm_postcopy_handle_resume() void Arun Menon
@ 2025-07-21 12:46 ` Akihiko Odaki
2025-07-25 7:15 ` Arun Menon
0 siblings, 1 reply; 55+ messages in thread
From: Akihiko Odaki @ 2025-07-21 12:46 UTC (permalink / raw)
To: Arun Menon, qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Dmitry Osipenko,
Matthew Rosato, Daniel P. Berrangé
On 2025/07/21 20:29, Arun Menon wrote:
> This is an incremental step in converting vmstate loading
> code to report error via Error objects instead of directly
> printing it to console/monitor.
>
> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
> Signed-off-by: Arun Menon <armenon@redhat.com>
> ---
> migration/savevm.c | 16 +++++-----------
> 1 file changed, 5 insertions(+), 11 deletions(-)
>
> diff --git a/migration/savevm.c b/migration/savevm.c
> index e472f79d5d5c4fb4410a28cbf43c298be028f4b4..6887877f2f8648f66e34bdb1cc3ca6dc7514f9df 100644
> --- a/migration/savevm.c
> +++ b/migration/savevm.c
> @@ -2339,12 +2339,12 @@ static void migrate_send_rp_req_pages_pending(MigrationIncomingState *mis)
> }
> }
>
> -static int loadvm_postcopy_handle_resume(MigrationIncomingState *mis)
> +static void loadvm_postcopy_handle_resume(MigrationIncomingState *mis)
> {
> if (mis->state != MIGRATION_STATUS_POSTCOPY_RECOVER) {
> - error_report("%s: illegal resume received", __func__);
> + warn_report("%s: illegal resume received", __func__);
> /* Don't fail the load, only for this. */
> - return 0;
> + return;
> }
>
> /*
> @@ -2396,8 +2396,6 @@ static int loadvm_postcopy_handle_resume(MigrationIncomingState *mis)
> /* Kick the fast ram load thread too */
> qemu_sem_post(&mis->postcopy_pause_sem_fast_load);
> }
> -
> - return 0;
> }
>
> /**
> @@ -2635,12 +2633,8 @@ static int loadvm_process_command(QEMUFile *f, Error **errp)
> return loadvm_postcopy_ram_handle_discard(mis, len, errp);
>
> case MIG_CMD_POSTCOPY_RESUME:
> - ret = loadvm_postcopy_handle_resume(mis);
> - if (ret < 0) {
> - error_setg(errp, "Failed to load device state command: %d", ret);
> - return -1;
> - }
> - return ret;
> + loadvm_postcopy_handle_resume(mis);
> + return 0;
This patch can be moved before "[PATCH v6 08/24] migration: push Error
**errp into loadvm_process_command()" to make it smaller.
>
> case MIG_CMD_RECV_BITMAP:
> ret = loadvm_handle_recv_bitmap(mis, len);
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 20/24] migration: push Error **errp into qemu_loadvm_state()
2025-07-21 11:29 ` [PATCH v6 20/24] migration: push Error **errp into qemu_loadvm_state() Arun Menon
@ 2025-07-21 13:01 ` Akihiko Odaki
2025-07-25 7:09 ` Arun Menon
0 siblings, 1 reply; 55+ messages in thread
From: Akihiko Odaki @ 2025-07-21 13:01 UTC (permalink / raw)
To: Arun Menon, qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Dmitry Osipenko,
Matthew Rosato
On 2025/07/21 20:29, Arun Menon wrote:
> This is an incremental step in converting vmstate loading
> code to report error via Error objects instead of directly
> printing it to console/monitor.
> It is ensured that qemu_loadvm_state() must report an error
> in errp, in case of failure.
>
> Signed-off-by: Arun Menon <armenon@redhat.com>
> ---
> migration/migration.c | 5 +++--
> migration/savevm.c | 25 +++++++++++++------------
> migration/savevm.h | 2 +-
> 3 files changed, 17 insertions(+), 15 deletions(-)
>
> diff --git a/migration/migration.c b/migration/migration.c
> index d748a02712dc4ebc2de6b0488fb199c92c4d4079..09fadf36dbbbd2f68df1e4cafbf3a51b18531978 100644
> --- a/migration/migration.c
> +++ b/migration/migration.c
> @@ -881,7 +881,7 @@ process_incoming_migration_co(void *opaque)
> MIGRATION_STATUS_ACTIVE);
>
> mis->loadvm_co = qemu_coroutine_self();
> - ret = qemu_loadvm_state(mis->from_src_file);
> + ret = qemu_loadvm_state(mis->from_src_file, &local_err);
> mis->loadvm_co = NULL;
>
> trace_vmstate_downtime_checkpoint("dst-precopy-loadvm-completed");
> @@ -908,7 +908,8 @@ process_incoming_migration_co(void *opaque)
> }
>
> if (ret < 0) {
> - error_setg(&local_err, "load of migration failed: %s", strerror(-ret));
> + error_prepend(&local_err, "load of migration failed: %s ",
> + strerror(-ret));
> goto fail;
> }
>
> diff --git a/migration/savevm.c b/migration/savevm.c
> index ba146f91427f2a36880aadeb16b11ab2b7df099a..1261e81c86f836e6b5a155ba1880b5823a779567 100644
> --- a/migration/savevm.c
> +++ b/migration/savevm.c
> @@ -3137,27 +3137,24 @@ out:
> return ret;
> }
>
> -int qemu_loadvm_state(QEMUFile *f)
> +int qemu_loadvm_state(QEMUFile *f, Error **errp)
> {
> MigrationState *s = migrate_get_current();
> MigrationIncomingState *mis = migration_incoming_get_current();
> - Error *local_err = NULL;
> int ret;
>
> - if (qemu_savevm_state_blocked(&local_err)) {
> - error_report_err(local_err);
> + if (qemu_savevm_state_blocked(errp)) {
> return -EINVAL;
> }
>
> qemu_loadvm_thread_pool_create(mis);
>
> - ret = qemu_loadvm_state_header(f, NULL);
> + ret = qemu_loadvm_state_header(f, errp);
> if (ret) {
> return ret;
> }
>
> - if (qemu_loadvm_state_setup(f, &local_err) != 0) {
> - error_report_err(local_err);
> + if (qemu_loadvm_state_setup(f, errp) != 0) {
> return -EINVAL;
> }
>
> @@ -3167,7 +3164,7 @@ int qemu_loadvm_state(QEMUFile *f)
>
> cpu_synchronize_all_pre_loadvm();
>
> - ret = qemu_loadvm_state_main(f, mis, NULL);
> + ret = qemu_loadvm_state_main(f, mis, errp);
> qemu_event_set(&mis->main_thread_load_event);
>
> trace_qemu_loadvm_state_post_main(ret);
> @@ -3185,8 +3182,12 @@ int qemu_loadvm_state(QEMUFile *f)
> if (migrate_has_error(migrate_get_current()) ||
> !qemu_loadvm_thread_pool_wait(s, mis)) {
> ret = -EINVAL;
> + error_setg(errp, "Error while loading vmstate : %d", ret);
Printing ret here does not help much as ret is always -EINVAL here.
Having an error message different from qemu_file_get_error() will help
more as it will allow reliably distinguishing these two error conditions.
> } else {
> ret = qemu_file_get_error(f);
> + if (ret < 0) {
> + error_setg(errp, "Error while loading vmstate : %d", ret);
> + }
> }
> }
> /*
> @@ -3472,10 +3473,10 @@ void qmp_xen_load_devices_state(const char *filename, Error **errp)
> f = qemu_file_new_input(QIO_CHANNEL(ioc));
> object_unref(OBJECT(ioc));
>
> - ret = qemu_loadvm_state(f);
> + ret = qemu_loadvm_state(f, errp);
> qemu_fclose(f);
> if (ret < 0) {
> - error_setg(errp, "loading Xen device state failed");
> + error_prepend(errp, "loading Xen device state failed ");
> }
> migration_incoming_state_destroy();
> }
> @@ -3546,13 +3547,13 @@ bool load_snapshot(const char *name, const char *vmstate,
> ret = -EINVAL;
> goto err_drain;
> }
> - ret = qemu_loadvm_state(f);
> + ret = qemu_loadvm_state(f, errp);
> migration_incoming_state_destroy();
>
> bdrv_drain_all_end();
>
> if (ret < 0) {
> - error_setg(errp, "Error %d while loading VM state", ret);
> + error_prepend(errp, "Error %d while loading VM state ", ret);
> return false;
> }
>
> diff --git a/migration/savevm.h b/migration/savevm.h
> index fd7419e6ff90062970ed246b3ea71e6d49a6e372..a6df5198f3fe1a39fc0e6ce3e79cf7a5d8e032db 100644
> --- a/migration/savevm.h
> +++ b/migration/savevm.h
> @@ -64,7 +64,7 @@ void qemu_savevm_send_colo_enable(QEMUFile *f);
> void qemu_savevm_live_state(QEMUFile *f);
> int qemu_save_device_state(QEMUFile *f);
>
> -int qemu_loadvm_state(QEMUFile *f);
> +int qemu_loadvm_state(QEMUFile *f, Error **errp);
> void qemu_loadvm_state_cleanup(MigrationIncomingState *mis);
> int qemu_loadvm_state_main(QEMUFile *f, MigrationIncomingState *mis,
> Error **errp);
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 23/24] migration: Add error-parameterized function variants in VMSD struct
2025-07-21 11:29 ` [PATCH v6 23/24] migration: Add error-parameterized function variants in VMSD struct Arun Menon
@ 2025-07-21 13:14 ` Akihiko Odaki
2025-07-21 13:29 ` Daniel P. Berrangé
2025-07-21 13:32 ` Daniel P. Berrangé
1 sibling, 1 reply; 55+ messages in thread
From: Akihiko Odaki @ 2025-07-21 13:14 UTC (permalink / raw)
To: Arun Menon, qemu-devel
Cc: Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Dmitry Osipenko,
Matthew Rosato
On 2025/07/21 20:29, Arun Menon wrote:
> - We need to have good error reporting in the callbacks in
> VMStateDescription struct. Specifically pre_save, post_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.
>
> Signed-off-by: Arun Menon <armenon@redhat.com>
> ---
> include/migration/vmstate.h | 11 +++++++++++
> migration/vmstate.c | 47 +++++++++++++++++++++++++++++++++++++++------
> 2 files changed, 52 insertions(+), 6 deletions(-)
>
> diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
> index 056781b1c21e737583f081594d9f88b32adfd674..53fa72c1bbde399be02c88fc8745fdbb79bfd7c8 100644
> --- a/include/migration/vmstate.h
> +++ b/include/migration/vmstate.h
> @@ -200,15 +200,26 @@ 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.
> */
> +
> 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);
> + int (*post_save_errp)(void *opaque, Error **errp);
I think the new functions should have void as return value instead.
As I discussed before, I think having an integer return value is a
source of confusion:
https://lore.kernel.org/qemu-devel/0447e269-c242-4cd7-b68e-d0c7211784a7@rsg.ci.i.u-tokyo.ac.jp/
In the previous discussion, I suggested using bool, but void fits better
in this particular case.
include/qapi/error.h says:
> Whenever practical, also return a value that indicates success /
> failure. This can make the error checking more concise, and can avoid
> useless error object creation and destruction. Note that we still
> have many functions returning void.
There will be more implementations of these function pointers than their
callers, so it makes more sense to let return void and make
implementations more concise while making the callers less so. There is
also DeviceRealize, an example of function pointer type that takes errp
but returns void.
> bool (*needed)(void *opaque);
> bool (*dev_unplug_pending)(void *opaque);
>
> diff --git a/migration/vmstate.c b/migration/vmstate.c
> index 288b57e1ed778cce21247b64d5e97dfef41ad586..d96908d12ccffaef421e5d399a48e26cada2cb77 100644
> --- a/migration/vmstate.c
> +++ b/migration/vmstate.c
> @@ -152,7 +152,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) {
> + error_prepend(errp, "VM pre load 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, "VM pre load failed for: '%s', "
> @@ -236,10 +245,17 @@ 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, "VM Post load 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, "VM Post load failed for: %s, version_id: %d,"
> + error_setg(errp, "VM Post load failed for: %s, version_id: %d, "
> "minimum_version: %d, ret: %d", vmsd->name,
> vmsd->version_id, vmsd->minimum_version_id, ret);
> }
> @@ -410,11 +426,19 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
> void *opaque, JSONWriter *vmdesc, int version_id, Error **errp)
> {
> int ret = 0;
> + Error *local_err = NULL;
> 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) {
> + error_prepend(errp, "pre-save failed: %s ", vmsd->name);
> + return ret;
> + }
> + } else if (vmsd->pre_save) {
> ret = vmsd->pre_save(opaque);
> trace_vmstate_save_state_pre_save_res(vmsd->name, ret);
> if (ret) {
> @@ -524,7 +548,12 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
> if (ret) {
> error_setg(errp, "Save of field %s/%s failed",
> vmsd->name, field->name);
> - if (vmsd->post_save) {
> + if (vmsd->post_save_errp) {
> + ret = vmsd->post_save_errp(opaque, &local_err);
> + if (ret < 0) {
> + error_propagate(errp, local_err);
> + }
> + } else if (vmsd->post_save) {
> vmsd->post_save(opaque);
> }
> return ret;
> @@ -552,7 +581,13 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
>
> ret = vmstate_subsection_save(f, vmsd, opaque, vmdesc, errp);
>
> - if (vmsd->post_save) {
> + if (vmsd->post_save_errp) {
> + int ps_ret = vmsd->post_save_errp(opaque, &local_err);
> + if (!ret && ps_ret) {
> + ret = ps_ret;
> + error_propagate(errp, local_err);
> + }
> + } else if (vmsd->post_save) {
> int ps_ret = vmsd->post_save(opaque);
> if (!ret && ps_ret) {
> ret = ps_ret;
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 23/24] migration: Add error-parameterized function variants in VMSD struct
2025-07-21 13:14 ` Akihiko Odaki
@ 2025-07-21 13:29 ` Daniel P. Berrangé
2025-07-21 15:15 ` Akihiko Odaki
0 siblings, 1 reply; 55+ messages in thread
From: Daniel P. Berrangé @ 2025-07-21 13:29 UTC (permalink / raw)
To: Akihiko Odaki
Cc: Arun Menon, qemu-devel, Michael S. Tsirkin, Marcel Apfelbaum,
Cornelia Huck, Halil Pasic, Eric Farman, Richard Henderson,
David Hildenbrand, Ilya Leoshkevich, Thomas Huth,
Christian Borntraeger, Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Dmitry Osipenko,
Matthew Rosato
On Mon, Jul 21, 2025 at 10:14:30PM +0900, Akihiko Odaki wrote:
> On 2025/07/21 20:29, Arun Menon wrote:
> > - We need to have good error reporting in the callbacks in
> > VMStateDescription struct. Specifically pre_save, post_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.
> >
> > Signed-off-by: Arun Menon <armenon@redhat.com>
> > ---
> > include/migration/vmstate.h | 11 +++++++++++
> > migration/vmstate.c | 47 +++++++++++++++++++++++++++++++++++++++------
> > 2 files changed, 52 insertions(+), 6 deletions(-)
> >
> > diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
> > index 056781b1c21e737583f081594d9f88b32adfd674..53fa72c1bbde399be02c88fc8745fdbb79bfd7c8 100644
> > --- a/include/migration/vmstate.h
> > +++ b/include/migration/vmstate.h
> > @@ -200,15 +200,26 @@ 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.
> > */
> > +
> > 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);
> > + int (*post_save_errp)(void *opaque, Error **errp);
>
> I think the new functions should have void as return value instead.
>
> As I discussed before, I think having an integer return value is a source of
> confusion:
> https://lore.kernel.org/qemu-devel/0447e269-c242-4cd7-b68e-d0c7211784a7@rsg.ci.i.u-tokyo.ac.jp/
>
> In the previous discussion, I suggested using bool, but void fits better in
> this particular case.
>
> include/qapi/error.h says:
> > Whenever practical, also return a value that indicates success /
> > failure. This can make the error checking more concise, and can avoid
> > useless error object creation and destruction. Note that we still
> > have many functions returning void.
>
> There will be more implementations of these function pointers than their
> callers, so it makes more sense to let return void and make implementations
> more concise while making the callers less so. There is also DeviceRealize,
> an example of function pointer type that takes errp but returns void.
No, please do NOT make these functions void. As that text you quote
says, we want functions to return a value indicating success/failure.
'void' return is a historical practice we don't want to continue
in QEMU.
Given that the existing methods all return 'int', we should remain
consistent with the new functions and return 'int', with -1 for
failure, 0 for success, and not use bool.
With regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 23/24] migration: Add error-parameterized function variants in VMSD struct
2025-07-21 11:29 ` [PATCH v6 23/24] migration: Add error-parameterized function variants in VMSD struct Arun Menon
2025-07-21 13:14 ` Akihiko Odaki
@ 2025-07-21 13:32 ` Daniel P. Berrangé
2025-07-21 13:54 ` Arun Menon
1 sibling, 1 reply; 55+ messages in thread
From: Daniel P. Berrangé @ 2025-07-21 13:32 UTC (permalink / raw)
To: Arun Menon
Cc: qemu-devel, Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck,
Halil Pasic, Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato
On Mon, Jul 21, 2025 at 04:59:28PM +0530, Arun Menon wrote:
> - We need to have good error reporting in the callbacks in
> VMStateDescription struct. Specifically pre_save, post_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.
>
> Signed-off-by: Arun Menon <armenon@redhat.com>
> ---
> include/migration/vmstate.h | 11 +++++++++++
> migration/vmstate.c | 47 +++++++++++++++++++++++++++++++++++++++------
> 2 files changed, 52 insertions(+), 6 deletions(-)
>
> diff --git a/migration/vmstate.c b/migration/vmstate.c
> index 288b57e1ed778cce21247b64d5e97dfef41ad586..d96908d12ccffaef421e5d399a48e26cada2cb77 100644
> --- a/migration/vmstate.c
> +++ b/migration/vmstate.c
> @@ -524,7 +548,12 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
> if (ret) {
> error_setg(errp, "Save of field %s/%s failed",
> vmsd->name, field->name);
> - if (vmsd->post_save) {
> + if (vmsd->post_save_errp) {
> + ret = vmsd->post_save_errp(opaque, &local_err);
> + if (ret < 0) {
> + error_propagate(errp, local_err);
> + }
This is still broken. 'errp' is already set a few lines earlier, so you
can't propagate a new error over the top
> + } else if (vmsd->post_save) {
> vmsd->post_save(opaque);
> }
> return ret;
> @@ -552,7 +581,13 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
>
> ret = vmstate_subsection_save(f, vmsd, opaque, vmdesc, errp);
>
> - if (vmsd->post_save) {
> + if (vmsd->post_save_errp) {
> + int ps_ret = vmsd->post_save_errp(opaque, &local_err);
> + if (!ret && ps_ret) {
> + ret = ps_ret;
> + error_propagate(errp, local_err);
> + }
Again, propagating over the top of an existing error
> + } else if (vmsd->post_save) {
> int ps_ret = vmsd->post_save(opaque);
> if (!ret && ps_ret) {
> ret = ps_ret;
>
> --
> 2.50.0
>
>
With regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 23/24] migration: Add error-parameterized function variants in VMSD struct
2025-07-21 13:32 ` Daniel P. Berrangé
@ 2025-07-21 13:54 ` Arun Menon
2025-07-21 14:05 ` Daniel P. Berrangé
0 siblings, 1 reply; 55+ messages in thread
From: Arun Menon @ 2025-07-21 13:54 UTC (permalink / raw)
To: Daniel P. Berrangé
Cc: qemu-devel, Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck,
Halil Pasic, Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato
Hi,
Thank you for the review.
On Mon, Jul 21, 2025 at 02:32:48PM +0100, Daniel P. Berrangé wrote:
> On Mon, Jul 21, 2025 at 04:59:28PM +0530, Arun Menon wrote:
> > - We need to have good error reporting in the callbacks in
> > VMStateDescription struct. Specifically pre_save, post_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.
> >
> > Signed-off-by: Arun Menon <armenon@redhat.com>
> > ---
> > include/migration/vmstate.h | 11 +++++++++++
> > migration/vmstate.c | 47 +++++++++++++++++++++++++++++++++++++++------
> > 2 files changed, 52 insertions(+), 6 deletions(-)
> >
>
> > diff --git a/migration/vmstate.c b/migration/vmstate.c
> > index 288b57e1ed778cce21247b64d5e97dfef41ad586..d96908d12ccffaef421e5d399a48e26cada2cb77 100644
> > --- a/migration/vmstate.c
> > +++ b/migration/vmstate.c
>
> > @@ -524,7 +548,12 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
> > if (ret) {
> > error_setg(errp, "Save of field %s/%s failed",
> > vmsd->name, field->name);
> > - if (vmsd->post_save) {
> > + if (vmsd->post_save_errp) {
> > + ret = vmsd->post_save_errp(opaque, &local_err);
> > + if (ret < 0) {
> > + error_propagate(errp, local_err);
> > + }
>
> This is still broken. 'errp' is already set a few lines earlier, so you
> can't propagate a new error over the top
I was wondering that we should preserve the first error that was encountered.
So even if local_err was set, and in case errp already has an error, then it will
be a no-op and local_err will be freed.
>
> > + } else if (vmsd->post_save) {
> > vmsd->post_save(opaque);
> > }
> > return ret;
> > @@ -552,7 +581,13 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
> >
> > ret = vmstate_subsection_save(f, vmsd, opaque, vmdesc, errp);
> >
> > - if (vmsd->post_save) {
> > + if (vmsd->post_save_errp) {
> > + int ps_ret = vmsd->post_save_errp(opaque, &local_err);
> > + if (!ret && ps_ret) {
> > + ret = ps_ret;
> > + error_propagate(errp, local_err);
> > + }
>
> Again, propagating over the top of an existing error
Sorry, correct me if I am wrong.
Since we have 'if (!ret && ps_ret)' ,
if vmstate_subsection_save() fails, the above condition will not hold true.
Only if the first function call vmstate_subsection_save() is successful and the second one
post_save_errp() fails then we try to propagate, again hoping to preserve the first error.
>
> > + } else if (vmsd->post_save) {
> > int ps_ret = vmsd->post_save(opaque);
> > if (!ret && ps_ret) {
> > ret = ps_ret;
> >
> > --
> > 2.50.0
> >
> >
>
> With regards,
> Daniel
> --
> |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org -o- https://fstop138.berrange.com :|
> |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
>
Regards,
Arun Menon
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 23/24] migration: Add error-parameterized function variants in VMSD struct
2025-07-21 13:54 ` Arun Menon
@ 2025-07-21 14:05 ` Daniel P. Berrangé
2025-07-21 15:10 ` Arun Menon
0 siblings, 1 reply; 55+ messages in thread
From: Daniel P. Berrangé @ 2025-07-21 14:05 UTC (permalink / raw)
To: Arun Menon
Cc: qemu-devel, Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck,
Halil Pasic, Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato
On Mon, Jul 21, 2025 at 07:24:23PM +0530, Arun Menon wrote:
> Hi,
> Thank you for the review.
>
> On Mon, Jul 21, 2025 at 02:32:48PM +0100, Daniel P. Berrangé wrote:
> > On Mon, Jul 21, 2025 at 04:59:28PM +0530, Arun Menon wrote:
> > > - We need to have good error reporting in the callbacks in
> > > VMStateDescription struct. Specifically pre_save, post_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.
> > >
> > > Signed-off-by: Arun Menon <armenon@redhat.com>
> > > ---
> > > include/migration/vmstate.h | 11 +++++++++++
> > > migration/vmstate.c | 47 +++++++++++++++++++++++++++++++++++++++------
> > > 2 files changed, 52 insertions(+), 6 deletions(-)
> > >
> >
> > > diff --git a/migration/vmstate.c b/migration/vmstate.c
> > > index 288b57e1ed778cce21247b64d5e97dfef41ad586..d96908d12ccffaef421e5d399a48e26cada2cb77 100644
> > > --- a/migration/vmstate.c
> > > +++ b/migration/vmstate.c
> >
> > > @@ -524,7 +548,12 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
> > > if (ret) {
> > > error_setg(errp, "Save of field %s/%s failed",
> > > vmsd->name, field->name);
> > > - if (vmsd->post_save) {
> > > + if (vmsd->post_save_errp) {
> > > + ret = vmsd->post_save_errp(opaque, &local_err);
> > > + if (ret < 0) {
> > > + error_propagate(errp, local_err);
> > > + }
> >
> > This is still broken. 'errp' is already set a few lines earlier, so you
> > can't propagate a new error over the top
>
> I was wondering that we should preserve the first error that was encountered.
> So even if local_err was set, and in case errp already has an error, then it will
> be a no-op and local_err will be freed.
We know that 'local_err' is definitely set when 'post_save_errp' is called,
because there's a call to 'error_setg' right above it.
> > > + } else if (vmsd->post_save) {
> > > vmsd->post_save(opaque);
> > > }
... pre-existing mistake not checking return value of
post_save.
> > > return ret;
> > > @@ -552,7 +581,13 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
> > >
> > > ret = vmstate_subsection_save(f, vmsd, opaque, vmdesc, errp);
> > >
> > > - if (vmsd->post_save) {
> > > + if (vmsd->post_save_errp) {
> > > + int ps_ret = vmsd->post_save_errp(opaque, &local_err);
> > > + if (!ret && ps_ret) {
> > > + ret = ps_ret;
> > > + error_propagate(errp, local_err);
> > > + }
> >
> > Again, propagating over the top of an existing error
>
> Sorry, correct me if I am wrong.
> Since we have 'if (!ret && ps_ret)' ,
> if vmstate_subsection_save() fails, the above condition will not hold true.
> Only if the first function call vmstate_subsection_save() is successful and the second one
> post_save_errp() fails then we try to propagate, again hoping to preserve the first error.
Opps, yes, you're right - I missed the 'ps_ret' check. That means this
code is a memory leak when 'ret' is non-zero, as nothing frees 'local_err'
in that case.
>
> >
> > > + } else if (vmsd->post_save) {
> > > int ps_ret = vmsd->post_save(opaque);
> > > if (!ret && ps_ret) {
> > > ret = ps_ret;
> > >
> > > --
> > > 2.50.0
> > >
> > >
> >
> > With regards,
> > Daniel
> > --
> > |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
> > |: https://libvirt.org -o- https://fstop138.berrange.com :|
> > |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
> >
>
> Regards,
> Arun Menon
>
With regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 23/24] migration: Add error-parameterized function variants in VMSD struct
2025-07-21 14:05 ` Daniel P. Berrangé
@ 2025-07-21 15:10 ` Arun Menon
2025-07-25 6:39 ` Arun Menon
0 siblings, 1 reply; 55+ messages in thread
From: Arun Menon @ 2025-07-21 15:10 UTC (permalink / raw)
To: Daniel P. Berrangé
Cc: qemu-devel, Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck,
Halil Pasic, Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato
On Mon, Jul 21, 2025 at 03:05:59PM +0100, Daniel P. Berrangé wrote:
> On Mon, Jul 21, 2025 at 07:24:23PM +0530, Arun Menon wrote:
> > Hi,
> > Thank you for the review.
> >
> > On Mon, Jul 21, 2025 at 02:32:48PM +0100, Daniel P. Berrangé wrote:
> > > On Mon, Jul 21, 2025 at 04:59:28PM +0530, Arun Menon wrote:
> > > > - We need to have good error reporting in the callbacks in
> > > > VMStateDescription struct. Specifically pre_save, post_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.
> > > >
> > > > Signed-off-by: Arun Menon <armenon@redhat.com>
> > > > ---
> > > > include/migration/vmstate.h | 11 +++++++++++
> > > > migration/vmstate.c | 47 +++++++++++++++++++++++++++++++++++++++------
> > > > 2 files changed, 52 insertions(+), 6 deletions(-)
> > > >
> > >
> > > > diff --git a/migration/vmstate.c b/migration/vmstate.c
> > > > index 288b57e1ed778cce21247b64d5e97dfef41ad586..d96908d12ccffaef421e5d399a48e26cada2cb77 100644
> > > > --- a/migration/vmstate.c
> > > > +++ b/migration/vmstate.c
> > >
> > > > @@ -524,7 +548,12 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
> > > > if (ret) {
> > > > error_setg(errp, "Save of field %s/%s failed",
> > > > vmsd->name, field->name);
> > > > - if (vmsd->post_save) {
> > > > + if (vmsd->post_save_errp) {
> > > > + ret = vmsd->post_save_errp(opaque, &local_err);
> > > > + if (ret < 0) {
> > > > + error_propagate(errp, local_err);
> > > > + }
> > >
> > > This is still broken. 'errp' is already set a few lines earlier, so you
> > > can't propagate a new error over the top
> >
> > I was wondering that we should preserve the first error that was encountered.
> > So even if local_err was set, and in case errp already has an error, then it will
> > be a no-op and local_err will be freed.
>
> We know that 'local_err' is definitely set when 'post_save_errp' is called,
> because there's a call to 'error_setg' right above it.
mmm, error_setg() above that sets errp, local_err is set only of post_save_errp() has
errors. Do we want both the erros to be propagated? or is it okay to propagate the first
error that was encountered.
>
>
>
> > > > + } else if (vmsd->post_save) {
> > > > vmsd->post_save(opaque);
> > > > }
>
> ... pre-existing mistake not checking return value of
> post_save.
>
> > > > return ret;
> > > > @@ -552,7 +581,13 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
> > > >
> > > > ret = vmstate_subsection_save(f, vmsd, opaque, vmdesc, errp);
> > > >
> > > > - if (vmsd->post_save) {
> > > > + if (vmsd->post_save_errp) {
> > > > + int ps_ret = vmsd->post_save_errp(opaque, &local_err);
> > > > + if (!ret && ps_ret) {
> > > > + ret = ps_ret;
> > > > + error_propagate(errp, local_err);
> > > > + }
> > >
> > > Again, propagating over the top of an existing error
> >
> > Sorry, correct me if I am wrong.
> > Since we have 'if (!ret && ps_ret)' ,
> > if vmstate_subsection_save() fails, the above condition will not hold true.
> > Only if the first function call vmstate_subsection_save() is successful and the second one
> > post_save_errp() fails then we try to propagate, again hoping to preserve the first error.
>
> Opps, yes, you're right - I missed the 'ps_ret' check. That means this
> code is a memory leak when 'ret' is non-zero, as nothing frees 'local_err'
> in that case.
Yes, maybe I can null check local_err and error_free() it.
>
> >
> > >
> > > > + } else if (vmsd->post_save) {
> > > > int ps_ret = vmsd->post_save(opaque);
> > > > if (!ret && ps_ret) {
> > > > ret = ps_ret;
> > > >
> > > > --
> > > > 2.50.0
> > > >
> > > >
> > >
> > > With regards,
> > > Daniel
> > > --
> > > |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
> > > |: https://libvirt.org -o- https://fstop138.berrange.com :|
> > > |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
> > >
> >
> > Regards,
> > Arun Menon
> >
>
> With regards,
> Daniel
> --
> |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org -o- https://fstop138.berrange.com :|
> |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
>
Regards,
Arun
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 23/24] migration: Add error-parameterized function variants in VMSD struct
2025-07-21 13:29 ` Daniel P. Berrangé
@ 2025-07-21 15:15 ` Akihiko Odaki
2025-08-09 8:17 ` Markus Armbruster
0 siblings, 1 reply; 55+ messages in thread
From: Akihiko Odaki @ 2025-07-21 15:15 UTC (permalink / raw)
To: Daniel P. Berrangé, Markus Armbruster
Cc: Arun Menon, qemu-devel, Michael S. Tsirkin, Marcel Apfelbaum,
Cornelia Huck, Halil Pasic, Eric Farman, Richard Henderson,
David Hildenbrand, Ilya Leoshkevich, Thomas Huth,
Christian Borntraeger, Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Dmitry Osipenko,
Matthew Rosato
On 2025/07/21 22:29, Daniel P. Berrangé wrote:
> On Mon, Jul 21, 2025 at 10:14:30PM +0900, Akihiko Odaki wrote:
>> On 2025/07/21 20:29, Arun Menon wrote:
>>> - We need to have good error reporting in the callbacks in
>>> VMStateDescription struct. Specifically pre_save, post_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.
>>>
>>> Signed-off-by: Arun Menon <armenon@redhat.com>
>>> ---
>>> include/migration/vmstate.h | 11 +++++++++++
>>> migration/vmstate.c | 47 +++++++++++++++++++++++++++++++++++++++------
>>> 2 files changed, 52 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
>>> index 056781b1c21e737583f081594d9f88b32adfd674..53fa72c1bbde399be02c88fc8745fdbb79bfd7c8 100644
>>> --- a/include/migration/vmstate.h
>>> +++ b/include/migration/vmstate.h
>>> @@ -200,15 +200,26 @@ 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.
>>> */
>>> +
>>> 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);
>>> + int (*post_save_errp)(void *opaque, Error **errp);
>>
>> I think the new functions should have void as return value instead.
>>
>> As I discussed before, I think having an integer return value is a source of
>> confusion:
>> https://lore.kernel.org/qemu-devel/0447e269-c242-4cd7-b68e-d0c7211784a7@rsg.ci.i.u-tokyo.ac.jp/
>>
>> In the previous discussion, I suggested using bool, but void fits better in
>> this particular case.
>>
>> include/qapi/error.h says:
>>> Whenever practical, also return a value that indicates success /
>>> failure. This can make the error checking more concise, and can avoid
>>> useless error object creation and destruction. Note that we still
>>> have many functions returning void.
>>
>> There will be more implementations of these function pointers than their
>> callers, so it makes more sense to let return void and make implementations
>> more concise while making the callers less so. There is also DeviceRealize,
>> an example of function pointer type that takes errp but returns void.
>
> No, please do NOT make these functions void. As that text you quote
> says, we want functions to return a value indicating success/failure.
> 'void' return is a historical practice we don't want to continue
> in QEMU.
>
> Given that the existing methods all return 'int', we should remain
> consistent with the new functions and return 'int', with -1 for
> failure, 0 for success, and not use bool.
Markus, I'd also like to hear your opinion since you are the maintainer
of the error reporting facility.
Regards,
Akihiko Odaki
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 23/24] migration: Add error-parameterized function variants in VMSD struct
2025-07-21 15:10 ` Arun Menon
@ 2025-07-25 6:39 ` Arun Menon
0 siblings, 0 replies; 55+ messages in thread
From: Arun Menon @ 2025-07-25 6:39 UTC (permalink / raw)
To: Daniel P. Berrangé
Cc: qemu-devel, Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck,
Halil Pasic, Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Akihiko Odaki,
Dmitry Osipenko, Matthew Rosato
Hi Daniel,
On Mon, Jul 21, 2025 at 08:40:10PM +0530, Arun Menon wrote:
> On Mon, Jul 21, 2025 at 03:05:59PM +0100, Daniel P. Berrangé wrote:
> > On Mon, Jul 21, 2025 at 07:24:23PM +0530, Arun Menon wrote:
> > > Hi,
> > > Thank you for the review.
> > >
> > > On Mon, Jul 21, 2025 at 02:32:48PM +0100, Daniel P. Berrangé wrote:
> > > > On Mon, Jul 21, 2025 at 04:59:28PM +0530, Arun Menon wrote:
> > > > > - We need to have good error reporting in the callbacks in
> > > > > VMStateDescription struct. Specifically pre_save, post_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.
> > > > >
> > > > > Signed-off-by: Arun Menon <armenon@redhat.com>
> > > > > ---
> > > > > include/migration/vmstate.h | 11 +++++++++++
> > > > > migration/vmstate.c | 47 +++++++++++++++++++++++++++++++++++++++------
> > > > > 2 files changed, 52 insertions(+), 6 deletions(-)
> > > > >
> > > >
> > > > > diff --git a/migration/vmstate.c b/migration/vmstate.c
> > > > > index 288b57e1ed778cce21247b64d5e97dfef41ad586..d96908d12ccffaef421e5d399a48e26cada2cb77 100644
> > > > > --- a/migration/vmstate.c
> > > > > +++ b/migration/vmstate.c
> > > >
> > > > > @@ -524,7 +548,12 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
> > > > > if (ret) {
> > > > > error_setg(errp, "Save of field %s/%s failed",
> > > > > vmsd->name, field->name);
> > > > > - if (vmsd->post_save) {
> > > > > + if (vmsd->post_save_errp) {
> > > > > + ret = vmsd->post_save_errp(opaque, &local_err);
> > > > > + if (ret < 0) {
> > > > > + error_propagate(errp, local_err);
> > > > > + }
> > > >
> > > > This is still broken. 'errp' is already set a few lines earlier, so you
> > > > can't propagate a new error over the top
> > >
> > > I was wondering that we should preserve the first error that was encountered.
> > > So even if local_err was set, and in case errp already has an error, then it will
> > > be a no-op and local_err will be freed.
> >
> > We know that 'local_err' is definitely set when 'post_save_errp' is called,
> > because there's a call to 'error_setg' right above it.
>
> mmm, error_setg() above that sets errp, local_err is set only of post_save_errp() has
> errors. Do we want both the erros to be propagated? or is it okay to propagate the first
> error that was encountered.
I see your point. If we set errp, then there is no point in writing error_propagate()
because that will never allow local_err to be propagated because the first param is set.
I am intending to catch both the errors,
a. from vmstate_save_state_v() or explicitly set by us using error_setg(), in errp
b. from calling post_save_errp() , in local_err
and then, if we have both a and b, then we propagate b.
and if we only have a, then a will be propagated.
I think this will be consistent with the original logic of setting the error using
error_setg() and calling vmsd->post_save() only in the failure path. Please correct me
if I am wrong.
> >
> >
> >
> > > > > + } else if (vmsd->post_save) {
> > > > > vmsd->post_save(opaque);
> > > > > }
> >
> > ... pre-existing mistake not checking return value of
> > post_save.
> >
> > > > > return ret;
> > > > > @@ -552,7 +581,13 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
> > > > >
> > > > > ret = vmstate_subsection_save(f, vmsd, opaque, vmdesc, errp);
> > > > >
> > > > > - if (vmsd->post_save) {
> > > > > + if (vmsd->post_save_errp) {
> > > > > + int ps_ret = vmsd->post_save_errp(opaque, &local_err);
> > > > > + if (!ret && ps_ret) {
> > > > > + ret = ps_ret;
> > > > > + error_propagate(errp, local_err);
> > > > > + }
> > > >
> > > > Again, propagating over the top of an existing error
> > >
> > > Sorry, correct me if I am wrong.
> > > Since we have 'if (!ret && ps_ret)' ,
> > > if vmstate_subsection_save() fails, the above condition will not hold true.
> > > Only if the first function call vmstate_subsection_save() is successful and the second one
> > > post_save_errp() fails then we try to propagate, again hoping to preserve the first error.
> >
> > Opps, yes, you're right - I missed the 'ps_ret' check. That means this
> > code is a memory leak when 'ret' is non-zero, as nothing frees 'local_err'
> > in that case.
>
> Yes, maybe I can null check local_err and error_free() it.
>
> >
> > >
> > > >
> > > > > + } else if (vmsd->post_save) {
> > > > > int ps_ret = vmsd->post_save(opaque);
> > > > > if (!ret && ps_ret) {
> > > > > ret = ps_ret;
> > > > >
> > > > > --
> > > > > 2.50.0
> > > > >
> > > > >
> > > >
> > > > With regards,
> > > > Daniel
> > > > --
> > > > |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
> > > > |: https://libvirt.org -o- https://fstop138.berrange.com :|
> > > > |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
> > > >
> > >
> > > Regards,
> > > Arun Menon
> > >
> >
> > With regards,
> > Daniel
> > --
> > |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
> > |: https://libvirt.org -o- https://fstop138.berrange.com :|
> > |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
> >
> Regards,
> Arun
Regards,
Arun
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 20/24] migration: push Error **errp into qemu_loadvm_state()
2025-07-21 13:01 ` Akihiko Odaki
@ 2025-07-25 7:09 ` Arun Menon
0 siblings, 0 replies; 55+ messages in thread
From: Arun Menon @ 2025-07-25 7:09 UTC (permalink / raw)
To: Akihiko Odaki
Cc: qemu-devel, Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck,
Halil Pasic, Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Dmitry Osipenko,
Matthew Rosato
Hi,
Thanks for the review
On Mon, Jul 21, 2025 at 10:01:24PM +0900, Akihiko Odaki wrote:
> On 2025/07/21 20:29, Arun Menon wrote:
> > This is an incremental step in converting vmstate loading
> > code to report error via Error objects instead of directly
> > printing it to console/monitor.
> > It is ensured that qemu_loadvm_state() must report an error
> > in errp, in case of failure.
> >
> > Signed-off-by: Arun Menon <armenon@redhat.com>
> > ---
> > migration/migration.c | 5 +++--
> > migration/savevm.c | 25 +++++++++++++------------
> > migration/savevm.h | 2 +-
> > 3 files changed, 17 insertions(+), 15 deletions(-)
> >
> > diff --git a/migration/migration.c b/migration/migration.c
> > index d748a02712dc4ebc2de6b0488fb199c92c4d4079..09fadf36dbbbd2f68df1e4cafbf3a51b18531978 100644
> > --- a/migration/migration.c
> > +++ b/migration/migration.c
> > @@ -881,7 +881,7 @@ process_incoming_migration_co(void *opaque)
> > MIGRATION_STATUS_ACTIVE);
> > mis->loadvm_co = qemu_coroutine_self();
> > - ret = qemu_loadvm_state(mis->from_src_file);
> > + ret = qemu_loadvm_state(mis->from_src_file, &local_err);
> > mis->loadvm_co = NULL;
> > trace_vmstate_downtime_checkpoint("dst-precopy-loadvm-completed");
> > @@ -908,7 +908,8 @@ process_incoming_migration_co(void *opaque)
> > }
> > if (ret < 0) {
> > - error_setg(&local_err, "load of migration failed: %s", strerror(-ret));
> > + error_prepend(&local_err, "load of migration failed: %s ",
> > + strerror(-ret));
> > goto fail;
> > }
> > diff --git a/migration/savevm.c b/migration/savevm.c
> > index ba146f91427f2a36880aadeb16b11ab2b7df099a..1261e81c86f836e6b5a155ba1880b5823a779567 100644
> > --- a/migration/savevm.c
> > +++ b/migration/savevm.c
> > @@ -3137,27 +3137,24 @@ out:
> > return ret;
> > }
> > -int qemu_loadvm_state(QEMUFile *f)
> > +int qemu_loadvm_state(QEMUFile *f, Error **errp)
> > {
> > MigrationState *s = migrate_get_current();
> > MigrationIncomingState *mis = migration_incoming_get_current();
> > - Error *local_err = NULL;
> > int ret;
> > - if (qemu_savevm_state_blocked(&local_err)) {
> > - error_report_err(local_err);
> > + if (qemu_savevm_state_blocked(errp)) {
> > return -EINVAL;
> > }
> > qemu_loadvm_thread_pool_create(mis);
> > - ret = qemu_loadvm_state_header(f, NULL);
> > + ret = qemu_loadvm_state_header(f, errp);
> > if (ret) {
> > return ret;
> > }
> > - if (qemu_loadvm_state_setup(f, &local_err) != 0) {
> > - error_report_err(local_err);
> > + if (qemu_loadvm_state_setup(f, errp) != 0) {
> > return -EINVAL;
> > }
> > @@ -3167,7 +3164,7 @@ int qemu_loadvm_state(QEMUFile *f)
> > cpu_synchronize_all_pre_loadvm();
> > - ret = qemu_loadvm_state_main(f, mis, NULL);
> > + ret = qemu_loadvm_state_main(f, mis, errp);
> > qemu_event_set(&mis->main_thread_load_event);
> > trace_qemu_loadvm_state_post_main(ret);
> > @@ -3185,8 +3182,12 @@ int qemu_loadvm_state(QEMUFile *f)
> > if (migrate_has_error(migrate_get_current()) ||
> > !qemu_loadvm_thread_pool_wait(s, mis)) {
> > ret = -EINVAL;
> > + error_setg(errp, "Error while loading vmstate : %d", ret);
>
> Printing ret here does not help much as ret is always -EINVAL here.
>
> Having an error message different from qemu_file_get_error() will help more
> as it will allow reliably distinguishing these two error conditions.
Yes, maybe I can add "Migration stream has error" to the error message.
>
> > } else {
> > ret = qemu_file_get_error(f);
> > + if (ret < 0) {
> > + error_setg(errp, "Error while loading vmstate : %d", ret);
> > + }
> > }
> > }
> > /*
> > @@ -3472,10 +3473,10 @@ void qmp_xen_load_devices_state(const char *filename, Error **errp)
> > f = qemu_file_new_input(QIO_CHANNEL(ioc));
> > object_unref(OBJECT(ioc));
> > - ret = qemu_loadvm_state(f);
> > + ret = qemu_loadvm_state(f, errp);
> > qemu_fclose(f);
> > if (ret < 0) {
> > - error_setg(errp, "loading Xen device state failed");
> > + error_prepend(errp, "loading Xen device state failed ");
> > }
> > migration_incoming_state_destroy();
> > }
> > @@ -3546,13 +3547,13 @@ bool load_snapshot(const char *name, const char *vmstate,
> > ret = -EINVAL;
> > goto err_drain;
> > }
> > - ret = qemu_loadvm_state(f);
> > + ret = qemu_loadvm_state(f, errp);
> > migration_incoming_state_destroy();
> > bdrv_drain_all_end();
> > if (ret < 0) {
> > - error_setg(errp, "Error %d while loading VM state", ret);
> > + error_prepend(errp, "Error %d while loading VM state ", ret);
> > return false;
> > }
> > diff --git a/migration/savevm.h b/migration/savevm.h
> > index fd7419e6ff90062970ed246b3ea71e6d49a6e372..a6df5198f3fe1a39fc0e6ce3e79cf7a5d8e032db 100644
> > --- a/migration/savevm.h
> > +++ b/migration/savevm.h
> > @@ -64,7 +64,7 @@ void qemu_savevm_send_colo_enable(QEMUFile *f);
> > void qemu_savevm_live_state(QEMUFile *f);
> > int qemu_save_device_state(QEMUFile *f);
> > -int qemu_loadvm_state(QEMUFile *f);
> > +int qemu_loadvm_state(QEMUFile *f, Error **errp);
> > void qemu_loadvm_state_cleanup(MigrationIncomingState *mis);
> > int qemu_loadvm_state_main(QEMUFile *f, MigrationIncomingState *mis,
> > Error **errp);
> >
>
Regards,
Arun
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 01/24] migration: push Error **errp into vmstate_subsection_load()
2025-07-21 12:10 ` Akihiko Odaki
@ 2025-07-25 7:09 ` Arun Menon
0 siblings, 0 replies; 55+ messages in thread
From: Arun Menon @ 2025-07-25 7:09 UTC (permalink / raw)
To: Akihiko Odaki, y
Cc: qemu-devel, Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck,
Halil Pasic, Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Dmitry Osipenko,
Matthew Rosato
Hi,
Thanks for the review.
On Mon, Jul 21, 2025 at 09:10:21PM +0900, Akihiko Odaki wrote:
> On 2025/07/21 20:29, Arun Menon wrote:
> > This is an incremental step in converting vmstate loading
> > code to report error via Error objects instead of directly
> > printing it to console/monitor.
> > It is ensured that vmstate_subsection_load() must report an error
> > in errp, in case of failure.
> >
> > Signed-off-by: Arun Menon <armenon@redhat.com>
> > ---
> > migration/vmstate.c | 10 +++++++---
> > 1 file changed, 7 insertions(+), 3 deletions(-)
> >
> > diff --git a/migration/vmstate.c b/migration/vmstate.c
> > index 5feaa3244d259874f03048326b2497e7db32e47c..129b19d7603a0ddf8ab6e946e41c1c4d773d1fa8 100644
> > --- a/migration/vmstate.c
> > +++ b/migration/vmstate.c
> > @@ -25,7 +25,7 @@ static int vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
> > void *opaque, JSONWriter *vmdesc,
> > Error **errp);
> > static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
> > - void *opaque);
> > + void *opaque, Error **errp);
> > /* Whether this field should exist for either save or load the VM? */
> > static bool
> > @@ -225,7 +225,7 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
> > field++;
> > }
> > assert(field->flags == VMS_END);
> > - ret = vmstate_subsection_load(f, vmsd, opaque);
> > + ret = vmstate_subsection_load(f, vmsd, opaque, NULL);
> > if (ret != 0) {
> > qemu_file_set_error(f, ret);
> > return ret;
> > @@ -566,7 +566,7 @@ vmstate_get_subsection(const VMStateDescription * const *sub,
> > }
> > static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
> > - void *opaque)
> > + void *opaque, Error **errp)
> > {
> > trace_vmstate_subsection_load(vmsd->name);
> > @@ -598,6 +598,8 @@ static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
> > sub_vmsd = vmstate_get_subsection(vmsd->subsections, idstr);
> > if (sub_vmsd == NULL) {
> > trace_vmstate_subsection_load_bad(vmsd->name, idstr, "(lookup)");
> > + error_setg(errp, "VM subsection '%s' in '%s' does not exist",
>
> There are two whitespaces before "in" but I think we only need one.
Yes, missed that. Thanks. Will amend in the next version.
>
> > + idstr, vmsd->name);
> > return -ENOENT;
> > }
> > qemu_file_skip(f, 1); /* subsection */
> > @@ -608,6 +610,8 @@ static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
> > ret = vmstate_load_state(f, sub_vmsd, opaque, version_id);
> > if (ret) {
> > trace_vmstate_subsection_load_bad(vmsd->name, idstr, "(child)");
> > + error_setg(errp, "Loading VM subsection '%s' in '%s' failed : %d",
> > + idstr, vmsd->name, ret);
> > return ret;
> > }
> > }
> >
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 02/24] migration: push Error **errp into vmstate_load_state()
2025-07-21 12:24 ` Akihiko Odaki
@ 2025-07-25 7:11 ` Arun Menon
0 siblings, 0 replies; 55+ messages in thread
From: Arun Menon @ 2025-07-25 7:11 UTC (permalink / raw)
To: Akihiko Odaki
Cc: qemu-devel, Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck,
Halil Pasic, Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Dmitry Osipenko,
Matthew Rosato
Hi,
Thanks for the review.
On Mon, Jul 21, 2025 at 09:24:58PM +0900, Akihiko Odaki wrote:
> On 2025/07/21 20:29, Arun Menon wrote:
> > This is an incremental step in converting vmstate loading
> > code to report error via Error objects instead of directly
> > printing it to console/monitor.
> > It is ensured that vmstate_load_state() must report an error
> > in errp, in case of failure.
> >
> > Signed-off-by: Arun Menon <armenon@redhat.com>
> > ---
> > hw/display/virtio-gpu.c | 2 +-
> > hw/pci/pci.c | 2 +-
> > hw/s390x/virtio-ccw.c | 2 +-
> > hw/scsi/spapr_vscsi.c | 2 +-
> > hw/vfio/pci.c | 2 +-
> > hw/virtio/virtio-mmio.c | 2 +-
> > hw/virtio/virtio-pci.c | 2 +-
> > hw/virtio/virtio.c | 4 ++--
> > include/migration/vmstate.h | 2 +-
> > migration/cpr.c | 4 ++--
> > migration/savevm.c | 6 ++++--
> > migration/vmstate-types.c | 10 +++++-----
> > migration/vmstate.c | 45 ++++++++++++++++++++++++++++-----------------
> > tests/unit/test-vmstate.c | 18 +++++++++---------
> > ui/vdagent.c | 2 +-
> > 15 files changed, 59 insertions(+), 46 deletions(-)
> >
> > diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
> > index 0a1a625b0ea6cf26cb0d799171a57ed3d3ab2442..5d2ca8d8b864350133a674802d7316abd379591c 100644
> > --- a/hw/display/virtio-gpu.c
> > +++ b/hw/display/virtio-gpu.c
> > @@ -1343,7 +1343,7 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
> > }
> > /* load & apply scanout state */
> > - vmstate_load_state(f, &vmstate_virtio_gpu_scanouts, g, 1);
> > + vmstate_load_state(f, &vmstate_virtio_gpu_scanouts, g, 1, NULL);
> > return 0;
> > }
> > diff --git a/hw/pci/pci.c b/hw/pci/pci.c
> > index c70b5ceebaf1f2b10768bd030526cbb518da2b8d..2ab5d30bb3c319ac1c7bfc9a2acf6a2b38082066 100644
> > --- a/hw/pci/pci.c
> > +++ b/hw/pci/pci.c
> > @@ -934,7 +934,7 @@ void pci_device_save(PCIDevice *s, QEMUFile *f)
> > int pci_device_load(PCIDevice *s, QEMUFile *f)
> > {
> > int ret;
> > - ret = vmstate_load_state(f, &vmstate_pci_device, s, s->version_id);
> > + ret = vmstate_load_state(f, &vmstate_pci_device, s, s->version_id, NULL);
> > /* Restore the interrupt status bit. */
> > pci_update_irq_status(s);
> > return ret;
> > diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
> > index d2f85b39f30f7fc82e0c600144c0a958e1269b2c..2f6feff2b0a22d7d7f6aecfd7e7870d8362f1a73 100644
> > --- a/hw/s390x/virtio-ccw.c
> > +++ b/hw/s390x/virtio-ccw.c
> > @@ -1136,7 +1136,7 @@ static void virtio_ccw_save_config(DeviceState *d, QEMUFile *f)
> > static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f)
> > {
> > VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
> > - return vmstate_load_state(f, &vmstate_virtio_ccw_dev, dev, 1);
> > + return vmstate_load_state(f, &vmstate_virtio_ccw_dev, dev, 1, NULL);
> > }
> > static void virtio_ccw_pre_plugged(DeviceState *d, Error **errp)
> > diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c
> > index 20f70fb2729de78b9636a6b8c869695dab4f8902..573fdea668536b464bca11f001e9e0288e781493 100644
> > --- a/hw/scsi/spapr_vscsi.c
> > +++ b/hw/scsi/spapr_vscsi.c
> > @@ -648,7 +648,7 @@ static void *vscsi_load_request(QEMUFile *f, SCSIRequest *sreq)
> > assert(!req->active);
> > memset(req, 0, sizeof(*req));
> > - rc = vmstate_load_state(f, &vmstate_spapr_vscsi_req, req, 1);
> > + rc = vmstate_load_state(f, &vmstate_spapr_vscsi_req, req, 1, NULL);
> > if (rc) {
> > fprintf(stderr, "VSCSI: failed loading request tag#%u\n", sreq->tag);
> > return NULL;
> > diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
> > index be05002b9819fafa45cf2fb4d2a0acdc475c558c..f8ce4a40dbe4c070a0d6c111051051ee97542719 100644
> > --- a/hw/vfio/pci.c
> > +++ b/hw/vfio/pci.c
> > @@ -2797,7 +2797,7 @@ static int vfio_pci_load_config(VFIODevice *vbasedev, QEMUFile *f)
> > old_addr[bar] = pdev->io_regions[bar].addr;
> > }
> > - ret = vmstate_load_state(f, &vmstate_vfio_pci_config, vdev, 1);
> > + ret = vmstate_load_state(f, &vmstate_vfio_pci_config, vdev, 1, NULL);
> > if (ret) {
> > return ret;
> > }
> > diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c
> > index 532c67107ba1d2978a76cf49f9cdc1de1dea3e11..9058b1563462d4464dcba799643a583c93fb5683 100644
> > --- a/hw/virtio/virtio-mmio.c
> > +++ b/hw/virtio/virtio-mmio.c
> > @@ -619,7 +619,7 @@ static int virtio_mmio_load_extra_state(DeviceState *opaque, QEMUFile *f)
> > {
> > VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
> > - return vmstate_load_state(f, &vmstate_virtio_mmio, proxy, 1);
> > + return vmstate_load_state(f, &vmstate_virtio_mmio, proxy, 1, NULL);
> > }
> > static bool virtio_mmio_has_extra_state(DeviceState *opaque)
> > diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
> > index 767216d795998708f5716a23ae16c79cd90ff489..f8b52a611e56c22d844fd4cae3619da4f2686d03 100644
> > --- a/hw/virtio/virtio-pci.c
> > +++ b/hw/virtio/virtio-pci.c
> > @@ -161,7 +161,7 @@ static int virtio_pci_load_extra_state(DeviceState *d, QEMUFile *f)
> > {
> > VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
> > - return vmstate_load_state(f, &vmstate_virtio_pci, proxy, 1);
> > + return vmstate_load_state(f, &vmstate_virtio_pci, proxy, 1, NULL);
> > }
> > static void virtio_pci_save_queue(DeviceState *d, int n, QEMUFile *f)
> > diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
> > index 2ab1d20769495ea39445b87e3673b076ad172510..d5698b062a1e95437f6113f41136e90ae06f1974 100644
> > --- a/hw/virtio/virtio.c
> > +++ b/hw/virtio/virtio.c
> > @@ -3317,14 +3317,14 @@ virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
> > }
> > if (vdc->vmsd) {
> > - ret = vmstate_load_state(f, vdc->vmsd, vdev, version_id);
> > + ret = vmstate_load_state(f, vdc->vmsd, vdev, version_id, NULL);
> > if (ret) {
> > return ret;
> > }
> > }
> > /* Subsections */
> > - ret = vmstate_load_state(f, &vmstate_virtio, vdev, 1);
> > + ret = vmstate_load_state(f, &vmstate_virtio, vdev, 1, NULL);
> > if (ret) {
> > return ret;
> > }
> > diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
> > index 1ff7bd9ac425ba67cd5ca7ad97bcf570f9e19abe..056781b1c21e737583f081594d9f88b32adfd674 100644
> > --- a/include/migration/vmstate.h
> > +++ b/include/migration/vmstate.h
> > @@ -1196,7 +1196,7 @@ extern const VMStateInfo vmstate_info_qlist;
> > }
> > int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
> > - void *opaque, int version_id);
> > + void *opaque, int version_id, Error **errp);
> > int vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
> > void *opaque, JSONWriter *vmdesc);
> > int vmstate_save_state_with_err(QEMUFile *f, const VMStateDescription *vmsd,
> > diff --git a/migration/cpr.c b/migration/cpr.c
> > index 42ad0b0d500e5de57faf0c6517e216b2d1c0cacf..74fac9521717ec568d14dabcbcb574b19fc1da67 100644
> > --- a/migration/cpr.c
> > +++ b/migration/cpr.c
> > @@ -233,9 +233,9 @@ int cpr_state_load(MigrationChannel *channel, Error **errp)
> > return -ENOTSUP;
> > }
> > - ret = vmstate_load_state(f, &vmstate_cpr_state, &cpr_state, 1);
> > + ret = vmstate_load_state(f, &vmstate_cpr_state, &cpr_state, 1, errp);
> > if (ret) {
> > - error_setg(errp, "vmstate_load_state error %d", ret);
> > + error_prepend(errp, "vmstate_load_state error %d ", ret);
> > qemu_fclose(f);
> > return ret;
> > }
> > diff --git a/migration/savevm.c b/migration/savevm.c
> > index fabbeb296ae987d0c06ba6dafda63720205fecfd..ab947620f724874f325fb9fb59bef50b7c16fb51 100644
> > --- a/migration/savevm.c
> > +++ b/migration/savevm.c
> > @@ -969,7 +969,8 @@ static int vmstate_load(QEMUFile *f, SaveStateEntry *se)
> > if (!se->vmsd) { /* Old style */
> > return se->ops->load_state(f, se->opaque, se->load_version_id);
> > }
> > - return vmstate_load_state(f, se->vmsd, se->opaque, se->load_version_id);
> > + return vmstate_load_state(f, se->vmsd, se->opaque, se->load_version_id,
> > + NULL);
> > }
> > static void vmstate_save_old_style(QEMUFile *f, SaveStateEntry *se,
> > @@ -2839,7 +2840,8 @@ static int qemu_loadvm_state_header(QEMUFile *f)
> > error_report("Configuration section missing");
> > return -EINVAL;
> > }
> > - ret = vmstate_load_state(f, &vmstate_configuration, &savevm_state, 0);
> > + ret = vmstate_load_state(f, &vmstate_configuration, &savevm_state, 0,
> > + NULL);
> > if (ret) {
> > return ret;
> > diff --git a/migration/vmstate-types.c b/migration/vmstate-types.c
> > index 741a588b7e18c6d37724b08a0101edc8bc74a0a5..1c5b76e1dd198030847971bc35637867c9d54fc0 100644
> > --- a/migration/vmstate-types.c
> > +++ b/migration/vmstate-types.c
> > @@ -549,7 +549,7 @@ static int get_tmp(QEMUFile *f, void *pv, size_t size,
> > /* Writes the parent field which is at the start of the tmp */
> > *(void **)tmp = pv;
> > - ret = vmstate_load_state(f, vmsd, tmp, version_id);
> > + ret = vmstate_load_state(f, vmsd, tmp, version_id, NULL);
> > g_free(tmp);
> > return ret;
> > }
> > @@ -649,7 +649,7 @@ static int get_qtailq(QEMUFile *f, void *pv, size_t unused_size,
> > while (qemu_get_byte(f)) {
> > elm = g_malloc(size);
> > - ret = vmstate_load_state(f, vmsd, elm, version_id);
> > + ret = vmstate_load_state(f, vmsd, elm, version_id, NULL);
> > if (ret) {
> > return ret;
> > }
> > @@ -803,7 +803,7 @@ static int get_gtree(QEMUFile *f, void *pv, size_t unused_size,
> > key = (void *)(uintptr_t)qemu_get_be64(f);
> > } else {
> > key = g_malloc0(key_size);
> > - ret = vmstate_load_state(f, key_vmsd, key, version_id);
> > + ret = vmstate_load_state(f, key_vmsd, key, version_id, NULL);
> > if (ret) {
> > error_report("%s : failed to load %s (%d)",
> > field->name, key_vmsd->name, ret);
> > @@ -811,7 +811,7 @@ static int get_gtree(QEMUFile *f, void *pv, size_t unused_size,
> > }
> > }
> > val = g_malloc0(val_size);
> > - ret = vmstate_load_state(f, val_vmsd, val, version_id);
> > + ret = vmstate_load_state(f, val_vmsd, val, version_id, NULL);
> > if (ret) {
> > error_report("%s : failed to load %s (%d)",
> > field->name, val_vmsd->name, ret);
> > @@ -892,7 +892,7 @@ static int get_qlist(QEMUFile *f, void *pv, size_t unused_size,
> > while (qemu_get_byte(f)) {
> > elm = g_malloc(size);
> > - ret = vmstate_load_state(f, vmsd, elm, version_id);
> > + ret = vmstate_load_state(f, vmsd, elm, version_id, NULL);
> > if (ret) {
> > error_report("%s: failed to load %s (%d)", field->name,
> > vmsd->name, ret);
> > diff --git a/migration/vmstate.c b/migration/vmstate.c
> > index 129b19d7603a0ddf8ab6e946e41c1c4d773d1fa8..288b57e1ed778cce21247b64d5e97dfef41ad586 100644
> > --- a/migration/vmstate.c
> > +++ b/migration/vmstate.c
> > @@ -132,29 +132,33 @@ static void vmstate_handle_alloc(void *ptr, const VMStateField *field,
> > }
> > int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
> > - void *opaque, int version_id)
> > + void *opaque, int version_id, Error **errp)
> > {
> > const VMStateField *field = vmsd->fields;
> > int ret = 0;
> > trace_vmstate_load_state(vmsd->name, version_id);
> > if (version_id > vmsd->version_id) {
> > - error_report("%s: incoming version_id %d is too new "
> > - "for local version_id %d",
> > - vmsd->name, version_id, vmsd->version_id);
> > + error_setg(errp, "%s: incoming version_id %d is too new "
> > + "for local version_id %d",
> > + vmsd->name, version_id, vmsd->version_id);
> > trace_vmstate_load_state_end(vmsd->name, "too new", -EINVAL);
> > return -EINVAL;
> > }
> > if (version_id < vmsd->minimum_version_id) {
> > - error_report("%s: incoming version_id %d is too old "
> > - "for local minimum version_id %d",
> > - vmsd->name, version_id, vmsd->minimum_version_id);
> > + error_setg(errp, "%s: incoming version_id %d is too old "
> > + "for local minimum version_id %d",
> > + vmsd->name, version_id, vmsd->minimum_version_id);
> > trace_vmstate_load_state_end(vmsd->name, "too old", -EINVAL);
> > return -EINVAL;
> > }
> > if (vmsd->pre_load) {
> > ret = vmsd->pre_load(opaque);
> > if (ret) {
> > + error_setg(errp, "VM pre load failed for: '%s', "
> > + "version_id: '%d', minimum version_id: '%d', ret: %d",
> > + vmsd->name, vmsd->version_id, vmsd->minimum_version_id,
> > + ret);
> > return ret;
> > }
> > }
> > @@ -192,10 +196,12 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
> > if (inner_field->flags & VMS_STRUCT) {
> > ret = vmstate_load_state(f, inner_field->vmsd, curr_elem,
> > - inner_field->vmsd->version_id);
> > + inner_field->vmsd->version_id,
> > + errp);
> > } else if (inner_field->flags & VMS_VSTRUCT) {
> > ret = vmstate_load_state(f, inner_field->vmsd, curr_elem,
> > - inner_field->struct_version_id);
> > + inner_field->struct_version_id,
> > + errp);
> > } else {
> > ret = inner_field->info->get(f, curr_elem, size,
> > inner_field);
> > @@ -211,27 +217,32 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
> > }
> > if (ret < 0) {
> > qemu_file_set_error(f, ret);
> > - error_report("Failed to load %s:%s", vmsd->name,
> > - field->name);
> > + error_prepend(errp, "Failed to load %s:%s version_id: %d ",
> > + vmsd->name, field->name, vmsd->version_id);
> > trace_vmstate_load_field_error(field->name, ret);
> > return ret;
> > }
> > }
> > } else if (field->flags & VMS_MUST_EXIST) {
> > - error_report("Input validation failed: %s/%s",
> > - vmsd->name, field->name);
> > + error_setg(errp, "Input validation failed: %s/%s version_id: %d",
> > + vmsd->name, field->name, vmsd->version_id);
> > return -1;
> > }
> > field++;
> > }
> > assert(field->flags == VMS_END);
> > - ret = vmstate_subsection_load(f, vmsd, opaque, NULL);
> > + ret = vmstate_subsection_load(f, vmsd, opaque, errp);
> > if (ret != 0) {
> > qemu_file_set_error(f, ret);
> > return ret;
> > }
> > if (vmsd->post_load) {
> > ret = vmsd->post_load(opaque, version_id);
> > + if (ret < 0) {
> > + error_setg(errp, "VM Post load failed for: %s, version_id: %d,"
> > + "minimum_version: %d, ret: %d", vmsd->name,
>
> This error message lacks a whitespace between "," and "minimum_version".
Yes, shall amend.
>
> By the way, I prefer not to have line breaks in string literals to ease code
> search.
>
> While QEMU's coding style guide says nothing about the length limit for a
> line with a string literal, scripts/checkpatch.pl make an exemption for such
> a line.
>
> scripts/checkpatch.pl came from Linux, and Linux's coding style guide says:
> > However, never break user-visible strings such as printk messages
> > because that breaks the ability to grep for them.
>
> https://www.kernel.org/doc/html/v6.15/process/coding-style.html#breaking-long-lines-and-strings
>
> While we don't have to follow Linux's style, I think this particular
> statement makes sense for QEMU too.
Given that I want to make the script work, because it is part of the workflow
'b4 prep --check; b4 send;' and that I also agree to what you say about searching
the codebase using these strings, I shall try to use bare minimum line breaks, if
that is ok.
I will keep grep searchability in mind while making these line break decisions.
>
> > + vmsd->version_id, vmsd->minimum_version_id, ret);
> > + }
> > }
> > trace_vmstate_load_state_end(vmsd->name, "end", ret);
> > return ret;
> > @@ -607,11 +618,11 @@ static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
> > qemu_file_skip(f, len); /* idstr */
> > version_id = qemu_get_be32(f);
> > - ret = vmstate_load_state(f, sub_vmsd, opaque, version_id);
> > + ret = vmstate_load_state(f, sub_vmsd, opaque, version_id, errp);
> > if (ret) {
> > trace_vmstate_subsection_load_bad(vmsd->name, idstr, "(child)");
> > - error_setg(errp, "Loading VM subsection '%s' in '%s' failed : %d",
> > - idstr, vmsd->name, ret);
> > + error_prepend(errp, "Loading VM subsection '%s'"
> > + "in '%s' failed : %d ", idstr, vmsd->name, ret);
> > return ret;
> > }
> > }
> > diff --git a/tests/unit/test-vmstate.c b/tests/unit/test-vmstate.c
> > index 63f28f26f45691a70936d33e7341d16477a3471f..ca5e0ba1e3e5e2bb0a1ce39143a292f2c6f9420a 100644
> > --- a/tests/unit/test-vmstate.c
> > +++ b/tests/unit/test-vmstate.c
> > @@ -114,7 +114,7 @@ static int load_vmstate_one(const VMStateDescription *desc, void *obj,
> > qemu_fclose(f);
> > f = open_test_file(false);
> > - ret = vmstate_load_state(f, desc, obj, version);
> > + ret = vmstate_load_state(f, desc, obj, version, NULL);
> > if (ret) {
> > g_assert(qemu_file_get_error(f));
> > } else{
> > @@ -365,7 +365,7 @@ static void test_load_v1(void)
> > QEMUFile *loading = open_test_file(false);
> > TestStruct obj = { .b = 200, .e = 500, .f = 600 };
> > - vmstate_load_state(loading, &vmstate_versioned, &obj, 1);
> > + vmstate_load_state(loading, &vmstate_versioned, &obj, 1, NULL);
> > g_assert(!qemu_file_get_error(loading));
> > g_assert_cmpint(obj.a, ==, 10);
> > g_assert_cmpint(obj.b, ==, 200);
> > @@ -391,7 +391,7 @@ static void test_load_v2(void)
> > QEMUFile *loading = open_test_file(false);
> > TestStruct obj;
> > - vmstate_load_state(loading, &vmstate_versioned, &obj, 2);
> > + vmstate_load_state(loading, &vmstate_versioned, &obj, 2, NULL);
> > g_assert_cmpint(obj.a, ==, 10);
> > g_assert_cmpint(obj.b, ==, 20);
> > g_assert_cmpint(obj.c, ==, 30);
> > @@ -480,7 +480,7 @@ static void test_load_noskip(void)
> > QEMUFile *loading = open_test_file(false);
> > TestStruct obj = { .skip_c_e = false };
> > - vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
> > + vmstate_load_state(loading, &vmstate_skipping, &obj, 2, NULL);
> > g_assert(!qemu_file_get_error(loading));
> > g_assert_cmpint(obj.a, ==, 10);
> > g_assert_cmpint(obj.b, ==, 20);
> > @@ -504,7 +504,7 @@ static void test_load_skip(void)
> > QEMUFile *loading = open_test_file(false);
> > TestStruct obj = { .skip_c_e = true, .c = 300, .e = 500 };
> > - vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
> > + vmstate_load_state(loading, &vmstate_skipping, &obj, 2, NULL);
> > g_assert(!qemu_file_get_error(loading));
> > g_assert_cmpint(obj.a, ==, 10);
> > g_assert_cmpint(obj.b, ==, 20);
> > @@ -773,7 +773,7 @@ static void test_load_q(void)
> > TestQtailq tgt;
> > QTAILQ_INIT(&tgt.q);
> > - vmstate_load_state(fload, &vmstate_q, &tgt, 1);
> > + vmstate_load_state(fload, &vmstate_q, &tgt, 1, NULL);
> > char eof = qemu_get_byte(fload);
> > g_assert(!qemu_file_get_error(fload));
> > g_assert_cmpint(tgt.i16, ==, obj_q.i16);
> > @@ -1127,7 +1127,7 @@ static void test_gtree_load_domain(void)
> > fload = open_test_file(false);
> > - vmstate_load_state(fload, &vmstate_domain, dest_domain, 1);
> > + vmstate_load_state(fload, &vmstate_domain, dest_domain, 1, NULL);
> > eof = qemu_get_byte(fload);
> > g_assert(!qemu_file_get_error(fload));
> > g_assert_cmpint(orig_domain->id, ==, dest_domain->id);
> > @@ -1241,7 +1241,7 @@ static void test_gtree_load_iommu(void)
> > qemu_fclose(fsave);
> > fload = open_test_file(false);
> > - vmstate_load_state(fload, &vmstate_iommu, dest_iommu, 1);
> > + vmstate_load_state(fload, &vmstate_iommu, dest_iommu, 1, NULL);
> > eof = qemu_get_byte(fload);
> > g_assert(!qemu_file_get_error(fload));
> > g_assert_cmpint(orig_iommu->id, ==, dest_iommu->id);
> > @@ -1376,7 +1376,7 @@ static void test_load_qlist(void)
> > qemu_fclose(fsave);
> > fload = open_test_file(false);
> > - vmstate_load_state(fload, &vmstate_container, dest_container, 1);
> > + vmstate_load_state(fload, &vmstate_container, dest_container, 1, NULL);
> > eof = qemu_get_byte(fload);
> > g_assert(!qemu_file_get_error(fload));
> > g_assert_cmpint(eof, ==, QEMU_VM_EOF);
> > diff --git a/ui/vdagent.c b/ui/vdagent.c
> > index c0746fe5b168fdc7aeb4866de2ba0c3387566649..83457dee0767433ad0778b37b41b9c673a0e1860 100644
> > --- a/ui/vdagent.c
> > +++ b/ui/vdagent.c
> > @@ -1008,7 +1008,7 @@ static int get_cbinfo(QEMUFile *f, void *pv, size_t size,
> > vdagent_clipboard_peer_register(vd);
> > - ret = vmstate_load_state(f, &vmstate_cbinfo_array, &cbinfo, 0);
> > + ret = vmstate_load_state(f, &vmstate_cbinfo_array, &cbinfo, 0, NULL);
> > if (ret) {
> > return ret;
> > }
> >
>
Regards,
Arun
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 02/24] migration: push Error **errp into vmstate_load_state()
2025-07-21 12:30 ` Marc-André Lureau
@ 2025-07-25 7:12 ` Arun Menon
0 siblings, 0 replies; 55+ messages in thread
From: Arun Menon @ 2025-07-25 7:12 UTC (permalink / raw)
To: Marc-André Lureau
Cc: Armbruster, Markus, qemu-devel, Michael S. Tsirkin,
Marcel Apfelbaum, Cornelia Huck, Halil Pasic, Eric Farman,
Richard Henderson, David Hildenbrand, Ilya Leoshkevich,
Thomas Huth, Christian Borntraeger, Paolo Bonzini, Fam Zheng,
Nicholas Piggin, Daniel Henrique Barboza, Harsh Prateek Bora,
Alex Williamson, Cédric Le Goater, Peter Xu, Fabiano Rosas,
Hailiang Zhang, Steve Sistare, qemu-s390x, qemu-ppc,
Stefan Berger, Alex Bennée, Akihiko Odaki, Dmitry Osipenko,
Matthew Rosato
Hi,
Thanks for the review.
On Mon, Jul 21, 2025 at 04:30:36PM +0400, Marc-André Lureau wrote:
> Hi
>
> On Mon, Jul 21, 2025 at 3:35 PM Arun Menon <armenon@redhat.com> wrote:
>
> > This is an incremental step in converting vmstate loading
> > code to report error via Error objects instead of directly
> > printing it to console/monitor.
> > It is ensured that vmstate_load_state() must report an error
> > in errp, in case of failure.
> >
> > Signed-off-by: Arun Menon <armenon@redhat.com>
> > ---
> > hw/display/virtio-gpu.c | 2 +-
> > hw/pci/pci.c | 2 +-
> > hw/s390x/virtio-ccw.c | 2 +-
> > hw/scsi/spapr_vscsi.c | 2 +-
> > hw/vfio/pci.c | 2 +-
> > hw/virtio/virtio-mmio.c | 2 +-
> > hw/virtio/virtio-pci.c | 2 +-
> > hw/virtio/virtio.c | 4 ++--
> > include/migration/vmstate.h | 2 +-
> > migration/cpr.c | 4 ++--
> > migration/savevm.c | 6 ++++--
> > migration/vmstate-types.c | 10 +++++-----
> > migration/vmstate.c | 45
> > ++++++++++++++++++++++++++++-----------------
> > tests/unit/test-vmstate.c | 18 +++++++++---------
> > ui/vdagent.c | 2 +-
> > 15 files changed, 59 insertions(+), 46 deletions(-)
> >
> > diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
> > index
> > 0a1a625b0ea6cf26cb0d799171a57ed3d3ab2442..5d2ca8d8b864350133a674802d7316abd379591c
> > 100644
> > --- a/hw/display/virtio-gpu.c
> > +++ b/hw/display/virtio-gpu.c
> > @@ -1343,7 +1343,7 @@ static int virtio_gpu_load(QEMUFile *f, void
> > *opaque, size_t size,
> > }
> >
> > /* load & apply scanout state */
> > - vmstate_load_state(f, &vmstate_virtio_gpu_scanouts, g, 1);
> > + vmstate_load_state(f, &vmstate_virtio_gpu_scanouts, g, 1, NULL);
> >
> > return 0;
> > }
> > diff --git a/hw/pci/pci.c b/hw/pci/pci.c
> > index
> > c70b5ceebaf1f2b10768bd030526cbb518da2b8d..2ab5d30bb3c319ac1c7bfc9a2acf6a2b38082066
> > 100644
> > --- a/hw/pci/pci.c
> > +++ b/hw/pci/pci.c
> > @@ -934,7 +934,7 @@ void pci_device_save(PCIDevice *s, QEMUFile *f)
> > int pci_device_load(PCIDevice *s, QEMUFile *f)
> > {
> > int ret;
> > - ret = vmstate_load_state(f, &vmstate_pci_device, s, s->version_id);
> > + ret = vmstate_load_state(f, &vmstate_pci_device, s, s->version_id,
> > NULL);
> > /* Restore the interrupt status bit. */
> > pci_update_irq_status(s);
> > return ret;
> > diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
> > index
> > d2f85b39f30f7fc82e0c600144c0a958e1269b2c..2f6feff2b0a22d7d7f6aecfd7e7870d8362f1a73
> > 100644
> > --- a/hw/s390x/virtio-ccw.c
> > +++ b/hw/s390x/virtio-ccw.c
> > @@ -1136,7 +1136,7 @@ static void virtio_ccw_save_config(DeviceState *d,
> > QEMUFile *f)
> > static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f)
> > {
> > VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
> > - return vmstate_load_state(f, &vmstate_virtio_ccw_dev, dev, 1);
> > + return vmstate_load_state(f, &vmstate_virtio_ccw_dev, dev, 1, NULL);
> > }
> >
> > static void virtio_ccw_pre_plugged(DeviceState *d, Error **errp)
> > diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c
> > index
> > 20f70fb2729de78b9636a6b8c869695dab4f8902..573fdea668536b464bca11f001e9e0288e781493
> > 100644
> > --- a/hw/scsi/spapr_vscsi.c
> > +++ b/hw/scsi/spapr_vscsi.c
> > @@ -648,7 +648,7 @@ static void *vscsi_load_request(QEMUFile *f,
> > SCSIRequest *sreq)
> > assert(!req->active);
> >
> > memset(req, 0, sizeof(*req));
> > - rc = vmstate_load_state(f, &vmstate_spapr_vscsi_req, req, 1);
> > + rc = vmstate_load_state(f, &vmstate_spapr_vscsi_req, req, 1, NULL);
> > if (rc) {
> > fprintf(stderr, "VSCSI: failed loading request tag#%u\n",
> > sreq->tag);
> > return NULL;
> > diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
> > index
> > be05002b9819fafa45cf2fb4d2a0acdc475c558c..f8ce4a40dbe4c070a0d6c111051051ee97542719
> > 100644
> > --- a/hw/vfio/pci.c
> > +++ b/hw/vfio/pci.c
> > @@ -2797,7 +2797,7 @@ static int vfio_pci_load_config(VFIODevice
> > *vbasedev, QEMUFile *f)
> > old_addr[bar] = pdev->io_regions[bar].addr;
> > }
> >
> > - ret = vmstate_load_state(f, &vmstate_vfio_pci_config, vdev, 1);
> > + ret = vmstate_load_state(f, &vmstate_vfio_pci_config, vdev, 1, NULL);
> > if (ret) {
> > return ret;
> > }
> > diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c
> > index
> > 532c67107ba1d2978a76cf49f9cdc1de1dea3e11..9058b1563462d4464dcba799643a583c93fb5683
> > 100644
> > --- a/hw/virtio/virtio-mmio.c
> > +++ b/hw/virtio/virtio-mmio.c
> > @@ -619,7 +619,7 @@ static int virtio_mmio_load_extra_state(DeviceState
> > *opaque, QEMUFile *f)
> > {
> > VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
> >
> > - return vmstate_load_state(f, &vmstate_virtio_mmio, proxy, 1);
> > + return vmstate_load_state(f, &vmstate_virtio_mmio, proxy, 1, NULL);
> > }
> >
> > static bool virtio_mmio_has_extra_state(DeviceState *opaque)
> > diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
> > index
> > 767216d795998708f5716a23ae16c79cd90ff489..f8b52a611e56c22d844fd4cae3619da4f2686d03
> > 100644
> > --- a/hw/virtio/virtio-pci.c
> > +++ b/hw/virtio/virtio-pci.c
> > @@ -161,7 +161,7 @@ static int virtio_pci_load_extra_state(DeviceState *d,
> > QEMUFile *f)
> > {
> > VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
> >
> > - return vmstate_load_state(f, &vmstate_virtio_pci, proxy, 1);
> > + return vmstate_load_state(f, &vmstate_virtio_pci, proxy, 1, NULL);
> > }
> >
> > static void virtio_pci_save_queue(DeviceState *d, int n, QEMUFile *f)
> > diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
> > index
> > 2ab1d20769495ea39445b87e3673b076ad172510..d5698b062a1e95437f6113f41136e90ae06f1974
> > 100644
> > --- a/hw/virtio/virtio.c
> > +++ b/hw/virtio/virtio.c
> > @@ -3317,14 +3317,14 @@ virtio_load(VirtIODevice *vdev, QEMUFile *f, int
> > version_id)
> > }
> >
> > if (vdc->vmsd) {
> > - ret = vmstate_load_state(f, vdc->vmsd, vdev, version_id);
> > + ret = vmstate_load_state(f, vdc->vmsd, vdev, version_id, NULL);
> > if (ret) {
> > return ret;
> > }
> > }
> >
> > /* Subsections */
> > - ret = vmstate_load_state(f, &vmstate_virtio, vdev, 1);
> > + ret = vmstate_load_state(f, &vmstate_virtio, vdev, 1, NULL);
> > if (ret) {
> > return ret;
> > }
> > diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
> > index
> > 1ff7bd9ac425ba67cd5ca7ad97bcf570f9e19abe..056781b1c21e737583f081594d9f88b32adfd674
> > 100644
> > --- a/include/migration/vmstate.h
> > +++ b/include/migration/vmstate.h
> > @@ -1196,7 +1196,7 @@ extern const VMStateInfo vmstate_info_qlist;
> > }
> >
> > int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
> > - void *opaque, int version_id);
> > + void *opaque, int version_id, Error **errp);
> > int vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
> > void *opaque, JSONWriter *vmdesc);
> > int vmstate_save_state_with_err(QEMUFile *f, const VMStateDescription
> > *vmsd,
> > diff --git a/migration/cpr.c b/migration/cpr.c
> > index
> > 42ad0b0d500e5de57faf0c6517e216b2d1c0cacf..74fac9521717ec568d14dabcbcb574b19fc1da67
> > 100644
> > --- a/migration/cpr.c
> > +++ b/migration/cpr.c
> > @@ -233,9 +233,9 @@ int cpr_state_load(MigrationChannel *channel, Error
> > **errp)
> > return -ENOTSUP;
> > }
> >
> > - ret = vmstate_load_state(f, &vmstate_cpr_state, &cpr_state, 1);
> > + ret = vmstate_load_state(f, &vmstate_cpr_state, &cpr_state, 1, errp);
> > if (ret) {
> > - error_setg(errp, "vmstate_load_state error %d", ret);
> > + error_prepend(errp, "vmstate_load_state error %d ", ret);
> >
>
> Although it's not enforced, I think it's recommended to end the
> error_prepend() string with ": ", not just a space.
Agreed. Will do in the next version.
>
>
> > qemu_fclose(f);
> > return ret;
> > }
> > diff --git a/migration/savevm.c b/migration/savevm.c
> > index
> > fabbeb296ae987d0c06ba6dafda63720205fecfd..ab947620f724874f325fb9fb59bef50b7c16fb51
> > 100644
> > --- a/migration/savevm.c
> > +++ b/migration/savevm.c
> > @@ -969,7 +969,8 @@ static int vmstate_load(QEMUFile *f, SaveStateEntry
> > *se)
> > if (!se->vmsd) { /* Old style */
> > return se->ops->load_state(f, se->opaque, se->load_version_id);
> > }
> > - return vmstate_load_state(f, se->vmsd, se->opaque,
> > se->load_version_id);
> > + return vmstate_load_state(f, se->vmsd, se->opaque,
> > se->load_version_id,
> > + NULL);
> > }
> >
> > static void vmstate_save_old_style(QEMUFile *f, SaveStateEntry *se,
> > @@ -2839,7 +2840,8 @@ static int qemu_loadvm_state_header(QEMUFile *f)
> > error_report("Configuration section missing");
> > return -EINVAL;
> > }
> > - ret = vmstate_load_state(f, &vmstate_configuration,
> > &savevm_state, 0);
> > + ret = vmstate_load_state(f, &vmstate_configuration,
> > &savevm_state, 0,
> > + NULL);
> >
> > if (ret) {
> > return ret;
> > diff --git a/migration/vmstate-types.c b/migration/vmstate-types.c
> > index
> > 741a588b7e18c6d37724b08a0101edc8bc74a0a5..1c5b76e1dd198030847971bc35637867c9d54fc0
> > 100644
> > --- a/migration/vmstate-types.c
> > +++ b/migration/vmstate-types.c
> > @@ -549,7 +549,7 @@ static int get_tmp(QEMUFile *f, void *pv, size_t size,
> >
> > /* Writes the parent field which is at the start of the tmp */
> > *(void **)tmp = pv;
> > - ret = vmstate_load_state(f, vmsd, tmp, version_id);
> > + ret = vmstate_load_state(f, vmsd, tmp, version_id, NULL);
> > g_free(tmp);
> > return ret;
> > }
> > @@ -649,7 +649,7 @@ static int get_qtailq(QEMUFile *f, void *pv, size_t
> > unused_size,
> >
> > while (qemu_get_byte(f)) {
> > elm = g_malloc(size);
> > - ret = vmstate_load_state(f, vmsd, elm, version_id);
> > + ret = vmstate_load_state(f, vmsd, elm, version_id, NULL);
> > if (ret) {
> > return ret;
> > }
> > @@ -803,7 +803,7 @@ static int get_gtree(QEMUFile *f, void *pv, size_t
> > unused_size,
> > key = (void *)(uintptr_t)qemu_get_be64(f);
> > } else {
> > key = g_malloc0(key_size);
> > - ret = vmstate_load_state(f, key_vmsd, key, version_id);
> > + ret = vmstate_load_state(f, key_vmsd, key, version_id, NULL);
> > if (ret) {
> > error_report("%s : failed to load %s (%d)",
> > field->name, key_vmsd->name, ret);
> > @@ -811,7 +811,7 @@ static int get_gtree(QEMUFile *f, void *pv, size_t
> > unused_size,
> > }
> > }
> > val = g_malloc0(val_size);
> > - ret = vmstate_load_state(f, val_vmsd, val, version_id);
> > + ret = vmstate_load_state(f, val_vmsd, val, version_id, NULL);
> > if (ret) {
> > error_report("%s : failed to load %s (%d)",
> > field->name, val_vmsd->name, ret);
> > @@ -892,7 +892,7 @@ static int get_qlist(QEMUFile *f, void *pv, size_t
> > unused_size,
> >
> > while (qemu_get_byte(f)) {
> > elm = g_malloc(size);
> > - ret = vmstate_load_state(f, vmsd, elm, version_id);
> > + ret = vmstate_load_state(f, vmsd, elm, version_id, NULL);
> > if (ret) {
> > error_report("%s: failed to load %s (%d)", field->name,
> > vmsd->name, ret);
> > diff --git a/migration/vmstate.c b/migration/vmstate.c
> > index
> > 129b19d7603a0ddf8ab6e946e41c1c4d773d1fa8..288b57e1ed778cce21247b64d5e97dfef41ad586
> > 100644
> > --- a/migration/vmstate.c
> > +++ b/migration/vmstate.c
> > @@ -132,29 +132,33 @@ static void vmstate_handle_alloc(void *ptr, const
> > VMStateField *field,
> > }
> >
> > int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
> > - void *opaque, int version_id)
> > + void *opaque, int version_id, Error **errp)
> > {
> > const VMStateField *field = vmsd->fields;
> > int ret = 0;
> >
> > trace_vmstate_load_state(vmsd->name, version_id);
> > if (version_id > vmsd->version_id) {
> > - error_report("%s: incoming version_id %d is too new "
> > - "for local version_id %d",
> > - vmsd->name, version_id, vmsd->version_id);
> > + error_setg(errp, "%s: incoming version_id %d is too new "
> > + "for local version_id %d",
> > + vmsd->name, version_id, vmsd->version_id);
> > trace_vmstate_load_state_end(vmsd->name, "too new", -EINVAL);
> > return -EINVAL;
> > }
> > if (version_id < vmsd->minimum_version_id) {
> > - error_report("%s: incoming version_id %d is too old "
> > - "for local minimum version_id %d",
> > - vmsd->name, version_id, vmsd->minimum_version_id);
> > + error_setg(errp, "%s: incoming version_id %d is too old "
> > + "for local minimum version_id %d",
> > + vmsd->name, version_id, vmsd->minimum_version_id);
> > trace_vmstate_load_state_end(vmsd->name, "too old", -EINVAL);
> > return -EINVAL;
> > }
> > if (vmsd->pre_load) {
> > ret = vmsd->pre_load(opaque);
> > if (ret) {
> > + error_setg(errp, "VM pre load failed for: '%s', "
> > + "version_id: '%d', minimum version_id: '%d', ret:
> > %d",
> > + vmsd->name, vmsd->version_id,
> > vmsd->minimum_version_id,
> > + ret);
> > return ret;
> > }
> > }
> > @@ -192,10 +196,12 @@ int vmstate_load_state(QEMUFile *f, const
> > VMStateDescription *vmsd,
> >
> > if (inner_field->flags & VMS_STRUCT) {
> > ret = vmstate_load_state(f, inner_field->vmsd,
> > curr_elem,
> > -
> > inner_field->vmsd->version_id);
> > +
> > inner_field->vmsd->version_id,
> > + errp);
> > } else if (inner_field->flags & VMS_VSTRUCT) {
> > ret = vmstate_load_state(f, inner_field->vmsd,
> > curr_elem,
> > -
> > inner_field->struct_version_id);
> > +
> > inner_field->struct_version_id,
> > + errp);
> > } else {
> > ret = inner_field->info->get(f, curr_elem, size,
> > inner_field);
> > @@ -211,27 +217,32 @@ int vmstate_load_state(QEMUFile *f, const
> > VMStateDescription *vmsd,
> > }
> > if (ret < 0) {
> > qemu_file_set_error(f, ret);
> > - error_report("Failed to load %s:%s", vmsd->name,
> > - field->name);
> > + error_prepend(errp, "Failed to load %s:%s version_id:
> > %d ",
> > + vmsd->name, field->name,
> > vmsd->version_id);
> > trace_vmstate_load_field_error(field->name, ret);
> > return ret;
> > }
> > }
> > } else if (field->flags & VMS_MUST_EXIST) {
> > - error_report("Input validation failed: %s/%s",
> > - vmsd->name, field->name);
> > + error_setg(errp, "Input validation failed: %s/%s version_id:
> > %d",
> > + vmsd->name, field->name, vmsd->version_id);
> > return -1;
> > }
> > field++;
> > }
> > assert(field->flags == VMS_END);
> > - ret = vmstate_subsection_load(f, vmsd, opaque, NULL);
> > + ret = vmstate_subsection_load(f, vmsd, opaque, errp);
> > if (ret != 0) {
> > qemu_file_set_error(f, ret);
> > return ret;
> > }
> > if (vmsd->post_load) {
> > ret = vmsd->post_load(opaque, version_id);
> > + if (ret < 0) {
> > + error_setg(errp, "VM Post load failed for: %s, version_id:
> > %d,"
> > + "minimum_version: %d, ret: %d", vmsd->name,
> > + vmsd->version_id, vmsd->minimum_version_id, ret);
> > + }
> > }
> > trace_vmstate_load_state_end(vmsd->name, "end", ret);
> > return ret;
> > @@ -607,11 +618,11 @@ static int vmstate_subsection_load(QEMUFile *f,
> > const VMStateDescription *vmsd,
> > qemu_file_skip(f, len); /* idstr */
> > version_id = qemu_get_be32(f);
> >
> > - ret = vmstate_load_state(f, sub_vmsd, opaque, version_id);
> > + ret = vmstate_load_state(f, sub_vmsd, opaque, version_id, errp);
> > if (ret) {
> > trace_vmstate_subsection_load_bad(vmsd->name, idstr,
> > "(child)");
> > - error_setg(errp, "Loading VM subsection '%s' in '%s' failed :
> > %d",
> > - idstr, vmsd->name, ret);
> > + error_prepend(errp, "Loading VM subsection '%s'"
> > + "in '%s' failed : %d ", idstr, vmsd->name, ret);
> > return ret;
> > }
> > }
> > diff --git a/tests/unit/test-vmstate.c b/tests/unit/test-vmstate.c
> > index
> > 63f28f26f45691a70936d33e7341d16477a3471f..ca5e0ba1e3e5e2bb0a1ce39143a292f2c6f9420a
> > 100644
> > --- a/tests/unit/test-vmstate.c
> > +++ b/tests/unit/test-vmstate.c
> > @@ -114,7 +114,7 @@ static int load_vmstate_one(const VMStateDescription
> > *desc, void *obj,
> > qemu_fclose(f);
> >
> > f = open_test_file(false);
> > - ret = vmstate_load_state(f, desc, obj, version);
> > + ret = vmstate_load_state(f, desc, obj, version, NULL);
> > if (ret) {
> > g_assert(qemu_file_get_error(f));
> > } else{
> > @@ -365,7 +365,7 @@ static void test_load_v1(void)
> >
> > QEMUFile *loading = open_test_file(false);
> > TestStruct obj = { .b = 200, .e = 500, .f = 600 };
> > - vmstate_load_state(loading, &vmstate_versioned, &obj, 1);
> > + vmstate_load_state(loading, &vmstate_versioned, &obj, 1, NULL);
> > g_assert(!qemu_file_get_error(loading));
> > g_assert_cmpint(obj.a, ==, 10);
> > g_assert_cmpint(obj.b, ==, 200);
> > @@ -391,7 +391,7 @@ static void test_load_v2(void)
> >
> > QEMUFile *loading = open_test_file(false);
> > TestStruct obj;
> > - vmstate_load_state(loading, &vmstate_versioned, &obj, 2);
> > + vmstate_load_state(loading, &vmstate_versioned, &obj, 2, NULL);
> > g_assert_cmpint(obj.a, ==, 10);
> > g_assert_cmpint(obj.b, ==, 20);
> > g_assert_cmpint(obj.c, ==, 30);
> > @@ -480,7 +480,7 @@ static void test_load_noskip(void)
> >
> > QEMUFile *loading = open_test_file(false);
> > TestStruct obj = { .skip_c_e = false };
> > - vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
> > + vmstate_load_state(loading, &vmstate_skipping, &obj, 2, NULL);
> > g_assert(!qemu_file_get_error(loading));
> > g_assert_cmpint(obj.a, ==, 10);
> > g_assert_cmpint(obj.b, ==, 20);
> > @@ -504,7 +504,7 @@ static void test_load_skip(void)
> >
> > QEMUFile *loading = open_test_file(false);
> > TestStruct obj = { .skip_c_e = true, .c = 300, .e = 500 };
> > - vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
> > + vmstate_load_state(loading, &vmstate_skipping, &obj, 2, NULL);
> > g_assert(!qemu_file_get_error(loading));
> > g_assert_cmpint(obj.a, ==, 10);
> > g_assert_cmpint(obj.b, ==, 20);
> > @@ -773,7 +773,7 @@ static void test_load_q(void)
> > TestQtailq tgt;
> >
> > QTAILQ_INIT(&tgt.q);
> > - vmstate_load_state(fload, &vmstate_q, &tgt, 1);
> > + vmstate_load_state(fload, &vmstate_q, &tgt, 1, NULL);
> > char eof = qemu_get_byte(fload);
> > g_assert(!qemu_file_get_error(fload));
> > g_assert_cmpint(tgt.i16, ==, obj_q.i16);
> > @@ -1127,7 +1127,7 @@ static void test_gtree_load_domain(void)
> >
> > fload = open_test_file(false);
> >
> > - vmstate_load_state(fload, &vmstate_domain, dest_domain, 1);
> > + vmstate_load_state(fload, &vmstate_domain, dest_domain, 1, NULL);
> > eof = qemu_get_byte(fload);
> > g_assert(!qemu_file_get_error(fload));
> > g_assert_cmpint(orig_domain->id, ==, dest_domain->id);
> > @@ -1241,7 +1241,7 @@ static void test_gtree_load_iommu(void)
> > qemu_fclose(fsave);
> >
> > fload = open_test_file(false);
> > - vmstate_load_state(fload, &vmstate_iommu, dest_iommu, 1);
> > + vmstate_load_state(fload, &vmstate_iommu, dest_iommu, 1, NULL);
> > eof = qemu_get_byte(fload);
> > g_assert(!qemu_file_get_error(fload));
> > g_assert_cmpint(orig_iommu->id, ==, dest_iommu->id);
> > @@ -1376,7 +1376,7 @@ static void test_load_qlist(void)
> > qemu_fclose(fsave);
> >
> > fload = open_test_file(false);
> > - vmstate_load_state(fload, &vmstate_container, dest_container, 1);
> > + vmstate_load_state(fload, &vmstate_container, dest_container, 1,
> > NULL);
> > eof = qemu_get_byte(fload);
> > g_assert(!qemu_file_get_error(fload));
> > g_assert_cmpint(eof, ==, QEMU_VM_EOF);
> > diff --git a/ui/vdagent.c b/ui/vdagent.c
> > index
> > c0746fe5b168fdc7aeb4866de2ba0c3387566649..83457dee0767433ad0778b37b41b9c673a0e1860
> > 100644
> > --- a/ui/vdagent.c
> > +++ b/ui/vdagent.c
> > @@ -1008,7 +1008,7 @@ static int get_cbinfo(QEMUFile *f, void *pv, size_t
> > size,
> >
> > vdagent_clipboard_peer_register(vd);
> >
> > - ret = vmstate_load_state(f, &vmstate_cbinfo_array, &cbinfo, 0);
> > + ret = vmstate_load_state(f, &vmstate_cbinfo_array, &cbinfo, 0, NULL);
> > if (ret) {
> > return ret;
> > }
> >
> > --
> > 2.50.0
> >
> >
Regards,
Arun
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 03/24] migration: push Error **errp into qemu_loadvm_state_header()
2025-07-21 12:34 ` Marc-André Lureau
@ 2025-07-25 7:12 ` Arun Menon
0 siblings, 0 replies; 55+ messages in thread
From: Arun Menon @ 2025-07-25 7:12 UTC (permalink / raw)
To: Marc-André Lureau
Cc: qemu-devel, Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck,
Halil Pasic, Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Alex Bennée, Akihiko Odaki, Dmitry Osipenko, Matthew Rosato
Hi,
Thanks for the review.
On Mon, Jul 21, 2025 at 04:34:12PM +0400, Marc-André Lureau wrote:
> Hi
>
> On Mon, Jul 21, 2025 at 3:30 PM Arun Menon <armenon@redhat.com> wrote:
>
> > This is an incremental step in converting vmstate loading
> > code to report error via Error objects instead of directly
> > printing it to console/monitor.
> > It is ensured that qemu_loadvm_state_header() must report an error
> > in errp, in case of failure.
> >
> > Signed-off-by: Arun Menon <armenon@redhat.com>
> > ---
> > migration/savevm.c | 25 ++++++++++++++++---------
> > 1 file changed, 16 insertions(+), 9 deletions(-)
> >
> > diff --git a/migration/savevm.c b/migration/savevm.c
> > index
> > ab947620f724874f325fb9fb59bef50b7c16fb51..162fb05933fae5993eeef107811f97cb08726ac3
> > 100644
> > --- a/migration/savevm.c
> > +++ b/migration/savevm.c
> > @@ -2814,35 +2814,42 @@ qemu_loadvm_section_part_end(QEMUFile *f, uint8_t
> > type)
> > return 0;
> > }
> >
> > -static int qemu_loadvm_state_header(QEMUFile *f)
> > +static int qemu_loadvm_state_header(QEMUFile *f, Error **errp)
> > {
> > unsigned int v;
> > int ret;
> >
> > v = qemu_get_be32(f);
> > if (v != QEMU_VM_FILE_MAGIC) {
> > - error_report("Not a migration stream");
> > + error_setg(errp, "Not a migration stream, "
> > + "magic: %x != %x", v, QEMU_VM_FILE_MAGIC);
> > return -EINVAL;
> > }
> >
> > v = qemu_get_be32(f);
> > if (v == QEMU_VM_FILE_VERSION_COMPAT) {
> > - error_report("SaveVM v2 format is obsolete and don't work
> > anymore");
> > + error_setg(errp, "SaveVM v2 format is obsolete and no"
> > + "longer supported, file version %x != %x",
> >
>
> As Akihiko said in patch 2 review, better "not to have line breaks in
> string literals" .. here, there is a missing space now.
Agreed. I am going to amend all the commits once and check for these kind of
breaks. However, I do not want to have the line too long also (more than 100 chars).
I will try to find a way in which I can use minimum breaks, while keeping in mind
that a grep search should be able to find the line in the codebase, if that is ok.
>
> + v, QEMU_VM_FILE_VERSION_COMPAT);
> > +
> > return -ENOTSUP;
> > }
> > if (v != QEMU_VM_FILE_VERSION) {
> > - error_report("Unsupported migration stream version");
> > + error_setg(errp, "Unsupported migration stream "
> > + "version, file version %x != %x", v,
> > QEMU_VM_FILE_VERSION);
> > return -ENOTSUP;
> > }
> >
> > if (migrate_get_current()->send_configuration) {
> > - if (qemu_get_byte(f) != QEMU_VM_CONFIGURATION) {
> > - error_report("Configuration section missing");
> > + v = qemu_get_byte(f);
> > + if (v != QEMU_VM_CONFIGURATION) {
> > + error_setg(errp, "Configuration section missing,"
> >
>
> here too
yes
>
>
> > + "%x != %x", v, QEMU_VM_CONFIGURATION);
> > return -EINVAL;
> > }
> > - ret = vmstate_load_state(f, &vmstate_configuration,
> > &savevm_state, 0,
> > - NULL);
> >
> > + ret = vmstate_load_state(f, &vmstate_configuration,
> > &savevm_state, 0,
> > + errp);
> > if (ret) {
> > return ret;
> > }
> > @@ -3119,7 +3126,7 @@ int qemu_loadvm_state(QEMUFile *f)
> >
> > qemu_loadvm_thread_pool_create(mis);
> >
> > - ret = qemu_loadvm_state_header(f);
> > + ret = qemu_loadvm_state_header(f, NULL);
> > if (ret) {
> > return ret;
> > }
> >
> > --
> > 2.50.0
> >
> >
Regards,
Arun
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 08/24] migration: push Error **errp into loadvm_process_command()
2025-07-21 12:38 ` Akihiko Odaki
@ 2025-07-25 7:13 ` Arun Menon
0 siblings, 0 replies; 55+ messages in thread
From: Arun Menon @ 2025-07-25 7:13 UTC (permalink / raw)
To: Akihiko Odaki
Cc: qemu-devel, Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck,
Halil Pasic, Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Dmitry Osipenko,
Matthew Rosato
Hi,
Thanks for the review.
On Mon, Jul 21, 2025 at 09:38:53PM +0900, Akihiko Odaki wrote:
> On 2025/07/21 20:29, Arun Menon wrote:
> > This is an incremental step in converting vmstate loading
> > code to report error via Error objects instead of directly
> > printing it to console/monitor.
> > It is ensured that loadvm_process_command() must report an error
> > in errp, in case of failure.
> >
> > Signed-off-by: Arun Menon <armenon@redhat.com>
> > ---
> > migration/savevm.c | 87 +++++++++++++++++++++++++++++++++++++++++-------------
> > 1 file changed, 66 insertions(+), 21 deletions(-)
> >
> > diff --git a/migration/savevm.c b/migration/savevm.c
> > index 96af7b412f2ed43468f4bcac8b833cda223f8321..d8feb9e1599d019636cd400ee7ebe594df27bd1d 100644
> > --- a/migration/savevm.c
> > +++ b/migration/savevm.c
> > @@ -2546,12 +2546,13 @@ static int loadvm_postcopy_handle_switchover_start(void)
> > * LOADVM_QUIT All good, but exit the loop
> > * <0 Error
> > */
> > -static int loadvm_process_command(QEMUFile *f)
> > +static int loadvm_process_command(QEMUFile *f, Error **errp)
> > {
> > MigrationIncomingState *mis = migration_incoming_get_current();
> > uint16_t cmd;
> > uint16_t len;
> > uint32_t tmp32;
> > + int ret;
> > cmd = qemu_get_be16(f);
> > len = qemu_get_be16(f);
> > @@ -2562,16 +2563,16 @@ static int loadvm_process_command(QEMUFile *f)
> > }
> > if (cmd >= MIG_CMD_MAX || cmd == MIG_CMD_INVALID) {
> > - error_report("MIG_CMD 0x%x unknown (len 0x%x)", cmd, len);
> > + error_setg(errp, "MIG_CMD 0x%x unknown (len 0x%x)", cmd, len);
> > return -EINVAL;
> > }
> > trace_loadvm_process_command(mig_cmd_args[cmd].name, len);
> > if (mig_cmd_args[cmd].len != -1 && mig_cmd_args[cmd].len != len) {
> > - error_report("%s received with bad length - expecting %zu, got %d",
> > - mig_cmd_args[cmd].name,
> > - (size_t)mig_cmd_args[cmd].len, len);
> > + error_setg(errp, "%s received with bad length - expecting %zu, got %d",
> > + mig_cmd_args[cmd].name,
> > + (size_t)mig_cmd_args[cmd].len, len);
> > return -ERANGE;
> > }
> > @@ -2590,11 +2591,10 @@ static int loadvm_process_command(QEMUFile *f)
> > * been created.
> > */
> > if (migrate_switchover_ack() && !mis->switchover_ack_pending_num) {
> > - int ret = migrate_send_rp_switchover_ack(mis);
> > + ret = migrate_send_rp_switchover_ack(mis);
> > if (ret) {
> > - error_report(
> > - "Could not send switchover ack RP MSG, err %d (%s)", ret,
> > - strerror(-ret));
> > + error_setg(errp, "Could not send switchover ack "
> > + "RP MSG, err %d (%s)", ret, strerror(-ret));
> > return ret;
> > }
> > }
> > @@ -2604,39 +2604,84 @@ static int loadvm_process_command(QEMUFile *f)
> > tmp32 = qemu_get_be32(f);
> > trace_loadvm_process_command_ping(tmp32);
> > if (!mis->to_src_file) {
> > - error_report("CMD_PING (0x%x) received with no return path",
> > - tmp32);
> > + error_setg(errp, "CMD_PING (0x%x) received with no return path",
> > + tmp32);
> > return -1;
> > }
> > migrate_send_rp_pong(mis, tmp32);
> > break;
> > case MIG_CMD_PACKAGED:
> > - return loadvm_handle_cmd_packaged(mis);
> > + ret = loadvm_handle_cmd_packaged(mis);
> > + if (ret < 0) {
> > + error_setg(errp, "Failed to load device state command: %d", ret);
> > + return -1;
>
> This "return -1" is extraneous.
>
> The error_setg() call is later replaced with "[PATCH v6 09/24] migration:
> push Error **errp into loadvm_handle_cmd_packaged()", but this "return -1"
> is simply removed in the patch. There is no need to add it in the first
> place.
Agreed. I will remove the return -1 here.
>
> > + }
> > + return ret;
> > case MIG_CMD_POSTCOPY_ADVISE:
> > - return loadvm_postcopy_handle_advise(mis, len);
> > + ret = loadvm_postcopy_handle_advise(mis, len);
> > + if (ret < 0) {
> > + error_setg(errp, "Failed to load device state command: %d", ret);
> > + return -1;
> > + }
> > + return ret;
> > case MIG_CMD_POSTCOPY_LISTEN:
> > - return loadvm_postcopy_handle_listen(mis);
> > + ret = loadvm_postcopy_handle_listen(mis);
> > + if (ret < 0) {
> > + error_setg(errp, "Failed to load device state command: %d", ret);
> > + return -1;
> > + }
> > + return ret;
> > case MIG_CMD_POSTCOPY_RUN:
> > - return loadvm_postcopy_handle_run(mis);
> > + ret = loadvm_postcopy_handle_run(mis);
> > + if (ret < 0) {
> > + error_setg(errp, "Failed to load device state command: %d", ret);
> > + return -1;
> > + }
> > + return ret;
> > case MIG_CMD_POSTCOPY_RAM_DISCARD:
> > - return loadvm_postcopy_ram_handle_discard(mis, len);
> > + ret = loadvm_postcopy_ram_handle_discard(mis, len);
> > + if (ret < 0) {
> > + error_setg(errp, "Failed to load device state command: %d", ret);
> > + return -1;
> > + }
> > + return ret;
> > case MIG_CMD_POSTCOPY_RESUME:
> > - return loadvm_postcopy_handle_resume(mis);
> > + ret = loadvm_postcopy_handle_resume(mis);
> > + if (ret < 0) {
> > + error_setg(errp, "Failed to load device state command: %d", ret);
> > + return -1;
> > + }
> > + return ret;
> > case MIG_CMD_RECV_BITMAP:
> > - return loadvm_handle_recv_bitmap(mis, len);
> > + ret = loadvm_handle_recv_bitmap(mis, len);
> > + if (ret < 0) {
> > + error_setg(errp, "Failed to load device state command: %d", ret);
> > + return -1;
> > + }
> > + return ret;
> > case MIG_CMD_ENABLE_COLO:
> > - return loadvm_process_enable_colo(mis);
> > + ret = loadvm_process_enable_colo(mis);
> > + if (ret < 0) {
> > + error_setg(errp, "Failed to load device state command: %d", ret);
> > + return -1;
> > + }
> > + return ret;
> > case MIG_CMD_SWITCHOVER_START:
> > - return loadvm_postcopy_handle_switchover_start();
> > + ret = loadvm_postcopy_handle_switchover_start();
> > + if (ret < 0) {
> > + error_setg(errp, "Failed to load device state command: %d", ret);
> > + return -1;
> > + }
> > + return ret;
> > }
> > return 0;
> > @@ -3074,7 +3119,7 @@ retry:
> > }
> > break;
> > case QEMU_VM_COMMAND:
> > - ret = loadvm_process_command(f);
> > + ret = loadvm_process_command(f, NULL);
> > trace_qemu_loadvm_state_section_command(ret);
> > if ((ret < 0) || (ret == LOADVM_QUIT)) {
> > goto out;
> >
>
Regards,
Arun
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 11/24] migration: push Error **errp into loadvm_postcopy_handle_advise()
2025-07-21 12:43 ` Akihiko Odaki
@ 2025-07-25 7:14 ` Arun Menon
0 siblings, 0 replies; 55+ messages in thread
From: Arun Menon @ 2025-07-25 7:14 UTC (permalink / raw)
To: Akihiko Odaki
Cc: qemu-devel, Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck,
Halil Pasic, Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Dmitry Osipenko,
Matthew Rosato, Daniel P. Berrangé
Hi,
Thanks for the review.
On Mon, Jul 21, 2025 at 09:43:30PM +0900, Akihiko Odaki wrote:
> On 2025/07/21 20:29, Arun Menon wrote:
> > This is an incremental step in converting vmstate loading
> > code to report error via Error objects instead of directly
> > printing it to console/monitor.
> > It is ensured that loadvm_postcopy_handle_advise() must report an error
> > in errp, in case of failure.
> >
> > Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
> > Signed-off-by: Arun Menon <armenon@redhat.com>
> > ---
> > migration/savevm.c | 39 +++++++++++++++++----------------------
> > 1 file changed, 17 insertions(+), 22 deletions(-)
> >
> > diff --git a/migration/savevm.c b/migration/savevm.c
> > index 6b8c78bfb9bde2a8e7500b0342cd386b0d12db97..4a3db9498678a19597257e683029cd3f6c8d1a65 100644
> > --- a/migration/savevm.c
> > +++ b/migration/savevm.c
> > @@ -1912,39 +1912,39 @@ enum LoadVMExitCodes {
> > * quickly.
> > */
> > static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis,
> > - uint16_t len)
> > + uint16_t len, Error **errp)
> > {
> > PostcopyState ps = postcopy_state_set(POSTCOPY_INCOMING_ADVISE);
> > uint64_t remote_pagesize_summary, local_pagesize_summary, remote_tps;
> > size_t page_size = qemu_target_page_size();
> > - Error *local_err = NULL;
> > trace_loadvm_postcopy_handle_advise();
> > if (ps != POSTCOPY_INCOMING_NONE) {
> > - error_report("CMD_POSTCOPY_ADVISE in wrong postcopy state (%d)", ps);
> > + error_setg(errp, "CMD_POSTCOPY_ADVISE in wrong postcopy "
> > + "state (%d)", ps);
> > return -1;
> > }
> > switch (len) {
> > case 0:
> > if (migrate_postcopy_ram()) {
> > - error_report("RAM postcopy is enabled but have 0 byte advise");
> > + error_setg(errp, "RAM postcopy is enabled but have 0 byte advise");
> > return -EINVAL;
> > }
> > return 0;
> > case 8 + 8:
> > if (!migrate_postcopy_ram()) {
> > - error_report("RAM postcopy is disabled but have 16 byte advise");
> > + error_setg(errp, "RAM postcopy is disabled but have 16 "
> > + "byte advise");
> > return -EINVAL;
> > }
> > break;
> > default:
> > - error_report("CMD_POSTCOPY_ADVISE invalid length (%d)", len);
> > + error_setg(errp, "CMD_POSTCOPY_ADVISE invalid length (%d)", len);
> > return -EINVAL;
> > }
> > - if (!postcopy_ram_supported_by_host(mis, &local_err)) {
> > - error_report_err(local_err);
> > + if (!postcopy_ram_supported_by_host(mis, errp)) {
> > postcopy_state_set(POSTCOPY_INCOMING_NONE);
> > return -1;
> > }
> > @@ -1967,9 +1967,9 @@ static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis,
> > * also fails when passed to an older qemu that doesn't
> > * do huge pages.
> > */
> > - error_report("Postcopy needs matching RAM page sizes (s=%" PRIx64
> > - " d=%" PRIx64 ")",
> > - remote_pagesize_summary, local_pagesize_summary);
> > + error_setg(errp, "Postcopy needs matching RAM "
> > + "page sizes (s=%" PRIx64 " d=%" PRIx64 ")",
> > + remote_pagesize_summary, local_pagesize_summary);
> > return -1;
> > }
> > @@ -1979,17 +1979,17 @@ static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis,
> > * Again, some differences could be dealt with, but for now keep it
> > * simple.
> > */
> > - error_report("Postcopy needs matching target page sizes (s=%d d=%zd)",
> > - (int)remote_tps, page_size);
> > + error_setg(errp, "Postcopy needs matching target "
> > + "page sizes (s=%d d=%zd)", (int)remote_tps, page_size);
> > return -1;
> > }
> > - if (postcopy_notify(POSTCOPY_NOTIFY_INBOUND_ADVISE, &local_err)) {
> > - error_report_err(local_err);
> > + if (postcopy_notify(POSTCOPY_NOTIFY_INBOUND_ADVISE, errp)) {
> > return -1;
> > }
> > - if (ram_postcopy_incoming_init(mis, NULL) < 0) {
> > + if (ram_postcopy_incoming_init(mis, errp) < 0) {
> > + error_prepend(errp, "PostCopy RAM incoming init failed ");
>
> Nitpick: s/PostCopy/Postcopy/ for consistency with other error messages.
>
Good catch, thanks.
Might as well amend it while working on the new version.
Regards,
Arun
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 15/24] migration: make loadvm_postcopy_handle_resume() void
2025-07-21 12:46 ` Akihiko Odaki
@ 2025-07-25 7:15 ` Arun Menon
0 siblings, 0 replies; 55+ messages in thread
From: Arun Menon @ 2025-07-25 7:15 UTC (permalink / raw)
To: Akihiko Odaki
Cc: qemu-devel, Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck,
Halil Pasic, Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Dmitry Osipenko,
Matthew Rosato, Daniel P. Berrangé
Hi,
Thanks for the review.
On Mon, Jul 21, 2025 at 09:46:59PM +0900, Akihiko Odaki wrote:
> On 2025/07/21 20:29, Arun Menon wrote:
> > This is an incremental step in converting vmstate loading
> > code to report error via Error objects instead of directly
> > printing it to console/monitor.
> >
> > Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
> > Signed-off-by: Arun Menon <armenon@redhat.com>
> > ---
> > migration/savevm.c | 16 +++++-----------
> > 1 file changed, 5 insertions(+), 11 deletions(-)
> >
> > diff --git a/migration/savevm.c b/migration/savevm.c
> > index e472f79d5d5c4fb4410a28cbf43c298be028f4b4..6887877f2f8648f66e34bdb1cc3ca6dc7514f9df 100644
> > --- a/migration/savevm.c
> > +++ b/migration/savevm.c
> > @@ -2339,12 +2339,12 @@ static void migrate_send_rp_req_pages_pending(MigrationIncomingState *mis)
> > }
> > }
> > -static int loadvm_postcopy_handle_resume(MigrationIncomingState *mis)
> > +static void loadvm_postcopy_handle_resume(MigrationIncomingState *mis)
> > {
> > if (mis->state != MIGRATION_STATUS_POSTCOPY_RECOVER) {
> > - error_report("%s: illegal resume received", __func__);
> > + warn_report("%s: illegal resume received", __func__);
> > /* Don't fail the load, only for this. */
> > - return 0;
> > + return;
> > }
> > /*
> > @@ -2396,8 +2396,6 @@ static int loadvm_postcopy_handle_resume(MigrationIncomingState *mis)
> > /* Kick the fast ram load thread too */
> > qemu_sem_post(&mis->postcopy_pause_sem_fast_load);
> > }
> > -
> > - return 0;
> > }
> > /**
> > @@ -2635,12 +2633,8 @@ static int loadvm_process_command(QEMUFile *f, Error **errp)
> > return loadvm_postcopy_ram_handle_discard(mis, len, errp);
> > case MIG_CMD_POSTCOPY_RESUME:
> > - ret = loadvm_postcopy_handle_resume(mis);
> > - if (ret < 0) {
> > - error_setg(errp, "Failed to load device state command: %d", ret);
> > - return -1;
> > - }
> > - return ret;
> > + loadvm_postcopy_handle_resume(mis);
> > + return 0;
>
> This patch can be moved before "[PATCH v6 08/24] migration: push Error
> **errp into loadvm_process_command()" to make it smaller.
Agreed. Will do.
>
> > case MIG_CMD_RECV_BITMAP:
> > ret = loadvm_handle_recv_bitmap(mis, len);
> >
>
Regards,
Arun
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 23/24] migration: Add error-parameterized function variants in VMSD struct
2025-07-21 15:15 ` Akihiko Odaki
@ 2025-08-09 8:17 ` Markus Armbruster
2025-08-09 9:53 ` Akihiko Odaki
0 siblings, 1 reply; 55+ messages in thread
From: Markus Armbruster @ 2025-08-09 8:17 UTC (permalink / raw)
To: Akihiko Odaki
Cc: Daniel P. Berrangé, Arun Menon, qemu-devel,
Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Dmitry Osipenko,
Matthew Rosato
Almost missed this, sorry.
Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> writes:
> On 2025/07/21 22:29, Daniel P. Berrangé wrote:
>> On Mon, Jul 21, 2025 at 10:14:30PM +0900, Akihiko Odaki wrote:
>>> On 2025/07/21 20:29, Arun Menon wrote:
>>>> - We need to have good error reporting in the callbacks in
>>>> VMStateDescription struct. Specifically pre_save, post_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.
>>>>
>>>> Signed-off-by: Arun Menon <armenon@redhat.com>
>>>> ---
>>>> include/migration/vmstate.h | 11 +++++++++++
>>>> migration/vmstate.c | 47 +++++++++++++++++++++++++++++++++++++++------
>>>> 2 files changed, 52 insertions(+), 6 deletions(-)
>>>>
>>>> diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
>>>> index 056781b1c21e737583f081594d9f88b32adfd674..53fa72c1bbde399be02c88fc8745fdbb79bfd7c8 100644
>>>> --- a/include/migration/vmstate.h
>>>> +++ b/include/migration/vmstate.h
>>>> @@ -200,15 +200,26 @@ 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.
>>>> */
>>>> +
>>>> 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);
>>>> + int (*post_save_errp)(void *opaque, Error **errp);
>>>
>>> I think the new functions should have void as return value instead.
>>>
>>> As I discussed before, I think having an integer return value is a source of
>>> confusion:
>>> https://lore.kernel.org/qemu-devel/0447e269-c242-4cd7-b68e-d0c7211784a7@rsg.ci.i.u-tokyo.ac.jp/
I disagree.
We've discussed this a few times. Here's a recent instance:
https://lore.kernel.org/qemu-devel/87jz5tbbqx.fsf@pond.sub.org/
>>> In the previous discussion, I suggested using bool, but void fits better in
>>> this particular case.
>>>
>>> include/qapi/error.h says:
>>>> Whenever practical, also return a value that indicates success /
>>>> failure. This can make the error checking more concise, and can avoid
>>>> useless error object creation and destruction. Note that we still
>>>> have many functions returning void.
>>>
>>> There will be more implementations of these function pointers than their
>>> callers, so it makes more sense to let return void and make implementations
>>> more concise while making the callers less so. There is also DeviceRealize,
>>> an example of function pointer type that takes errp but returns void.
>>
>> No, please do NOT make these functions void. As that text you quote
>> says, we want functions to return a value indicating success/failure.
>> 'void' return is a historical practice we don't want to continue
>> in QEMU.
>>
>> Given that the existing methods all return 'int', we should remain
>> consistent with the new functions and return 'int', with -1 for
>> failure, 0 for success, and not use bool.
>
> Markus, I'd also like to hear your opinion since you are the maintainer of the error reporting facility.
I'm with Daniel.
New code should stick to the rules.
Changing existing code from "sticks to the rules" to not requires pretty
compelling justification.
The other direction is more welcome, but whether the juice is worth the
squeeze still needs to be decided case by case.
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 23/24] migration: Add error-parameterized function variants in VMSD struct
2025-08-09 8:17 ` Markus Armbruster
@ 2025-08-09 9:53 ` Akihiko Odaki
2025-08-09 14:30 ` Markus Armbruster
0 siblings, 1 reply; 55+ messages in thread
From: Akihiko Odaki @ 2025-08-09 9:53 UTC (permalink / raw)
To: Markus Armbruster
Cc: Daniel P. Berrangé, Arun Menon, qemu-devel,
Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Dmitry Osipenko,
Matthew Rosato
On 2025/08/09 17:17, Markus Armbruster wrote:
> Almost missed this, sorry.
>
> Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> writes:
>
>> On 2025/07/21 22:29, Daniel P. Berrangé wrote:
>>> On Mon, Jul 21, 2025 at 10:14:30PM +0900, Akihiko Odaki wrote:
>>>> On 2025/07/21 20:29, Arun Menon wrote:
>>>>> - We need to have good error reporting in the callbacks in
>>>>> VMStateDescription struct. Specifically pre_save, post_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.
>>>>>
>>>>> Signed-off-by: Arun Menon <armenon@redhat.com>
>>>>> ---
>>>>> include/migration/vmstate.h | 11 +++++++++++
>>>>> migration/vmstate.c | 47 +++++++++++++++++++++++++++++++++++++++------
>>>>> 2 files changed, 52 insertions(+), 6 deletions(-)
>>>>>
>>>>> diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
>>>>> index 056781b1c21e737583f081594d9f88b32adfd674..53fa72c1bbde399be02c88fc8745fdbb79bfd7c8 100644
>>>>> --- a/include/migration/vmstate.h
>>>>> +++ b/include/migration/vmstate.h
>>>>> @@ -200,15 +200,26 @@ 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.
>>>>> */
>>>>> +
>>>>> 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);
>>>>> + int (*post_save_errp)(void *opaque, Error **errp);
>>>>
>>>> I think the new functions should have void as return value instead.
>>>>
>>>> As I discussed before, I think having an integer return value is a source of
>>>> confusion:
>>>> https://lore.kernel.org/qemu-devel/0447e269-c242-4cd7-b68e-d0c7211784a7@rsg.ci.i.u-tokyo.ac.jp/
>
> I disagree.
>
> We've discussed this a few times. Here's a recent instance:
> https://lore.kernel.org/qemu-devel/87jz5tbbqx.fsf@pond.sub.org/
>
>>>> In the previous discussion, I suggested using bool, but void fits better in
>>>> this particular case.
>>>>
>>>> include/qapi/error.h says:
>>>>> Whenever practical, also return a value that indicates success /
>>>>> failure. This can make the error checking more concise, and can avoid
>>>>> useless error object creation and destruction. Note that we still
>>>>> have many functions returning void.
>>>>
>>>> There will be more implementations of these function pointers than their
>>>> callers, so it makes more sense to let return void and make implementations
>>>> more concise while making the callers less so. There is also DeviceRealize,
>>>> an example of function pointer type that takes errp but returns void.
>>>
>>> No, please do NOT make these functions void. As that text you quote
>>> says, we want functions to return a value indicating success/failure.
>>> 'void' return is a historical practice we don't want to continue
>>> in QEMU.
>>>
>>> Given that the existing methods all return 'int', we should remain
>>> consistent with the new functions and return 'int', with -1 for
>>> failure, 0 for success, and not use bool.
>>
>> Markus, I'd also like to hear your opinion since you are the maintainer of the error reporting facility.
>
> I'm with Daniel.
>
> New code should stick to the rules.
>
> Changing existing code from "sticks to the rules" to not requires pretty
> compelling justification.
>
> The other direction is more welcome, but whether the juice is worth the
> squeeze still needs to be decided case by case.
What do you refer with the rules?
There were three options on the table: bool, int, and void.
The previous discussion you referred explains why void should be
avoided, and include/qapi/error.h also says void should be avoided.
There is pre_load() that does not use Error returns int, but now we are
adding pre_load_errp() that uses Error.
Then what pre_load_errp() should return: bool or int?
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 23/24] migration: Add error-parameterized function variants in VMSD struct
2025-08-09 9:53 ` Akihiko Odaki
@ 2025-08-09 14:30 ` Markus Armbruster
2025-08-10 4:59 ` Akihiko Odaki
0 siblings, 1 reply; 55+ messages in thread
From: Markus Armbruster @ 2025-08-09 14:30 UTC (permalink / raw)
To: Akihiko Odaki
Cc: Markus Armbruster, Daniel P. Berrangé, Arun Menon,
qemu-devel, Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck,
Halil Pasic, Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Dmitry Osipenko,
Matthew Rosato
Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> writes:
> On 2025/08/09 17:17, Markus Armbruster wrote:
>> Almost missed this, sorry.
>> Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> writes:
>>
>>> On 2025/07/21 22:29, Daniel P. Berrangé wrote:
[...]
>>>> No, please do NOT make these functions void. As that text you quote
>>>> says, we want functions to return a value indicating success/failure.
>>>> 'void' return is a historical practice we don't want to continue
>>>> in QEMU.
>>>>
>>>> Given that the existing methods all return 'int', we should remain
>>>> consistent with the new functions and return 'int', with -1 for
>>>> failure, 0 for success, and not use bool.
>>>
>>> Markus, I'd also like to hear your opinion since you are the maintainer of the error reporting facility.
>>
>> I'm with Daniel.
>>
>> New code should stick to the rules.
>>
>> Changing existing code from "sticks to the rules" to not requires pretty
>> compelling justification.
>>
>> The other direction is more welcome, but whether the juice is worth the
>> squeeze still needs to be decided case by case.
>
> What do you refer with the rules?
The big comment in qapi/error.h starts with a section = Rules =.
> There were three options on the table: bool, int, and void.
>
> The previous discussion you referred explains why void should be avoided, and include/qapi/error.h also says void should be avoided.
>
> There is pre_load() that does not use Error returns int, but now we are adding pre_load_errp() that uses Error.
>
> Then what pre_load_errp() should return: bool or int?
I like bool when it's all we need.
When we need to return a non-negative int on success, use int and return
-1 or a negative error code on failure.
Another reason to pick int is local consistency: related functions
already use int.
Changing working code from int to bool doesn't seem worth the bother.
Questions?
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 23/24] migration: Add error-parameterized function variants in VMSD struct
2025-08-09 14:30 ` Markus Armbruster
@ 2025-08-10 4:59 ` Akihiko Odaki
2025-08-25 12:00 ` Markus Armbruster
0 siblings, 1 reply; 55+ messages in thread
From: Akihiko Odaki @ 2025-08-10 4:59 UTC (permalink / raw)
To: Markus Armbruster
Cc: Daniel P. Berrangé, Arun Menon, qemu-devel,
Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Dmitry Osipenko,
Matthew Rosato
On 2025/08/09 23:30, Markus Armbruster wrote:
> Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> writes:
>
>> On 2025/08/09 17:17, Markus Armbruster wrote:
>>> Almost missed this, sorry.
>>> Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> writes:
>>>
>>>> On 2025/07/21 22:29, Daniel P. Berrangé wrote:
>
> [...]
>
>>>>> No, please do NOT make these functions void. As that text you quote
>>>>> says, we want functions to return a value indicating success/failure.
>>>>> 'void' return is a historical practice we don't want to continue
>>>>> in QEMU.
>>>>>
>>>>> Given that the existing methods all return 'int', we should remain
>>>>> consistent with the new functions and return 'int', with -1 for
>>>>> failure, 0 for success, and not use bool.
>>>>
>>>> Markus, I'd also like to hear your opinion since you are the maintainer of the error reporting facility.
>>>
>>> I'm with Daniel.
>>>
>>> New code should stick to the rules.
>>>
>>> Changing existing code from "sticks to the rules" to not requires pretty
>>> compelling justification.
>>>
>>> The other direction is more welcome, but whether the juice is worth the
>>> squeeze still needs to be decided case by case.
>>
>> What do you refer with the rules?
>
> The big comment in qapi/error.h starts with a section = Rules =.
>
>> There were three options on the table: bool, int, and void.
>>
>> The previous discussion you referred explains why void should be avoided, and include/qapi/error.h also says void should be avoided.
>>
>> There is pre_load() that does not use Error returns int, but now we are adding pre_load_errp() that uses Error.
>>
>> Then what pre_load_errp() should return: bool or int?
>
> I like bool when it's all we need.
>
> When we need to return a non-negative int on success, use int and return
> -1 or a negative error code on failure.
>
> Another reason to pick int is local consistency: related functions
> already use int.
>
> Changing working code from int to bool doesn't seem worth the bother.
>
> Questions?
>
I at least see what "[PATCH v9 26/27] migration: Add error-parameterized
function variants in VMSD struct" says is undesirable. It says:
> For the errp variants,
> Returns: 0 on success,
> <0 on error where -value is an error number from errno.h
There are already non-errp variant implementations that return -1 (e.g.,
dbus_vmstate_post_load). Adding errp variants that require to return
errno is degradation.
I'm still not sure what conclusion will be drawn. I can make two
opposite conclusions:
- Non-errp variants return int, so errp variants should also return int
for local consistency.
- bool is all we need, but changing non-errp variants doesn't seem worth
the bother, so only errp variants should return bool.
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v6 23/24] migration: Add error-parameterized function variants in VMSD struct
2025-08-10 4:59 ` Akihiko Odaki
@ 2025-08-25 12:00 ` Markus Armbruster
0 siblings, 0 replies; 55+ messages in thread
From: Markus Armbruster @ 2025-08-25 12:00 UTC (permalink / raw)
To: Akihiko Odaki
Cc: Daniel P. Berrangé, Arun Menon, qemu-devel,
Michael S. Tsirkin, Marcel Apfelbaum, Cornelia Huck, Halil Pasic,
Eric Farman, Richard Henderson, David Hildenbrand,
Ilya Leoshkevich, Thomas Huth, Christian Borntraeger,
Paolo Bonzini, Fam Zheng, Nicholas Piggin,
Daniel Henrique Barboza, Harsh Prateek Bora, Alex Williamson,
Cédric Le Goater, Peter Xu, Fabiano Rosas, Hailiang Zhang,
Steve Sistare, qemu-s390x, qemu-ppc, Stefan Berger,
Marc-André Lureau, Alex Bennée, Dmitry Osipenko,
Matthew Rosato
Please excuse the delayed response, I was on vacation.
Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> writes:
> On 2025/08/09 23:30, Markus Armbruster wrote:
>> Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> writes:
[...]
>>> There were three options on the table: bool, int, and void.
>>>
>>> The previous discussion you referred explains why void should be avoided, and include/qapi/error.h also says void should be avoided.
>>>
>>> There is pre_load() that does not use Error returns int, but now we are adding pre_load_errp() that uses Error.
>>>
>>> Then what pre_load_errp() should return: bool or int?
>>
>> I like bool when it's all we need.
>>
>> When we need to return a non-negative int on success, use int and return
>> -1 or a negative error code on failure.
>>
>> Another reason to pick int is local consistency: related functions
>> already use int.
>>
>> Changing working code from int to bool doesn't seem worth the bother.
>>
>> Questions?
>
> I at least see what "[PATCH v9 26/27] migration: Add error-parameterized function variants in VMSD struct" says is undesirable. It says:
>
>> For the errp variants,
>> Returns: 0 on success,
>> <0 on error where -value is an error number from errno.h
Does any caller use errno codes to discriminate between failures?
> There are already non-errp variant implementations that return -1 (e.g., dbus_vmstate_post_load). Adding errp variants that require to return errno is degradation.
However, the non-errp variants are intended to be removed. Any
inconsistency with them would hopefully be temporary. We can accept
that when other considerations call for it.
> I'm still not sure what conclusion will be drawn. I can make two opposite conclusions:
>
> - Non-errp variants return int, so errp variants should also return int
> for local consistency.
>
> - bool is all we need, but changing non-errp variants doesn't seem worth
> the bother, so only errp variants should return bool.
Here's my recommendation.
If any caller needs to use errno codes, use int and return -errno on
failure. This is inconsistent with the old callbacks, but callers'
needs trump that.
Else if we want consistency with the old callbacks even though we intend
to remove them, use int and return -1 on failure.
Else use bool and return false on failure.
^ permalink raw reply [flat|nested] 55+ messages in thread
end of thread, other threads:[~2025-08-25 12:01 UTC | newest]
Thread overview: 55+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-21 11:29 [PATCH v6 00/24] migration: propagate vTPM errors using Error objects Arun Menon
2025-07-21 11:29 ` [PATCH v6 01/24] migration: push Error **errp into vmstate_subsection_load() Arun Menon
2025-07-21 12:10 ` Akihiko Odaki
2025-07-25 7:09 ` Arun Menon
2025-07-21 11:29 ` [PATCH v6 02/24] migration: push Error **errp into vmstate_load_state() Arun Menon
2025-07-21 12:24 ` Akihiko Odaki
2025-07-25 7:11 ` Arun Menon
2025-07-21 12:30 ` Marc-André Lureau
2025-07-25 7:12 ` Arun Menon
2025-07-21 11:29 ` [PATCH v6 03/24] migration: push Error **errp into qemu_loadvm_state_header() Arun Menon
2025-07-21 12:34 ` Marc-André Lureau
2025-07-25 7:12 ` Arun Menon
2025-07-21 11:29 ` [PATCH v6 04/24] migration: push Error **errp into vmstate_load() Arun Menon
2025-07-21 11:29 ` [PATCH v6 05/24] migration: push Error **errp into qemu_loadvm_section_start_full() Arun Menon
2025-07-21 11:29 ` [PATCH v6 06/24] migration: push Error **errp into qemu_loadvm_section_part_end() Arun Menon
2025-07-21 11:29 ` [PATCH v6 07/24] migration: Update qemu_file_get_return_path() docs and remove dead checks Arun Menon
2025-07-21 12:24 ` Daniel P. Berrangé
2025-07-21 11:29 ` [PATCH v6 08/24] migration: push Error **errp into loadvm_process_command() Arun Menon
2025-07-21 12:38 ` Akihiko Odaki
2025-07-25 7:13 ` Arun Menon
2025-07-21 11:29 ` [PATCH v6 09/24] migration: push Error **errp into loadvm_handle_cmd_packaged() Arun Menon
2025-07-21 11:29 ` [PATCH v6 10/24] migration: push Error **errp into ram_postcopy_incoming_init() Arun Menon
2025-07-21 11:29 ` [PATCH v6 11/24] migration: push Error **errp into loadvm_postcopy_handle_advise() Arun Menon
2025-07-21 12:43 ` Akihiko Odaki
2025-07-25 7:14 ` Arun Menon
2025-07-21 11:29 ` [PATCH v6 12/24] migration: push Error **errp into loadvm_postcopy_handle_listen() Arun Menon
2025-07-21 11:29 ` [PATCH v6 13/24] migration: push Error **errp into loadvm_postcopy_handle_run() Arun Menon
2025-07-21 11:29 ` [PATCH v6 14/24] migration: push Error **errp into loadvm_postcopy_ram_handle_discard() Arun Menon
2025-07-21 11:29 ` [PATCH v6 15/24] migration: make loadvm_postcopy_handle_resume() void Arun Menon
2025-07-21 12:46 ` Akihiko Odaki
2025-07-25 7:15 ` Arun Menon
2025-07-21 11:29 ` [PATCH v6 16/24] migration: push Error **errp into loadvm_handle_recv_bitmap() Arun Menon
2025-07-21 11:29 ` [PATCH v6 17/24] migration: push Error **errp into loadvm_process_enable_colo() Arun Menon
2025-07-21 11:29 ` [PATCH v6 18/24] migration: push Error **errp into loadvm_postcopy_handle_switchover_start() Arun Menon
2025-07-21 11:29 ` [PATCH v6 19/24] migration: push Error **errp into qemu_loadvm_state_main() Arun Menon
2025-07-21 11:29 ` [PATCH v6 20/24] migration: push Error **errp into qemu_loadvm_state() Arun Menon
2025-07-21 13:01 ` Akihiko Odaki
2025-07-25 7:09 ` Arun Menon
2025-07-21 11:29 ` [PATCH v6 21/24] migration: push Error **errp into qemu_load_device_state() Arun Menon
2025-07-21 11:29 ` [PATCH v6 22/24] migration: Capture error in postcopy_ram_listen_thread() Arun Menon
2025-07-21 11:29 ` [PATCH v6 23/24] migration: Add error-parameterized function variants in VMSD struct Arun Menon
2025-07-21 13:14 ` Akihiko Odaki
2025-07-21 13:29 ` Daniel P. Berrangé
2025-07-21 15:15 ` Akihiko Odaki
2025-08-09 8:17 ` Markus Armbruster
2025-08-09 9:53 ` Akihiko Odaki
2025-08-09 14:30 ` Markus Armbruster
2025-08-10 4:59 ` Akihiko Odaki
2025-08-25 12:00 ` Markus Armbruster
2025-07-21 13:32 ` Daniel P. Berrangé
2025-07-21 13:54 ` Arun Menon
2025-07-21 14:05 ` Daniel P. Berrangé
2025-07-21 15:10 ` Arun Menon
2025-07-25 6:39 ` Arun Menon
2025-07-21 11:29 ` [PATCH v6 24/24] backends/tpm: Propagate vTPM error on migration failure Arun Menon
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).