[PATCH v3 01/14] migration: Propagate errors in migration_completion_precopy()

Avihai Horon posted 14 patches 2 months ago
Maintainers: Alex Williamson <alex@shazbot.org>, "Cédric Le Goater" <clg@redhat.com>, Peter Xu <peterx@redhat.com>, Fabiano Rosas <farosas@suse.de>, Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>, "Philippe Mathieu-Daudé" <philmd@mailo.com>, Zhao Liu <zhao1.liu@intel.com>, Halil Pasic <pasic@linux.ibm.com>, Christian Borntraeger <borntraeger@linux.ibm.com>, Jason Herne <jjherne@linux.ibm.com>, Richard Henderson <richard.henderson@linaro.org>, Ilya Leoshkevich <iii@linux.ibm.com>, David Hildenbrand <david@kernel.org>, Eric Farman <farman@linux.ibm.com>, Matthew Rosato <mjrosato@linux.ibm.com>, Cornelia Huck <cohuck@redhat.com>, Eric Blake <eblake@redhat.com>, Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>, John Snow <jsnow@redhat.com>, Markus Armbruster <armbru@redhat.com>
There is a newer version of this series
[PATCH v3 01/14] migration: Propagate errors in migration_completion_precopy()
Posted by Avihai Horon 2 months ago
migration_completion_precopy() doesn't propagate errors to migration
core which leads to error information loss. Fix that.

This prepares for a follow-up where migration_switchover_start() can
fail on switchover-ack and still report a useful error.

Signed-off-by: Avihai Horon <avihaih@nvidia.com>
---
 migration/savevm.h    |  2 +-
 migration/migration.c | 13 ++++++++-----
 migration/savevm.c    | 29 +++++++++++++++++------------
 3 files changed, 26 insertions(+), 18 deletions(-)

diff --git a/migration/savevm.h b/migration/savevm.h
index 96fdf96d4e..b6bb4fa977 100644
--- a/migration/savevm.h
+++ b/migration/savevm.h
@@ -44,7 +44,7 @@ void qemu_savevm_state_header(QEMUFile *f);
 int qemu_savevm_state_iterate(QEMUFile *f, bool postcopy);
 void qemu_savevm_state_cleanup(void);
 void qemu_savevm_state_complete_postcopy(QEMUFile *f);
-int qemu_savevm_state_complete_precopy(MigrationState *s);
+int qemu_savevm_state_complete_precopy(MigrationState *s, Error **errp);
 void qemu_savevm_query_pending(MigPendingData *pending, bool exact);
 int qemu_savevm_state_complete_precopy_iterable(QEMUFile *f, bool in_postcopy);
 bool qemu_savevm_state_postcopy_prepare(QEMUFile *f, Error **errp);
diff --git a/migration/migration.c b/migration/migration.c
index 074d3f2c69..aad23f3228 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -2814,7 +2814,7 @@ static bool migration_switchover_start(MigrationState *s, Error **errp)
     return true;
 }
 
