public inbox for qemu-devel@nongnu.org
 help / color / mirror / Atom feed
* [PATCH v3 00/18] migration: more bool+errp APIs
@ 2026-03-04 21:22 Vladimir Sementsov-Ogievskiy
  2026-03-04 21:22 ` [PATCH v3 01/18] migration: vmstate_save_state_v: fix double error_setg Vladimir Sementsov-Ogievskiy
                   ` (18 more replies)
  0 siblings, 19 replies; 33+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2026-03-04 21:22 UTC (permalink / raw)
  To: peterx; +Cc: farosas, vsementsov, qemu-devel

v3:
01,02: add r-bs by Fabiano and Peter
03: improve comment, add r-b by Peter
04: add r-bs by Fabiano and Peter
05: new, replacement for dropped "[PATCH v2 05/16] migration: vmstate_save/load_state(): stop tracing errors"
06: rebase on kept trace-points, keep r-b by Peter
07-09: add r-b by Peter
10: rebase on kept trace-points, keep r-b by Peter
11-12: add r-b by Peter
13: rebase ion kept traces and logic around trace_vmstate_load_field_error() already refactored, fix indent, drop r-b
14: add r-b by Peter
15: add r-b by Peter, use "else { if () {} }"
16-17: new
18: rebased on dropped err_hint, drop r-b

Vladimir Sementsov-Ogievskiy (18):
  migration: vmstate_save_state_v: fix double error_setg
  migration: make vmstate_save_state_v() static
  migration: make .post_save() a void function
  migration: vmstate_load_state(): add some newlines
  migration: vmstate_save/load_state(): refactor tracing errors
  migration: factor out vmstate_pre_save() from vmstate_save_state()
  migration: factor out vmstate_save_field() from vmstate_save_state()
  migration: factor out vmstate_pre_load() from vmstate_load_state()
  migration: factor out vmstate_load_field() from vmstate_load_state()
  migration: factor out vmstate_post_load() from vmstate_load_state()
  migration: convert vmstate_subsection_save/load functions to bool
  migration: VMStateInfo: introduce new handlers with errp
  migration: introduce vmstate_load_vmsd() and vmstate_save_vmsd()
  migration/cpr: move to new migration APIs
  migration/savevm: move to new migration APIs
  hw/s390x/css: drop use of .err_hint for vmstate
  migration: drop VMStateField.err_hint
  migration/vmstate-types: move to new migration APIs

 docs/devel/migration/main.rst |   2 +-
 hw/block/fdc.c                |   2 +-
 hw/display/qxl.c              |   4 +-
 hw/display/vga.c              |   2 +-
 hw/display/virtio-gpu.c       |   2 +-
 hw/display/vmware_vga.c       |   2 +-
 hw/i386/vmmouse.c             |   2 +-
 hw/ide/ahci.c                 |   2 +-
 hw/intc/openpic.c             |   2 +-
 hw/intc/spapr_xive.c          |   2 +-
 hw/intc/xics.c                |   2 +-
 hw/intc/xive.c                |   2 +-
 hw/nvram/eeprom93xx.c         |   2 +-
 hw/pci/pci.c                  |   2 +-
 hw/pci/pcie_aer.c             |   2 +-
 hw/ppc/spapr_iommu.c          |   2 +-
 hw/ppc/spapr_pci.c            |   7 +-
 hw/ppc/spapr_vio.c            |   4 +-
 hw/s390x/css.c                |  15 +-
 hw/usb/hcd-uhci.c             |   2 +-
 include/migration/cpr.h       |   2 +-
 include/migration/vmstate.h   |  73 ++--
 migration/cpr.c               |  22 +-
 migration/savevm.c            | 108 +++---
 migration/trace-events        |  30 +-
 migration/vmstate-types.c     | 642 +++++++++++++++++-----------------
 migration/vmstate.c           | 354 +++++++++++--------
 target/arm/machine.c          |   4 +-
 target/ppc/machine.c          |   6 +-
 29 files changed, 691 insertions(+), 612 deletions(-)

-- 
2.52.0



^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 01/18] migration: vmstate_save_state_v: fix double error_setg
  2026-03-04 21:22 [PATCH v3 00/18] migration: more bool+errp APIs Vladimir Sementsov-Ogievskiy
@ 2026-03-04 21:22 ` Vladimir Sementsov-Ogievskiy
  2026-03-04 21:22 ` [PATCH v3 02/18] migration: make vmstate_save_state_v() static Vladimir Sementsov-Ogievskiy
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2026-03-04 21:22 UTC (permalink / raw)
  To: peterx; +Cc: farosas, vsementsov, qemu-devel

We may call error_setg twice on same errp if inner
vmstate_save_state_v() or vmstate_save_state() call fails. Next we will
crash on assertion in error_setv().

Fixes: 848a0503422d043 "migration: Update error description outside migration.c"
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
Reviewed-by: Fabiano Rosas <farosas@suse.de>
Reviewed-by: Peter Xu <peterx@redhat.com>
---
 migration/vmstate.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/migration/vmstate.c b/migration/vmstate.c
index 4d28364f7ba..fccd030dfd1 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -539,6 +539,9 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
                 } else {
                     ret = inner_field->info->put(f, curr_elem, size,
                                                  inner_field, vmdesc_loop);
+                    if (ret < 0) {
+                        error_setg(errp, "put failed");
+                    }
                 }
 
                 written_bytes = qemu_file_transferred(f) - old_offset;
@@ -551,8 +554,8 @@ 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);
+                    error_prepend(errp, "Save of field %s/%s failed: ",
+                                  vmsd->name, field->name);
                     if (vmsd->post_save) {
                         vmsd->post_save(opaque);
                     }
-- 
2.52.0



