Hi Akihiko,
Thanks for the review.

On Wed, Aug 06, 2025 at 02:45:01PM +0900, Akihiko Odaki wrote:
> On 2025/08/06 3:25, Arun Menon wrote:
> > - We need to have good error reporting in the callbacks in
> >    VMStateDescription struct. Specifically pre_save, post_save,
> >    pre_load and post_load callbacks.
> > - It is not possible to change these functions everywhere in one
> >    patch, therefore, we introduce a duplicate set of callbacks
> >    with Error object passed to them.
> > - So, in this commit, we implement 'errp' variants of these callbacks,
> >    introducing an explicit Error object parameter.
> > - This is a functional step towards transitioning the entire codebase
> >    to the new error-parameterized functions.
> > - Deliberately called in mutual exclusion from their counterparts,
> >    to prevent conflicts during the transition.
> > - New impls should preferentally use 'errp' variants of
> >    these methods, and existing impls incrementally converted.
> >    The variants without 'errp' are intended to be removed
> >    once all usage is converted.
> > 
> > Signed-off-by: Arun Menon <arme...@redhat.com>
> > ---
> >   docs/devel/migration/main.rst | 24 ++++++++++++++++++++++++
> >   include/migration/vmstate.h   | 15 +++++++++++++++
> >   migration/vmstate.c           | 34 ++++++++++++++++++++++++++++++----
> >   3 files changed, 69 insertions(+), 4 deletions(-)
> > 
> > diff --git a/docs/devel/migration/main.rst b/docs/devel/migration/main.rst
> > index 
> > 6493c1d2bca48a2fa34d92f6c0979c215c56b8d5..35bf5ae26c87f3c82964eb15618be373ab5a41fc
> >  100644
> > --- a/docs/devel/migration/main.rst
> > +++ b/docs/devel/migration/main.rst
> > @@ -444,6 +444,30 @@ The functions to do that are inside a vmstate 
> > definition, and are called:
> >     This function is called after we save the state of one device
> >     (even upon failure, unless the call to pre_save returned an error).
> > +Following are the errp variants of these functions.
> > +
> > +- ``int (*pre_load_errp)(void *opaque, Error **errp);``
> > +
> > +  This function is called before we load the state of one device.
> > +
> > +- ``int (*post_load_errp)(void *opaque, int version_id, Error **errp);``
> > +
> > +  This function is called after we load the state of one device.
> > +
> > +- ``int (*pre_save_errp)(void *opaque, Error **errp);``
> > +
> > +  This function is called before we save the state of one device.
> > +
> > +- ``int (*post_save_errp)(void *opaque, Error **errp);``
> > +
> > +  This function is called after we save the state of one device
> > +  (even upon failure, unless the call to pre_save returned an error).
> 
> Reviewing "[PATCH v9 24/27] migration: Propagate last encountered error in
> vmstate_save_state_v() function", I wondered why it has never been a problem
> post_load(), and this says only post_save_errp() is called upon failure.
> 
> Now I suspect it may be better to clarify their differences and avoid
> introducing post_save_errp() instead.
> 
> My guess is that post_save_errp() is being introduced for consistency with
> post_load(), but they cannot have "consistency" if post_load() and
> post_save() are not corresponding functions of save/load but are independent
> two functions. Perhaps the true problem here is that post_load() and
> post_save() look similar; if so, that can be solved by:
> - Renaming post_save() to e.g., cleanup_save()
> - Changing it to return void
> 
That is insightful. I agree. It was introduced because of the nomenclature. 
>From what I have seen, the functionality indeed differs, in the sense that,
currently post_load does some sanity checks after loading the device state,
and therefore it can fail and return an error; whereas post_save is not known
to fail until now.

It is therefore possible to implement your suggestion : renaming it to
cleanup_save and returning void. This will avoid us in having the extra
patch 24/27.
While I have deviated a bit from TPM backend to make these changes in the
migration module, I believe they are important and hope the maintainers
will agree.