-static int migration_completion_precopy(MigrationState *s)
+static int migration_completion_precopy(MigrationState *s, Error **errp)
 {
     int ret;
 
@@ -2823,16 +2823,17 @@ static int migration_completion_precopy(MigrationState *s)
     if (!migrate_mode_is_cpr()) {
         ret = migration_stop_vm(s, RUN_STATE_FINISH_MIGRATE);
         if (ret < 0) {
+            error_setg_errno(errp, -ret, "Failed to stop the VM");
             goto out_unlock;
         }
     }
 
-    if (!migration_switchover_start(s, NULL)) {
+    if (!migration_switchover_start(s, errp)) {
         ret = -EFAULT;
         goto out_unlock;
     }
 
-    ret = qemu_savevm_state_complete_precopy(s);
+    ret = qemu_savevm_state_complete_precopy(s, errp);
 out_unlock:
     bql_unlock();
     return ret;
@@ -2869,7 +2870,7 @@ static void migration_completion(MigrationState *s)
     Error *local_err = NULL;
 
     if (s->state == MIGRATION_STATUS_ACTIVE) {
-        ret = migration_completion_precopy(s);
+        ret = migration_completion_precopy(s, &local_err);
     } else if (s->state == MIGRATION_STATUS_POSTCOPY_ACTIVE) {
         migration_completion_postcopy(s);
     } else {
@@ -2900,7 +2901,9 @@ static void migration_completion(MigrationState *s)
     return;
 
 fail:
-    if (qemu_file_get_error_obj(s->to_dst_file, &local_err)) {
+    if (local_err) {
+        migrate_error_propagate(s, local_err);
+    } else if (qemu_file_get_error_obj(s->to_dst_file, &local_err)) {
         migrate_error_propagate(s, local_err);
     } else if (ret) {
         error_setg_errno(&local_err, -ret, "Error in migration completion");
diff --git a/migration/savevm.c b/migration/savevm.c
index 23adaf9dd9..9d1d58c8f4 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -1771,28 +1771,34 @@ int qemu_savevm_state_non_iterable(QEMUFile *f, Error **errp)
     return 0;
 }
 
-int qemu_savevm_state_complete_precopy(MigrationState *s)
+int qemu_savevm_state_complete_precopy(MigrationState *s, Error **errp)
 {
+    ERRP_GUARD();
     QEMUFile *f = s->to_dst_file;
-    Error *local_err = NULL;
     int ret;
 
     ret = qemu_savevm_state_complete_precopy_iterable(f, false);
     if (ret) {
+        qemu_file_get_error_obj(f, errp);
+        error_prepend(errp, "Failed to save iterable device state: ");
         return ret;
     }
 
-    /* TODO: pass error upper */
-    ret = qemu_savevm_state_non_iterable(f, &local_err);
+    ret = qemu_savevm_state_non_iterable(f, errp);
     if (ret) {
-        migrate_error_propagate(s, error_copy(local_err));
-        error_report_err(local_err);
         return ret;
     }
 
     qemu_savevm_state_end_precopy(s, f);
 
-    return qemu_fflush(f);
+    ret = qemu_fflush(f);
+    if (ret) {
+        qemu_file_get_error_obj(f, errp);
+        error_prepend(errp, "%s: Failed to flush QEMUFile", __func__);
+        return ret;
+    }
+
+    return 0;
 }
 
 void qemu_savevm_query_pending(MigPendingData *pending, bool exact)
@@ -1874,13 +1880,12 @@ static int qemu_savevm_state(QEMUFile *f, Error **errp)
     }
 
     ret = qemu_file_get_error(f);
-    if (ret == 0) {
-        qemu_savevm_state_complete_precopy(ms);
-        ret = qemu_file_get_error(f);
-    }
-    if (ret != 0) {
+    if (ret) {
         error_setg_errno(errp, -ret, "Error while writing VM state");
+        goto cleanup;
     }
+
+    ret = qemu_savevm_state_complete_precopy(ms, errp);
 cleanup:
     qemu_savevm_state_cleanup();
 
-- 
2.40.1
Re: [PATCH v3 01/14] migration: Propagate errors in migration_completion_precopy()
Posted by Philippe Mathieu-Daudé 2 months ago
On 9/6/26 09:57, Avihai Horon wrote:
> migration_completion_precopy() doesn't propagate errors to migration
> core which leads to error information loss. Fix that.
> 
> This prepares for a follow-up where migration_switchover_start() can
> fail on switchover-ack and still report a useful error.
> 
> Signed-off-by: Avihai Horon <avihaih@nvidia.com>
> ---
>   migration/savevm.h    |  2 +-
>   migration/migration.c | 13 ++++++++-----
>   migration/savevm.c    | 29 +++++++++++++++++------------
>   3 files changed, 26 insertions(+), 18 deletions(-)
> 
> diff --git a/migration/savevm.h b/migration/savevm.h
> index 96fdf96d4e..b6bb4fa977 100644
> --- a/migration/savevm.h
> +++ b/migration/savevm.h
> @@ -44,7 +44,7 @@ void qemu_savevm_state_header(QEMUFile *f);
>   int qemu_savevm_state_iterate(QEMUFile *f, bool postcopy);
>   void qemu_savevm_state_cleanup(void);
>   void qemu_savevm_state_complete_postcopy(QEMUFile *f);
> -int qemu_savevm_state_complete_precopy(MigrationState *s);
> +int qemu_savevm_state_complete_precopy(MigrationState *s, Error **errp);
>   void qemu_savevm_query_pending(MigPendingData *pending, bool exact);
>   int qemu_savevm_state_complete_precopy_iterable(QEMUFile *f, bool in_postcopy);
>   bool qemu_savevm_state_postcopy_prepare(QEMUFile *f, Error **errp);
> diff --git a/migration/migration.c b/migration/migration.c
> index 074d3f2c69..aad23f3228 100644
> --- a/migration/migration.c
> +++ b/migration/migration.c
> @@ -2814,7 +2814,7 @@ static bool migration_switchover_start(MigrationState *s, Error **errp)
>       return true;
>   }
>   
> -static int migration_completion_precopy(MigrationState *s)
> +static int migration_completion_precopy(MigrationState *s, Error **errp)
>   {
>       int ret;
>   
> @@ -2823,16 +2823,17 @@ static int migration_completion_precopy(MigrationState *s)
>       if (!migrate_mode_is_cpr()) {
>           ret = migration_stop_vm(s, RUN_STATE_FINISH_MIGRATE);
>           if (ret < 0) {
> +            error_setg_errno(errp, -ret, "Failed to stop the VM");
>               goto out_unlock;
>           }
>       }
>   
> -    if (!migration_switchover_start(s, NULL)) {
> +    if (!migration_switchover_start(s, errp)) {
>           ret = -EFAULT;

This function should now returns a boolean IMHO.

>           goto out_unlock;
>       }
>   
> -    ret = qemu_savevm_state_complete_precopy(s);
> +    ret = qemu_savevm_state_complete_precopy(s, errp);
>   out_unlock:
>       bql_unlock();
>       return ret;
> @@ -2869,7 +2870,7 @@ static void migration_completion(MigrationState *s)
>       Error *local_err = NULL;
>   
>       if (s->state == MIGRATION_STATUS_ACTIVE) {
> -        ret = migration_completion_precopy(s);
> +        ret = migration_completion_precopy(s, &local_err);
>       } else if (s->state == MIGRATION_STATUS_POSTCOPY_ACTIVE) {
>           migration_completion_postcopy(s);
>       } else {
> @@ -2900,7 +2901,9 @@ static void migration_completion(MigrationState *s)
>       return;
>   
>   fail:
> -    if (qemu_file_get_error_obj(s->to_dst_file, &local_err)) {
> +    if (local_err) {
> +        migrate_error_propagate(s, local_err);
> +    } else if (qemu_file_get_error_obj(s->to_dst_file, &local_err)) {

   if (local_err
       || qemu_file_get_error_obj(s->to_dst_file, &local_err)) {

>           migrate_error_propagate(s, local_err);
>       } else if (ret) {
>           error_setg_errno(&local_err, -ret, "Error in migration completion");
> diff --git a/migration/savevm.c b/migration/savevm.c
> index 23adaf9dd9..9d1d58c8f4 100644
> --- a/migration/savevm.c
> +++ b/migration/savevm.c
> @@ -1771,28 +1771,34 @@ int qemu_savevm_state_non_iterable(QEMUFile *f, Error **errp)
>       return 0;
>   }
>   
> -int qemu_savevm_state_complete_precopy(MigrationState *s)
> +int qemu_savevm_state_complete_precopy(MigrationState *s, Error **errp)
>   {
> +    ERRP_GUARD();
>       QEMUFile *f = s->to_dst_file;
> -    Error *local_err = NULL;
>       int ret;
>   
>       ret = qemu_savevm_state_complete_precopy_iterable(f, false);
>       if (ret) {
> +        qemu_file_get_error_obj(f, errp);
> +        error_prepend(errp, "Failed to save iterable device state: ");
>           return ret;
>       }
>   
> -    /* TODO: pass error upper */
> -    ret = qemu_savevm_state_non_iterable(f, &local_err);
> +    ret = qemu_savevm_state_non_iterable(f, errp);
>       if (ret) {
> -        migrate_error_propagate(s, error_copy(local_err));
> -        error_report_err(local_err);
>           return ret;
>       }
>   
>       qemu_savevm_state_end_precopy(s, f);
>   
> -    return qemu_fflush(f);
> +    ret = qemu_fflush(f);
> +    if (ret) {
> +        qemu_file_get_error_obj(f, errp);
> +        error_prepend(errp, "%s: Failed to flush QEMUFile", __func__);

Ditto, directly return boolean.

Anyway can be done on top, so:
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>

> +        return ret;
> +    }
> +
> +    return 0;
>   }
>   
>   void qemu_savevm_query_pending(MigPendingData *pending, bool exact)
> @@ -1874,13 +1880,12 @@ static int qemu_savevm_state(QEMUFile *f, Error **errp)
>       }
>   
>       ret = qemu_file_get_error(f);
> -    if (ret == 0) {
> -        qemu_savevm_state_complete_precopy(ms);
> -        ret = qemu_file_get_error(f);
> -    }
> -    if (ret != 0) {
> +    if (ret) {
>           error_setg_errno(errp, -ret, "Error while writing VM state");
> +        goto cleanup;
>       }
> +
> +    ret = qemu_savevm_state_complete_precopy(ms, errp);
>   cleanup:
>       qemu_savevm_state_cleanup();
>   


Re: [PATCH v3 01/14] migration: Propagate errors in migration_completion_precopy()
Posted by Peter Xu 2 months ago
On Tue, Jun 09, 2026 at 02:11:00PM +0200, Philippe Mathieu-Daudé wrote:
> On 9/6/26 09:57, Avihai Horon wrote:
> > migration_completion_precopy() doesn't propagate errors to migration
> > core which leads to error information loss. Fix that.
> > 
> > This prepares for a follow-up where migration_switchover_start() can
> > fail on switchover-ack and still report a useful error.
> > 
> > Signed-off-by: Avihai Horon <avihaih@nvidia.com>
> > ---
> >   migration/savevm.h    |  2 +-
> >   migration/migration.c | 13 ++++++++-----
> >   migration/savevm.c    | 29 +++++++++++++++++------------
> >   3 files changed, 26 insertions(+), 18 deletions(-)
> > 
> > diff --git a/migration/savevm.h b/migration/savevm.h
> > index 96fdf96d4e..b6bb4fa977 100644
> > --- a/migration/savevm.h
> > +++ b/migration/savevm.h
> > @@ -44,7 +44,7 @@ void qemu_savevm_state_header(QEMUFile *f);
> >   int qemu_savevm_state_iterate(QEMUFile *f, bool postcopy);
> >   void qemu_savevm_state_cleanup(void);
> >   void qemu_savevm_state_complete_postcopy(QEMUFile *f);
> > -int qemu_savevm_state_complete_precopy(MigrationState *s);
> > +int qemu_savevm_state_complete_precopy(MigrationState *s, Error **errp);
> >   void qemu_savevm_query_pending(MigPendingData *pending, bool exact);
> >   int qemu_savevm_state_complete_precopy_iterable(QEMUFile *f, bool in_postcopy);
> >   bool qemu_savevm_state_postcopy_prepare(QEMUFile *f, Error **errp);
> > diff --git a/migration/migration.c b/migration/migration.c
> > index 074d3f2c69..aad23f3228 100644
> > --- a/migration/migration.c
> > +++ b/migration/migration.c
> > @@ -2814,7 +2814,7 @@ static bool migration_switchover_start(MigrationState *s, Error **errp)
> >       return true;
> >   }
> > -static int migration_completion_precopy(MigrationState *s)
> > +static int migration_completion_precopy(MigrationState *s, Error **errp)
> >   {
> >       int ret;
> > @@ -2823,16 +2823,17 @@ static int migration_completion_precopy(MigrationState *s)
> >       if (!migrate_mode_is_cpr()) {
> >           ret = migration_stop_vm(s, RUN_STATE_FINISH_MIGRATE);
> >           if (ret < 0) {
> > +            error_setg_errno(errp, -ret, "Failed to stop the VM");
> >               goto out_unlock;
> >           }
> >       }
> > -    if (!migration_switchover_start(s, NULL)) {
> > +    if (!migration_switchover_start(s, errp)) {
> >           ret = -EFAULT;
> 
> This function should now returns a boolean IMHO.
> 
> >           goto out_unlock;
> >       }
> > -    ret = qemu_savevm_state_complete_precopy(s);
> > +    ret = qemu_savevm_state_complete_precopy(s, errp);
> >   out_unlock:
> >       bql_unlock();
> >       return ret;
> > @@ -2869,7 +2870,7 @@ static void migration_completion(MigrationState *s)
> >       Error *local_err = NULL;
> >       if (s->state == MIGRATION_STATUS_ACTIVE) {
> > -        ret = migration_completion_precopy(s);
> > +        ret = migration_completion_precopy(s, &local_err);
> >       } else if (s->state == MIGRATION_STATUS_POSTCOPY_ACTIVE) {
> >           migration_completion_postcopy(s);
> >       } else {
> > @@ -2900,7 +2901,9 @@ static void migration_completion(MigrationState *s)
> >       return;
> >   fail:
> > -    if (qemu_file_get_error_obj(s->to_dst_file, &local_err)) {
> > +    if (local_err) {
> > +        migrate_error_propagate(s, local_err);
> > +    } else if (qemu_file_get_error_obj(s->to_dst_file, &local_err)) {
> 
>   if (local_err
>       || qemu_file_get_error_obj(s->to_dst_file, &local_err)) {
> 
> >           migrate_error_propagate(s, local_err);
> >       } else if (ret) {
> >           error_setg_errno(&local_err, -ret, "Error in migration completion");
> > diff --git a/migration/savevm.c b/migration/savevm.c
> > index 23adaf9dd9..9d1d58c8f4 100644
> > --- a/migration/savevm.c
> > +++ b/migration/savevm.c
> > @@ -1771,28 +1771,34 @@ int qemu_savevm_state_non_iterable(QEMUFile *f, Error **errp)
> >       return 0;
> >   }
> > -int qemu_savevm_state_complete_precopy(MigrationState *s)
> > +int qemu_savevm_state_complete_precopy(MigrationState *s, Error **errp)
> >   {
> > +    ERRP_GUARD();
> >       QEMUFile *f = s->to_dst_file;
> > -    Error *local_err = NULL;
> >       int ret;
> >       ret = qemu_savevm_state_complete_precopy_iterable(f, false);
> >       if (ret) {
> > +        qemu_file_get_error_obj(f, errp);
> > +        error_prepend(errp, "Failed to save iterable device state: ");
> >           return ret;
> >       }
> > -    /* TODO: pass error upper */
> > -    ret = qemu_savevm_state_non_iterable(f, &local_err);
> > +    ret = qemu_savevm_state_non_iterable(f, errp);
> >       if (ret) {
> > -        migrate_error_propagate(s, error_copy(local_err));
> > -        error_report_err(local_err);
> >           return ret;
> >       }
> >       qemu_savevm_state_end_precopy(s, f);
> > -    return qemu_fflush(f);
> > +    ret = qemu_fflush(f);
> > +    if (ret) {
> > +        qemu_file_get_error_obj(f, errp);
> > +        error_prepend(errp, "%s: Failed to flush QEMUFile", __func__);
> 
> Ditto, directly return boolean.
> 
> Anyway can be done on top, so:

Agreed, I didn't mention this because I know touching the retval needs
further touch callers.  Can be done on top.

> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>

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

-- 
Peter Xu


Re: [PATCH v3 01/14] migration: Propagate errors in migration_completion_precopy()
Posted by Avihai Horon 2 months ago
On 6/12/2026 7:03 PM, Peter Xu wrote:
> External email: Use caution opening links or attachments
>
>
> On Tue, Jun 09, 2026 at 02:11:00PM +0200, Philippe Mathieu-Daudé wrote:
>> On 9/6/26 09:57, Avihai Horon wrote:
>>> migration_completion_precopy() doesn't propagate errors to migration
>>> core which leads to error information loss. Fix that.
>>>
>>> This prepares for a follow-up where migration_switchover_start() can
>>> fail on switchover-ack and still report a useful error.
>>>
>>> Signed-off-by: Avihai Horon <avihaih@nvidia.com>
>>> ---
>>>    migration/savevm.h    |  2 +-
>>>    migration/migration.c | 13 ++++++++-----
>>>    migration/savevm.c    | 29 +++++++++++++++++------------
>>>    3 files changed, 26 insertions(+), 18 deletions(-)
>>>
>>> diff --git a/migration/savevm.h b/migration/savevm.h
>>> index 96fdf96d4e..b6bb4fa977 100644
>>> --- a/migration/savevm.h
>>> +++ b/migration/savevm.h
>>> @@ -44,7 +44,7 @@ void qemu_savevm_state_header(QEMUFile *f);
>>>    int qemu_savevm_state_iterate(QEMUFile *f, bool postcopy);
>>>    void qemu_savevm_state_cleanup(void);
>>>    void qemu_savevm_state_complete_postcopy(QEMUFile *f);
>>> -int qemu_savevm_state_complete_precopy(MigrationState *s);
>>> +int qemu_savevm_state_complete_precopy(MigrationState *s, Error **errp);
>>>    void qemu_savevm_query_pending(MigPendingData *pending, bool exact);
>>>    int qemu_savevm_state_complete_precopy_iterable(QEMUFile *f, bool in_postcopy);
>>>    bool qemu_savevm_state_postcopy_prepare(QEMUFile *f, Error **errp);
>>> diff --git a/migration/migration.c b/migration/migration.c
>>> index 074d3f2c69..aad23f3228 100644
>>> --- a/migration/migration.c
>>> +++ b/migration/migration.c
>>> @@ -2814,7 +2814,7 @@ static bool migration_switchover_start(MigrationState *s, Error **errp)
>>>        return true;
>>>    }
>>> -static int migration_completion_precopy(MigrationState *s)
>>> +static int migration_completion_precopy(MigrationState *s, Error **errp)
>>>    {
>>>        int ret;
>>> @@ -2823,16 +2823,17 @@ static int migration_completion_precopy(MigrationState *s)
>>>        if (!migrate_mode_is_cpr()) {
>>>            ret = migration_stop_vm(s, RUN_STATE_FINISH_MIGRATE);
>>>            if (ret < 0) {
>>> +            error_setg_errno(errp, -ret, "Failed to stop the VM");
>>>                goto out_unlock;
>>>            }
>>>        }
>>> -    if (!migration_switchover_start(s, NULL)) {
>>> +    if (!migration_switchover_start(s, errp)) {
>>>            ret = -EFAULT;
>> This function should now returns a boolean IMHO.
>>
>>>            goto out_unlock;
>>>        }
>>> -    ret = qemu_savevm_state_complete_precopy(s);
>>> +    ret = qemu_savevm_state_complete_precopy(s, errp);
>>>    out_unlock:
>>>        bql_unlock();
>>>        return ret;
>>> @@ -2869,7 +2870,7 @@ static void migration_completion(MigrationState *s)
>>>        Error *local_err = NULL;
>>>        if (s->state == MIGRATION_STATUS_ACTIVE) {
>>> -        ret = migration_completion_precopy(s);
>>> +        ret = migration_completion_precopy(s, &local_err);
>>>        } else if (s->state == MIGRATION_STATUS_POSTCOPY_ACTIVE) {
>>>            migration_completion_postcopy(s);
>>>        } else {
>>> @@ -2900,7 +2901,9 @@ static void migration_completion(MigrationState *s)
>>>        return;
>>>    fail:
>>> -    if (qemu_file_get_error_obj(s->to_dst_file, &local_err)) {
>>> +    if (local_err) {
>>> +        migrate_error_propagate(s, local_err);
>>> +    } else if (qemu_file_get_error_obj(s->to_dst_file, &local_err)) {
>>    if (local_err
>>        || qemu_file_get_error_obj(s->to_dst_file, &local_err)) {
>>
>>>            migrate_error_propagate(s, local_err);
>>>        } else if (ret) {
>>>            error_setg_errno(&local_err, -ret, "Error in migration completion");
>>> diff --git a/migration/savevm.c b/migration/savevm.c
>>> index 23adaf9dd9..9d1d58c8f4 100644
>>> --- a/migration/savevm.c
>>> +++ b/migration/savevm.c
>>> @@ -1771,28 +1771,34 @@ int qemu_savevm_state_non_iterable(QEMUFile *f, Error **errp)
>>>        return 0;
>>>    }
>>> -int qemu_savevm_state_complete_precopy(MigrationState *s)
>>> +int qemu_savevm_state_complete_precopy(MigrationState *s, Error **errp)
>>>    {
>>> +    ERRP_GUARD();
>>>        QEMUFile *f = s->to_dst_file;
>>> -    Error *local_err = NULL;
>>>        int ret;
>>>        ret = qemu_savevm_state_complete_precopy_iterable(f, false);
>>>        if (ret) {
>>> +        qemu_file_get_error_obj(f, errp);
>>> +        error_prepend(errp, "Failed to save iterable device state: ");
>>>            return ret;
>>>        }
>>> -    /* TODO: pass error upper */
>>> -    ret = qemu_savevm_state_non_iterable(f, &local_err);
>>> +    ret = qemu_savevm_state_non_iterable(f, errp);
>>>        if (ret) {
>>> -        migrate_error_propagate(s, error_copy(local_err));
>>> -        error_report_err(local_err);
>>>            return ret;
>>>        }
>>>        qemu_savevm_state_end_precopy(s, f);
>>> -    return qemu_fflush(f);
>>> +    ret = qemu_fflush(f);
>>> +    if (ret) {
>>> +        qemu_file_get_error_obj(f, errp);
>>> +        error_prepend(errp, "%s: Failed to flush QEMUFile", __func__);
>> Ditto, directly return boolean.
>>
>> Anyway can be done on top, so:
> Agreed, I didn't mention this because I know touching the retval needs
> further touch callers.  Can be done on top.

Sure, I can send a patch for that later.

Thanks.

>
>> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
> Reviewed-by: Peter Xu <peterx@redhat.com>
>
> --
> Peter Xu
>