^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 02/18] migration: make vmstate_save_state_v() static
  2026-03-04 21:22 [PATCH v3 00/18] migration: more bool+errp APIs Vladimir Sementsov-Ogievskiy
  2026-03-04 21:22 ` [PATCH v3 01/18] migration: vmstate_save_state_v: fix double error_setg Vladimir Sementsov-Ogievskiy
@ 2026-03-04 21:22 ` Vladimir Sementsov-Ogievskiy
  2026-03-04 21:22 ` [PATCH v3 03/18] migration: make .post_save() a void function Vladimir Sementsov-Ogievskiy
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2026-03-04 21:22 UTC (permalink / raw)
  To: peterx; +Cc: farosas, vsementsov, qemu-devel

It's used only in vmstate.c.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
Reviewed-by: Fabiano Rosas <farosas@suse.de>
Reviewed-by: Peter Xu <peterx@redhat.com>
---
 include/migration/vmstate.h |  3 ---
 migration/vmstate.c         | 19 ++++++++++---------
 2 files changed, 10 insertions(+), 12 deletions(-)

diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 89f9f49d20a..3695afd483f 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -1234,9 +1234,6 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
                        void *opaque, int version_id, Error **errp);
 int vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
                        void *opaque, JSONWriter *vmdesc, Error **errp);
-int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
-                         void *opaque, JSONWriter *vmdesc,
-                         int version_id, Error **errp);
 
 bool vmstate_section_needed(const VMStateDescription *vmsd, void *opaque);
 
diff --git a/migration/vmstate.c b/migration/vmstate.c
index fccd030dfd1..651c3fe0115 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -420,15 +420,9 @@ bool vmstate_section_needed(const VMStateDescription *vmsd, void *opaque)
     return true;
 }
 
-
-int vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
-                       void *opaque, JSONWriter *vmdesc_id, Error **errp)
-{
-    return vmstate_save_state_v(f, vmsd, opaque, vmdesc_id, vmsd->version_id, errp);
-}
-
-int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
-                         void *opaque, JSONWriter *vmdesc, int version_id, Error **errp)
+static int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
+                                void *opaque, JSONWriter *vmdesc,
+                                int version_id, Error **errp)
 {
     ERRP_GUARD();
     int ret = 0;
@@ -608,6 +602,13 @@ vmstate_get_subsection(const VMStateDescription * const *sub,
     return NULL;
 }
 
+int vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
+                       void *opaque, JSONWriter *vmdesc_id, Error **errp)
+{
+    return vmstate_save_state_v(f, vmsd, opaque, vmdesc_id, vmsd->version_id,
+                                errp);
+}
+
 static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
                                    void *opaque, Error **errp)
 {
-- 
2.52.0



^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 03/18] migration: make .post_save() a void function
  2026-03-04 21:22 [PATCH v3 00/18] migration: more bool+errp APIs Vladimir Sementsov-Ogievskiy
  2026-03-04 21:22 ` [PATCH v3 01/18] migration: vmstate_save_state_v: fix double error_setg Vladimir Sementsov-Ogievskiy
  2026-03-04 21:22 ` [PATCH v3 02/18] migration: make vmstate_save_state_v() static Vladimir Sementsov-Ogievskiy
@ 2026-03-04 21:22 ` Vladimir Sementsov-Ogievskiy
  2026-03-06 23:20   ` Fabiano Rosas
  2026-03-04 21:22 ` [PATCH v3 04/18] migration: vmstate_load_state(): add some newlines Vladimir Sementsov-Ogievskiy
                   ` (15 subsequent siblings)
  18 siblings, 1 reply; 33+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2026-03-04 21:22 UTC (permalink / raw)
  To: peterx
  Cc: farosas, vsementsov, qemu-devel, Pierrick Bouvier,
	Nicholas Piggin, Harsh Prateek Bora, Peter Maydell,
	open list:sPAPR (pseries), open list:ARM TCG CPUs

All other handlers now have _errp() variants. Should we go this way
for .post_save()? Actually it's rather strange, when the vmstate do
successful preparations in .pre_save(), then successfully save all
sections and subsections, end then fail when all the state is
successfully transferred to the target.

Happily, we have only three .post_save() realizations, all always
successful. Let's make this a rule.

Also note, that we call .post_save() in two places, and handle
its (theoretical) failure inconsistently. Fix that too.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
Reviewed-by: Peter Xu <peterx@redhat.com>
---
 docs/devel/migration/main.rst |  2 +-
 hw/ppc/spapr_pci.c            |  3 +--
 include/migration/vmstate.h   |  8 +++++++-
 migration/savevm.c            |  3 +--
 migration/vmstate.c           | 12 +++---------
 target/arm/machine.c          |  4 +---
 6 files changed, 14 insertions(+), 18 deletions(-)

diff --git a/docs/devel/migration/main.rst b/docs/devel/migration/main.rst
index 234d280249a..2de70507640 100644
--- a/docs/devel/migration/main.rst
+++ b/docs/devel/migration/main.rst
@@ -439,7 +439,7 @@ The functions to do that are inside a vmstate definition, and are called:
 
   This function is called before we save the state of one device.
 
-- ``int (*post_save)(void *opaque);``
+- ``void (*post_save)(void *opaque);``
 
   This function is called after we save the state of one device
   (even upon failure, unless the call to pre_save returned an error).
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index ea998bdff15..1dc3b02659f 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -2093,14 +2093,13 @@ static int spapr_pci_pre_save(void *opaque)
     return 0;
 }
 
-static int spapr_pci_post_save(void *opaque)
+static void spapr_pci_post_save(void *opaque)
 {
     SpaprPhbState *sphb = opaque;
 
     g_free(sphb->msi_devs);
     sphb->msi_devs = NULL;
     sphb->msi_devs_num = 0;
-    return 0;
 }
 
 static int spapr_pci_post_load(void *opaque, int version_id)
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 3695afd483f..85838a49aee 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -223,7 +223,13 @@ struct VMStateDescription {
     bool (*post_load_errp)(void *opaque, int version_id, Error **errp);
     int (*pre_save)(void *opaque);
     bool (*pre_save_errp)(void *opaque, Error **errp);
-    int (*post_save)(void *opaque);
+
+    /*
+     * Unless .pre_save() fails, .post_save() is called after saving
+     * fields and subsections. It should not fail because at this
+     * point the state has potentially already been transferred.
+     */
+    void (*post_save)(void *opaque);
     bool (*needed)(void *opaque);
     bool (*dev_unplug_pending)(void *opaque);
 
diff --git a/migration/savevm.c b/migration/savevm.c
index 3a16c467b25..c5236e71ba1 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -321,14 +321,13 @@ static int configuration_pre_save(void *opaque)
     return 0;
 }
 
-static int configuration_post_save(void *opaque)
+static void configuration_post_save(void *opaque)
 {
     SaveState *state = opaque;
 
     g_free(state->capabilities);
     state->capabilities = NULL;
     state->caps_count = 0;
-    return 0;
 }
 
 static int configuration_pre_load(void *opaque)
diff --git a/migration/vmstate.c b/migration/vmstate.c
index 651c3fe0115..5111e7a141f 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -550,10 +550,7 @@ static int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
                 if (ret) {
                     error_prepend(errp, "Save of field %s/%s failed: ",
                                   vmsd->name, field->name);
-                    if (vmsd->post_save) {
-                        vmsd->post_save(opaque);
-                    }
-                    return ret;
+                    goto out;
                 }
 
                 /* Compressed arrays only care about the first element */
@@ -578,12 +575,9 @@ static int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
 
     ret = vmstate_subsection_save(f, vmsd, opaque, vmdesc, errp);
 
+out:
     if (vmsd->post_save) {
-        int ps_ret = vmsd->post_save(opaque);
-        if (!ret && ps_ret) {
-            ret = ps_ret;
-            error_setg(errp, "post-save failed: %s", vmsd->name);
-        }
+        vmsd->post_save(opaque);
     }
     return ret;
 }
diff --git a/target/arm/machine.c b/target/arm/machine.c
index bbaae344492..de810220e25 100644
--- a/target/arm/machine.c
+++ b/target/arm/machine.c
@@ -993,15 +993,13 @@ static int cpu_pre_save(void *opaque)
     return 0;
 }
 
-static int cpu_post_save(void *opaque)
+static void cpu_post_save(void *opaque)
 {
     ARMCPU *cpu = opaque;
 
     if (!kvm_enabled()) {
         pmu_op_finish(&cpu->env);
     }
-
-    return 0;
 }
 
 static int cpu_pre_load(void *opaque)
-- 
2.52.0



^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 04/18] migration: vmstate_load_state(): add some newlines
  2026-03-04 21:22 [PATCH v3 00/18] migration: more bool+errp APIs Vladimir Sementsov-Ogievskiy
                   ` (2 preceding siblings ...)
  2026-03-04 21:22 ` [PATCH v3 03/18] migration: make .post_save() a void function Vladimir Sementsov-Ogievskiy
@ 2026-03-04 21:22 ` Vladimir Sementsov-Ogievskiy
  2026-03-04 21:22 ` [PATCH v3 05/18] migration: vmstate_save/load_state(): refactor tracing errors Vladimir Sementsov-Ogievskiy
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2026-03-04 21:22 UTC (permalink / raw)
  To: peterx; +Cc: farosas, vsementsov, qemu-devel

Split logical blocks by newlines, that simplify reading the code.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
Reviewed-by: Fabiano Rosas <farosas@suse.de>
Reviewed-by: Peter Xu <peterx@redhat.com>
---
 migration/vmstate.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/migration/vmstate.c b/migration/vmstate.c
index 5111e7a141f..dd7cd279937 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -139,6 +139,7 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
     int ret = 0;
 
     trace_vmstate_load_state(vmsd->name, version_id);
+
     if (version_id > vmsd->version_id) {
         error_setg(errp, "%s: incoming version_id %d is too new "
                    "for local version_id %d",
@@ -146,6 +147,7 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
         trace_vmstate_load_state_end(vmsd->name, "too new", -EINVAL);
         return -EINVAL;
     }
+
     if  (version_id < vmsd->minimum_version_id) {
         error_setg(errp, "%s: incoming version_id %d is too old "
                    "for local minimum version_id %d",
@@ -153,6 +155,7 @@ 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_errp) {
         if (!vmsd->pre_load_errp(opaque, errp)) {
             error_prepend(errp, "pre load hook failed for: '%s', "
@@ -171,9 +174,12 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
             return ret;
         }
     }
+
     while (field->name) {
         bool exists = vmstate_field_exists(vmsd, field, opaque, version_id);
+
         trace_vmstate_load_state_field(vmsd->name, field->name, exists);
+
         if (exists) {
             void *first_elem = opaque + field->offset;
             int i, n_elems = vmstate_n_elems(opaque, field);
@@ -184,6 +190,7 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
                 first_elem = *(void **)first_elem;
                 assert(first_elem || !n_elems || !size);
             }
+
             for (i = 0; i < n_elems; i++) {
                 void *curr_elem = first_elem + size * i;
                 const VMStateField *inner_field;
@@ -235,6 +242,7 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
                                    vmsd->name, ret);
                     }
                 }
+
                 if (ret < 0) {
                     qemu_file_set_error(f, ret);
                     trace_vmstate_load_field_error(field->name, ret);
@@ -249,11 +257,13 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
         field++;
     }
     assert(field->flags == VMS_END);
+
     ret = vmstate_subsection_load(f, vmsd, opaque, errp);
     if (ret != 0) {
         qemu_file_set_error(f, ret);
         return ret;
     }
+
     if (vmsd->post_load_errp) {
         if (!vmsd->post_load_errp(opaque, version_id, errp)) {
             error_prepend(errp, "post load hook failed for: %s, version_id: "
@@ -271,7 +281,9 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
                        ret);
         }
     }
+
     trace_vmstate_load_state_end(vmsd->name, "end", ret);
+
     return ret;
 }
 
-- 
2.52.0



^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 05/18] migration: vmstate_save/load_state(): refactor tracing errors
  2026-03-04 21:22 [PATCH v3 00/18] migration: more bool+errp APIs Vladimir Sementsov-Ogievskiy
                   ` (3 preceding siblings ...)
  2026-03-04 21:22 ` [PATCH v3 04/18] migration: vmstate_load_state(): add some newlines Vladimir Sementsov-Ogievskiy
@ 2026-03-04 21:22 ` Vladimir Sementsov-Ogievskiy
  2026-03-05 16:59   ` Peter Xu
  2026-03-04 21:22 ` [PATCH v3 06/18] migration: factor out vmstate_pre_save() from vmstate_save_state() Vladimir Sementsov-Ogievskiy
                   ` (13 subsequent siblings)
  18 siblings, 1 reply; 33+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2026-03-04 21:22 UTC (permalink / raw)
  To: peterx; +Cc: farosas, vsementsov, qemu-devel

To simplify further changes (convertion to bool+errp APIs),
let's rework some error paths:

- get rid of int ret in traces, as we are moving to bool+errp APIs
- split traces to _fail / _success (seems better than add boolean
  result to the message).
- prefer short error paths (return immediately on error)
- around trace_vmstate_load_field_error(), do not call
  qemu_file_set_error(), if the erroc comes from qemu_file_get_error()

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
 migration/trace-events |  6 ++++--
 migration/vmstate.c    | 25 +++++++++++++++----------
 2 files changed, 19 insertions(+), 12 deletions(-)

diff --git a/migration/trace-events b/migration/trace-events
index 90629f828f8..0b3f759ccc4 100644
--- a/migration/trace-events
+++ b/migration/trace-events
@@ -57,13 +57,15 @@ postcopy_page_req_sync(void *host_addr) "sync page req %p"
 # vmstate.c
 vmstate_load_field_error(const char *field, int ret) "field \"%s\" load failed, ret = %d"
 vmstate_load_state(const char *name, int version_id) "%s v%d"
-vmstate_load_state_end(const char *name, const char *reason, int val) "%s %s/%d"
+vmstate_load_state_fail(const char *name, const char *reason) "%s %s"
+vmstate_load_state_success(const char *name) "%s"
 vmstate_load_state_field(const char *name, const char *field, bool exists) "%s:%s exists=%d"
 vmstate_n_elems(const char *name, int n_elems) "%s: %d"
 vmstate_subsection_load(const char *parent) "%s"
 vmstate_subsection_load_bad(const char *parent,  const char *sub, const char *sub2) "%s: %s/%s"
 vmstate_subsection_load_good(const char *parent) "%s"
-vmstate_save_state_pre_save_res(const char *name, int res) "%s/%d"
+vmstate_save_state_pre_save_fail(const char *name) "%s"
+vmstate_save_state_pre_save_success(const char *name) "%s"
 vmstate_save_state_loop(const char *name, const char *field, int n_elems) "%s/%s[%d]"
 vmstate_save_state_top(const char *idstr) "%s"
 vmstate_subsection_save_loop(const char *name, const char *sub) "%s/%s"
diff --git a/migration/vmstate.c b/migration/vmstate.c
index dd7cd279937..87e1f049592 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -144,7 +144,7 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
         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);
+        trace_vmstate_load_state_fail(vmsd->name, "too new");
         return -EINVAL;
     }
 
@@ -152,7 +152,7 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
         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);
+        trace_vmstate_load_state_fail(vmsd->name, "too old");
         return -EINVAL;
     }
 
@@ -240,10 +240,10 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
                         error_setg(errp,
                                    "Failed to load %s state: stream error: %d",
                                    vmsd->name, ret);
+                        trace_vmstate_load_field_error(field->name, ret);
+                        return ret;
                     }
-                }
-
-                if (ret < 0) {
+                } else {
                     qemu_file_set_error(f, ret);
                     trace_vmstate_load_field_error(field->name, ret);
                     return ret;
@@ -269,7 +269,8 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
             error_prepend(errp, "post load hook failed for: %s, version_id: "
                           "%d, minimum_version: %d: ", vmsd->name,
                           vmsd->version_id, vmsd->minimum_version_id);
-            ret = -EINVAL;
+            trace_vmstate_load_state_fail(vmsd->name, "post-load");
+            return -EINVAL;
         }
     } else if (vmsd->post_load) {
         ret = vmsd->post_load(opaque, version_id);
@@ -279,12 +280,14 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
                        "minimum_version: %d, ret: %d",
                        vmsd->name, vmsd->version_id, vmsd->minimum_version_id,
                        ret);
+            trace_vmstate_load_state_fail(vmsd->name, "post-load");
+            return ret;
         }
     }
 
-    trace_vmstate_load_state_end(vmsd->name, "end", ret);
+    trace_vmstate_load_state_success(vmsd->name);
 
-    return ret;
+    return 0;
 }
 
 static int vmfield_name_num(const VMStateField *start,
@@ -444,20 +447,22 @@ static int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
 
     if (vmsd->pre_save_errp) {
         ret = vmsd->pre_save_errp(opaque, errp) ? 0 : -EINVAL;
-        trace_vmstate_save_state_pre_save_res(vmsd->name, ret);
         if (ret < 0) {
             error_prepend(errp, "pre-save for %s failed: ", vmsd->name);
+            trace_vmstate_save_state_pre_save_fail(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) {
             error_setg(errp, "pre-save failed: %s", vmsd->name);
+            trace_vmstate_save_state_pre_save_fail(vmsd->name);
             return ret;
         }
     }
 
+    trace_vmstate_save_state_pre_save_success(vmsd->name);
+
     if (vmdesc) {
         json_writer_str(vmdesc, "vmsd_name", vmsd->name);
         json_writer_int64(vmdesc, "version", version_id);
-- 
2.52.0



^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 06/18] migration: factor out vmstate_pre_save() from vmstate_save_state()
  2026-03-04 21:22 [PATCH v3 00/18] migration: more bool+errp APIs Vladimir Sementsov-Ogievskiy
                   ` (4 preceding siblings ...)
  2026-03-04 21:22 ` [PATCH v3 05/18] migration: vmstate_save/load_state(): refactor tracing errors Vladimir Sementsov-Ogievskiy
@ 2026-03-04 21:22 ` Vladimir Sementsov-Ogievskiy
  2026-03-04 21:22 ` [PATCH v3 07/18] migration: factor out vmstate_save_field() " Vladimir Sementsov-Ogievskiy
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2026-03-04 21:22 UTC (permalink / raw)
  To: peterx; +Cc: farosas, vsementsov, qemu-devel

Simplify vmstate_save_state() which is rather big, and simplify further
refactoring.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
Reviewed-by: Peter Xu <peterx@redhat.com>
---
 migration/vmstate.c | 37 +++++++++++++++++++++++--------------
 1 file changed, 23 insertions(+), 14 deletions(-)

diff --git a/migration/vmstate.c b/migration/vmstate.c
index 87e1f049592..605b5c59c76 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -435,6 +435,26 @@ bool vmstate_section_needed(const VMStateDescription *vmsd, void *opaque)
     return true;
 }
 
+static bool vmstate_pre_save(const VMStateDescription *vmsd, void *opaque,
+                             Error **errp)
+{
+    ERRP_GUARD();
+
+    if (vmsd->pre_save_errp) {
+        if (!vmsd->pre_save_errp(opaque, errp)) {
+            error_prepend(errp, "pre-save for %s failed: ", vmsd->name);
+            return false;
+        }
+    } else if (vmsd->pre_save) {
+        if (vmsd->pre_save(opaque) < 0) {
+            error_setg(errp, "pre-save failed: %s", vmsd->name);
+            return false;
+        }
+    }
+
+    return true;
+}
+
 static int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
                                 void *opaque, JSONWriter *vmdesc,
                                 int version_id, Error **errp)
@@ -445,20 +465,9 @@ static int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
 
     trace_vmstate_save_state_top(vmsd->name);
 
-    if (vmsd->pre_save_errp) {
-        ret = vmsd->pre_save_errp(opaque, errp) ? 0 : -EINVAL;
-        if (ret < 0) {
-            error_prepend(errp, "pre-save for %s failed: ", vmsd->name);
-            trace_vmstate_save_state_pre_save_fail(vmsd->name);
-            return ret;
-        }
-    } else if (vmsd->pre_save) {
-        ret = vmsd->pre_save(opaque);
-        if (ret) {
-            error_setg(errp, "pre-save failed: %s", vmsd->name);
-            trace_vmstate_save_state_pre_save_fail(vmsd->name);
-            return ret;
-        }
+    if (!vmstate_pre_save(vmsd, opaque, errp)) {
+        trace_vmstate_save_state_pre_save_fail(vmsd->name);
+        return -EINVAL;
     }
 
     trace_vmstate_save_state_pre_save_success(vmsd->name);
-- 
2.52.0



^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 07/18] migration: factor out vmstate_save_field() from vmstate_save_state()
  2026-03-04 21:22 [PATCH v3 00/18] migration: more bool+errp APIs Vladimir Sementsov-Ogievskiy
                   ` (5 preceding siblings ...)
  2026-03-04 21:22 ` [PATCH v3 06/18] migration: factor out vmstate_pre_save() from vmstate_save_state() Vladimir Sementsov-Ogievskiy
@ 2026-03-04 21:22 ` Vladimir Sementsov-Ogievskiy
  2026-03-04 21:22 ` [PATCH v3 08/18] migration: factor out vmstate_pre_load() from vmstate_load_state() Vladimir Sementsov-Ogievskiy
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2026-03-04 21:22 UTC (permalink / raw)
  To: peterx; +Cc: farosas, vsementsov, qemu-devel

Simplify vmstate_save_state() which is rather big, and simplify further
refactoring.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
Reviewed-by: Peter Xu <peterx@redhat.com>
---
 migration/vmstate.c | 40 +++++++++++++++++++++++++---------------
 1 file changed, 25 insertions(+), 15 deletions(-)

diff --git a/migration/vmstate.c b/migration/vmstate.c
index 605b5c59c76..2ce26527124 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -26,6 +26,9 @@ static int vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
                                    Error **errp);
 static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
                                    void *opaque, Error **errp);
+static int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
+                                void *opaque, JSONWriter *vmdesc,
+                                int version_id, Error **errp);
 
 /* Whether this field should exist for either save or load the VM? */
 static bool
@@ -455,6 +458,26 @@ static bool vmstate_pre_save(const VMStateDescription *vmsd, void *opaque,
     return true;
 }
 
+static bool vmstate_save_field(QEMUFile *f, void *pv, size_t size,
+                               const VMStateField *field,
+                               JSONWriter *vmdesc, Error **errp)
+{
+    if (field->flags & VMS_STRUCT) {
+        return vmstate_save_state(f, field->vmsd, pv, vmdesc, errp) >= 0;
+    } else if (field->flags & VMS_VSTRUCT) {
+        return vmstate_save_state_v(f, field->vmsd, pv, vmdesc,
+                                    field->struct_version_id,
+                                    errp) >= 0;
+    }
+
+    if (field->info->put(f, pv, size, field, vmdesc) < 0) {
+        error_setg(errp, "put failed");
+        return false;
+    }
+
+    return true;
+}
+
 static int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
                                 void *opaque, JSONWriter *vmdesc,
                                 int version_id, Error **errp)
@@ -548,21 +571,8 @@ static int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
                 vmsd_desc_field_start(vmsd, vmdesc_loop, inner_field,
                                       i, max_elems);
 
-                if (inner_field->flags & VMS_STRUCT) {
-                    ret = vmstate_save_state(f, inner_field->vmsd,
-                                             curr_elem, vmdesc_loop, errp);
-                } else if (inner_field->flags & VMS_VSTRUCT) {
-                    ret = vmstate_save_state_v(f, inner_field->vmsd,
-                                               curr_elem, vmdesc_loop,
-                                               inner_field->struct_version_id,
-                                               errp);
-                } else {
-                    ret = inner_field->info->put(f, curr_elem, size,
-                                                 inner_field, vmdesc_loop);
-                    if (ret < 0) {
-                        error_setg(errp, "put failed");
-                    }
-                }
+                ret = vmstate_save_field(f, curr_elem, size, inner_field,
+                                         vmdesc_loop, errp) ? 0 : -EINVAL;
 
                 written_bytes = qemu_file_transferred(f) - old_offset;
                 vmsd_desc_field_end(vmsd, vmdesc_loop, inner_field,
-- 
2.52.0



^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 08/18] migration: factor out vmstate_pre_load() from vmstate_load_state()
  2026-03-04 21:22 [PATCH v3 00/18] migration: more bool+errp APIs Vladimir Sementsov-Ogievskiy
                   ` (6 preceding siblings ...)
  2026-03-04 21:22 ` [PATCH v3 07/18] migration: factor out vmstate_save_field() " Vladimir Sementsov-Ogievskiy
@ 2026-03-04 21:22 ` Vladimir Sementsov-Ogievskiy
  2026-03-04 21:22 ` [PATCH v3 09/18] migration: factor out vmstate_load_field() " Vladimir Sementsov-Ogievskiy
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2026-03-04 21:22 UTC (permalink / raw)
  To: peterx; +Cc: farosas, vsementsov, qemu-devel

Simplify vmstate_load_state() which is rather big, and simplify further
refactoring.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
Reviewed-by: Peter Xu <peterx@redhat.com>
---
 migration/vmstate.c | 46 ++++++++++++++++++++++++++++-----------------
 1 file changed, 29 insertions(+), 17 deletions(-)

diff --git a/migration/vmstate.c b/migration/vmstate.c
index 2ce26527124..35dbe1550e9 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -134,6 +134,33 @@ static void vmstate_handle_alloc(void *ptr, const VMStateField *field,
     }
 }
 
+static bool vmstate_pre_load(const VMStateDescription *vmsd, void *opaque,
+                             Error **errp)
+{
+    ERRP_GUARD();
+
+    if (vmsd->pre_load_errp) {
+        if (!vmsd->pre_load_errp(opaque, errp)) {
+            error_prepend(errp, "pre load hook failed for: '%s', "
+                          "version_id: %d, minimum version_id: %d: ",
+                          vmsd->name, vmsd->version_id,
+                          vmsd->minimum_version_id);
+            return false;
+        }
+    } else if (vmsd->pre_load) {
+        int ret = vmsd->pre_load(opaque);
+        if (ret) {
+            error_setg(errp, "pre load hook failed for: '%s', "
+                       "version_id: %d, minimum version_id: %d, ret: %d",
+                       vmsd->name, vmsd->version_id, vmsd->minimum_version_id,
+                       ret);
+            return false;
+        }
+    }
+
+    return true;
+}
+
 int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
                        void *opaque, int version_id, Error **errp)
 {
@@ -159,23 +186,8 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
         return -EINVAL;
     }
 
-    if (vmsd->pre_load_errp) {
-        if (!vmsd->pre_load_errp(opaque, errp)) {
-            error_prepend(errp, "pre load hook failed for: '%s', "
-                          "version_id: %d, minimum version_id: %d: ",
-                          vmsd->name, vmsd->version_id,
-                          vmsd->minimum_version_id);
-            return -EINVAL;
-        }
-    } else if (vmsd->pre_load) {
-        ret = vmsd->pre_load(opaque);
-        if (ret) {
-            error_setg(errp, "pre load hook failed for: '%s', "
-                       "version_id: %d, minimum version_id: %d, ret: %d",
-                       vmsd->name, vmsd->version_id, vmsd->minimum_version_id,
-                       ret);
-            return ret;
-        }
+    if (!vmstate_pre_load(vmsd, opaque, errp)) {
+        return -EINVAL;
     }
 
     while (field->name) {
-- 
2.52.0



^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 09/18] migration: factor out vmstate_load_field() from vmstate_load_state()
  2026-03-04 21:22 [PATCH v3 00/18] migration: more bool+errp APIs Vladimir Sementsov-Ogievskiy
                   ` (7 preceding siblings ...)
  2026-03-04 21:22 ` [PATCH v3 08/18] migration: factor out vmstate_pre_load() from vmstate_load_state() Vladimir Sementsov-Ogievskiy
@ 2026-03-04 21:22 ` Vladimir Sementsov-Ogievskiy
  2026-03-04 21:22 ` [PATCH v3 10/18] migration: factor out vmstate_post_load() " Vladimir Sementsov-Ogievskiy
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2026-03-04 21:22 UTC (permalink / raw)
  To: peterx; +Cc: farosas, vsementsov, qemu-devel

Simplify vmstate_load_state() which is rather big, and simplify further
refactoring.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
Reviewed-by: Peter Xu <peterx@redhat.com>
---
 migration/vmstate.c | 41 +++++++++++++++++++++++------------------
 1 file changed, 23 insertions(+), 18 deletions(-)

diff --git a/migration/vmstate.c b/migration/vmstate.c
index 35dbe1550e9..32944c04443 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -161,6 +161,27 @@ static bool vmstate_pre_load(const VMStateDescription *vmsd, void *opaque,
     return true;
 }
 
+static bool vmstate_load_field(QEMUFile *f, void *pv, size_t size,
+                               const VMStateField *field, Error **errp)
+{
+    if (field->flags & VMS_STRUCT) {
+        return vmstate_load_state(f, field->vmsd, pv, field->vmsd->version_id,
+                                  errp) >= 0;
+    } else if (field->flags & VMS_VSTRUCT) {
+        return vmstate_load_state(f, field->vmsd, pv, field->struct_version_id,
+                                  errp) >= 0;
+    }
+
+    if (field->info->get(f, pv, size, field) < 0) {
+        error_setg(errp,
+                   "Failed to load element of type %s for %s",
+                   field->info->name, field->name);
+        return false;
+    }
+
+    return true;
+}
+
 int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
                        void *opaque, int version_id, Error **errp)
 {
@@ -225,24 +246,8 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
                     inner_field = field;
                 }
 
-                if (inner_field->flags & VMS_STRUCT) {
-                    ret = vmstate_load_state(f, inner_field->vmsd, curr_elem,
-                                             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,
-                                             errp);
-                } else {
-                    ret = inner_field->info->get(f, curr_elem, size,
-                                                 inner_field);
-                    if (ret < 0) {
-                        error_setg(errp,
-                                   "Failed to load element of type %s for %s: "
-                                   "%d", inner_field->info->name,
-                                   inner_field->name, ret);
-                    }
-                }
+                ret = vmstate_load_field(f, curr_elem, size, inner_field,
+                                         errp) ? 0 : -EINVAL;
 
                 /* If we used a fake temp field.. free it now */
                 if (inner_field != field) {
-- 
2.52.0



^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 10/18] migration: factor out vmstate_post_load() from vmstate_load_state()
  2026-03-04 21:22 [PATCH v3 00/18] migration: more bool+errp APIs Vladimir Sementsov-Ogievskiy
                   ` (8 preceding siblings ...)
  2026-03-04 21:22 ` [PATCH v3 09/18] migration: factor out vmstate_load_field() " Vladimir Sementsov-Ogievskiy
@ 2026-03-04 21:22 ` Vladimir Sementsov-Ogievskiy
  2026-03-04 21:22 ` [PATCH v3 11/18] migration: convert vmstate_subsection_save/load functions to bool Vladimir Sementsov-Ogievskiy
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2026-03-04 21:22 UTC (permalink / raw)
  To: peterx; +Cc: farosas, vsementsov, qemu-devel

Simplify vmstate_load_state() which is rather big, and simplify further
refactoring.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
Reviewed-by: Peter Xu <peterx@redhat.com>
---
 migration/vmstate.c | 49 +++++++++++++++++++++++++++------------------
 1 file changed, 30 insertions(+), 19 deletions(-)

diff --git a/migration/vmstate.c b/migration/vmstate.c
index 32944c04443..53b57c09d82 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -182,6 +182,33 @@ static bool vmstate_load_field(QEMUFile *f, void *pv, size_t size,
     return true;
 }
 
+static bool vmstate_post_load(const VMStateDescription *vmsd,
+                              void *opaque, int version_id, Error **errp)
+{
+    ERRP_GUARD();
+
+    if (vmsd->post_load_errp) {
+        if (!vmsd->post_load_errp(opaque, version_id, errp)) {
+            error_prepend(errp, "post load hook failed for: %s, version_id: "
+                          "%d, minimum_version: %d: ", vmsd->name,
+                          vmsd->version_id, vmsd->minimum_version_id);
+            return false;
+        }
+    } else if (vmsd->post_load) {
+        int ret = vmsd->post_load(opaque, version_id);
+        if (ret < 0) {
+            error_setg(errp,
+                       "post load hook failed for: %s, version_id: %d, "
+                       "minimum_version: %d, ret: %d",
+                       vmsd->name, vmsd->version_id, vmsd->minimum_version_id,
+                       ret);
+            return false;
+        }
+    }
+
+    return true;
+}
+
 int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
                        void *opaque, int version_id, Error **errp)
 {
@@ -284,25 +311,9 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
         return ret;
     }
 
-    if (vmsd->post_load_errp) {
-        if (!vmsd->post_load_errp(opaque, version_id, errp)) {
-            error_prepend(errp, "post load hook failed for: %s, version_id: "
-                          "%d, minimum_version: %d: ", vmsd->name,
-                          vmsd->version_id, vmsd->minimum_version_id);
-            trace_vmstate_load_state_fail(vmsd->name, "post-load");
-            return -EINVAL;
-        }
-    } else if (vmsd->post_load) {
-        ret = vmsd->post_load(opaque, version_id);
-        if (ret < 0) {
-            error_setg(errp,
-                       "post load hook failed for: %s, version_id: %d, "
-                       "minimum_version: %d, ret: %d",
-                       vmsd->name, vmsd->version_id, vmsd->minimum_version_id,
-                       ret);
-            trace_vmstate_load_state_fail(vmsd->name, "post-load");
-            return ret;
-        }
+    if (!vmstate_post_load(vmsd, opaque, version_id, errp)) {
+        trace_vmstate_load_state_fail(vmsd->name, "post-load");
+        return -EINVAL;
     }
 
     trace_vmstate_load_state_success(vmsd->name);
-- 
2.52.0



^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 11/18] migration: convert vmstate_subsection_save/load functions to bool
  2026-03-04 21:22 [PATCH v3 00/18] migration: more bool+errp APIs Vladimir Sementsov-Ogievskiy
                   ` (9 preceding siblings ...)
  2026-03-04 21:22 ` [PATCH v3 10/18] migration: factor out vmstate_post_load() " Vladimir Sementsov-Ogievskiy
@ 2026-03-04 21:22 ` Vladimir Sementsov-Ogievskiy
  2026-03-04 21:22 ` [PATCH v3 12/18] migration: VMStateInfo: introduce new handlers with errp Vladimir Sementsov-Ogievskiy
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2026-03-04 21:22 UTC (permalink / raw)
  To: peterx; +Cc: farosas, vsementsov, qemu-devel

Convert them to bool return value, as preparation to further
convertion of vmstate_save/load_state().

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
Reviewed-by: Peter Xu <peterx@redhat.com>
---
 migration/vmstate.c | 57 +++++++++++++++++++++------------------------
 1 file changed, 26 insertions(+), 31 deletions(-)

diff --git a/migration/vmstate.c b/migration/vmstate.c
index 53b57c09d82..8825aa3b1f1 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -21,11 +21,11 @@
 #include "qemu/error-report.h"
 #include "trace.h"
 
-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, Error **errp);
+static bool vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
+                                    void *opaque, JSONWriter *vmdesc,
+                                    Error **errp);
+static bool vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
+                                    void *opaque, Error **errp);
 static int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
                                 void *opaque, JSONWriter *vmdesc,
                                 int version_id, Error **errp);
@@ -305,10 +305,9 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
     }
     assert(field->flags == VMS_END);
 
-    ret = vmstate_subsection_load(f, vmsd, opaque, errp);
-    if (ret != 0) {
-        qemu_file_set_error(f, ret);
-        return ret;
+    if (!vmstate_subsection_load(f, vmsd, opaque, errp)) {
+        qemu_file_set_error(f, -EINVAL);
+        return -EINVAL;
     }
 
     if (!vmstate_post_load(vmsd, opaque, version_id, errp)) {
@@ -637,7 +636,7 @@ static int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
         json_writer_end_array(vmdesc);
     }
 
-    ret = vmstate_subsection_save(f, vmsd, opaque, vmdesc, errp);
+    ret = vmstate_subsection_save(f, vmsd, opaque, vmdesc, errp) ? 0 : -EINVAL;
 
 out:
     if (vmsd->post_save) {
@@ -667,15 +666,14 @@ int vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
                                 errp);
 }
 
-static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
-                                   void *opaque, Error **errp)
+static bool vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
+                                    void *opaque, Error **errp)
 {
     ERRP_GUARD();
     trace_vmstate_subsection_load(vmsd->name);
 
     while (qemu_peek_byte(f, 0) == QEMU_VM_SUBSECTION) {
         char idstr[256], *idstr_ret;
-        int ret;
         uint8_t version_id, len, size;
         const VMStateDescription *sub_vmsd;
 
@@ -683,12 +681,12 @@ static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
         if (len < strlen(vmsd->name) + 1) {
             /* subsection name has to be "section_name/a" */
             trace_vmstate_subsection_load_bad(vmsd->name, "(short)", "");
-            return 0;
+            return true;
         }
         size = qemu_peek_buffer(f, (uint8_t **)&idstr_ret, len, 2);
         if (size != len) {
             trace_vmstate_subsection_load_bad(vmsd->name, "(peek fail)", "");
-            return 0;
+            return true;
         }
         memcpy(idstr, idstr_ret, size);
         idstr[size] = 0;
@@ -696,41 +694,39 @@ static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
         if (strncmp(vmsd->name, idstr, strlen(vmsd->name)) != 0) {
             trace_vmstate_subsection_load_bad(vmsd->name, idstr, "(prefix)");
             /* it doesn't have a valid subsection name */
-            return 0;
+            return true;
         }
         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;
+            return false;
         }
         qemu_file_skip(f, 1); /* subsection */
         qemu_file_skip(f, 1); /* len */
         qemu_file_skip(f, len); /* idstr */
         version_id = qemu_get_be32(f);
 
-        ret = vmstate_load_state(f, sub_vmsd, opaque, version_id, errp);
-        if (ret) {
+        if (vmstate_load_state(f, sub_vmsd, opaque, version_id, errp) < 0) {
             trace_vmstate_subsection_load_bad(vmsd->name, idstr, "(child)");
             error_prepend(errp,
-                          "Loading VM subsection '%s' in '%s' failed: %d: ",
-                          idstr, vmsd->name, ret);
-            return ret;
+                          "Loading VM subsection '%s' in '%s' failed: ",
+                          idstr, vmsd->name);
+            return false;
         }
     }
 
     trace_vmstate_subsection_load_good(vmsd->name);
-    return 0;
+    return true;
 }
 
-static int vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
-                                   void *opaque, JSONWriter *vmdesc,
-                                   Error **errp)
+static bool vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
+                                    void *opaque, JSONWriter *vmdesc,
+                                    Error **errp)
 {
     const VMStateDescription * const *sub = vmsd->subsections;
     bool vmdesc_has_subsections = false;
-    int ret = 0;
 
     trace_vmstate_subsection_save_top(vmsd->name);
     while (sub && *sub) {
@@ -754,9 +750,8 @@ static int vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
             qemu_put_byte(f, len);
             qemu_put_buffer(f, (uint8_t *)vmsdsub->name, len);
             qemu_put_be32(f, vmsdsub->version_id);
-            ret = vmstate_save_state(f, vmsdsub, opaque, vmdesc, errp);
-            if (ret) {
-                return ret;
+            if (vmstate_save_state(f, vmsdsub, opaque, vmdesc, errp) < 0) {
+                return false;
             }
 
             if (vmdesc) {
@@ -770,5 +765,5 @@ static int vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
         json_writer_end_array(vmdesc);
     }
 
-    return ret;
+    return true;
 }
-- 
2.52.0



^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 12/18] migration: VMStateInfo: introduce new handlers with errp
  2026-03-04 21:22 [PATCH v3 00/18] migration: more bool+errp APIs Vladimir Sementsov-Ogievskiy
                   ` (10 preceding siblings ...)
  2026-03-04 21:22 ` [PATCH v3 11/18] migration: convert vmstate_subsection_save/load functions to bool Vladimir Sementsov-Ogievskiy
@ 2026-03-04 21:22 ` Vladimir Sementsov-Ogievskiy
  2026-03-04 21:22 ` [PATCH v3 13/18] migration: introduce vmstate_load_vmsd() and vmstate_save_vmsd() Vladimir Sementsov-Ogievskiy
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2026-03-04 21:22 UTC (permalink / raw)
  To: peterx; +Cc: farosas, vsementsov, qemu-devel

Add new APIs with errp, to allow handlers report good
error messages. We'll convert existing handlers soon.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
Reviewed-by: Peter Xu <peterx@redhat.com>
---
 include/migration/vmstate.h | 17 ++++++++++++++---
 migration/vmstate.c         |  4 ++++
 2 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 85838a49aee..77d58d27d41 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -32,12 +32,16 @@
 typedef struct VMStateInfo VMStateInfo;
 typedef struct VMStateField VMStateField;
 
-/* VMStateInfo allows customized migration of objects that don't fit in
+/*
+ * VMStateInfo allows customized migration of objects that don't fit in
  * any category in VMStateFlags. Additional information is always passed
- * into get and put in terms of field and vmdesc parameters. However
+ * into load and save in terms of field and vmdesc parameters. However
  * these two parameters should only be used in cases when customized
  * handling is needed, such as QTAILQ. For primitive data types such as
- * integer, field and vmdesc parameters should be ignored inside get/put.
+ * integer, field and vmdesc parameters should be ignored inside load/save.
+ *
+ * @get and @put are deprecated copies of @load and @save. For new interfaces
+ * use @load and @save.
  */
 struct VMStateInfo {
     const char *name;
@@ -46,6 +50,13 @@ struct VMStateInfo {
     int coroutine_mixed_fn (*put)(QEMUFile *f, void *pv, size_t size,
                                   const VMStateField *field,
                                   JSONWriter *vmdesc);
+    bool coroutine_mixed_fn (*load)(QEMUFile *f, void *pv, size_t size,
+                                    const VMStateField *field,
+                                    Error **errp);
+    bool coroutine_mixed_fn (*save)(QEMUFile *f, void *pv, size_t size,
+                                    const VMStateField *field,
+                                    JSONWriter *vmdesc,
+                                    Error **errp);
 };
 
 enum VMStateFlags {
diff --git a/migration/vmstate.c b/migration/vmstate.c
index 8825aa3b1f1..f16626d7d11 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -170,6 +170,8 @@ static bool vmstate_load_field(QEMUFile *f, void *pv, size_t size,
     } else if (field->flags & VMS_VSTRUCT) {
         return vmstate_load_state(f, field->vmsd, pv, field->struct_version_id,
                                   errp) >= 0;
+    } else if (field->info->load) {
+        return field->info->load(f, pv, size, field, errp);
     }
 
     if (field->info->get(f, pv, size, field) < 0) {
@@ -495,6 +497,8 @@ static bool vmstate_save_field(QEMUFile *f, void *pv, size_t size,
         return vmstate_save_state_v(f, field->vmsd, pv, vmdesc,
                                     field->struct_version_id,
                                     errp) >= 0;
+    } else if (field->info->save) {
+        return field->info->save(f, pv, size, field, vmdesc, errp);
     }
 
     if (field->info->put(f, pv, size, field, vmdesc) < 0) {
-- 
2.52.0



^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 13/18] migration: introduce vmstate_load_vmsd() and vmstate_save_vmsd()
  2026-03-04 21:22 [PATCH v3 00/18] migration: more bool+errp APIs Vladimir Sementsov-Ogievskiy
                   ` (11 preceding siblings ...)
  2026-03-04 21:22 ` [PATCH v3 12/18] migration: VMStateInfo: introduce new handlers with errp Vladimir Sementsov-Ogievskiy
@ 2026-03-04 21:22 ` Vladimir Sementsov-Ogievskiy
  2026-03-05 17:01   ` Peter Xu
  2026-03-04 21:22 ` [PATCH v3 14/18] migration/cpr: move to new migration APIs Vladimir Sementsov-Ogievskiy
                   ` (5 subsequent siblings)
  18 siblings, 1 reply; 33+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2026-03-04 21:22 UTC (permalink / raw)
  To: peterx; +Cc: farosas, vsementsov, qemu-devel

Introduce new APIs, returning bool.
The analysis
https://lore.kernel.org/qemu-devel/aQDdRn8t0B8oE3gf@x1.local/
shows, that vmstate_load_state() return value actually only
used to check for success, specific errno values doesn't make
sense.

With this commit we introduce new functions with modern bool
interface, and in following commits we'll update the
code base to use them, starting from migration/ code, and
finally we will remove old vmstate_load_state() and
vmstate_save_state().

This patch reworks existing functions to new one, so that
old interfaces are simple wrappers, which will be easy to
remove later.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
 include/migration/vmstate.h |  9 ++++
 migration/vmstate.c         | 89 ++++++++++++++++++++-----------------
 2 files changed, 58 insertions(+), 40 deletions(-)

diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 77d58d27d41..3c1d84f2d67 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -1247,10 +1247,19 @@ extern const VMStateInfo vmstate_info_qlist;
         .flags = VMS_END, \
     }
 
+/*
+ * vmstate_load_state() and vmstate_save_state() are
+ * depreacated, use vmstate_load_vmsd() and vmstate_save_vmsd()
+ * instead.
+ */
 int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
                        void *opaque, int version_id, Error **errp);
 int vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
                        void *opaque, JSONWriter *vmdesc, Error **errp);
+bool vmstate_load_vmsd(QEMUFile *f, const VMStateDescription *vmsd,
+                       void *opaque, int version_id, Error **errp);
+bool vmstate_save_vmsd(QEMUFile *f, const VMStateDescription *vmsd,
+                       void *opaque, JSONWriter *vmdesc, Error **errp);
 
 bool vmstate_section_needed(const VMStateDescription *vmsd, void *opaque);
 
diff --git a/migration/vmstate.c b/migration/vmstate.c
index f16626d7d11..e98b5f5346c 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -26,7 +26,7 @@ static bool vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
                                     Error **errp);
 static bool vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
                                     void *opaque, Error **errp);
-static int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
+static bool vmstate_save_vmsd_v(QEMUFile *f, const VMStateDescription *vmsd,
                                 void *opaque, JSONWriter *vmdesc,
                                 int version_id, Error **errp);
 
@@ -165,11 +165,11 @@ static bool vmstate_load_field(QEMUFile *f, void *pv, size_t size,
                                const VMStateField *field, Error **errp)
 {
     if (field->flags & VMS_STRUCT) {
-        return vmstate_load_state(f, field->vmsd, pv, field->vmsd->version_id,
-                                  errp) >= 0;
+        return vmstate_load_vmsd(f, field->vmsd, pv, field->vmsd->version_id,
+                                 errp);
     } else if (field->flags & VMS_VSTRUCT) {
-        return vmstate_load_state(f, field->vmsd, pv, field->struct_version_id,
-                                  errp) >= 0;
+        return vmstate_load_vmsd(f, field->vmsd, pv, field->struct_version_id,
+                                 errp);
     } else if (field->info->load) {
         return field->info->load(f, pv, size, field, errp);
     }
@@ -211,12 +211,11 @@ static bool vmstate_post_load(const VMStateDescription *vmsd,
     return true;
 }
 
-int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
+bool vmstate_load_vmsd(QEMUFile *f, const VMStateDescription *vmsd,
                        void *opaque, int version_id, Error **errp)
 {
     ERRP_GUARD();
     const VMStateField *field = vmsd->fields;
-    int ret = 0;
 
     trace_vmstate_load_state(vmsd->name, version_id);
 
@@ -225,7 +224,7 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
                    "for local version_id %d",
                    vmsd->name, version_id, vmsd->version_id);
         trace_vmstate_load_state_fail(vmsd->name, "too new");
-        return -EINVAL;
+        return false;
     }
 
     if  (version_id < vmsd->minimum_version_id) {
@@ -233,11 +232,11 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
                    "for local minimum version_id %d",
                    vmsd->name, version_id, vmsd->minimum_version_id);
         trace_vmstate_load_state_fail(vmsd->name, "too old");
-        return -EINVAL;
+        return false;
     }
 
     if (!vmstate_pre_load(vmsd, opaque, errp)) {
-        return -EINVAL;
+        return false;
     }
 
     while (field->name) {
@@ -257,6 +256,7 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
             }
 
             for (i = 0; i < n_elems; i++) {
+                bool ok;
                 void *curr_elem = first_elem + size * i;
                 const VMStateField *inner_field;
 
@@ -275,33 +275,32 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
                     inner_field = field;
                 }
 
-                ret = vmstate_load_field(f, curr_elem, size, inner_field,
-                                         errp) ? 0 : -EINVAL;
+                ok = vmstate_load_field(f, curr_elem, size, inner_field, errp);
 
                 /* If we used a fake temp field.. free it now */
                 if (inner_field != field) {
                     g_clear_pointer((gpointer *)&inner_field, g_free);
                 }
 
-                if (ret >= 0) {
-                    ret = qemu_file_get_error(f);
+                if (ok) {
+                    int ret = qemu_file_get_error(f);
                     if (ret < 0) {
                         error_setg(errp,
                                    "Failed to load %s state: stream error: %d",
                                    vmsd->name, ret);
                         trace_vmstate_load_field_error(field->name, ret);
-                        return ret;
+                        return false;
                     }
                 } else {
-                    qemu_file_set_error(f, ret);
-                    trace_vmstate_load_field_error(field->name, ret);
-                    return ret;
+                    qemu_file_set_error(f, -EINVAL);
+                    trace_vmstate_load_field_error(field->name, -EINVAL);
+                    return false;
                 }
             }
         } else if (field->flags & VMS_MUST_EXIST) {
             error_setg(errp, "Input validation failed: %s/%s version_id: %d",
                        vmsd->name, field->name, vmsd->version_id);
-            return -1;
+            return false;
         }
         field++;
     }
@@ -309,17 +308,16 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
 
     if (!vmstate_subsection_load(f, vmsd, opaque, errp)) {
         qemu_file_set_error(f, -EINVAL);
-        return -EINVAL;
+        return false;
     }
 
     if (!vmstate_post_load(vmsd, opaque, version_id, errp)) {
         trace_vmstate_load_state_fail(vmsd->name, "post-load");
-        return -EINVAL;
+        return false;
     }
 
     trace_vmstate_load_state_success(vmsd->name);
-
-    return 0;
+    return true;
 }
 
 static int vmfield_name_num(const VMStateField *start,
@@ -492,11 +490,10 @@ static bool vmstate_save_field(QEMUFile *f, void *pv, size_t size,
                                JSONWriter *vmdesc, Error **errp)
 {
     if (field->flags & VMS_STRUCT) {
-        return vmstate_save_state(f, field->vmsd, pv, vmdesc, errp) >= 0;
+        return vmstate_save_vmsd(f, field->vmsd, pv, vmdesc, errp);
     } else if (field->flags & VMS_VSTRUCT) {
-        return vmstate_save_state_v(f, field->vmsd, pv, vmdesc,
-                                    field->struct_version_id,
-                                    errp) >= 0;
+        return vmstate_save_vmsd_v(f, field->vmsd, pv, vmdesc,
+                                   field->struct_version_id, errp);
     } else if (field->info->save) {
         return field->info->save(f, pv, size, field, vmdesc, errp);
     }
@@ -509,19 +506,19 @@ static bool vmstate_save_field(QEMUFile *f, void *pv, size_t size,
     return true;
 }
 
-static int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
+static bool vmstate_save_vmsd_v(QEMUFile *f, const VMStateDescription *vmsd,
                                 void *opaque, JSONWriter *vmdesc,
                                 int version_id, Error **errp)
 {
     ERRP_GUARD();
-    int ret = 0;
+    bool ok = true;
     const VMStateField *field = vmsd->fields;
 
     trace_vmstate_save_state_top(vmsd->name);
 
     if (!vmstate_pre_save(vmsd, opaque, errp)) {
         trace_vmstate_save_state_pre_save_fail(vmsd->name);
-        return -EINVAL;
+        return false;
     }
 
     trace_vmstate_save_state_pre_save_success(vmsd->name);
@@ -602,8 +599,8 @@ static int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
                 vmsd_desc_field_start(vmsd, vmdesc_loop, inner_field,
                                       i, max_elems);
 
-                ret = vmstate_save_field(f, curr_elem, size, inner_field,
-                                         vmdesc_loop, errp) ? 0 : -EINVAL;
+                ok = vmstate_save_field(f, curr_elem, size, inner_field,
+                                        vmdesc_loop, errp);
 
                 written_bytes = qemu_file_transferred(f) - old_offset;
                 vmsd_desc_field_end(vmsd, vmdesc_loop, inner_field,
@@ -614,7 +611,7 @@ static int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
                     g_clear_pointer((gpointer *)&inner_field, g_free);
                 }
 
-                if (ret) {
+                if (!ok) {
                     error_prepend(errp, "Save of field %s/%s failed: ",
                                   vmsd->name, field->name);
                     goto out;
@@ -640,13 +637,13 @@ static int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
         json_writer_end_array(vmdesc);
     }
 
-    ret = vmstate_subsection_save(f, vmsd, opaque, vmdesc, errp) ? 0 : -EINVAL;
+    ok = vmstate_subsection_save(f, vmsd, opaque, vmdesc, errp);
 
 out:
     if (vmsd->post_save) {
         vmsd->post_save(opaque);
     }
-    return ret;
+    return ok;
 }
 
 static const VMStateDescription *
@@ -663,11 +660,11 @@ vmstate_get_subsection(const VMStateDescription * const *sub,
     return NULL;
 }
 
-int vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
+bool vmstate_save_vmsd(QEMUFile *f, const VMStateDescription *vmsd,
                        void *opaque, JSONWriter *vmdesc_id, Error **errp)
 {
-    return vmstate_save_state_v(f, vmsd, opaque, vmdesc_id, vmsd->version_id,
-                                errp);
+    return vmstate_save_vmsd_v(f, vmsd, opaque, vmdesc_id, vmsd->version_id,
+                               errp);
 }
 
 static bool vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
@@ -712,7 +709,7 @@ static bool vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
         qemu_file_skip(f, len); /* idstr */
         version_id = qemu_get_be32(f);
 
-        if (vmstate_load_state(f, sub_vmsd, opaque, version_id, errp) < 0) {
+        if (!vmstate_load_vmsd(f, sub_vmsd, opaque, version_id, errp)) {
             trace_vmstate_subsection_load_bad(vmsd->name, idstr, "(child)");
             error_prepend(errp,
                           "Loading VM subsection '%s' in '%s' failed: ",
@@ -754,7 +751,7 @@ static bool vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
             qemu_put_byte(f, len);
             qemu_put_buffer(f, (uint8_t *)vmsdsub->name, len);
             qemu_put_be32(f, vmsdsub->version_id);
-            if (vmstate_save_state(f, vmsdsub, opaque, vmdesc, errp) < 0) {
+            if (!vmstate_save_vmsd(f, vmsdsub, opaque, vmdesc, errp)) {
                 return false;
             }
 
@@ -771,3 +768,15 @@ static bool vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
 
     return true;
 }
+
+int vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
+                       void *opaque, JSONWriter *vmdesc_id, Error **errp)
+{
+    return vmstate_save_vmsd(f, vmsd, opaque, vmdesc_id, errp) ? 0 : -EINVAL;
+}
+
+int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
+                        void *opaque, int version_id, Error **errp)
+{
+    return vmstate_load_vmsd(f, vmsd, opaque, version_id, errp) ? 0 : -EINVAL;
+}
-- 
2.52.0



^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 14/18] migration/cpr: move to new migration APIs
  2026-03-04 21:22 [PATCH v3 00/18] migration: more bool+errp APIs Vladimir Sementsov-Ogievskiy
                   ` (12 preceding siblings ...)
  2026-03-04 21:22 ` [PATCH v3 13/18] migration: introduce vmstate_load_vmsd() and vmstate_save_vmsd() Vladimir Sementsov-Ogievskiy
@ 2026-03-04 21:22 ` Vladimir Sementsov-Ogievskiy
  2026-03-04 21:22 ` [PATCH v3 15/18] migration/savevm: " Vladimir Sementsov-Ogievskiy
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2026-03-04 21:22 UTC (permalink / raw)
  To: peterx; +Cc: farosas, vsementsov, qemu-devel, Mark Kanda, Ben Chaney

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
Reviewed-by: Peter Xu <peterx@redhat.com>
---
 include/migration/cpr.h |  2 +-
 migration/cpr.c         | 22 +++++++++-------------
 2 files changed, 10 insertions(+), 14 deletions(-)

diff --git a/include/migration/cpr.h b/include/migration/cpr.h
index 5850fd1788b..96ce26e7117 100644
--- a/include/migration/cpr.h
+++ b/include/migration/cpr.h
@@ -43,7 +43,7 @@ void cpr_set_incoming_mode(MigMode mode);
 bool cpr_is_incoming(void);
 
 bool cpr_state_save(MigrationChannel *channel, Error **errp);
-int cpr_state_load(MigrationChannel *channel, Error **errp);
+bool cpr_state_load(MigrationChannel *channel, Error **errp);
 void cpr_state_close(void);
 struct QIOChannel *cpr_state_ioc(void);
 
diff --git a/migration/cpr.c b/migration/cpr.c
index a0b37007f55..05266dfcfd3 100644
--- a/migration/cpr.c
+++ b/migration/cpr.c
@@ -178,7 +178,6 @@ bool cpr_is_incoming(void)
 
 bool cpr_state_save(MigrationChannel *channel, Error **errp)
 {
-    int ret;
     QEMUFile *f;
     MigMode mode = migrate_mode();
 
@@ -199,8 +198,7 @@ bool cpr_state_save(MigrationChannel *channel, Error **errp)
     qemu_put_be32(f, QEMU_CPR_FILE_MAGIC);
     qemu_put_be32(f, QEMU_CPR_FILE_VERSION);
 
-    ret = vmstate_save_state(f, &vmstate_cpr_state, &cpr_state, 0, errp);
-    if (ret) {
+    if (!vmstate_save_vmsd(f, &vmstate_cpr_state, &cpr_state, 0, errp)) {
         qemu_fclose(f);
         return false;
     }
@@ -223,9 +221,8 @@ bool cpr_state_save(MigrationChannel *channel, Error **errp)
     return true;
 }
 
-int cpr_state_load(MigrationChannel *channel, Error **errp)
+bool cpr_state_load(MigrationChannel *channel, Error **errp)
 {
-    int ret;
     uint32_t v;
     QEMUFile *f;
     MigMode mode = 0;
@@ -241,10 +238,10 @@ int cpr_state_load(MigrationChannel *channel, Error **errp)
         cpr_set_incoming_mode(mode);
         f = cpr_transfer_input(channel, errp);
     } else {
-        return 0;
+        return true;
     }
     if (!f) {
-        return -1;
+        return false;
     }
 
     trace_cpr_state_load(MigMode_str(mode));
@@ -254,19 +251,18 @@ int cpr_state_load(MigrationChannel *channel, Error **errp)
     if (v != QEMU_CPR_FILE_MAGIC) {
         error_setg(errp, "Not a migration stream (bad magic %x)", v);
         qemu_fclose(f);
-        return -EINVAL;
+        return false;
     }
     v = qemu_get_be32(f);
     if (v != QEMU_CPR_FILE_VERSION) {
         error_setg(errp, "Unsupported migration stream version %d", v);
         qemu_fclose(f);
-        return -ENOTSUP;
+        return false;
     }
 
-    ret = vmstate_load_state(f, &vmstate_cpr_state, &cpr_state, 1, errp);
-    if (ret) {
+    if (!vmstate_load_vmsd(f, &vmstate_cpr_state, &cpr_state, 1, errp)) {
         qemu_fclose(f);
-        return ret;
+        return false;
     }
 
     if (migrate_mode() == MIG_MODE_CPR_EXEC) {
@@ -280,7 +276,7 @@ int cpr_state_load(MigrationChannel *channel, Error **errp)
      */
     cpr_state_file = f;
 
-    return ret;
+    return true;
 }
 
 void cpr_state_close(void)
-- 
2.52.0



^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 15/18] migration/savevm: move to new migration APIs
  2026-03-04 21:22 [PATCH v3 00/18] migration: more bool+errp APIs Vladimir Sementsov-Ogievskiy
                   ` (13 preceding siblings ...)
  2026-03-04 21:22 ` [PATCH v3 14/18] migration/cpr: move to new migration APIs Vladimir Sementsov-Ogievskiy
@ 2026-03-04 21:22 ` Vladimir Sementsov-Ogievskiy
  2026-03-04 21:23 ` [PATCH v3 16/18] hw/s390x/css: drop use of .err_hint for vmstate Vladimir Sementsov-Ogievskiy
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2026-03-04 21:22 UTC (permalink / raw)
  To: peterx; +Cc: farosas, vsementsov, qemu-devel

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
Reviewed-by: Peter Xu <peterx@redhat.com>
---
 migration/savevm.c | 105 ++++++++++++++++++++++++---------------------
 1 file changed, 55 insertions(+), 50 deletions(-)

diff --git a/migration/savevm.c b/migration/savevm.c
index c5236e71ba1..a4c64dda0a2 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -205,27 +205,28 @@ void timer_get(QEMUFile *f, QEMUTimer *ts)
  * Not in vmstate.c to not add qemu-timer.c as dependency to vmstate.c
  */
 
-static int get_timer(QEMUFile *f, void *pv, size_t size,
-                     const VMStateField *field)
+static bool load_timer(QEMUFile *f, void *pv, size_t size,
+                       const VMStateField *field, Error **errp)
 {
     QEMUTimer *v = pv;
     timer_get(f, v);
-    return 0;
+    return true;
 }
 
-static int put_timer(QEMUFile *f, void *pv, size_t size,
-                     const VMStateField *field, JSONWriter *vmdesc)
+static bool save_timer(QEMUFile *f, void *pv, size_t size,
+                       const VMStateField *field, JSONWriter *vmdesc,
+                       Error **errp)
 {
     QEMUTimer *v = pv;
     timer_put(f, v);
 
-    return 0;
+    return true;
 }
 
 const VMStateInfo vmstate_info_timer = {
     .name = "timer",
-    .get  = get_timer,
-    .put  = put_timer,
+    .load  = load_timer,
+    .save  = save_timer,
 };
 
 
@@ -297,7 +298,7 @@ static uint32_t get_validatable_capabilities_count(void)
     return result;
 }
 
-static int configuration_pre_save(void *opaque)
+static bool configuration_pre_save(void *opaque, Error **errp)
 {
     SaveState *state = opaque;
     const char *current_name = MACHINE_GET_CLASS(current_machine)->name;
@@ -318,7 +319,7 @@ static int configuration_pre_save(void *opaque)
     }
     state->uuid = qemu_uuid;
 
-    return 0;
+    return true;
 }
 
 static void configuration_post_save(void *opaque)
@@ -330,7 +331,7 @@ static void configuration_post_save(void *opaque)
     state->caps_count = 0;
 }
 
-static int configuration_pre_load(void *opaque)
+static bool configuration_pre_load(void *opaque, Error **errp)
 {
     SaveState *state = opaque;
 
@@ -339,7 +340,7 @@ static int configuration_pre_load(void *opaque)
      * minimum possible value for this CPU.
      */
     state->target_page_bits = migration_legacy_page_bits();
-    return 0;
+    return true;
 }
 
 static bool configuration_validate_capabilities(SaveState *state)
@@ -376,28 +377,31 @@ static bool configuration_validate_capabilities(SaveState *state)
     return ret;
 }
 
-static int configuration_post_load(void *opaque, int version_id)
+static bool configuration_post_load(void *opaque, int version_id, Error **errp)
 {
     SaveState *state = opaque;
     const char *current_name = MACHINE_GET_CLASS(current_machine)->name;
-    int ret = 0;
+    bool ok = true;
 
     if (strncmp(state->name, current_name, state->len) != 0) {
-        error_report("Machine type received is '%.*s' and local is '%s'",
-                     (int) state->len, state->name, current_name);
-        ret = -EINVAL;
+        error_setg(errp,
+                   "Machine type received is '%.*s' and local is '%s'",
+                   (int) state->len, state->name, current_name);
+        ok = false;
         goto out;
     }
 
     if (state->target_page_bits != qemu_target_page_bits()) {
-        error_report("Received TARGET_PAGE_BITS is %d but local is %d",
-                     state->target_page_bits, qemu_target_page_bits());
-        ret = -EINVAL;
+        error_setg(errp,
+                   "Received TARGET_PAGE_BITS is %d but local is %d",
+                   state->target_page_bits, qemu_target_page_bits());
+        ok = false;
         goto out;
     }
 
     if (!configuration_validate_capabilities(state)) {
-        ret = -EINVAL;
+        error_setg(errp, "Failed to validate capabilities");
+        ok = false;
         goto out;
     }
 
@@ -409,11 +413,12 @@ out:
     state->capabilities = NULL;
     state->caps_count = 0;
 
-    return ret;
+    return ok;
 }
 
-static int get_capability(QEMUFile *f, void *pv, size_t size,
-                          const VMStateField *field)
+static bool load_capability(QEMUFile *f, void *pv, size_t size,
+                            const VMStateField *field,
+                            Error **errp)
 {
     MigrationCapability *capability = pv;
     char capability_str[UINT8_MAX + 1];
@@ -426,15 +431,16 @@ static int get_capability(QEMUFile *f, void *pv, size_t size,
     for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
         if (!strcmp(MigrationCapability_str(i), capability_str)) {
             *capability = i;
-            return 0;
+            return true;
         }
     }
-    error_report("Received unknown capability %s", capability_str);
-    return -EINVAL;
+    error_setg(errp, "Received unknown capability %s", capability_str);
+    return false;
 }
 
-static int put_capability(QEMUFile *f, void *pv, size_t size,
-                          const VMStateField *field, JSONWriter *vmdesc)
+static bool save_capability(QEMUFile *f, void *pv, size_t size,
+                            const VMStateField *field, JSONWriter *vmdesc,
+                            Error **errp)
 {
     MigrationCapability *capability = pv;
     const char *capability_str = MigrationCapability_str(*capability);
@@ -443,13 +449,13 @@ static int put_capability(QEMUFile *f, void *pv, size_t size,
 
     qemu_put_byte(f, len);
     qemu_put_buffer(f, (uint8_t *)capability_str, len);
-    return 0;
+    return true;
 }
 
 static const VMStateInfo vmstate_info_capability = {
     .name = "capability",
-    .get  = get_capability,
-    .put  = put_capability,
+    .load = load_capability,
+    .save = save_capability,
 };
 
 /* The target-page-bits subsection is present only if the
@@ -539,9 +545,9 @@ static const VMStateDescription vmstate_uuid = {
 static const VMStateDescription vmstate_configuration = {
     .name = "configuration",
     .version_id = 1,
-    .pre_load = configuration_pre_load,
-    .post_load = configuration_post_load,
-    .pre_save = configuration_pre_save,
+    .pre_load_errp = configuration_pre_load,
+    .post_load_errp = configuration_post_load,
+    .pre_save_errp = configuration_pre_save,
     .post_save = configuration_post_save,
     .fields = (const VMStateField[]) {
         VMSTATE_UINT32(len, SaveState),
@@ -969,8 +975,13 @@ static int vmstate_load(QEMUFile *f, SaveStateEntry *se, Error **errp)
         }
         return ret;
     }
-    return vmstate_load_state(f, se->vmsd, se->opaque, se->load_version_id,
-                              errp);
+
+    if (!vmstate_load_vmsd(f, se->vmsd, se->opaque, se->load_version_id,
+                           errp)) {
+        return -EINVAL;
+    }
+
+    return 0;
 }
 
 static void vmstate_save_old_style(QEMUFile *f, SaveStateEntry *se,
@@ -1028,8 +1039,6 @@ static void save_section_footer(QEMUFile *f, SaveStateEntry *se)
 static int vmstate_save(QEMUFile *f, SaveStateEntry *se, JSONWriter *vmdesc,
                         Error **errp)
 {
-    int ret;
-
     if ((!se->ops || !se->ops->save_state) && !se->vmsd) {
         return 0;
     }
@@ -1050,10 +1059,8 @@ static int vmstate_save(QEMUFile *f, SaveStateEntry *se, JSONWriter *vmdesc,
     if (!se->vmsd) {
         vmstate_save_old_style(f, se, vmdesc);
     } else {
-        ret = vmstate_save_state(f, se->vmsd, se->opaque, vmdesc,
-                                 errp);
-        if (ret) {
-            return ret;
+        if (!vmstate_save_vmsd(f, se->vmsd, se->opaque, vmdesc, errp)) {
+            return -EINVAL;
         }
     }
 
@@ -1317,8 +1324,8 @@ static void qemu_savevm_send_configuration(MigrationState *s, QEMUFile *f)
         json_writer_start_object(vmdesc, "configuration");
     }
 
-    vmstate_save_state(f, &vmstate_configuration, &savevm_state,
-                       vmdesc, &local_err);
+    vmstate_save_vmsd(f, &vmstate_configuration, &savevm_state,
+                      vmdesc, &local_err);
     if (local_err) {
         error_report_err(local_err);
     }
@@ -2748,7 +2755,6 @@ qemu_loadvm_section_part_end(QEMUFile *f, uint8_t type, Error **errp)
 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) {
@@ -2779,10 +2785,9 @@ static int qemu_loadvm_state_header(QEMUFile *f, Error **errp)
             return -EINVAL;
         }
 
-        ret = vmstate_load_state(f, &vmstate_configuration, &savevm_state, 0,
-                                 errp);
-        if (ret) {
-            return ret;
+        if (!vmstate_load_vmsd(f, &vmstate_configuration, &savevm_state, 0,
+                               errp)) {
+            return -EINVAL;
         }
     }
     return 0;
-- 
2.52.0



^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 16/18] hw/s390x/css: drop use of .err_hint for vmstate
  2026-03-04 21:22 [PATCH v3 00/18] migration: more bool+errp APIs Vladimir Sementsov-Ogievskiy
                   ` (14 preceding siblings ...)
  2026-03-04 21:22 ` [PATCH v3 15/18] migration/savevm: " Vladimir Sementsov-Ogievskiy
@ 2026-03-04 21:23 ` Vladimir Sementsov-Ogievskiy
  2026-03-05  2:29   ` Eric Farman
  2026-03-05 17:14   ` Peter Xu
  2026-03-04 21:23 ` [PATCH v3 17/18] migration: drop VMStateField.err_hint Vladimir Sementsov-Ogievskiy
                   ` (2 subsequent siblings)
  18 siblings, 2 replies; 33+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2026-03-04 21:23 UTC (permalink / raw)
  To: peterx
  Cc: farosas, vsementsov, qemu-devel, Halil Pasic,
	Christian Borntraeger, Eric Farman, Farhan Ali, Thomas Huth,
	Richard Henderson, Ilya Leoshkevich, David Hildenbrand,
	Matthew Rosato, open list:S390 channel subs...