> > +
> > +New impls should preferentally use 'errp' variants of these
> > +methods and existing impls incrementally converted.
> > +The variants without 'errp' are intended to be removed
> > +once all usage is converted.
> > +
> >   Example: You can look at hpet.c, that uses the first three functions
> >   to massage the state that is transferred.
> > diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
> > index 
> > 5fe9bbf39058d0cf97c1adab54cc516dbe8dc32a..51baf6c7f9d061ee33949d7e798f2184e50b4cbf
> >  100644
> > --- a/include/migration/vmstate.h
> > +++ b/include/migration/vmstate.h
> > @@ -200,15 +200,30 @@ struct VMStateDescription {
> >        * exclusive. For this reason, also early_setup VMSDs are migrated in 
> > a
> >        * QEMU_VM_SECTION_FULL section, while save_setup() data is migrated 
> > in
> >        * a QEMU_VM_SECTION_START section.
> > +     *
> > +     * There are duplicate impls of the post/pre save/load hooks.
> > +     * New impls should preferentally use 'errp' variants of these
> > +     * methods and existing impls incrementally converted.
> > +     * The variants without 'errp' are intended to be removed
> > +     * once all usage is converted.
> > +     *
> > +     * For the errp variants,
> > +     * Returns: 0 on success,
> > +     *          <0 on error where -value is an error number from errno.h
> >        */
> > +
> >       bool early_setup;
> >       int version_id;
> >       int minimum_version_id;
> >       MigrationPriority priority;
> >       int (*pre_load)(void *opaque);
> > +    int (*pre_load_errp)(void *opaque, Error **errp);
> >       int (*post_load)(void *opaque, int version_id);
> > +    int (*post_load_errp)(void *opaque, int version_id, Error **errp);
> >       int (*pre_save)(void *opaque);
> > +    int (*pre_save_errp)(void *opaque, Error **errp);
> >       int (*post_save)(void *opaque);
> > +    int (*post_save_errp)(void *opaque, Error **errp);
> >       bool (*needed)(void *opaque);
> >       bool (*dev_unplug_pending)(void *opaque);
> > diff --git a/migration/vmstate.c b/migration/vmstate.c
> > index 
> > 569e66ea983f833e6a0d651d2a751f34a64e8f5c..0acaa855cfec8ddac63e33d4562e39c345856213
> >  100644
> > --- a/migration/vmstate.c
> > +++ b/migration/vmstate.c
> > @@ -152,7 +152,16 @@ int vmstate_load_state(QEMUFile *f, const 
> > VMStateDescription *vmsd,
> >           trace_vmstate_load_state_end(vmsd->name, "too old", -EINVAL);
> >           return -EINVAL;
> >       }
> > -    if (vmsd->pre_load) {
> > +    if (vmsd->pre_load_errp) {
> > +        ret = vmsd->pre_load_errp(opaque, errp);
> > +        if (ret) {
> > +            error_prepend(errp, "VM pre load failed for: '%s', "
> > +                          "version_id: %d, minimum version_id: %d, "
> > +                          "ret: %d: ", vmsd->name, vmsd->version_id,
> > +                          vmsd->minimum_version_id, ret);
> > +            return ret;
> > +        }
> > +    } else if (vmsd->pre_load) {
> >           ret = vmsd->pre_load(opaque);
> >           if (ret) {
> >               error_setg(errp, "VM pre load failed for: '%s', "
> > @@ -242,7 +251,14 @@ int vmstate_load_state(QEMUFile *f, const 
> > VMStateDescription *vmsd,
> >           qemu_file_set_error(f, ret);
> >           return ret;
> >       }
> > -    if (vmsd->post_load) {
> > +    if (vmsd->post_load_errp) {
> > +        ret = vmsd->post_load_errp(opaque, version_id, errp);
> > +        if (ret < 0) {
> > +            error_prepend(errp, "VM Post load failed for: %s, version_id: 
> > %d, "
> > +                          "minimum_version: %d, ret: %d: ", vmsd->name,
> > +                          vmsd->version_id, vmsd->minimum_version_id, ret);
> > +        }
> > +    } else if (vmsd->post_load) {
> >           ret = vmsd->post_load(opaque, version_id);
> >           if (ret < 0) {
> >               error_setg(errp,
> > @@ -411,8 +427,16 @@ int vmstate_save_state(QEMUFile *f, const 
> > VMStateDescription *vmsd,
> >   static int pre_save_dispatch(const VMStateDescription *vmsd, void *opaque,
> >                                Error **errp)
> >   {
> > +    ERRP_GUARD();
> >       int ret = 0;
> > -    if (vmsd->pre_save) {
> > +    if (vmsd->pre_save_errp) {
> > +        ret = vmsd->pre_save_errp(opaque, errp);
> > +        trace_vmstate_save_state_pre_save_res(vmsd->name, ret);
> > +        if (ret) {
> > +            error_prepend(errp, "pre-save for %s failed, ret: %d: ",
> > +                          vmsd->name, ret);
> > +        }
> > +    } else if (vmsd->pre_save) {
> >           ret = vmsd->pre_save(opaque);
> >           trace_vmstate_save_state_pre_save_res(vmsd->name, ret);
> >           if (ret) {
> > @@ -427,7 +451,9 @@ static int post_save_dispatch(const VMStateDescription 
> > *vmsd, void *opaque,
> >                                 Error **errp)
> >   {
> >       int ret = 0;
> > -    if (vmsd->post_save) {
> > +    if (vmsd->post_save_errp) {
> > +        ret = vmsd->post_save_errp(opaque, errp);
> > +    } else if (vmsd->post_save) {
> >           ret = vmsd->post_save(opaque);
> >           error_setg(errp, "post-save for %s failed, ret: %d",
> >                      vmsd->name, ret);
> > 
> 
Regards,
Arun


Reply via email to