That's the only usage through the whole base. Doesn't
worth keeping the whole complexity. And 2.7 machines were
long ago.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
 hw/s390x/css.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index 04ce3178a0b..df5f0bc27f1 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -192,10 +192,6 @@ static const VMStateDescription vmstate_schdev_orb = {
 static int subch_dev_post_load(void *opaque, int version_id);
 static int subch_dev_pre_save(void *opaque);
 
-const char err_hint_devno[] = "Devno mismatch, tried to load wrong section!"
-    " Likely reason: some sequences of plug and unplug  can break"
-    " migration for machine versions prior to  2.7 (known design flaw).";
-
 const VMStateDescription vmstate_subch_dev = {
     .name = "s390_subch_dev",
     .version_id = 1,
@@ -203,10 +199,15 @@ const VMStateDescription vmstate_subch_dev = {
     .post_load = subch_dev_post_load,
     .pre_save = subch_dev_pre_save,
     .fields = (const VMStateField[]) {
-        VMSTATE_UINT8_EQUAL(cssid, SubchDev, "Bug!"),
-        VMSTATE_UINT8_EQUAL(ssid, SubchDev, "Bug!"),
+        VMSTATE_UINT8_EQUAL(cssid, SubchDev, NULL),
+        VMSTATE_UINT8_EQUAL(ssid, SubchDev, NULL),
         VMSTATE_UINT16(migrated_schid, SubchDev),
-        VMSTATE_UINT16_EQUAL(devno, SubchDev, err_hint_devno),
+        /*
+         * If devno mismatch on target, it may be due to some
+         * sequences of plug and unplug breaks migration for
+         * machine versions prior to 2.7 (known design flaw).
+         */
+        VMSTATE_UINT16_EQUAL(devno, SubchDev, NULL),
         VMSTATE_BOOL(thinint_active, SubchDev),
         VMSTATE_STRUCT(curr_status, SubchDev, 0, vmstate_schib, SCHIB),
         VMSTATE_UINT8_ARRAY(sense_data, SubchDev, 32),
-- 
2.52.0



^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 17/18] migration: drop VMStateField.err_hint
  2026-03-04 21:22 [PATCH v3 00/18] migration: more bool+errp APIs Vladimir Sementsov-Ogievskiy
                   ` (15 preceding siblings ...)
  2026-03-04 21:23 ` [PATCH v3 16/18] hw/s390x/css: drop use of .err_hint for vmstate Vladimir Sementsov-Ogievskiy
@ 2026-03-04 21:23 ` Vladimir Sementsov-Ogievskiy
  2026-03-05  2:39   ` Eric Farman
                     ` (2 more replies)
  2026-03-04 21:23 ` [PATCH v3 18/18] migration/vmstate-types: move to new migration APIs Vladimir Sementsov-Ogievskiy
  2026-03-06 20:53 ` [PATCH v3 00/18] migration: more bool+errp APIs Fabiano Rosas
  18 siblings, 3 replies; 33+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2026-03-04 21:23 UTC (permalink / raw)
  To: peterx
  Cc: farosas, vsementsov, qemu-devel, John Snow, Kevin Wolf,
	Hanna Reitz, Gerd Hoffmann, Michael S. Tsirkin, Alex Bennée,
	Akihiko Odaki, Dmitry Osipenko, Dmitry Fleytman, Marcel Apfelbaum,
	Paolo Bonzini, Richard Henderson, Eduardo Habkost,
	Mark Cave-Ayland, Gautam Menghani, Glenn Miles, Nicholas Piggin,
	Harsh Prateek Bora, Stefan Weil, Halil Pasic,
	Christian Borntraeger, Eric Farman, Farhan Ali, Matthew Rosato,
	Ilya Leoshkevich, David Hildenbrand, Thomas Huth, Chinmay Rath,
	open list:Floppy, open list:XIVE, open list:S390 channel subs...

The field is unused, all users of VMSTATE_*_EQUAL pass _err_hint=NULL.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
 hw/block/fdc.c              |  2 +-
 hw/display/qxl.c            |  4 ++--
 hw/display/vga.c            |  2 +-
 hw/display/virtio-gpu.c     |  2 +-
 hw/display/vmware_vga.c     |  2 +-
 hw/i386/vmmouse.c           |  2 +-
 hw/ide/ahci.c               |  2 +-
 hw/intc/openpic.c           |  2 +-
 hw/intc/spapr_xive.c        |  2 +-
 hw/intc/xics.c              |  2 +-
 hw/intc/xive.c              |  2 +-
 hw/nvram/eeprom93xx.c       |  2 +-
 hw/pci/pci.c                |  2 +-
 hw/pci/pcie_aer.c           |  2 +-
 hw/ppc/spapr_iommu.c        |  2 +-
 hw/ppc/spapr_pci.c          |  4 ++--
 hw/ppc/spapr_vio.c          |  4 ++--
 hw/s390x/css.c              |  6 +++---
 hw/usb/hcd-uhci.c           |  2 +-
 include/migration/vmstate.h | 36 +++++++++++++++++-------------------
 migration/vmstate-types.c   | 15 ---------------
 target/ppc/machine.c        |  6 +++---
 22 files changed, 44 insertions(+), 61 deletions(-)

diff --git a/hw/block/fdc.c b/hw/block/fdc.c
index 4585640af92..2c1681b7d0a 100644
--- a/hw/block/fdc.c
+++ b/hw/block/fdc.c
@@ -1051,7 +1051,7 @@ const VMStateDescription vmstate_fdc = {
         VMSTATE_UINT8(config, FDCtrl),
         VMSTATE_UINT8(lock, FDCtrl),
         VMSTATE_UINT8(pwrd, FDCtrl),
-        VMSTATE_UINT8_EQUAL(num_floppies, FDCtrl, NULL),
+        VMSTATE_UINT8_EQUAL(num_floppies, FDCtrl),
         VMSTATE_STRUCT_ARRAY(drives, FDCtrl, MAX_FD, 1,
                              vmstate_fdrive, FDrive),
         VMSTATE_END_OF_LIST()
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index 0551b38230b..a63b70f4ebc 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -2442,12 +2442,12 @@ static const VMStateDescription qxl_vmstate = {
         VMSTATE_UINT32(last_release_offset, PCIQXLDevice),
         VMSTATE_UINT32(mode, PCIQXLDevice),
         VMSTATE_UINT32(ssd.unique, PCIQXLDevice),
-        VMSTATE_INT32_EQUAL(num_memslots, PCIQXLDevice, NULL),
+        VMSTATE_INT32_EQUAL(num_memslots, PCIQXLDevice),
         VMSTATE_STRUCT_ARRAY(guest_slots, PCIQXLDevice, NUM_MEMSLOTS, 0,
                              qxl_memslot, struct guest_slots),
         VMSTATE_STRUCT(guest_primary.surface, PCIQXLDevice, 0,
                        qxl_surface, QXLSurfaceCreate),
-        VMSTATE_INT32_EQUAL(ssd.num_surfaces, PCIQXLDevice, NULL),
+        VMSTATE_INT32_EQUAL(ssd.num_surfaces, PCIQXLDevice),
         VMSTATE_VARRAY_INT32(guest_surfaces.cmds, PCIQXLDevice,
                              ssd.num_surfaces, 0,
                              vmstate_info_uint64, uint64_t),
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 59a65cbbff5..f936f47ad22 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -2160,7 +2160,7 @@ const VMStateDescription vmstate_vga_common = {
         VMSTATE_BUFFER(palette, VGACommonState),
 
         VMSTATE_INT32(bank_offset, VGACommonState),
-        VMSTATE_UINT8_EQUAL(is_vbe_vmstate, VGACommonState, NULL),
+        VMSTATE_UINT8_EQUAL(is_vbe_vmstate, VGACommonState),
         VMSTATE_UINT16(vbe_index, VGACommonState),
         VMSTATE_UINT16_ARRAY(vbe_regs, VGACommonState, VBE_DISPI_INDEX_NB),
         VMSTATE_UINT32(vbe_start_addr, VGACommonState),
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 643e91ca2a7..9aeeef16410 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -1211,7 +1211,7 @@ static const VMStateDescription vmstate_virtio_gpu_scanouts = {
     .fields = (const VMStateField[]) {
         VMSTATE_INT32(parent_obj.enable, struct VirtIOGPU),
         VMSTATE_UINT32_EQUAL(parent_obj.conf.max_outputs,
-                             struct VirtIOGPU, NULL),
+                             struct VirtIOGPU),
         VMSTATE_STRUCT_VARRAY_UINT32(parent_obj.scanout, struct VirtIOGPU,
                                      parent_obj.conf.max_outputs, 1,
                                      vmstate_virtio_gpu_scanout,
diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
index ea7a9fca04e..d97a60cdf75 100644
--- a/hw/display/vmware_vga.c
+++ b/hw/display/vmware_vga.c
@@ -1209,7 +1209,7 @@ static const VMStateDescription vmstate_vmware_vga_internal = {
     .minimum_version_id = 0,
     .post_load = vmsvga_post_load,
     .fields = (const VMStateField[]) {
-        VMSTATE_INT32_EQUAL(new_depth, struct vmsvga_state_s, NULL),
+        VMSTATE_INT32_EQUAL(new_depth, struct vmsvga_state_s),
         VMSTATE_INT32(enable, struct vmsvga_state_s),
         VMSTATE_INT32(config, struct vmsvga_state_s),
         VMSTATE_INT32(cursor.id, struct vmsvga_state_s),
diff --git a/hw/i386/vmmouse.c b/hw/i386/vmmouse.c
index c1aeeca0c9a..417c3aecb92 100644
--- a/hw/i386/vmmouse.c
+++ b/hw/i386/vmmouse.c
@@ -278,7 +278,7 @@ static const VMStateDescription vmstate_vmmouse = {
     .minimum_version_id = 0,
     .post_load = vmmouse_post_load,
     .fields = (const VMStateField[]) {
-        VMSTATE_INT32_EQUAL(queue_size, VMMouseState, NULL),
+        VMSTATE_INT32_EQUAL(queue_size, VMMouseState),
         VMSTATE_UINT32_ARRAY(queue, VMMouseState, VMMOUSE_QUEUE_SIZE),
         VMSTATE_UINT16(nb_queue, VMMouseState),
         VMSTATE_UINT16(status, VMMouseState),
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 08f51c8e361..c2b4432b947 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -1795,7 +1795,7 @@ const VMStateDescription vmstate_ahci = {
         VMSTATE_UINT32(control_regs.impl, AHCIState),
         VMSTATE_UINT32(control_regs.version, AHCIState),
         VMSTATE_UINT32(idp_index, AHCIState),
-        VMSTATE_UINT32_EQUAL(ports, AHCIState, NULL),
+        VMSTATE_UINT32_EQUAL(ports, AHCIState),
         VMSTATE_END_OF_LIST()
     },
 };
diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c
index cd353a04f53..99d2a1e65ec 100644
--- a/hw/intc/openpic.c
+++ b/hw/intc/openpic.c
@@ -1477,7 +1477,7 @@ static const VMStateDescription vmstate_openpic = {
         VMSTATE_UINT32(max_irq, OpenPICState),
         VMSTATE_STRUCT_VARRAY_UINT32(src, OpenPICState, max_irq, 0,
                                      vmstate_openpic_irqsource, IRQSource),
-        VMSTATE_UINT32_EQUAL(nb_cpus, OpenPICState, NULL),
+        VMSTATE_UINT32_EQUAL(nb_cpus, OpenPICState),
         VMSTATE_STRUCT_VARRAY_UINT32(dst, OpenPICState, nb_cpus, 0,
                                      vmstate_openpic_irqdest, IRQDest),
         VMSTATE_STRUCT_ARRAY(timers, OpenPICState, OPENPIC_MAX_TMR, 0,
diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c
index 76ab476f59a..c30dace4e25 100644
--- a/hw/intc/spapr_xive.c
+++ b/hw/intc/spapr_xive.c
@@ -578,7 +578,7 @@ static const VMStateDescription vmstate_spapr_xive = {
     .pre_save = vmstate_spapr_xive_pre_save,
     .post_load = NULL, /* handled at the machine level */
     .fields = (const VMStateField[]) {
-        VMSTATE_UINT32_EQUAL(nr_irqs, SpaprXive, NULL),
+        VMSTATE_UINT32_EQUAL(nr_irqs, SpaprXive),
         VMSTATE_STRUCT_VARRAY_POINTER_UINT32(eat, SpaprXive, nr_irqs,
                                      vmstate_spapr_xive_eas, XiveEAS),
         VMSTATE_STRUCT_VARRAY_POINTER_UINT32(endt, SpaprXive, nr_ends,
diff --git a/hw/intc/xics.c b/hw/intc/xics.c
index 1d40c4386d1..c0a252d0519 100644
--- a/hw/intc/xics.c
+++ b/hw/intc/xics.c
@@ -668,7 +668,7 @@ static const VMStateDescription vmstate_ics = {
     .post_load = ics_post_load,
     .fields = (const VMStateField[]) {
         /* Sanity check */
-        VMSTATE_UINT32_EQUAL(nr_irqs, ICSState, NULL),
+        VMSTATE_UINT32_EQUAL(nr_irqs, ICSState),
 
         VMSTATE_STRUCT_VARRAY_POINTER_UINT32(irqs, ICSState, nr_irqs,
                                              vmstate_ics_irq,
diff --git a/hw/intc/xive.c b/hw/intc/xive.c
index d702b58bd0a..f473e6ac77e 100644
--- a/hw/intc/xive.c
+++ b/hw/intc/xive.c
@@ -1565,7 +1565,7 @@ static const VMStateDescription vmstate_xive_source = {
     .version_id = 1,
     .minimum_version_id = 1,
     .fields = (const VMStateField[]) {
-        VMSTATE_UINT32_EQUAL(nr_irqs, XiveSource, NULL),
+        VMSTATE_UINT32_EQUAL(nr_irqs, XiveSource),
         VMSTATE_VBUFFER_UINT32(status, XiveSource, 1, NULL, nr_irqs),
         VMSTATE_END_OF_LIST()
     },
diff --git a/hw/nvram/eeprom93xx.c b/hw/nvram/eeprom93xx.c
index a8fd60a8fb5..73b3d248d44 100644
--- a/hw/nvram/eeprom93xx.c
+++ b/hw/nvram/eeprom93xx.c
@@ -144,7 +144,7 @@ static const VMStateDescription vmstate_eeprom = {
         VMSTATE_UINT8(addrbits, eeprom_t),
         VMSTATE_UINT16_HACK_TEST(size, eeprom_t, is_old_eeprom_version),
         VMSTATE_UNUSED_TEST(is_old_eeprom_version, 1),
-        VMSTATE_UINT16_EQUAL_V(size, eeprom_t, EEPROM_VERSION, NULL),
+        VMSTATE_UINT16_EQUAL_V(size, eeprom_t, EEPROM_VERSION),
         VMSTATE_UINT16(data, eeprom_t),
         VMSTATE_VARRAY_UINT16_UNSAFE(contents, eeprom_t, size, 0,
                                      vmstate_info_uint16, uint16_t),
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 90d6d71efdc..8868d6ad387 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -106,7 +106,7 @@ static const VMStateDescription vmstate_pcibus = {
     .version_id = 1,
     .minimum_version_id = 1,
     .fields = (const VMStateField[]) {
-        VMSTATE_INT32_EQUAL(nirq, PCIBus, NULL),
+        VMSTATE_INT32_EQUAL(nirq, PCIBus),
         VMSTATE_VARRAY_INT32(irq_count, PCIBus,
                              nirq, 0, vmstate_info_int32,
                              int32_t),
diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c
index 2c85a78fcde..22497b1fd65 100644
--- a/hw/pci/pcie_aer.c
+++ b/hw/pci/pcie_aer.c
@@ -820,7 +820,7 @@ const VMStateDescription vmstate_pcie_aer_log = {
     .minimum_version_id = 1,
     .fields = (const VMStateField[]) {
         VMSTATE_UINT16(log_num, PCIEAERLog),
-        VMSTATE_UINT16_EQUAL(log_max, PCIEAERLog, NULL),
+        VMSTATE_UINT16_EQUAL(log_max, PCIEAERLog),
         VMSTATE_VALIDATE("log_num <= log_max", pcie_aer_state_log_num_valid),
         VMSTATE_STRUCT_VARRAY_POINTER_UINT16(log, PCIEAERLog, log_num,
                               vmstate_pcie_aer_err, PCIEAERErr),
diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
index c2432a0c00c..e6264b07854 100644
--- a/hw/ppc/spapr_iommu.c
+++ b/hw/ppc/spapr_iommu.c
@@ -285,7 +285,7 @@ static const VMStateDescription vmstate_spapr_tce_table = {
     .post_load = spapr_tce_table_post_load,
     .fields = (const VMStateField []) {
         /* Sanity check */
-        VMSTATE_UINT32_EQUAL(liobn, SpaprTceTable, NULL),
+        VMSTATE_UINT32_EQUAL(liobn, SpaprTceTable),
 
         /* IOMMU state */
         VMSTATE_UINT32(mig_nb_table, SpaprTceTable),
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index 1dc3b02659f..c1d4b7806e4 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -2051,7 +2051,7 @@ static const VMStateDescription vmstate_spapr_pci_lsi = {
     .version_id = 1,
     .minimum_version_id = 1,
     .fields = (const VMStateField[]) {
-        VMSTATE_UINT32_EQUAL(irq, SpaprPciLsi, NULL),
+        VMSTATE_UINT32_EQUAL(irq, SpaprPciLsi),
 
         VMSTATE_END_OF_LIST()
     },
@@ -2129,7 +2129,7 @@ static const VMStateDescription vmstate_spapr_pci = {
     .post_save = spapr_pci_post_save,
     .post_load = spapr_pci_post_load,
     .fields = (const VMStateField[]) {
-        VMSTATE_UINT64_EQUAL(buid, SpaprPhbState, NULL),
+        VMSTATE_UINT64_EQUAL(buid, SpaprPhbState),
         VMSTATE_STRUCT_ARRAY(lsi_table, SpaprPhbState, PCI_NUM_PINS, 0,
                              vmstate_spapr_pci_lsi, SpaprPciLsi),
         VMSTATE_INT32(msi_devs_num, SpaprPhbState),
diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c
index 501e82a7665..3f05081bada 100644
--- a/hw/ppc/spapr_vio.c
+++ b/hw/ppc/spapr_vio.c
@@ -609,8 +609,8 @@ const VMStateDescription vmstate_spapr_vio = {
     .minimum_version_id = 1,
     .fields = (const VMStateField[]) {
         /* Sanity check */
-        VMSTATE_UINT32_EQUAL(reg, SpaprVioDevice, NULL),
-        VMSTATE_UINT32_EQUAL(irq, SpaprVioDevice, NULL),
+        VMSTATE_UINT32_EQUAL(reg, SpaprVioDevice),
+        VMSTATE_UINT32_EQUAL(irq, SpaprVioDevice),
 
         /* General VIO device state */
         VMSTATE_UINT64(signal_state, SpaprVioDevice),
diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index df5f0bc27f1..ecd28fed5c3 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -199,15 +199,15 @@ const VMStateDescription vmstate_subch_dev = {
     .post_load = subch_dev_post_load,
     .pre_save = subch_dev_pre_save,
     .fields = (const VMStateField[]) {
-        VMSTATE_UINT8_EQUAL(cssid, SubchDev, NULL),
-        VMSTATE_UINT8_EQUAL(ssid, SubchDev, NULL),
+        VMSTATE_UINT8_EQUAL(cssid, SubchDev),
+        VMSTATE_UINT8_EQUAL(ssid, SubchDev),
         VMSTATE_UINT16(migrated_schid, SubchDev),
         /*
          * If devno mismatch on target, it may be due to some
          * sequences of plug and unplug breaks migration for
          * machine versions prior to 2.7 (known design flaw).
          */
-        VMSTATE_UINT16_EQUAL(devno, SubchDev, NULL),
+        VMSTATE_UINT16_EQUAL(devno, SubchDev),
         VMSTATE_BOOL(thinint_active, SubchDev),
         VMSTATE_STRUCT(curr_status, SubchDev, 0, vmstate_schib, SCHIB),
         VMSTATE_UINT8_ARRAY(sense_data, SubchDev, 32),
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index b2224c7f766..a7b9fe13175 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -364,7 +364,7 @@ static const VMStateDescription vmstate_uhci = {
     .post_load = uhci_post_load,
     .fields = (const VMStateField[]) {
         VMSTATE_PCI_DEVICE(dev, UHCIState),
-        VMSTATE_UINT8_EQUAL(num_ports_vmstate, UHCIState, NULL),
+        VMSTATE_UINT8_EQUAL(num_ports_vmstate, UHCIState),
         VMSTATE_STRUCT_ARRAY(ports, UHCIState, UHCI_PORTS, 1,
                              vmstate_uhci_port, UHCIPort),
         VMSTATE_UINT16(cmd, UHCIState),
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 3c1d84f2d67..ca702765020 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -182,7 +182,6 @@ typedef enum {
 
 struct VMStateField {
     const char *name;
-    const char *err_hint;
     size_t offset;
     size_t size;
     size_t start;
@@ -358,9 +357,8 @@ extern const VMStateInfo vmstate_info_qlist;
 }
 
 #define VMSTATE_SINGLE_FULL(_field, _state, _test, _version, _info,  \
-                            _type, _err_hint) {                      \
+                            _type) {                      \
     .name         = (stringify(_field)),                             \
-    .err_hint     = (_err_hint),                                     \
     .version_id   = (_version),                                      \
     .field_exists = (_test),                                         \
     .size         = sizeof(_type),                                   \
@@ -1012,35 +1010,35 @@ extern const VMStateInfo vmstate_info_qlist;
 
 #endif
 
-#define VMSTATE_UINT8_EQUAL(_f, _s, _err_hint)                        \
+#define VMSTATE_UINT8_EQUAL(_f, _s)                                   \
     VMSTATE_SINGLE_FULL(_f, _s, 0, 0,                                 \
-                        vmstate_info_uint8_equal, uint8_t, _err_hint)
+                        vmstate_info_uint8_equal, uint8_t)
 
-#define VMSTATE_UINT16_EQUAL(_f, _s, _err_hint)                       \
+#define VMSTATE_UINT16_EQUAL(_f, _s)                                  \
     VMSTATE_SINGLE_FULL(_f, _s, 0, 0,                                 \
-                        vmstate_info_uint16_equal, uint16_t, _err_hint)
+                        vmstate_info_uint16_equal, uint16_t)
 
-#define VMSTATE_UINT16_EQUAL_V(_f, _s, _v, _err_hint)                 \
+#define VMSTATE_UINT16_EQUAL_V(_f, _s, _v)                            \
     VMSTATE_SINGLE_FULL(_f, _s, 0,  _v,                               \
-                        vmstate_info_uint16_equal, uint16_t, _err_hint)
+                        vmstate_info_uint16_equal, uint16_t)
 
-#define VMSTATE_INT32_EQUAL(_f, _s, _err_hint)                        \
+#define VMSTATE_INT32_EQUAL(_f, _s)                                   \
     VMSTATE_SINGLE_FULL(_f, _s, 0, 0,                                 \
-                        vmstate_info_int32_equal, int32_t, _err_hint)
+                        vmstate_info_int32_equal, int32_t)
 
-#define VMSTATE_UINT32_EQUAL_V(_f, _s, _v, _err_hint)                 \
+#define VMSTATE_UINT32_EQUAL_V(_f, _s, _v)                            \
     VMSTATE_SINGLE_FULL(_f, _s, 0,  _v,                               \
-                        vmstate_info_uint32_equal, uint32_t, _err_hint)
+                        vmstate_info_uint32_equal, uint32_t)
 
-#define VMSTATE_UINT32_EQUAL(_f, _s, _err_hint)                       \
-    VMSTATE_UINT32_EQUAL_V(_f, _s, 0, _err_hint)
+#define VMSTATE_UINT32_EQUAL(_f, _s)                                  \
+    VMSTATE_UINT32_EQUAL_V(_f, _s, 0)
 
-#define VMSTATE_UINT64_EQUAL_V(_f, _s, _v, _err_hint)                 \
+#define VMSTATE_UINT64_EQUAL_V(_f, _s, _v)                            \
     VMSTATE_SINGLE_FULL(_f, _s, 0,  _v,                               \
-                        vmstate_info_uint64_equal, uint64_t, _err_hint)
+                        vmstate_info_uint64_equal, uint64_t)
 
-#define VMSTATE_UINT64_EQUAL(_f, _s, _err_hint)                       \
-    VMSTATE_UINT64_EQUAL_V(_f, _s, 0, _err_hint)
+#define VMSTATE_UINT64_EQUAL(_f, _s)                                  \
+    VMSTATE_UINT64_EQUAL_V(_f, _s, 0)
 
 #define VMSTATE_INT32_POSITIVE_LE(_f, _s)                             \
     VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_le, int32_t)
diff --git a/migration/vmstate-types.c b/migration/vmstate-types.c
index 89cb2114721..033a2685c8f 100644
--- a/migration/vmstate-types.c
+++ b/migration/vmstate-types.c
@@ -131,9 +131,6 @@ static int get_int32_equal(QEMUFile *f, void *pv, size_t size,
         return 0;
     }
     error_report("%" PRIx32 " != %" PRIx32, *v, v2);
-    if (field->err_hint) {
-        error_printf("%s\n", field->err_hint);
-    }
     return -EINVAL;
 }
 
@@ -280,9 +277,6 @@ static int get_uint32_equal(QEMUFile *f, void *pv, size_t size,
         return 0;
     }
     error_report("%" PRIx32 " != %" PRIx32, *v, v2);
-    if (field->err_hint) {
-        error_printf("%s\n", field->err_hint);
-    }
     return -EINVAL;
 }
 
@@ -391,9 +385,6 @@ static int get_uint64_equal(QEMUFile *f, void *pv, size_t size,
         return 0;
     }
     error_report("%" PRIx64 " != %" PRIx64, *v, v2);
-    if (field->err_hint) {
-        error_printf("%s\n", field->err_hint);
-    }
     return -EINVAL;
 }
 
@@ -417,9 +408,6 @@ static int get_uint8_equal(QEMUFile *f, void *pv, size_t size,
         return 0;
     }
     error_report("%x != %x", *v, v2);
-    if (field->err_hint) {
-        error_printf("%s\n", field->err_hint);
-    }
     return -EINVAL;
 }
 
@@ -443,9 +431,6 @@ static int get_uint16_equal(QEMUFile *f, void *pv, size_t size,
         return 0;
     }
     error_report("%x != %x", *v, v2);
-    if (field->err_hint) {
-        error_printf("%s\n", field->err_hint);
-    }
     return -EINVAL;
 }
 
diff --git a/target/ppc/machine.c b/target/ppc/machine.c
index 49cfdc6d674..9eae0ff647d 100644
--- a/target/ppc/machine.c
+++ b/target/ppc/machine.c
@@ -564,7 +564,7 @@ static const VMStateDescription vmstate_tlb6xx = {
     .minimum_version_id = 1,
     .needed = tlb6xx_needed,
     .fields = (const VMStateField[]) {
-        VMSTATE_INT32_EQUAL(env.nb_tlb, PowerPCCPU, NULL),
+        VMSTATE_INT32_EQUAL(env.nb_tlb, PowerPCCPU),
         VMSTATE_STRUCT_VARRAY_POINTER_INT32(env.tlb.tlb6, PowerPCCPU,
                                             env.nb_tlb,
                                             vmstate_tlb6xx_entry,
@@ -603,7 +603,7 @@ static const VMStateDescription vmstate_tlbemb = {
     .minimum_version_id = 1,
     .needed = tlbemb_needed,
     .fields = (const VMStateField[]) {
-        VMSTATE_INT32_EQUAL(env.nb_tlb, PowerPCCPU, NULL),
+        VMSTATE_INT32_EQUAL(env.nb_tlb, PowerPCCPU),
         VMSTATE_STRUCT_VARRAY_POINTER_INT32(env.tlb.tlbe, PowerPCCPU,
                                             env.nb_tlb,
                                             vmstate_tlbemb_entry,
@@ -639,7 +639,7 @@ static const VMStateDescription vmstate_tlbmas = {
     .minimum_version_id = 1,
     .needed = tlbmas_needed,
     .fields = (const VMStateField[]) {
-        VMSTATE_INT32_EQUAL(env.nb_tlb, PowerPCCPU, NULL),
+        VMSTATE_INT32_EQUAL(env.nb_tlb, PowerPCCPU),
         VMSTATE_STRUCT_VARRAY_POINTER_INT32(env.tlb.tlbm, PowerPCCPU,
                                             env.nb_tlb,
                                             vmstate_tlbmas_entry,
-- 
2.52.0



^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 18/18] migration/vmstate-types: move to new migration APIs
  2026-03-04 21:22 [PATCH v3 00/18] migration: more bool+errp APIs Vladimir Sementsov-Ogievskiy
                   ` (16 preceding siblings ...)
  2026-03-04 21:23 ` [PATCH v3 17/18] migration: drop VMStateField.err_hint Vladimir Sementsov-Ogievskiy
@ 2026-03-04 21:23 ` Vladimir Sementsov-Ogievskiy
  2026-03-05 17:15   ` Peter Xu
  2026-03-06 20:53 ` [PATCH v3 00/18] migration: more bool+errp APIs Fabiano Rosas
  18 siblings, 1 reply; 33+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2026-03-04 21:23 UTC (permalink / raw)
  To: peterx; +Cc: farosas, vsementsov, qemu-devel

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
 migration/trace-events    |  24 +-
 migration/vmstate-types.c | 627 +++++++++++++++++++-------------------
 2 files changed, 327 insertions(+), 324 deletions(-)

diff --git a/migration/trace-events b/migration/trace-events
index 0b3f759ccc4..5fe3cc59c01 100644
--- a/migration/trace-events
+++ b/migration/trace-events
@@ -73,20 +73,20 @@ vmstate_subsection_save_top(const char *idstr) "%s"
 vmstate_field_exists(const char *vmsd, const char *name, int field_version, int version, int result) "%s:%s field_version %d version %d result %d"
 
 # vmstate-types.c
-get_qtailq(const char *name, int version_id) "%s v%d"
-get_qtailq_end(const char *name, const char *reason, int val) "%s %s/%d"
-put_qtailq(const char *name, int version_id) "%s v%d"
-put_qtailq_end(const char *name, const char *reason) "%s %s"
+load_qtailq(const char *name, int version_id) "%s v%d"
+load_qtailq_end(const char *name) "%s"
+save_qtailq(const char *name, int version_id) "%s v%d"
+save_qtailq_end(const char *name) "%s"
 
-get_gtree(const char *field_name, const char *key_vmsd_name, const char *val_vmsd_name, uint32_t nnodes) "%s(%s/%s) nnodes=%d"
-get_gtree_end(const char *field_name, const char *key_vmsd_name, const char *val_vmsd_name, int ret) "%s(%s/%s) %d"
-put_gtree(const char *field_name, const char *key_vmsd_name, const char *val_vmsd_name, uint32_t nnodes) "%s(%s/%s) nnodes=%d"
-put_gtree_end(const char *field_name, const char *key_vmsd_name, const char *val_vmsd_name, int ret) "%s(%s/%s) %d"
+load_gtree(const char *field_name, const char *key_vmsd_name, const char *val_vmsd_name, uint32_t nnodes) "%s(%s/%s) nnodes=%d"
+load_gtree_end(const char *field_name, const char *key_vmsd_name, const char *val_vmsd_name) "%s(%s/%s)"
+save_gtree(const char *field_name, const char *key_vmsd_name, const char *val_vmsd_name, uint32_t nnodes) "%s(%s/%s) nnodes=%d"
+save_gtree_end(const char *field_name, const char *key_vmsd_name, const char *val_vmsd_name) "%s(%s/%s)"
 
-get_qlist(const char *field_name, const char *vmsd_name, int version_id) "%s(%s v%d)"
-get_qlist_end(const char *field_name, const char *vmsd_name) "%s(%s)"
-put_qlist(const char *field_name, const char *vmsd_name, int version_id) "%s(%s v%d)"
-put_qlist_end(const char *field_name, const char *vmsd_name) "%s(%s)"
+load_qlist(const char *field_name, const char *vmsd_name, int version_id) "%s(%s v%d)"
+load_qlist_end(const char *field_name, const char *vmsd_name) "%s(%s)"
+save_qlist(const char *field_name, const char *vmsd_name, int version_id) "%s(%s v%d)"
+save_qlist_end(const char *field_name, const char *vmsd_name) "%s(%s)"
 
 # qemu-file.c
 qemu_file_fclose(void) ""
diff --git a/migration/vmstate-types.c b/migration/vmstate-types.c
index 033a2685c8f..23f34336964 100644
--- a/migration/vmstate-types.c
+++ b/migration/vmstate-types.c
@@ -23,129 +23,135 @@
 
 /* bool */
 
-static int get_bool(QEMUFile *f, void *pv, size_t size,
-                    const VMStateField *field)
+static bool load_bool(QEMUFile *f, void *pv, size_t size,
+                      const VMStateField *field, Error **errp)
 {
     bool *v = pv;
     *v = qemu_get_byte(f);
-    return 0;
+    return true;
 }
 
-static int put_bool(QEMUFile *f, void *pv, size_t size,
-                    const VMStateField *field, JSONWriter *vmdesc)
+static bool save_bool(QEMUFile *f, void *pv, size_t size,
+                      const VMStateField *field, JSONWriter *vmdesc,
+                      Error **errp)
 {
     bool *v = pv;
     qemu_put_byte(f, *v);
-    return 0;
+    return true;
 }
 
 const VMStateInfo vmstate_info_bool = {
     .name = "bool",
-    .get  = get_bool,
-    .put  = put_bool,
+    .load = load_bool,
+    .save = save_bool,
 };
 
 /* 8 bit int */
 
-static int get_int8(QEMUFile *f, void *pv, size_t size,
-                    const VMStateField *field)
+static bool load_int8(QEMUFile *f, void *pv, size_t size,
+                      const VMStateField *field, Error **errp)
 {
     int8_t *v = pv;
     qemu_get_s8s(f, v);
-    return 0;
+    return true;
 }
 
-static int put_int8(QEMUFile *f, void *pv, size_t size,
-                    const VMStateField *field, JSONWriter *vmdesc)
+static bool save_int8(QEMUFile *f, void *pv, size_t size,
+                      const VMStateField *field, JSONWriter *vmdesc,
+                      Error **errp)
 {
     int8_t *v = pv;
     qemu_put_s8s(f, v);
-    return 0;
+    return true;
 }
 
 const VMStateInfo vmstate_info_int8 = {
     .name = "int8",
-    .get  = get_int8,
-    .put  = put_int8,
+    .load = load_int8,
+    .save = save_int8,
 };
 
 /* 16 bit int */
 
-static int get_int16(QEMUFile *f, void *pv, size_t size,
-                     const VMStateField *field)
+static bool load_int16(QEMUFile *f, void *pv, size_t size,
+                       const VMStateField *field, Error **errp)
 {
     int16_t *v = pv;
     qemu_get_sbe16s(f, v);
-    return 0;
+    return true;
 }
 
-static int put_int16(QEMUFile *f, void *pv, size_t size,
-                     const VMStateField *field, JSONWriter *vmdesc)
+static bool save_int16(QEMUFile *f, void *pv, size_t size,
+                       const VMStateField *field, JSONWriter *vmdesc,
+                       Error **errp)
 {
     int16_t *v = pv;
     qemu_put_sbe16s(f, v);
-    return 0;
+    return true;
 }
 
 const VMStateInfo vmstate_info_int16 = {
     .name = "int16",
-    .get  = get_int16,
-    .put  = put_int16,
+    .load = load_int16,
+    .save = save_int16,
 };
 
 /* 32 bit int */
 
-static int get_int32(QEMUFile *f, void *pv, size_t size,
-                     const VMStateField *field)
+static bool load_int32(QEMUFile *f, void *pv, size_t size,
+                       const VMStateField *field, Error **errp)
 {
     int32_t *v = pv;
     qemu_get_sbe32s(f, v);
-    return 0;
+    return true;
 }
 
-static int put_int32(QEMUFile *f, void *pv, size_t size,
-                     const VMStateField *field, JSONWriter *vmdesc)
+static bool save_int32(QEMUFile *f, void *pv, size_t size,
+                       const VMStateField *field, JSONWriter *vmdesc,
+                       Error **errp)
 {
     int32_t *v = pv;
     qemu_put_sbe32s(f, v);
-    return 0;
+    return true;
 }
 
 const VMStateInfo vmstate_info_int32 = {
     .name = "int32",
-    .get  = get_int32,
-    .put  = put_int32,
+    .load = load_int32,
+    .save = save_int32,
 };
 
 /* 32 bit int. See that the received value is the same than the one
    in the field */
 
-static int get_int32_equal(QEMUFile *f, void *pv, size_t size,
-                           const VMStateField *field)
+static bool load_int32_equal(QEMUFile *f, void *pv, size_t size,
+                             const VMStateField *field, Error **errp)
 {
+    ERRP_GUARD();
     int32_t *v = pv;
     int32_t v2;
     qemu_get_sbe32s(f, &v2);
 
     if (*v == v2) {
-        return 0;
+        return true;
     }
-    error_report("%" PRIx32 " != %" PRIx32, *v, v2);
-    return -EINVAL;
+
+    error_setg(errp, "%" PRIx32 " != %" PRIx32, *v, v2);
+    return false;
 }
 
 const VMStateInfo vmstate_info_int32_equal = {
     .name = "int32 equal",
-    .get  = get_int32_equal,
-    .put  = put_int32,
+    .load = load_int32_equal,
+    .save = save_int32,
 };
 
 /* 32 bit int. Check that the received value is non-negative
  * and less than or equal to the one in the field.
  */
 
-static int get_int32_le(QEMUFile *f, void *pv, size_t size,
-                        const VMStateField *field)
+static bool load_int32_le(QEMUFile *f, void *pv, size_t size,
+                          const VMStateField *field, Error **errp)
 {
     int32_t *cur = pv;
     int32_t loaded;
@@ -153,348 +159,373 @@ static int get_int32_le(QEMUFile *f, void *pv, size_t size,
 
     if (loaded >= 0 && loaded <= *cur) {
         *cur = loaded;
-        return 0;
+        return true;
     }
-    error_report("Invalid value %" PRId32
-                 " expecting positive value <= %" PRId32,
-                 loaded, *cur);
-    return -EINVAL;
+
+    error_setg(errp, "Invalid value %" PRId32
+               " expecting positive value <= %" PRId32,
+               loaded, *cur);
+    return false;
 }
 
 const VMStateInfo vmstate_info_int32_le = {
     .name = "int32 le",
-    .get  = get_int32_le,
-    .put  = put_int32,
+    .load = load_int32_le,
+    .save = save_int32,
 };
 
 /* 64 bit int */
 
-static int get_int64(QEMUFile *f, void *pv, size_t size,
-                     const VMStateField *field)
+static bool load_int64(QEMUFile *f, void *pv, size_t size,
+                       const VMStateField *field, Error **errp)
 {
     int64_t *v = pv;
     qemu_get_sbe64s(f, v);
-    return 0;
+    return true;
 }
 
-static int put_int64(QEMUFile *f, void *pv, size_t size,
-                     const VMStateField *field, JSONWriter *vmdesc)
+static bool save_int64(QEMUFile *f, void *pv, size_t size,
+                       const VMStateField *field, JSONWriter *vmdesc,
+                       Error **errp)
 {
     int64_t *v = pv;
     qemu_put_sbe64s(f, v);
-    return 0;
+    return true;
 }
 
 const VMStateInfo vmstate_info_int64 = {
     .name = "int64",
-    .get  = get_int64,
-    .put  = put_int64,
+    .load = load_int64,
+    .save = save_int64,
 };
 
 /* 8 bit unsigned int */
 
-static int get_uint8(QEMUFile *f, void *pv, size_t size,
-                     const VMStateField *field)
+static bool load_uint8(QEMUFile *f, void *pv, size_t size,
+                       const VMStateField *field, Error **errp)
 {
     uint8_t *v = pv;
     qemu_get_8s(f, v);
-    return 0;
+    return true;
 }
 
-static int put_uint8(QEMUFile *f, void *pv, size_t size,
-                     const VMStateField *field, JSONWriter *vmdesc)
+static bool save_uint8(QEMUFile *f, void *pv, size_t size,
+                       const VMStateField *field, JSONWriter *vmdesc,
+                       Error **errp)
 {
     uint8_t *v = pv;
     qemu_put_8s(f, v);
-    return 0;
+    return true;
 }
 
 const VMStateInfo vmstate_info_uint8 = {
     .name = "uint8",
-    .get  = get_uint8,
-    .put  = put_uint8,
+    .load = load_uint8,
+    .save = save_uint8,
 };
 
 /* 16 bit unsigned int */
 
-static int get_uint16(QEMUFile *f, void *pv, size_t size,
-                      const VMStateField *field)
+static bool load_uint16(QEMUFile *f, void *pv, size_t size,
+                        const VMStateField *field, Error **errp)
 {
     uint16_t *v = pv;
     qemu_get_be16s(f, v);
-    return 0;
+    return true;
 }
 
-static int put_uint16(QEMUFile *f, void *pv, size_t size,
-                      const VMStateField *field, JSONWriter *vmdesc)
+static bool save_uint16(QEMUFile *f, void *pv, size_t size,
+                        const VMStateField *field, JSONWriter *vmdesc,
+                        Error **errp)
 {
     uint16_t *v = pv;
     qemu_put_be16s(f, v);
-    return 0;
+    return true;
 }
 
 const VMStateInfo vmstate_info_uint16 = {
     .name = "uint16",
-    .get  = get_uint16,
-    .put  = put_uint16,
+    .load = load_uint16,
+    .save = save_uint16,
 };
 
 /* 32 bit unsigned int */
 
-static int get_uint32(QEMUFile *f, void *pv, size_t size,
-                      const VMStateField *field)
+static bool load_uint32(QEMUFile *f, void *pv, size_t size,
+                        const VMStateField *field, Error **errp)
 {
     uint32_t *v = pv;
     qemu_get_be32s(f, v);
-    return 0;
+    return true;
 }
 
-static int put_uint32(QEMUFile *f, void *pv, size_t size,
-                      const VMStateField *field, JSONWriter *vmdesc)
+static bool save_uint32(QEMUFile *f, void *pv, size_t size,
+                        const VMStateField *field, JSONWriter *vmdesc,
+                        Error **errp)
 {
     uint32_t *v = pv;
     qemu_put_be32s(f, v);
-    return 0;
+    return true;
 }
 
 const VMStateInfo vmstate_info_uint32 = {
     .name = "uint32",
-    .get  = get_uint32,
-    .put  = put_uint32,
+    .load = load_uint32,
+    .save = save_uint32,
 };
 
 /* 32 bit uint. See that the received value is the same than the one
    in the field */
 
-static int get_uint32_equal(QEMUFile *f, void *pv, size_t size,
-                            const VMStateField *field)
+static bool load_uint32_equal(QEMUFile *f, void *pv, size_t size,
+                              const VMStateField *field, Error **errp)
 {
+    ERRP_GUARD();
     uint32_t *v = pv;
     uint32_t v2;
     qemu_get_be32s(f, &v2);
 
     if (*v == v2) {
-        return 0;
+        return true;
     }
-    error_report("%" PRIx32 " != %" PRIx32, *v, v2);
-    return -EINVAL;
+
+    error_setg(errp, "%" PRIx32 " != %" PRIx32, *v, v2);
+    return false;
 }
 
 const VMStateInfo vmstate_info_uint32_equal = {
     .name = "uint32 equal",
-    .get  = get_uint32_equal,
-    .put  = put_uint32,
+    .load = load_uint32_equal,
+    .save = save_uint32,
 };
 
 /* 64 bit unsigned int */
 
-static int get_uint64(QEMUFile *f, void *pv, size_t size,
-                      const VMStateField *field)
+static bool load_uint64(QEMUFile *f, void *pv, size_t size,
+                        const VMStateField *field, Error **errp)
 {
     uint64_t *v = pv;
     qemu_get_be64s(f, v);
-    return 0;
+    return true;
 }
 
-static int put_uint64(QEMUFile *f, void *pv, size_t size,
-                      const VMStateField *field, JSONWriter *vmdesc)
+static bool save_uint64(QEMUFile *f, void *pv, size_t size,
+                        const VMStateField *field, JSONWriter *vmdesc,
+                        Error **errp)
 {
     uint64_t *v = pv;
     qemu_put_be64s(f, v);
-    return 0;
+    return true;
 }
 
 const VMStateInfo vmstate_info_uint64 = {
     .name = "uint64",
-    .get  = get_uint64,
-    .put  = put_uint64,
+    .load = load_uint64,
+    .save = save_uint64,
 };
 
 /* File descriptor communicated via SCM_RIGHTS */
 
-static int get_fd(QEMUFile *f, void *pv, size_t size,
-                  const VMStateField *field)
+static bool load_fd(QEMUFile *f, void *pv, size_t size,
+                    const VMStateField *field, Error **errp)
 {
     int32_t *v = pv;
 
     if (migrate_mode() == MIG_MODE_CPR_EXEC) {
         qemu_get_sbe32s(f, v);
-        return 0;
+        return true;
     }
 
-    return qemu_file_get_fd(f, v);
+    return qemu_file_get_fd(f, v) >= 0;
 }
 
-static int put_fd(QEMUFile *f, void *pv, size_t size,
-                  const VMStateField *field, JSONWriter *vmdesc)
+static bool save_fd(QEMUFile *f, void *pv, size_t size,
+                    const VMStateField *field, JSONWriter *vmdesc,
+                    Error **errp)
 {
     int32_t *v = pv;
+
     if (migrate_mode() == MIG_MODE_CPR_EXEC) {
         qemu_put_sbe32s(f, v);
-        return 0;
+        return true;
     }
-    return qemu_file_put_fd(f, *v);
+
+    return qemu_file_put_fd(f, *v) >= 0;
 }
 
 const VMStateInfo vmstate_info_fd = {
     .name = "fd",
-    .get  = get_fd,
-    .put  = put_fd,
+    .load = load_fd,
+    .save = save_fd,
 };
 
-static int get_nullptr(QEMUFile *f, void *pv, size_t size,
-                       const VMStateField *field)
+static bool load_nullptr(QEMUFile *f, void *pv, size_t size,
+                         const VMStateField *field, Error **errp)
 
 {
     if (qemu_get_byte(f) == VMS_NULLPTR_MARKER) {
-        return  0;
+        return true;
     }
-    error_report("vmstate: get_nullptr expected VMS_NULLPTR_MARKER");
-    return -EINVAL;
+
+    error_setg(errp, "vmstate: load_nullptr expected VMS_NULLPTR_MARKER");
+    return false;
 }
 
-static int put_nullptr(QEMUFile *f, void *pv, size_t size,
-                        const VMStateField *field, JSONWriter *vmdesc)
+static bool save_nullptr(QEMUFile *f, void *pv, size_t size,
+                         const VMStateField *field, JSONWriter *vmdesc,
+                         Error **errp)
 
 {
     if (pv == NULL) {
         qemu_put_byte(f, VMS_NULLPTR_MARKER);
-        return 0;
+        return true;
     }
-    error_report("vmstate: put_nullptr must be called with pv == NULL");
-    return -EINVAL;
+
+    error_setg(errp, "vmstate: save_nullptr must be called with pv == NULL");
+    return false;
 }
 
 const VMStateInfo vmstate_info_nullptr = {
     .name = "nullptr",
-    .get  = get_nullptr,
-    .put  = put_nullptr,
+    .load = load_nullptr,
+    .save = save_nullptr,
 };
 
 /* 64 bit unsigned int. See that the received value is the same than the one
    in the field */
 
-static int get_uint64_equal(QEMUFile *f, void *pv, size_t size,
-                            const VMStateField *field)
+static bool load_uint64_equal(QEMUFile *f, void *pv, size_t size,
+                              const VMStateField *field, Error **errp)
 {
+    ERRP_GUARD();
     uint64_t *v = pv;
     uint64_t v2;
+
     qemu_get_be64s(f, &v2);
 
     if (*v == v2) {
-        return 0;
+        return true;
     }
-    error_report("%" PRIx64 " != %" PRIx64, *v, v2);
-    return -EINVAL;
+
+    error_setg(errp, "%" PRIx64 " != %" PRIx64, *v, v2);
+    return false;
 }
 
 const VMStateInfo vmstate_info_uint64_equal = {
     .name = "int64 equal",
-    .get  = get_uint64_equal,
-    .put  = put_uint64,
+    .load = load_uint64_equal,
+    .save = save_uint64,
 };
 
 /* 8 bit int. See that the received value is the same than the one
    in the field */
 
-static int get_uint8_equal(QEMUFile *f, void *pv, size_t size,
-                           const VMStateField *field)
+static bool load_uint8_equal(QEMUFile *f, void *pv, size_t size,
+                             const VMStateField *field, Error **errp)
 {
+    ERRP_GUARD();
     uint8_t *v = pv;
     uint8_t v2;
+
     qemu_get_8s(f, &v2);
 
     if (*v == v2) {
-        return 0;
+        return true;
     }
-    error_report("%x != %x", *v, v2);
-    return -EINVAL;
+
+    error_setg(errp, "%x != %x", *v, v2);
+    return false;
 }
 
 const VMStateInfo vmstate_info_uint8_equal = {
     .name = "uint8 equal",
-    .get  = get_uint8_equal,
-    .put  = put_uint8,
+    .load = load_uint8_equal,
+    .save = save_uint8,
 };
 
 /* 16 bit unsigned int int. See that the received value is the same than the one
    in the field */
 
-static int get_uint16_equal(QEMUFile *f, void *pv, size_t size,
-                            const VMStateField *field)
+static bool load_uint16_equal(QEMUFile *f, void *pv, size_t size,
+                              const VMStateField *field, Error **errp)
 {
+    ERRP_GUARD();
     uint16_t *v = pv;
     uint16_t v2;
+
     qemu_get_be16s(f, &v2);
 
     if (*v == v2) {
-        return 0;
+        return true;
     }
-    error_report("%x != %x", *v, v2);
-    return -EINVAL;
+
+    error_setg(errp, "%x != %x", *v, v2);
+    return false;
 }
 
 const VMStateInfo vmstate_info_uint16_equal = {
     .name = "uint16 equal",
-    .get  = get_uint16_equal,
-    .put  = put_uint16,
+    .load = load_uint16_equal,
+    .save = save_uint16,
 };
 
 /* CPU_DoubleU type */
 
-static int get_cpudouble(QEMUFile *f, void *pv, size_t size,
-                         const VMStateField *field)
+static bool load_cpudouble(QEMUFile *f, void *pv, size_t size,
+                           const VMStateField *field, Error **errp)
 {
     CPU_DoubleU *v = pv;
     qemu_get_be32s(f, &v->l.upper);
     qemu_get_be32s(f, &v->l.lower);
-    return 0;
+    return true;
 }
 
-static int put_cpudouble(QEMUFile *f, void *pv, size_t size,
-                         const VMStateField *field, JSONWriter *vmdesc)
+static bool save_cpudouble(QEMUFile *f, void *pv, size_t size,
+                           const VMStateField *field, JSONWriter *vmdesc,
+                           Error **errp)
 {
     CPU_DoubleU *v = pv;
     qemu_put_be32s(f, &v->l.upper);
     qemu_put_be32s(f, &v->l.lower);
-    return 0;
+    return true;
 }
 
 const VMStateInfo vmstate_info_cpudouble = {
     .name = "CPU_Double_U",
-    .get  = get_cpudouble,
-    .put  = put_cpudouble,
+    .load = load_cpudouble,
+    .save = save_cpudouble,
 };
 
 /* uint8_t buffers */
 
-static int get_buffer(QEMUFile *f, void *pv, size_t size,
-                      const VMStateField *field)
+static bool load_buffer(QEMUFile *f, void *pv, size_t size,
+                        const VMStateField *field, Error **errp)
 {
     uint8_t *v = pv;
     qemu_get_buffer(f, v, size);
-    return 0;
+    return true;
 }
 
-static int put_buffer(QEMUFile *f, void *pv, size_t size,
-                      const VMStateField *field, JSONWriter *vmdesc)
+static bool save_buffer(QEMUFile *f, void *pv, size_t size,
+                        const VMStateField *field, JSONWriter *vmdesc,
+                        Error **errp)
 {
     uint8_t *v = pv;
     qemu_put_buffer(f, v, size);
-    return 0;
+    return true;
 }
 
 const VMStateInfo vmstate_info_buffer = {
     .name = "buffer",
-    .get  = get_buffer,
-    .put  = put_buffer,
+    .load = load_buffer,
+    .save = save_buffer,
 };
 
 /* unused buffers: space that was used for some fields that are
    not useful anymore */
 
-static int get_unused_buffer(QEMUFile *f, void *pv, size_t size,
-                             const VMStateField *field)
+static bool load_unused_buffer(QEMUFile *f, void *pv, size_t size,
+                               const VMStateField *field, Error **errp)
 {
     uint8_t buf[1024];
     int block_len;
@@ -504,11 +535,13 @@ static int get_unused_buffer(QEMUFile *f, void *pv, size_t size,
         size -= block_len;
         qemu_get_buffer(f, buf, block_len);
     }
-   return 0;
+
+    return true;
 }
 
-static int put_unused_buffer(QEMUFile *f, void *pv, size_t size,
-                             const VMStateField *field, JSONWriter *vmdesc)
+static bool save_unused_buffer(QEMUFile *f, void *pv, size_t size,
+                               const VMStateField *field, JSONWriter *vmdesc,
+                               Error **errp)
 {
     static const uint8_t buf[1024];
     int block_len;
@@ -519,13 +552,13 @@ static int put_unused_buffer(QEMUFile *f, void *pv, size_t size,
         qemu_put_buffer(f, buf, block_len);
     }
 
-    return 0;
+    return true;
 }
 
 const VMStateInfo vmstate_info_unused_buffer = {
     .name = "unused_buffer",
-    .get  = get_unused_buffer,
-    .put  = put_unused_buffer,
+    .load = load_unused_buffer,
+    .save = save_unused_buffer,
 };
 
 /* vmstate_info_tmp, see VMSTATE_WITH_TMP, the idea is that we allocate
@@ -534,48 +567,34 @@ const VMStateInfo vmstate_info_unused_buffer = {
  * in fields that don't really exist in the parent but need to be in the
  * stream.
  */
-static int get_tmp(QEMUFile *f, void *pv, size_t size,
-                   const VMStateField *field)
+static bool load_tmp(QEMUFile *f, void *pv, size_t size,
+                     const VMStateField *field, Error **errp)
 {
-    int ret;
-    Error *local_err = NULL;
     const VMStateDescription *vmsd = field->vmsd;
     int version_id = field->version_id;
-    void *tmp = g_malloc(size);
+    g_autofree void *tmp = g_malloc(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, &local_err);
-    if (ret < 0) {
-        error_report_err(local_err);
-    }
-    g_free(tmp);
-    return ret;
+    return vmstate_load_vmsd(f, vmsd, tmp, version_id, errp);
 }
 
-static int put_tmp(QEMUFile *f, void *pv, size_t size,
-                   const VMStateField *field, JSONWriter *vmdesc)
+static bool save_tmp(QEMUFile *f, void *pv, size_t size,
+                     const VMStateField *field, JSONWriter *vmdesc,
+                     Error **errp)
 {
     const VMStateDescription *vmsd = field->vmsd;
-    void *tmp = g_malloc(size);
-    int ret;
-    Error *local_err = NULL;
+    g_autofree void *tmp = g_malloc(size);
 
     /* Writes the parent field which is at the start of the tmp */
     *(void **)tmp = pv;
-    ret = vmstate_save_state(f, vmsd, tmp, vmdesc, &local_err);
-    if (ret) {
-        error_report_err(local_err);
-    }
-    g_free(tmp);
-
-    return ret;
+    return vmstate_save_vmsd(f, vmsd, tmp, vmdesc, errp);
 }
 
 const VMStateInfo vmstate_info_tmp = {
     .name = "tmp",
-    .get = get_tmp,
-    .put = put_tmp,
+    .load = load_tmp,
+    .save = save_tmp,
 };
 
 /* bitmaps (as defined by bitmap.h). Note that size here is the size
@@ -585,11 +604,12 @@ const VMStateInfo vmstate_info_tmp = {
  */
 /* This is the number of 64 bit words sent over the wire */
 #define BITS_TO_U64S(nr) DIV_ROUND_UP(nr, 64)
-static int get_bitmap(QEMUFile *f, void *pv, size_t size,
-                      const VMStateField *field)
+static bool load_bitmap(QEMUFile *f, void *pv, size_t size,
+                        const VMStateField *field, Error **errp)
 {
     unsigned long *bmp = pv;
     int i, idx = 0;
+
     for (i = 0; i < BITS_TO_U64S(size); i++) {
         uint64_t w = qemu_get_be64(f);
         bmp[idx++] = w;
@@ -597,14 +617,17 @@ static int get_bitmap(QEMUFile *f, void *pv, size_t size,
             bmp[idx++] = w >> 32;
         }
     }
-    return 0;
+
+    return true;
 }
 
-static int put_bitmap(QEMUFile *f, void *pv, size_t size,
-                      const VMStateField *field, JSONWriter *vmdesc)
+static bool save_bitmap(QEMUFile *f, void *pv, size_t size,
+                        const VMStateField *field, JSONWriter *vmdesc,
+                        Error **errp)
 {
     unsigned long *bmp = pv;
     int i, idx = 0;
+
     for (i = 0; i < BITS_TO_U64S(size); i++) {
         uint64_t w = bmp[idx++];
         if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
@@ -613,23 +636,21 @@ static int put_bitmap(QEMUFile *f, void *pv, size_t size,
         qemu_put_be64(f, w);
     }
 
-    return 0;
+    return true;
 }
 
 const VMStateInfo vmstate_info_bitmap = {
     .name = "bitmap",
-    .get = get_bitmap,
-    .put = put_bitmap,
+    .load = load_bitmap,
+    .save = save_bitmap,
 };
 
 /* get for QTAILQ
  * meta data about the QTAILQ is encoded in a VMStateField structure
  */
-static int get_qtailq(QEMUFile *f, void *pv, size_t unused_size,
-                      const VMStateField *field)
+static bool load_qtailq(QEMUFile *f, void *pv, size_t unused_size,
+                        const VMStateField *field, Error **errp)
 {
-    int ret = 0;
-    Error *local_err = NULL;
     const VMStateDescription *vmsd = field->vmsd;
     /* size of a QTAILQ element */
     size_t size = field->size;
@@ -638,80 +659,76 @@ static int get_qtailq(QEMUFile *f, void *pv, size_t unused_size,
     int version_id = field->version_id;
     void *elm;
 
-    trace_get_qtailq(vmsd->name, version_id);
+    trace_load_qtailq(vmsd->name, version_id);
     if (version_id > vmsd->version_id) {
-        error_report("%s %s",  vmsd->name, "too new");
-        trace_get_qtailq_end(vmsd->name, "too new", -EINVAL);
-
-        return -EINVAL;
+        error_setg(errp, "%s %s",  vmsd->name, "too new");
+        return false;
     }
     if (version_id < vmsd->minimum_version_id) {
-        error_report("%s %s",  vmsd->name, "too old");
-        trace_get_qtailq_end(vmsd->name, "too old", -EINVAL);
-        return -EINVAL;
+        error_setg(errp, "%s %s",  vmsd->name, "too old");
+        return false;
     }
 
     while (qemu_get_byte(f)) {
         elm = g_malloc(size);
-        ret = vmstate_load_state(f, vmsd, elm, version_id, &local_err);
-        if (ret) {
-            error_report_err(local_err);
-            return ret;
+        if (!vmstate_load_vmsd(f, vmsd, elm, version_id, errp)) {
+            g_free(elm);
+            return false;
         }
         QTAILQ_RAW_INSERT_TAIL(pv, elm, entry_offset);
     }
 
-    trace_get_qtailq_end(vmsd->name, "end", ret);
-    return ret;
+    trace_load_qtailq_end(vmsd->name);
+    return true;
 }
 
-/* put for QTAILQ */
-static int put_qtailq(QEMUFile *f, void *pv, size_t unused_size,
-                      const VMStateField *field, JSONWriter *vmdesc)
+/* save for QTAILQ */
+static bool save_qtailq(QEMUFile *f, void *pv, size_t unused_size,
+                        const VMStateField *field, JSONWriter *vmdesc,
+                        Error **errp)
 {
     const VMStateDescription *vmsd = field->vmsd;
     /* offset of the QTAILQ entry in a QTAILQ element*/
     size_t entry_offset = field->start;
     void *elm;
-    int ret;
-    Error *local_err = NULL;
 
-    trace_put_qtailq(vmsd->name, vmsd->version_id);
+    trace_save_qtailq(vmsd->name, vmsd->version_id);
 
     QTAILQ_RAW_FOREACH(elm, pv, entry_offset) {
         qemu_put_byte(f, true);
-        ret = vmstate_save_state(f, vmsd, elm, vmdesc, &local_err);
-        if (ret) {
-            error_report_err(local_err);
-            return ret;
+        if (!vmstate_save_vmsd(f, vmsd, elm, vmdesc, errp)) {
+            return false;
         }
     }
     qemu_put_byte(f, false);
 
-    trace_put_qtailq_end(vmsd->name, "end");
+    trace_save_qtailq_end(vmsd->name);
 
-    return 0;
+    return true;
 }
 const VMStateInfo vmstate_info_qtailq = {
     .name = "qtailq",
-    .get  = get_qtailq,
-    .put  = put_qtailq,
+    .load = load_qtailq,
+    .save = save_qtailq,
 };
 
-struct put_gtree_data {
+struct save_gtree_data {
     QEMUFile *f;
     const VMStateDescription *key_vmsd;
     const VMStateDescription *val_vmsd;
     JSONWriter *vmdesc;
-    int ret;
+    Error **errp;
+    bool failed;
 };
 
-static gboolean put_gtree_elem(gpointer key, gpointer value, gpointer data)
+/*
+ * save_gtree_elem - func for g_tree_foreach, return true to stop
+ * iteration.
+ */
+static gboolean save_gtree_elem(gpointer key, gpointer value, gpointer data)
 {
-    struct put_gtree_data *capsule = (struct put_gtree_data *)data;
+    struct save_gtree_data *capsule = (struct save_gtree_data *)data;
     QEMUFile *f = capsule->f;
-    int ret;
-    Error *local_err = NULL;
 
     qemu_put_byte(f, true);
 
@@ -719,58 +736,56 @@ static gboolean put_gtree_elem(gpointer key, gpointer value, gpointer data)
     if (!capsule->key_vmsd) {
         qemu_put_be64(f, (uint64_t)(uintptr_t)(key)); /* direct key */
     } else {
-        ret = vmstate_save_state(f, capsule->key_vmsd, key, capsule->vmdesc,
-                                 &local_err);
-        if (ret) {
-            error_report_err(local_err);
-            capsule->ret = ret;
+        if (!vmstate_save_vmsd(f, capsule->key_vmsd, key, capsule->vmdesc,
+                               capsule->errp)) {
+            capsule->failed = true;
             return true;
         }
     }
 
     /* put the data */
-    ret = vmstate_save_state(f, capsule->val_vmsd, value, capsule->vmdesc,
-                             &local_err);
-    if (ret) {
-        error_report_err(local_err);
-        capsule->ret = ret;
+    if (!vmstate_save_vmsd(f, capsule->val_vmsd, value, capsule->vmdesc,
+                           capsule->errp)) {
+        capsule->failed = true;
         return true;
     }
     return false;
 }
 
-static int put_gtree(QEMUFile *f, void *pv, size_t unused_size,
-                     const VMStateField *field, JSONWriter *vmdesc)
+static bool save_gtree(QEMUFile *f, void *pv, size_t unused_size,
+                       const VMStateField *field, JSONWriter *vmdesc,
+                       Error **errp)
 {
     bool direct_key = (!field->start);
     const VMStateDescription *key_vmsd = direct_key ? NULL : &field->vmsd[1];
     const VMStateDescription *val_vmsd = &field->vmsd[0];
     const char *key_vmsd_name = direct_key ? "direct" : key_vmsd->name;
-    struct put_gtree_data capsule = {
+    struct save_gtree_data capsule = {
         .f = f,
         .key_vmsd = key_vmsd,
         .val_vmsd = val_vmsd,
         .vmdesc = vmdesc,
-        .ret = 0};
+        .errp = errp,
+        .failed = false};
     GTree **pval = pv;
     GTree *tree = *pval;
     uint32_t nnodes = g_tree_nnodes(tree);
-    int ret;
 
-    trace_put_gtree(field->name, key_vmsd_name, val_vmsd->name, nnodes);
+    trace_save_gtree(field->name, key_vmsd_name, val_vmsd->name, nnodes);
     qemu_put_be32(f, nnodes);
-    g_tree_foreach(tree, put_gtree_elem, (gpointer)&capsule);
+    g_tree_foreach(tree, save_gtree_elem, (gpointer)&capsule);
     qemu_put_byte(f, false);
-    ret = capsule.ret;
-    if (ret) {
-        error_report("%s : failed to save gtree (%d)", field->name, ret);
+    if (capsule.failed) {
+        trace_save_gtree_end(field->name, key_vmsd_name, val_vmsd->name);
+        return false;
     }
-    trace_put_gtree_end(field->name, key_vmsd_name, val_vmsd->name, ret);
-    return ret;
+
+    trace_save_gtree_end(field->name, key_vmsd_name, val_vmsd->name);
+    return true;
 }
 
-static int get_gtree(QEMUFile *f, void *pv, size_t unused_size,
-                     const VMStateField *field)
+static bool load_gtree(QEMUFile *f, void *pv, size_t unused_size,
+                       const VMStateField *field, Error **errp)
 {
     bool direct_key = (!field->start);
     const VMStateDescription *key_vmsd = direct_key ? NULL : &field->vmsd[1];
@@ -783,107 +798,97 @@ static int get_gtree(QEMUFile *f, void *pv, size_t unused_size,
     GTree **pval = pv;
     GTree *tree = *pval;
     void *key, *val;
-    int ret = 0;
-    Error *local_err = NULL;
 
     /* in case of direct key, the key vmsd can be {}, ie. check fields */
     if (!direct_key && version_id > key_vmsd->version_id) {
-        error_report("%s %s",  key_vmsd->name, "too new");
-        return -EINVAL;
+        error_setg(errp, "%s %s",  key_vmsd->name, "too new");
+        return false;
     }
     if (!direct_key && version_id < key_vmsd->minimum_version_id) {
-        error_report("%s %s",  key_vmsd->name, "too old");
-        return -EINVAL;
+        error_setg(errp, "%s %s",  key_vmsd->name, "too old");
+        return false;
     }
     if (version_id > val_vmsd->version_id) {
-        error_report("%s %s",  val_vmsd->name, "too new");
-        return -EINVAL;
+        error_setg(errp, "%s %s",  val_vmsd->name, "too new");
+        return false;
     }
     if (version_id < val_vmsd->minimum_version_id) {
-        error_report("%s %s",  val_vmsd->name, "too old");
-        return -EINVAL;
+        error_setg(errp, "%s %s",  val_vmsd->name, "too old");
+        return false;
     }
 
     nnodes = qemu_get_be32(f);
-    trace_get_gtree(field->name, key_vmsd_name, val_vmsd->name, nnodes);
+    trace_load_gtree(field->name, key_vmsd_name, val_vmsd->name, nnodes);
 
     while (qemu_get_byte(f)) {
         if ((++count) > nnodes) {
-            ret = -EINVAL;
             break;
         }
         if (direct_key) {
             key = (void *)(uintptr_t)qemu_get_be64(f);
         } else {
             key = g_malloc0(key_size);
-            ret = vmstate_load_state(f, key_vmsd, key, version_id, &local_err);
-            if (ret) {
-                error_report_err(local_err);
+            if (!vmstate_load_vmsd(f, key_vmsd, key, version_id, errp)) {
                 goto key_error;
             }
         }
         val = g_malloc0(val_size);
-        ret = vmstate_load_state(f, val_vmsd, val, version_id, &local_err);
-        if (ret) {
-            error_report_err(local_err);
+        if (!vmstate_load_vmsd(f, val_vmsd, val, version_id, errp)) {
             goto val_error;
         }
         g_tree_insert(tree, key, val);
     }
     if (count != nnodes) {
-        error_report("%s inconsistent stream when loading the gtree",
-                     field->name);
-        return -EINVAL;
+        error_setg(errp, "%s inconsistent stream when loading the gtree",
+                   field->name);
+        return false;
     }
-    trace_get_gtree_end(field->name, key_vmsd_name, val_vmsd->name, ret);
-    return ret;
+
+    trace_load_gtree_end(field->name, key_vmsd_name, val_vmsd->name);
+    return true;
+
 val_error:
     g_free(val);
+
 key_error:
     if (!direct_key) {
         g_free(key);
     }
-    trace_get_gtree_end(field->name, key_vmsd_name, val_vmsd->name, ret);
-    return ret;
+    return false;
 }
 
 
 const VMStateInfo vmstate_info_gtree = {
     .name = "gtree",
-    .get  = get_gtree,
-    .put  = put_gtree,
+    .load = load_gtree,
+    .save = save_gtree,
 };
 
-static int put_qlist(QEMUFile *f, void *pv, size_t unused_size,
-                     const VMStateField *field, JSONWriter *vmdesc)
+static bool save_qlist(QEMUFile *f, void *pv, size_t unused_size,
+                       const VMStateField *field, JSONWriter *vmdesc,
+                       Error **errp)
 {
     const VMStateDescription *vmsd = field->vmsd;
     /* offset of the QTAILQ entry in a QTAILQ element*/
     size_t entry_offset = field->start;
     void *elm;
-    int ret;
-    Error *local_err = NULL;
 
-    trace_put_qlist(field->name, vmsd->name, vmsd->version_id);
+    trace_save_qlist(field->name, vmsd->name, vmsd->version_id);
     QLIST_RAW_FOREACH(elm, pv, entry_offset) {
         qemu_put_byte(f, true);
-        ret = vmstate_save_state(f, vmsd, elm, vmdesc, &local_err);
-        if (ret) {
-            error_report_err(local_err);
-            return ret;
+        if (!vmstate_save_vmsd(f, vmsd, elm, vmdesc, errp)) {
+            return false;
         }
     }
     qemu_put_byte(f, false);
-    trace_put_qlist_end(field->name, vmsd->name);
+    trace_save_qlist_end(field->name, vmsd->name);
 
-    return 0;
+    return true;
 }
 
-static int get_qlist(QEMUFile *f, void *pv, size_t unused_size,
-                     const VMStateField *field)
+static bool load_qlist(QEMUFile *f, void *pv, size_t unused_size,
+                       const VMStateField *field, Error **errp)
 {
-    int ret = 0;
-    Error *local_err = NULL;
     const VMStateDescription *vmsd = field->vmsd;
     /* size of a QLIST element */
     size_t size = field->size;
@@ -892,23 +897,21 @@ static int get_qlist(QEMUFile *f, void *pv, size_t unused_size,
     int version_id = field->version_id;
     void *elm, *prev = NULL;
 
-    trace_get_qlist(field->name, vmsd->name, vmsd->version_id);
+    trace_load_qlist(field->name, vmsd->name, vmsd->version_id);
     if (version_id > vmsd->version_id) {
-        error_report("%s %s",  vmsd->name, "too new");
-        return -EINVAL;
+        error_setg(errp, "%s %s",  vmsd->name, "too new");
+        return false;
     }
     if (version_id < vmsd->minimum_version_id) {
-        error_report("%s %s",  vmsd->name, "too old");
-        return -EINVAL;
+        error_setg(errp, "%s %s",  vmsd->name, "too old");
+        return false;
     }
 
     while (qemu_get_byte(f)) {
         elm = g_malloc(size);
-        ret = vmstate_load_state(f, vmsd, elm, version_id, &local_err);
-        if (ret) {
-            error_report_err(local_err);
+        if (!vmstate_load_vmsd(f, vmsd, elm, version_id, errp)) {
             g_free(elm);
-            return ret;
+            return false;
         }
         if (!prev) {
             QLIST_RAW_INSERT_HEAD(pv, elm, entry_offset);
@@ -917,13 +920,13 @@ static int get_qlist(QEMUFile *f, void *pv, size_t unused_size,
         }
         prev = elm;
     }
-    trace_get_qlist_end(field->name, vmsd->name);
+    trace_load_qlist_end(field->name, vmsd->name);
 
-    return ret;
+    return true;
 }
 
 const VMStateInfo vmstate_info_qlist = {
     .name = "qlist",
-    .get  = get_qlist,
-    .put  = put_qlist,
+    .load = load_qlist,
+    .save = save_qlist,
 };
-- 
2.52.0



^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: [PATCH v3 16/18] hw/s390x/css: drop use of .err_hint for vmstate
  2026-03-04 21:23 ` [PATCH v3 16/18] hw/s390x/css: drop use of .err_hint for vmstate Vladimir Sementsov-Ogievskiy
@ 2026-03-05  2:29   ` Eric Farman
  2026-03-05 17:14   ` Peter Xu
  1 sibling, 0 replies; 33+ messages in thread
From: Eric Farman @ 2026-03-05  2:29 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy, peterx
  Cc: farosas, qemu-devel, Halil Pasic, Christian Borntraeger,
	Farhan Ali, Thomas Huth, Richard Henderson, Ilya Leoshkevich,
	David Hildenbrand, Matthew Rosato, open list:S390 channel subs...

On Thu, 2026-03-05 at 00:23 +0300, Vladimir Sementsov-Ogievskiy wrote:
> That's the only usage through the whole base. Doesn't
> worth keeping the whole complexity. And 2.7 machines were
> long ago.
> 
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
> ---
>  hw/s390x/css.c | 15 ++++++++-------
>  1 file changed, 8 insertions(+), 7 deletions(-)

Agreed that the two "Bug!" hints aren't helpful, and the devno hint is probably offering more
confusion than anything else.

Reviewed-by: Eric Farman <farman@linux.ibm.com>

> 
> diff --git a/hw/s390x/css.c b/hw/s390x/css.c
> index 04ce3178a0b..df5f0bc27f1 100644
> --- a/hw/s390x/css.c
> +++ b/hw/s390x/css.c
> @@ -192,10 +192,6 @@ static const VMStateDescription vmstate_schdev_orb = {
>  static int subch_dev_post_load(void *opaque, int version_id);
>  static int subch_dev_pre_save(void *opaque);
>  
> -const char err_hint_devno[] = "Devno mismatch, tried to load wrong section!"
> -    " Likely reason: some sequences of plug and unplug  can break"
> -    " migration for machine versions prior to  2.7 (known design flaw).";
> -
>  const VMStateDescription vmstate_subch_dev = {
>      .name = "s390_subch_dev",
>      .version_id = 1,
> @@ -203,10 +199,15 @@ const VMStateDescription vmstate_subch_dev = {
>      .post_load = subch_dev_post_load,
>      .pre_save = subch_dev_pre_save,
>      .fields = (const VMStateField[]) {
> -        VMSTATE_UINT8_EQUAL(cssid, SubchDev, "Bug!"),
> -        VMSTATE_UINT8_EQUAL(ssid, SubchDev, "Bug!"),
> +        VMSTATE_UINT8_EQUAL(cssid, SubchDev, NULL),
> +        VMSTATE_UINT8_EQUAL(ssid, SubchDev, NULL),
>          VMSTATE_UINT16(migrated_schid, SubchDev),
> -        VMSTATE_UINT16_EQUAL(devno, SubchDev, err_hint_devno),
> +        /*
> +         * If devno mismatch on target, it may be due to some
> +         * sequences of plug and unplug breaks migration for
> +         * machine versions prior to 2.7 (known design flaw).
> +         */
> +        VMSTATE_UINT16_EQUAL(devno, SubchDev, NULL),
>          VMSTATE_BOOL(thinint_active, SubchDev),
>          VMSTATE_STRUCT(curr_status, SubchDev, 0, vmstate_schib, SCHIB),
>          VMSTATE_UINT8_ARRAY(sense_data, SubchDev, 32),


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v3 17/18] migration: drop VMStateField.err_hint
  2026-03-04 21:23 ` [PATCH v3 17/18] migration: drop VMStateField.err_hint Vladimir Sementsov-Ogievskiy
@ 2026-03-05  2:39   ` Eric Farman
  2026-03-05  5:18   ` Akihiko Odaki
  2026-03-05 17:14   ` Peter Xu
  2 siblings, 0 replies; 33+ messages in thread
From: Eric Farman @ 2026-03-05  2:39 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy, peterx
  Cc: farosas, qemu-devel, John Snow, Kevin Wolf, Hanna Reitz,
	Gerd Hoffmann, Michael S. Tsirkin, Alex Bennée,
	Akihiko Odaki, Dmitry Osipenko, Dmitry Fleytman, Marcel Apfelbaum,
	Paolo Bonzini, Richard Henderson, Eduardo Habkost,
	Mark Cave-Ayland, Gautam Menghani, Glenn Miles, Nicholas Piggin,
	Harsh Prateek Bora, Stefan Weil, Halil Pasic,
	Christian Borntraeger, Farhan Ali, Matthew Rosato,
	Ilya Leoshkevich, David Hildenbrand, Thomas Huth, Chinmay Rath,
	open list:Floppy, open list:XIVE, open list:S390 channel subs...

On Thu, 2026-03-05 at 00:23 +0300, Vladimir Sementsov-Ogievskiy wrote:
> The field is unused, all users of VMSTATE_*_EQUAL pass _err_hint=NULL.
> 
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
> ---
>  hw/block/fdc.c              |  2 +-
>  hw/display/qxl.c            |  4 ++--
>  hw/display/vga.c            |  2 +-
>  hw/display/virtio-gpu.c     |  2 +-
>  hw/display/vmware_vga.c     |  2 +-
>  hw/i386/vmmouse.c           |  2 +-
>  hw/ide/ahci.c               |  2 +-
>  hw/intc/openpic.c           |  2 +-
>  hw/intc/spapr_xive.c        |  2 +-
>  hw/intc/xics.c              |  2 +-
>  hw/intc/xive.c              |  2 +-
>  hw/nvram/eeprom93xx.c       |  2 +-
>  hw/pci/pci.c                |  2 +-
>  hw/pci/pcie_aer.c           |  2 +-
>  hw/ppc/spapr_iommu.c        |  2 +-
>  hw/ppc/spapr_pci.c          |  4 ++--
>  hw/ppc/spapr_vio.c          |  4 ++--
>  hw/s390x/css.c              |  6 +++---
>  hw/usb/hcd-uhci.c           |  2 +-
>  include/migration/vmstate.h | 36 +++++++++++++++++-------------------
>  migration/vmstate-types.c   | 15 ---------------
>  target/ppc/machine.c        |  6 +++---
>  22 files changed, 44 insertions(+), 61 deletions(-)

Acked-by: Eric Farman <farman@linux.ibm.com>  # s390


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v3 17/18] migration: drop VMStateField.err_hint
  2026-03-04 21:23 ` [PATCH v3 17/18] migration: drop VMStateField.err_hint Vladimir Sementsov-Ogievskiy
  2026-03-05  2:39   ` Eric Farman
@ 2026-03-05  5:18   ` Akihiko Odaki
  2026-03-05 17:14   ` Peter Xu
  2 siblings, 0 replies; 33+ messages in thread
From: Akihiko Odaki @ 2026-03-05  5:18 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy, peterx
  Cc: farosas, qemu-devel, John Snow, Kevin Wolf, Hanna Reitz,
	Gerd Hoffmann, Michael S. Tsirkin, Alex Bennée,
	Dmitry Osipenko, Dmitry Fleytman, Marcel Apfelbaum, Paolo Bonzini,
	Richard Henderson, Eduardo Habkost, Mark Cave-Ayland,
	Gautam Menghani, Glenn Miles, Nicholas Piggin, Harsh Prateek Bora,
	Stefan Weil, Halil Pasic, Christian Borntraeger, Eric Farman,
	Farhan Ali, Matthew Rosato, Ilya Leoshkevich, David Hildenbrand,
	Thomas Huth, Chinmay Rath, open list:Floppy, open list:XIVE,
	open list:S390 channel subs...

On 2026/03/05 6:23, Vladimir Sementsov-Ogievskiy wrote:
> The field is unused, all users of VMSTATE_*_EQUAL pass _err_hint=NULL.
> 
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>

Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v3 05/18] migration: vmstate_save/load_state(): refactor tracing errors
  2026-03-04 21:22 ` [PATCH v3 05/18] migration: vmstate_save/load_state(): refactor tracing errors Vladimir Sementsov-Ogievskiy
@ 2026-03-05 16:59   ` Peter Xu
  0 siblings, 0 replies; 33+ messages in thread
From: Peter Xu @ 2026-03-05 16:59 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy; +Cc: farosas, qemu-devel

On Thu, Mar 05, 2026 at 12:22:49AM +0300, Vladimir Sementsov-Ogievskiy wrote:
> To simplify further changes (convertion to bool+errp APIs),
> let's rework some error paths:
> 
> - get rid of int ret in traces, as we are moving to bool+errp APIs
> - split traces to _fail / _success (seems better than add boolean
>   result to the message).
> - prefer short error paths (return immediately on error)
> - around trace_vmstate_load_field_error(), do not call
>   qemu_file_set_error(), if the erroc comes from qemu_file_get_error()
> 
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>

Reviewed-by: Peter Xu <peterx@redhat.com>

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v3 13/18] migration: introduce vmstate_load_vmsd() and vmstate_save_vmsd()
  2026-03-04 21:22 ` [PATCH v3 13/18] migration: introduce vmstate_load_vmsd() and vmstate_save_vmsd() Vladimir Sementsov-Ogievskiy
@ 2026-03-05 17:01   ` Peter Xu
  0 siblings, 0 replies; 33+ messages in thread
From: Peter Xu @ 2026-03-05 17:01 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy; +Cc: farosas, qemu-devel

On Thu, Mar 05, 2026 at 12:22:57AM +0300, Vladimir Sementsov-Ogievskiy wrote:
> Introduce new APIs, returning bool.
> The analysis
> https://lore.kernel.org/qemu-devel/aQDdRn8t0B8oE3gf@x1.local/
> shows, that vmstate_load_state() return value actually only
> used to check for success, specific errno values doesn't make
> sense.
> 
> With this commit we introduce new functions with modern bool
> interface, and in following commits we'll update the
> code base to use them, starting from migration/ code, and
> finally we will remove old vmstate_load_state() and
> vmstate_save_state().
> 
> This patch reworks existing functions to new one, so that
> old interfaces are simple wrappers, which will be easy to
> remove later.
> 
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>

Reviewed-by: Peter Xu <peterx@redhat.com>

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v3 16/18] hw/s390x/css: drop use of .err_hint for vmstate
  2026-03-04 21:23 ` [PATCH v3 16/18] hw/s390x/css: drop use of .err_hint for vmstate Vladimir Sementsov-Ogievskiy
  2026-03-05  2:29   ` Eric Farman
@ 2026-03-05 17:14   ` Peter Xu
  1 sibling, 0 replies; 33+ messages in thread
From: Peter Xu @ 2026-03-05 17:14 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: farosas, qemu-devel, Halil Pasic, Christian Borntraeger,
	Eric Farman, Farhan Ali, Thomas Huth, Richard Henderson,
	Ilya Leoshkevich, David Hildenbrand, Matthew Rosato,
	open list:S390 channel subs...

On Thu, Mar 05, 2026 at 12:23:00AM +0300, Vladimir Sementsov-Ogievskiy wrote:
> That's the only usage through the whole base. Doesn't
> worth keeping the whole complexity. And 2.7 machines were
> long ago.
> 
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>

Reviewed-by: Peter Xu <peterx@redhat.com>

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v3 17/18] migration: drop VMStateField.err_hint
  2026-03-04 21:23 ` [PATCH v3 17/18] migration: drop VMStateField.err_hint Vladimir Sementsov-Ogievskiy
  2026-03-05  2:39   ` Eric Farman
  2026-03-05  5:18   ` Akihiko Odaki
@ 2026-03-05 17:14   ` Peter Xu
  2 siblings, 0 replies; 33+ messages in thread
From: Peter Xu @ 2026-03-05 17:14 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: farosas, qemu-devel, John Snow, Kevin Wolf, Hanna Reitz,
	Gerd Hoffmann, Michael S. Tsirkin, Alex Bennée,
	Akihiko Odaki, Dmitry Osipenko, Dmitry Fleytman, Marcel Apfelbaum,
	Paolo Bonzini, Richard Henderson, Eduardo Habkost,
	Mark Cave-Ayland, Gautam Menghani, Glenn Miles, Nicholas Piggin,
	Harsh Prateek Bora, Stefan Weil, Halil Pasic,
	Christian Borntraeger, Eric Farman, Farhan Ali, Matthew Rosato,
	Ilya Leoshkevich, David Hildenbrand, Thomas Huth, Chinmay Rath,
	open list:Floppy, open list:XIVE, open list:S390 channel subs...

On Thu, Mar 05, 2026 at 12:23:01AM +0300, Vladimir Sementsov-Ogievskiy wrote:
> The field is unused, all users of VMSTATE_*_EQUAL pass _err_hint=NULL.
> 
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>

Reviewed-by: Peter Xu <peterx@redhat.com>

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v3 18/18] migration/vmstate-types: move to new migration APIs
  2026-03-04 21:23 ` [PATCH v3 18/18] migration/vmstate-types: move to new migration APIs Vladimir Sementsov-Ogievskiy
@ 2026-03-05 17:15   ` Peter Xu
  0 siblings, 0 replies; 33+ messages in thread
From: Peter Xu @ 2026-03-05 17:15 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy; +Cc: farosas, qemu-devel

On Thu, Mar 05, 2026 at 12:23:02AM +0300, Vladimir Sementsov-Ogievskiy wrote:
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>

Reviewed-by: Peter Xu <peterx@redhat.com>

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v3 00/18] migration: more bool+errp APIs
  2026-03-04 21:22 [PATCH v3 00/18] migration: more bool+errp APIs Vladimir Sementsov-Ogievskiy
                   ` (17 preceding siblings ...)
  2026-03-04 21:23 ` [PATCH v3 18/18] migration/vmstate-types: move to new migration APIs Vladimir Sementsov-Ogievskiy
@ 2026-03-06 20:53 ` Fabiano Rosas
  2026-03-24  7:22   ` Vladimir Sementsov-Ogievskiy
  18 siblings, 1 reply; 33+ messages in thread
From: Fabiano Rosas @ 2026-03-06 20:53 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy, peterx; +Cc: vsementsov, qemu-devel

Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> writes:

> v3:
> 01,02: add r-bs by Fabiano and Peter
> 03: improve comment, add r-b by Peter
> 04: add r-bs by Fabiano and Peter
> 05: new, replacement for dropped "[PATCH v2 05/16] migration: vmstate_save/load_state(): stop tracing errors"
> 06: rebase on kept trace-points, keep r-b by Peter
> 07-09: add r-b by Peter
> 10: rebase on kept trace-points, keep r-b by Peter
> 11-12: add r-b by Peter
> 13: rebase ion kept traces and logic around trace_vmstate_load_field_error() already refactored, fix indent, drop r-b
> 14: add r-b by Peter
> 15: add r-b by Peter, use "else { if () {} }"
> 16-17: new
> 18: rebased on dropped err_hint, drop r-b
>
> Vladimir Sementsov-Ogievskiy (18):
>   migration: vmstate_save_state_v: fix double error_setg
>   migration: make vmstate_save_state_v() static
>   migration: make .post_save() a void function
>   migration: vmstate_load_state(): add some newlines
>   migration: vmstate_save/load_state(): refactor tracing errors
>   migration: factor out vmstate_pre_save() from vmstate_save_state()
>   migration: factor out vmstate_save_field() from vmstate_save_state()
>   migration: factor out vmstate_pre_load() from vmstate_load_state()
>   migration: factor out vmstate_load_field() from vmstate_load_state()
>   migration: factor out vmstate_post_load() from vmstate_load_state()
>   migration: convert vmstate_subsection_save/load functions to bool
>   migration: VMStateInfo: introduce new handlers with errp
>   migration: introduce vmstate_load_vmsd() and vmstate_save_vmsd()
>   migration/cpr: move to new migration APIs
>   migration/savevm: move to new migration APIs
>   hw/s390x/css: drop use of .err_hint for vmstate
>   migration: drop VMStateField.err_hint
>   migration/vmstate-types: move to new migration APIs
>
>  docs/devel/migration/main.rst |   2 +-
>  hw/block/fdc.c                |   2 +-
>  hw/display/qxl.c              |   4 +-
>  hw/display/vga.c              |   2 +-
>  hw/display/virtio-gpu.c       |   2 +-
>  hw/display/vmware_vga.c       |   2 +-
>  hw/i386/vmmouse.c             |   2 +-
>  hw/ide/ahci.c                 |   2 +-
>  hw/intc/openpic.c             |   2 +-
>  hw/intc/spapr_xive.c          |   2 +-
>  hw/intc/xics.c                |   2 +-
>  hw/intc/xive.c                |   2 +-
>  hw/nvram/eeprom93xx.c         |   2 +-
>  hw/pci/pci.c                  |   2 +-
>  hw/pci/pcie_aer.c             |   2 +-
>  hw/ppc/spapr_iommu.c          |   2 +-
>  hw/ppc/spapr_pci.c            |   7 +-
>  hw/ppc/spapr_vio.c            |   4 +-
>  hw/s390x/css.c                |  15 +-
>  hw/usb/hcd-uhci.c             |   2 +-
>  include/migration/cpr.h       |   2 +-
>  include/migration/vmstate.h   |  73 ++--
>  migration/cpr.c               |  22 +-
>  migration/savevm.c            | 108 +++---
>  migration/trace-events        |  30 +-
>  migration/vmstate-types.c     | 642 +++++++++++++++++-----------------
>  migration/vmstate.c           | 354 +++++++++++--------
>  target/arm/machine.c          |   4 +-
>  target/ppc/machine.c          |   6 +-
>  29 files changed, 691 insertions(+), 612 deletions(-)

Queued, thanks!


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v3 03/18] migration: make .post_save() a void function
  2026-03-04 21:22 ` [PATCH v3 03/18] migration: make .post_save() a void function Vladimir Sementsov-Ogievskiy
@ 2026-03-06 23:20   ` Fabiano Rosas
  2026-03-06 23:34     ` noreply77-demartz@thinocorp.com
  2026-03-09 14:41     ` Zhao Liu
  0 siblings, 2 replies; 33+ messages in thread
From: Fabiano Rosas @ 2026-03-06 23:20 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy, peterx
  Cc: vsementsov, qemu-devel, Pierrick Bouvier, Nicholas Piggin,
	Harsh Prateek Bora, Peter Maydell, open list:sPAPR (pseries),
	open list:ARM TCG CPUs, Zhao Liu, Paolo Bonzini

Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> writes:

> All other handlers now have _errp() variants. Should we go this way
> for .post_save()? Actually it's rather strange, when the vmstate do
> successful preparations in .pre_save(), then successfully save all
> sections and subsections, end then fail when all the state is
> successfully transferred to the target.
>
> Happily, we have only three .post_save() realizations, all always
> successful. Let's make this a rule.
>
> Also note, that we call .post_save() in two places, and handle
> its (theoretical) failure inconsistently. Fix that too.
>
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
> Reviewed-by: Peter Xu <peterx@redhat.com>
> ---
>  docs/devel/migration/main.rst |  2 +-
>  hw/ppc/spapr_pci.c            |  3 +--
>  include/migration/vmstate.h   |  8 +++++++-
>  migration/savevm.c            |  3 +--
>  migration/vmstate.c           | 12 +++---------
>  target/arm/machine.c          |  4 +---
>  6 files changed, 14 insertions(+), 18 deletions(-)
>
> diff --git a/docs/devel/migration/main.rst b/docs/devel/migration/main.rst
> index 234d280249a..2de70507640 100644
> --- a/docs/devel/migration/main.rst
> +++ b/docs/devel/migration/main.rst
> @@ -439,7 +439,7 @@ The functions to do that are inside a vmstate definition, and are called:
>  
>    This function is called before we save the state of one device.
>  
> -- ``int (*post_save)(void *opaque);``
> +- ``void (*post_save)(void *opaque);``
>  
>    This function is called after we save the state of one device
>    (even upon failure, unless the call to pre_save returned an error).
> diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
> index ea998bdff15..1dc3b02659f 100644
> --- a/hw/ppc/spapr_pci.c
> +++ b/hw/ppc/spapr_pci.c
> @@ -2093,14 +2093,13 @@ static int spapr_pci_pre_save(void *opaque)
>      return 0;
>  }
>  
> -static int spapr_pci_post_save(void *opaque)
> +static void spapr_pci_post_save(void *opaque)
>  {
>      SpaprPhbState *sphb = opaque;
>  
>      g_free(sphb->msi_devs);
>      sphb->msi_devs = NULL;
>      sphb->msi_devs_num = 0;
> -    return 0;
>  }
>  
>  static int spapr_pci_post_load(void *opaque, int version_id)
> diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
> index 3695afd483f..85838a49aee 100644
> --- a/include/migration/vmstate.h
> +++ b/include/migration/vmstate.h
> @@ -223,7 +223,13 @@ struct VMStateDescription {
>      bool (*post_load_errp)(void *opaque, int version_id, Error **errp);
>      int (*pre_save)(void *opaque);
>      bool (*pre_save_errp)(void *opaque, Error **errp);
> -    int (*post_save)(void *opaque);
> +
> +    /*
> +     * Unless .pre_save() fails, .post_save() is called after saving
> +     * fields and subsections. It should not fail because at this
> +     * point the state has potentially already been transferred.
> +     */
> +    void (*post_save)(void *opaque);

+CC Paolo, Zhao

This change breaks the rust build:
https://gitlab.com/farosas/qemu/-/jobs/13393119755

  error[E0308]: mismatched types
     --> ../rust/migration/src/vmstate.rs:605:18
      |
  605 |             Some(vmstate_no_version_cb::<T, F>)
      |             ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn pointer, found fn item
      |             |
      |             arguments to this enum variant are incorrect
      |
      = note: expected fn pointer `unsafe extern "C" fn(_) -> ()`
                    found fn item `unsafe extern "C" fn(_) -> i32 {vmstate_no_version_cb::<T, F, impl Into<Errno>>}`


Is something like the following diff the right fix? It'd be nice to get
an ack so this series doesn't miss the freeze. (CI run:
https://gitlab.com/farosas/qemu/-/pipelines/2369688593)

-- >8 --
From 90a7b53d2b0d53692df1ef2cfe7607b13e4961d8 Mon Sep 17 00:00:00 2001
From: Fabiano Rosas <farosas@suse.de>
Date: Fri, 6 Mar 2026 18:53:14 -0300
Subject: [PATCH] fixup! migration: make .post_save() a void function

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 rust/migration/src/migratable.rs |  3 +--
 rust/migration/src/vmstate.rs    | 12 +++++++-----
 2 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/rust/migration/src/migratable.rs b/rust/migration/src/migratable.rs
index 7748aac2f2..7088c1b156 100644
--- a/rust/migration/src/migratable.rs
+++ b/rust/migration/src/migratable.rs
@@ -406,10 +406,9 @@ fn pre_save(&self) -> Result<(), InvalidError> {
         Ok(())
     }
 
-    fn post_save(&self) -> Result<(), InvalidError> {
+    fn post_save(&self) {
         let state = unsafe { Box::from_raw(self.migration_state.replace(ptr::null_mut())) };
         drop(state);
-        Ok(())
     }
 
     fn pre_load(&self) -> Result<(), InvalidError> {
diff --git a/rust/migration/src/vmstate.rs b/rust/migration/src/vmstate.rs
index edc7c70265..f34a36f680 100644
--- a/rust/migration/src/vmstate.rs
+++ b/rust/migration/src/vmstate.rs
@@ -492,6 +492,11 @@ fn from(_value: InvalidError) -> Errno {
     into_neg_errno(result)
 }
 
+unsafe extern "C" fn vmstate_post_save_cb<T, F: for<'a> FnCall<(&'a T,), ()>>(opaque: *mut c_void) {
+    // SAFETY: the function is used in T's implementation of VMState.
+    F::call((unsafe { &*(opaque.cast::<T>()) },));
+}
+
 unsafe extern "C" fn vmstate_post_load_cb<
     T,
     F: for<'a> FnCall<(&'a T, u8), Result<(), impl Into<Errno>>>,
@@ -597,12 +602,9 @@ pub const fn pre_save<F: for<'a> FnCall<(&'a T,), Result<(), impl Into<Errno>>>>
     }
 
     #[must_use]
-    pub const fn post_save<F: for<'a> FnCall<(&'a T,), Result<(), impl Into<Errno>>>>(
-        mut self,
-        _f: &F,
-    ) -> Self {
+    pub const fn post_save<F: for<'a> FnCall<(&'a T,), ()>>(mut self, _f: &F) -> Self {
         self.0.post_save = if F::IS_SOME {
-            Some(vmstate_no_version_cb::<T, F>)
+            Some(vmstate_post_save_cb::<T, F>)
         } else {
             None
         };
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: [PATCH v3 03/18] migration: make .post_save() a void function
  2026-03-06 23:20   ` Fabiano Rosas
@ 2026-03-06 23:34     ` noreply77-demartz@thinocorp.com
  2026-03-09 14:41     ` Zhao Liu
  1 sibling, 0 replies; 33+ messages in thread
From: noreply77-demartz@thinocorp.com @ 2026-03-06 23:34 UTC (permalink / raw)
  To: Fabiano Rosas
  Cc: Vladimir Sementsov-Ogievskiy, peterx, qemu-devel,
	Pierrick Bouvier, Nicholas Piggin, Harsh Prateek Bora,
	Peter Maydell, open list:sPAPR (pseries), open list:ARM TCG CPUs,
	Zhao Liu, Paolo Bonzini

[-- Attachment #1: Type: text/plain, Size: 7116 bytes --]

Hola,

Espero que este mensaje se encuentre bien.

Con respecto a la propuesta de Vladimir de cambiar .post_save() a una
función void en el proceso de migración, Fabiano ha señalado que este
cambio afecta actualmente la compilación en Rust.

Para evitar inconvenientes con el próximo "freeze", Fabiano ya ha sugerido
una solución técnica para corregir este error de compatibilidad. Quedamos a
la espera de sus comentarios o de su aprobación para proceder con los
ajustes necesarios y asegurar que la serie de parches pueda integrarse sin
problemas.

Saludos cordiales,

Jhosenad

Jhosenad@thinocorp.com

El vie, 6 de mar de 2026, 16:21, Fabiano Rosas <farosas@suse.de> escribió:

> Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> writes:
>
> > All other handlers now have _errp() variants. Should we go this way
> > for .post_save()? Actually it's rather strange, when the vmstate do
> > successful preparations in .pre_save(), then successfully save all
> > sections and subsections, end then fail when all the state is
> > successfully transferred to the target.
> >
> > Happily, we have only three .post_save() realizations, all always
> > successful. Let's make this a rule.
> >
> > Also note, that we call .post_save() in two places, and handle
> > its (theoretical) failure inconsistently. Fix that too.
> >
> > Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
> > Reviewed-by: Peter Xu <peterx@redhat.com>
> > ---
> >  docs/devel/migration/main.rst |  2 +-
> >  hw/ppc/spapr_pci.c            |  3 +--
> >  include/migration/vmstate.h   |  8 +++++++-
> >  migration/savevm.c            |  3 +--
> >  migration/vmstate.c           | 12 +++---------
> >  target/arm/machine.c          |  4 +---
> >  6 files changed, 14 insertions(+), 18 deletions(-)
> >
> > diff --git a/docs/devel/migration/main.rst
> b/docs/devel/migration/main.rst
> > index 234d280249a..2de70507640 100644
> > --- a/docs/devel/migration/main.rst
> > +++ b/docs/devel/migration/main.rst
> > @@ -439,7 +439,7 @@ The functions to do that are inside a vmstate
> definition, and are called:
> >
> >    This function is called before we save the state of one device.
> >
> > -- ``int (*post_save)(void *opaque);``
> > +- ``void (*post_save)(void *opaque);``
> >
> >    This function is called after we save the state of one device
> >    (even upon failure, unless the call to pre_save returned an error).
> > diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
> > index ea998bdff15..1dc3b02659f 100644
> > --- a/hw/ppc/spapr_pci.c
> > +++ b/hw/ppc/spapr_pci.c
> > @@ -2093,14 +2093,13 @@ static int spapr_pci_pre_save(void *opaque)
> >      return 0;
> >  }
> >
> > -static int spapr_pci_post_save(void *opaque)
> > +static void spapr_pci_post_save(void *opaque)
> >  {
> >      SpaprPhbState *sphb = opaque;
> >
> >      g_free(sphb->msi_devs);
> >      sphb->msi_devs = NULL;
> >      sphb->msi_devs_num = 0;
> > -    return 0;
> >  }
> >
> >  static int spapr_pci_post_load(void *opaque, int version_id)
> > diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
> > index 3695afd483f..85838a49aee 100644
> > --- a/include/migration/vmstate.h
> > +++ b/include/migration/vmstate.h
> > @@ -223,7 +223,13 @@ struct VMStateDescription {
> >      bool (*post_load_errp)(void *opaque, int version_id, Error **errp);
> >      int (*pre_save)(void *opaque);
> >      bool (*pre_save_errp)(void *opaque, Error **errp);
> > -    int (*post_save)(void *opaque);
> > +
> > +    /*
> > +     * Unless .pre_save() fails, .post_save() is called after saving
> > +     * fields and subsections. It should not fail because at this
> > +     * point the state has potentially already been transferred.
> > +     */
> > +    void (*post_save)(void *opaque);
>
> +CC Paolo, Zhao
>
> This change breaks the rust build:
> https://gitlab.com/farosas/qemu/-/jobs/13393119755
>
>   error[E0308]: mismatched types
>      --> ../rust/migration/src/vmstate.rs:605:18
>       |
>   605 |             Some(vmstate_no_version_cb::<T, F>)
>       |             ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn
> pointer, found fn item
>       |             |
>       |             arguments to this enum variant are incorrect
>       |
>       = note: expected fn pointer `unsafe extern "C" fn(_) -> ()`
>                     found fn item `unsafe extern "C" fn(_) -> i32
> {vmstate_no_version_cb::<T, F, impl Into<Errno>>}`
>
>
> Is something like the following diff the right fix? It'd be nice to get
> an ack so this series doesn't miss the freeze. (CI run:
> https://gitlab.com/farosas/qemu/-/pipelines/2369688593)
>
> -- >8 --
> From 90a7b53d2b0d53692df1ef2cfe7607b13e4961d8 Mon Sep 17 00:00:00 2001
> From: Fabiano Rosas <farosas@suse.de>
> Date: Fri, 6 Mar 2026 18:53:14 -0300
> Subject: [PATCH] fixup! migration: make .post_save() a void function
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> ---
>  rust/migration/src/migratable.rs |  3 +--
>  rust/migration/src/vmstate.rs    | 12 +++++++-----
>  2 files changed, 8 insertions(+), 7 deletions(-)
>
> diff --git a/rust/migration/src/migratable.rs
> b/rust/migration/src/migratable.rs
> index 7748aac2f2..7088c1b156 100644
> --- a/rust/migration/src/migratable.rs
> +++ b/rust/migration/src/migratable.rs
> @@ -406,10 +406,9 @@ fn pre_save(&self) -> Result<(), InvalidError> {
>          Ok(())
>      }
>
> -    fn post_save(&self) -> Result<(), InvalidError> {
> +    fn post_save(&self) {
>          let state = unsafe {
> Box::from_raw(self.migration_state.replace(ptr::null_mut())) };
>          drop(state);
> -        Ok(())
>      }
>
>      fn pre_load(&self) -> Result<(), InvalidError> {
> diff --git a/rust/migration/src/vmstate.rs b/rust/migration/src/vmstate.rs
> index edc7c70265..f34a36f680 100644
> --- a/rust/migration/src/vmstate.rs
> +++ b/rust/migration/src/vmstate.rs
> @@ -492,6 +492,11 @@ fn from(_value: InvalidError) -> Errno {
>      into_neg_errno(result)
>  }
>
> +unsafe extern "C" fn vmstate_post_save_cb<T, F: for<'a> FnCall<(&'a T,),
> ()>>(opaque: *mut c_void) {
> +    // SAFETY: the function is used in T's implementation of VMState.
> +    F::call((unsafe { &*(opaque.cast::<T>()) },));
> +}
> +
>  unsafe extern "C" fn vmstate_post_load_cb<
>      T,
>      F: for<'a> FnCall<(&'a T, u8), Result<(), impl Into<Errno>>>,
> @@ -597,12 +602,9 @@ pub const fn pre_save<F: for<'a> FnCall<(&'a T,),
> Result<(), impl Into<Errno>>>>
>      }
>
>      #[must_use]
> -    pub const fn post_save<F: for<'a> FnCall<(&'a T,), Result<(), impl
> Into<Errno>>>>(
> -        mut self,
> -        _f: &F,
> -    ) -> Self {
> +    pub const fn post_save<F: for<'a> FnCall<(&'a T,), ()>>(mut self, _f:
> &F) -> Self {
>          self.0.post_save = if F::IS_SOME {
> -            Some(vmstate_no_version_cb::<T, F>)
> +            Some(vmstate_post_save_cb::<T, F>)
>          } else {
>              None
>          };
> --
> 2.51.0
>
>
>

[-- Attachment #2: Type: text/html, Size: 9534 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v3 03/18] migration: make .post_save() a void function
  2026-03-06 23:20   ` Fabiano Rosas
  2026-03-06 23:34     ` noreply77-demartz@thinocorp.com
@ 2026-03-09 14:41     ` Zhao Liu
  1 sibling, 0 replies; 33+ messages in thread
From: Zhao Liu @ 2026-03-09 14:41 UTC (permalink / raw)
  To: Fabiano Rosas, Paolo Bonzini
  Cc: Vladimir Sementsov-Ogievskiy, peterx, qemu-devel,
	Pierrick Bouvier, Nicholas Piggin, Harsh Prateek Bora,
	Peter Maydell, open list:sPAPR (pseries), open list:ARM TCG CPUs,
	qemu-rust

> +CC Paolo, Zhao
> 
> This change breaks the rust build:
> https://gitlab.com/farosas/qemu/-/jobs/13393119755
> 
>   error[E0308]: mismatched types
>      --> ../rust/migration/src/vmstate.rs:605:18
>       |
>   605 |             Some(vmstate_no_version_cb::<T, F>)
>       |             ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn pointer, found fn item
>       |             |
>       |             arguments to this enum variant are incorrect
>       |
>       = note: expected fn pointer `unsafe extern "C" fn(_) -> ()`
>                     found fn item `unsafe extern "C" fn(_) -> i32 {vmstate_no_version_cb::<T, F, impl Into<Errno>>}`
> 
> 
> Is something like the following diff the right fix? It'd be nice to get
> an ack so this series doesn't miss the freeze. (CI run:
> https://gitlab.com/farosas/qemu/-/pipelines/2369688593)
> 
> -- >8 --
> From 90a7b53d2b0d53692df1ef2cfe7607b13e4961d8 Mon Sep 17 00:00:00 2001
> From: Fabiano Rosas <farosas@suse.de>
> Date: Fri, 6 Mar 2026 18:53:14 -0300
> Subject: [PATCH] fixup! migration: make .post_save() a void function
> 
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> ---
>  rust/migration/src/migratable.rs |  3 +--
>  rust/migration/src/vmstate.rs    | 12 +++++++-----
>  2 files changed, 8 insertions(+), 7 deletions(-)
> 
> diff --git a/rust/migration/src/migratable.rs b/rust/migration/src/migratable.rs
> index 7748aac2f2..7088c1b156 100644
> --- a/rust/migration/src/migratable.rs
> +++ b/rust/migration/src/migratable.rs
> @@ -406,10 +406,9 @@ fn pre_save(&self) -> Result<(), InvalidError> {
>          Ok(())
>      }
>  
> -    fn post_save(&self) -> Result<(), InvalidError> {
> +    fn post_save(&self) {
>          let state = unsafe { Box::from_raw(self.migration_state.replace(ptr::null_mut())) };
>          drop(state);
> -        Ok(())
>      }

What about this?

fn post_save(&self) {
    let _ = unsafe { Box::from_raw(self.migration_state.replace(ptr::null_mut())) };
}

Others LGTM,

Reviewed-by: Zhao Liu <zhao1.liu@intel.com>




^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v3 00/18] migration: more bool+errp APIs
  2026-03-06 20:53 ` [PATCH v3 00/18] migration: more bool+errp APIs Fabiano Rosas
@ 2026-03-24  7:22   ` Vladimir Sementsov-Ogievskiy
  2026-03-24 12:42     ` Fabiano Rosas
  0 siblings, 1 reply; 33+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2026-03-24  7:22 UTC (permalink / raw)
  To: Fabiano Rosas, peterx; +Cc: qemu-devel

On 06.03.26 23:53, Fabiano Rosas wrote:
> Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> writes:
> 
>> v3:
>> 01,02: add r-bs by Fabiano and Peter
>> 03: improve comment, add r-b by Peter
>> 04: add r-bs by Fabiano and Peter
>> 05: new, replacement for dropped "[PATCH v2 05/16] migration: vmstate_save/load_state(): stop tracing errors"
>> 06: rebase on kept trace-points, keep r-b by Peter
>> 07-09: add r-b by Peter
>> 10: rebase on kept trace-points, keep r-b by Peter
>> 11-12: add r-b by Peter
>> 13: rebase ion kept traces and logic around trace_vmstate_load_field_error() already refactored, fix indent, drop r-b
>> 14: add r-b by Peter
>> 15: add r-b by Peter, use "else { if () {} }"
>> 16-17: new
>> 18: rebased on dropped err_hint, drop r-b
>>
>> Vladimir Sementsov-Ogievskiy (18):
>>    migration: vmstate_save_state_v: fix double error_setg
>>    migration: make vmstate_save_state_v() static
>>    migration: make .post_save() a void function
>>    migration: vmstate_load_state(): add some newlines
>>    migration: vmstate_save/load_state(): refactor tracing errors
>>    migration: factor out vmstate_pre_save() from vmstate_save_state()
>>    migration: factor out vmstate_save_field() from vmstate_save_state()
>>    migration: factor out vmstate_pre_load() from vmstate_load_state()
>>    migration: factor out vmstate_load_field() from vmstate_load_state()
>>    migration: factor out vmstate_post_load() from vmstate_load_state()
>>    migration: convert vmstate_subsection_save/load functions to bool
>>    migration: VMStateInfo: introduce new handlers with errp
>>    migration: introduce vmstate_load_vmsd() and vmstate_save_vmsd()
>>    migration/cpr: move to new migration APIs
>>    migration/savevm: move to new migration APIs
>>    hw/s390x/css: drop use of .err_hint for vmstate
>>    migration: drop VMStateField.err_hint
>>    migration/vmstate-types: move to new migration APIs
>>
>>   docs/devel/migration/main.rst |   2 +-
>>   hw/block/fdc.c                |   2 +-
>>   hw/display/qxl.c              |   4 +-
>>   hw/display/vga.c              |   2 +-
>>   hw/display/virtio-gpu.c       |   2 +-
>>   hw/display/vmware_vga.c       |   2 +-
>>   hw/i386/vmmouse.c             |   2 +-
>>   hw/ide/ahci.c                 |   2 +-
>>   hw/intc/openpic.c             |   2 +-
>>   hw/intc/spapr_xive.c          |   2 +-
>>   hw/intc/xics.c                |   2 +-
>>   hw/intc/xive.c                |   2 +-
>>   hw/nvram/eeprom93xx.c         |   2 +-
>>   hw/pci/pci.c                  |   2 +-
>>   hw/pci/pcie_aer.c             |   2 +-
>>   hw/ppc/spapr_iommu.c          |   2 +-
>>   hw/ppc/spapr_pci.c            |   7 +-
>>   hw/ppc/spapr_vio.c            |   4 +-
>>   hw/s390x/css.c                |  15 +-
>>   hw/usb/hcd-uhci.c             |   2 +-
>>   include/migration/cpr.h       |   2 +-
>>   include/migration/vmstate.h   |  73 ++--
>>   migration/cpr.c               |  22 +-
>>   migration/savevm.c            | 108 +++---
>>   migration/trace-events        |  30 +-
>>   migration/vmstate-types.c     | 642 +++++++++++++++++-----------------
>>   migration/vmstate.c           | 354 +++++++++++--------
>>   target/arm/machine.c          |   4 +-
>>   target/ppc/machine.c          |   6 +-
>>   29 files changed, 691 insertions(+), 612 deletions(-)
> 
> Queued, thanks!


Hi! Aren't these patches lost?

-- 
Best regards,
Vladimir


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v3 00/18] migration: more bool+errp APIs
  2026-03-24  7:22   ` Vladimir Sementsov-Ogievskiy
@ 2026-03-24 12:42     ` Fabiano Rosas
  0 siblings, 0 replies; 33+ messages in thread
From: Fabiano Rosas @ 2026-03-24 12:42 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy, peterx; +Cc: qemu-devel

Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> writes:

> On 06.03.26 23:53, Fabiano Rosas wrote:
>> Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> writes:
>> 
>>> v3:
>>> 01,02: add r-bs by Fabiano and Peter
>>> 03: improve comment, add r-b by Peter
>>> 04: add r-bs by Fabiano and Peter
>>> 05: new, replacement for dropped "[PATCH v2 05/16] migration: vmstate_save/load_state(): stop tracing errors"
>>> 06: rebase on kept trace-points, keep r-b by Peter
>>> 07-09: add r-b by Peter
>>> 10: rebase on kept trace-points, keep r-b by Peter
>>> 11-12: add r-b by Peter
>>> 13: rebase ion kept traces and logic around trace_vmstate_load_field_error() already refactored, fix indent, drop r-b
>>> 14: add r-b by Peter
>>> 15: add r-b by Peter, use "else { if () {} }"
>>> 16-17: new
>>> 18: rebased on dropped err_hint, drop r-b
>>>
>>> Vladimir Sementsov-Ogievskiy (18):
>>>    migration: vmstate_save_state_v: fix double error_setg
>>>    migration: make vmstate_save_state_v() static
>>>    migration: make .post_save() a void function
>>>    migration: vmstate_load_state(): add some newlines
>>>    migration: vmstate_save/load_state(): refactor tracing errors
>>>    migration: factor out vmstate_pre_save() from vmstate_save_state()
>>>    migration: factor out vmstate_save_field() from vmstate_save_state()
>>>    migration: factor out vmstate_pre_load() from vmstate_load_state()
>>>    migration: factor out vmstate_load_field() from vmstate_load_state()
>>>    migration: factor out vmstate_post_load() from vmstate_load_state()
>>>    migration: convert vmstate_subsection_save/load functions to bool
>>>    migration: VMStateInfo: introduce new handlers with errp
>>>    migration: introduce vmstate_load_vmsd() and vmstate_save_vmsd()
>>>    migration/cpr: move to new migration APIs
>>>    migration/savevm: move to new migration APIs
>>>    hw/s390x/css: drop use of .err_hint for vmstate
>>>    migration: drop VMStateField.err_hint
>>>    migration/vmstate-types: move to new migration APIs
>>>
>>>   docs/devel/migration/main.rst |   2 +-
>>>   hw/block/fdc.c                |   2 +-
>>>   hw/display/qxl.c              |   4 +-
>>>   hw/display/vga.c              |   2 +-
>>>   hw/display/virtio-gpu.c       |   2 +-
>>>   hw/display/vmware_vga.c       |   2 +-
>>>   hw/i386/vmmouse.c             |   2 +-
>>>   hw/ide/ahci.c                 |   2 +-
>>>   hw/intc/openpic.c             |   2 +-
>>>   hw/intc/spapr_xive.c          |   2 +-
>>>   hw/intc/xics.c                |   2 +-
>>>   hw/intc/xive.c                |   2 +-
>>>   hw/nvram/eeprom93xx.c         |   2 +-
>>>   hw/pci/pci.c                  |   2 +-
>>>   hw/pci/pcie_aer.c             |   2 +-
>>>   hw/ppc/spapr_iommu.c          |   2 +-
>>>   hw/ppc/spapr_pci.c            |   7 +-
>>>   hw/ppc/spapr_vio.c            |   4 +-
>>>   hw/s390x/css.c                |  15 +-
>>>   hw/usb/hcd-uhci.c             |   2 +-
>>>   include/migration/cpr.h       |   2 +-
>>>   include/migration/vmstate.h   |  73 ++--
>>>   migration/cpr.c               |  22 +-
>>>   migration/savevm.c            | 108 +++---
>>>   migration/trace-events        |  30 +-
>>>   migration/vmstate-types.c     | 642 +++++++++++++++++-----------------
>>>   migration/vmstate.c           | 354 +++++++++++--------
>>>   target/arm/machine.c          |   4 +-
>>>   target/ppc/machine.c          |   6 +-
>>>   29 files changed, 691 insertions(+), 612 deletions(-)
>> 
>> Queued, thanks!
>
>
> Hi! Aren't these patches lost?

Hi, no, they are in my staging branch, I'll post when the devel window
reopens. Unfortunately the rust build issue took up the amount of time I
had slotted for this and I had to put it on hold to work on other
things.


^ permalink raw reply	[flat|nested] 33+ messages in thread

end of thread, other threads:[~2026-03-24 12:43 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-04 21:22 [PATCH v3 00/18] migration: more bool+errp APIs Vladimir Sementsov-Ogievskiy
2026-03-04 21:22 ` [PATCH v3 01/18] migration: vmstate_save_state_v: fix double error_setg Vladimir Sementsov-Ogievskiy
2026-03-04 21:22 ` [PATCH v3 02/18] migration: make vmstate_save_state_v() static Vladimir Sementsov-Ogievskiy
2026-03-04 21:22 ` [PATCH v3 03/18] migration: make .post_save() a void function Vladimir Sementsov-Ogievskiy
2026-03-06 23:20   ` Fabiano Rosas
2026-03-06 23:34     ` noreply77-demartz@thinocorp.com
2026-03-09 14:41     ` Zhao Liu
2026-03-04 21:22 ` [PATCH v3 04/18] migration: vmstate_load_state(): add some newlines Vladimir Sementsov-Ogievskiy
2026-03-04 21:22 ` [PATCH v3 05/18] migration: vmstate_save/load_state(): refactor tracing errors Vladimir Sementsov-Ogievskiy
2026-03-05 16:59   ` Peter Xu
2026-03-04 21:22 ` [PATCH v3 06/18] migration: factor out vmstate_pre_save() from vmstate_save_state() Vladimir Sementsov-Ogievskiy
2026-03-04 21:22 ` [PATCH v3 07/18] migration: factor out vmstate_save_field() " Vladimir Sementsov-Ogievskiy
2026-03-04 21:22 ` [PATCH v3 08/18] migration: factor out vmstate_pre_load() from vmstate_load_state() Vladimir Sementsov-Ogievskiy
2026-03-04 21:22 ` [PATCH v3 09/18] migration: factor out vmstate_load_field() " Vladimir Sementsov-Ogievskiy
2026-03-04 21:22 ` [PATCH v3 10/18] migration: factor out vmstate_post_load() " Vladimir Sementsov-Ogievskiy
2026-03-04 21:22 ` [PATCH v3 11/18] migration: convert vmstate_subsection_save/load functions to bool Vladimir Sementsov-Ogievskiy
2026-03-04 21:22 ` [PATCH v3 12/18] migration: VMStateInfo: introduce new handlers with errp Vladimir Sementsov-Ogievskiy
2026-03-04 21:22 ` [PATCH v3 13/18] migration: introduce vmstate_load_vmsd() and vmstate_save_vmsd() Vladimir Sementsov-Ogievskiy
2026-03-05 17:01   ` Peter Xu
2026-03-04 21:22 ` [PATCH v3 14/18] migration/cpr: move to new migration APIs Vladimir Sementsov-Ogievskiy
2026-03-04 21:22 ` [PATCH v3 15/18] migration/savevm: " Vladimir Sementsov-Ogievskiy
2026-03-04 21:23 ` [PATCH v3 16/18] hw/s390x/css: drop use of .err_hint for vmstate Vladimir Sementsov-Ogievskiy
2026-03-05  2:29   ` Eric Farman
2026-03-05 17:14   ` Peter Xu
2026-03-04 21:23 ` [PATCH v3 17/18] migration: drop VMStateField.err_hint Vladimir Sementsov-Ogievskiy
2026-03-05  2:39   ` Eric Farman
2026-03-05  5:18   ` Akihiko Odaki
2026-03-05 17:14   ` Peter Xu
2026-03-04 21:23 ` [PATCH v3 18/18] migration/vmstate-types: move to new migration APIs Vladimir Sementsov-Ogievskiy
2026-03-05 17:15   ` Peter Xu
2026-03-06 20:53 ` [PATCH v3 00/18] migration: more bool+errp APIs Fabiano Rosas
2026-03-24  7:22   ` Vladimir Sementsov-Ogievskiy
2026-03-24 12:42     ` Fabiano Rosas

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox