@samitouri / QOSamiQemu / commits / e37df09677

migration: Propagate errors in migration_completion_precopy()

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. Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Reviewed-by: Peter Xu <peterx@redhat.com> Signed-off-by: Avihai Horon <avihaih@nvidia.com> Link: https://lore.kernel.org/qemu-devel/20260706085211.13905-2-avihaih@nvidia.com Signed-off-by: Cédric Le Goater <clg@redhat.com>

Avihai Horon committed Jul 6, 2026 at 11:51 UTC e37df09677b819746a8190c76a7d1f9942562f33
3 files changed +26 -18
migration/migration.c
+8 -5
@@ -2820,7 +2820,7 @@ static bool migration_switchover_start(MigrationState *s, Error **errp)
2820 return true;
2821 }
2822
2823 -static int migration_completion_precopy(MigrationState *s)
2823 +static int migration_completion_precopy(MigrationState *s, Error **errp)
2824 {
2825 int ret;
2826
@@ -2829,16 +2829,17 @@ static int migration_completion_precopy(MigrationState *s)
2829 if (!migrate_mode_is_cpr()) {
2830 ret = migration_stop_vm(s, RUN_STATE_FINISH_MIGRATE);
2831 if (ret < 0) {
2832 + error_setg_errno(errp, -ret, "Failed to stop the VM");
2833 goto out_unlock;
2834 }
2835 }
2836
2836 - if (!migration_switchover_start(s, NULL)) {
2837 + if (!migration_switchover_start(s, errp)) {
2838 ret = -EFAULT;
2839 goto out_unlock;
2840 }
2841
2841 - ret = qemu_savevm_state_complete_precopy(s);
2842 + ret = qemu_savevm_state_complete_precopy(s, errp);
2843 out_unlock:
2844 bql_unlock();
2845 return ret;
@@ -2875,7 +2876,7 @@ static void migration_completion(MigrationState *s)
2876 Error *local_err = NULL;
2877
2878 if (s->state == MIGRATION_STATUS_ACTIVE) {
2878 - ret = migration_completion_precopy(s);
2879 + ret = migration_completion_precopy(s, &local_err);
2880 } else if (s->state == MIGRATION_STATUS_POSTCOPY_ACTIVE) {
2881 migration_completion_postcopy(s);
2882 } else {
@@ -2906,7 +2907,9 @@ static void migration_completion(MigrationState *s)
2907 return;
2908
2909 fail:
2909 - if (qemu_file_get_error_obj(s->to_dst_file, &local_err)) {
2910 + if (local_err) {
2911 + migrate_error_propagate(s, local_err);
2912 + } else if (qemu_file_get_error_obj(s->to_dst_file, &local_err)) {
2913 migrate_error_propagate(s, local_err);
2914 } else if (ret) {
2915 error_setg_errno(&local_err, -ret, "Error in migration completion");
migration/savevm.c
+17 -12
@@ -1771,28 +1771,34 @@ int qemu_savevm_state_non_iterable(QEMUFile *f, Error **errp)
1771 return 0;
1772 }
1773
1774 -int qemu_savevm_state_complete_precopy(MigrationState *s)
1774 +int qemu_savevm_state_complete_precopy(MigrationState *s, Error **errp)
1775 {
1776 + ERRP_GUARD();
1777 QEMUFile *f = s->to_dst_file;
1777 - Error *local_err = NULL;
1778 int ret;
1779
1780 ret = qemu_savevm_state_complete_precopy_iterable(f, false);
1781 if (ret) {
1782 + qemu_file_get_error_obj(f, errp);
1783 + error_prepend(errp, "Failed to save iterable device state: ");
1784 return ret;
1785 }
1786
1785 - /* TODO: pass error upper */
1786 - ret = qemu_savevm_state_non_iterable(f, &local_err);
1787 + ret = qemu_savevm_state_non_iterable(f, errp);
1788 if (ret) {
1788 - migrate_error_propagate(s, error_copy(local_err));
1789 - error_report_err(local_err);
1789 return ret;
1790 }
1791
1792 qemu_savevm_state_end_precopy(s, f);
1793
1795 - return qemu_fflush(f);
1794 + ret = qemu_fflush(f);
1795 + if (ret) {
1796 + qemu_file_get_error_obj(f, errp);
1797 + error_prepend(errp, "Failed to flush QEMUFile: ");
1798 + return ret;
1799 + }
1800 +
1801 + return 0;
1802 }
1803
1804 void qemu_savevm_query_pending(MigPendingData *pending, bool exact)
@@ -1874,13 +1880,12 @@ static int qemu_savevm_state(QEMUFile *f, Error **errp)
1880 }
1881
1882 ret = qemu_file_get_error(f);
1877 - if (ret == 0) {
1878 - qemu_savevm_state_complete_precopy(ms);
1879 - ret = qemu_file_get_error(f);
1880 - }
1881 - if (ret != 0) {
1883 + if (ret) {
1884 error_setg_errno(errp, -ret, "Error while writing VM state");
1885 + goto cleanup;
1886 }
1887 +
1888 + ret = qemu_savevm_state_complete_precopy(ms, errp);
1889 cleanup:
1890 qemu_savevm_state_cleanup();
1891
migration/savevm.h
+1 -1
@@ -44,7 +44,7 @@ void qemu_savevm_state_header(QEMUFile *f);
44 int qemu_savevm_state_iterate(QEMUFile *f, bool postcopy);
45 void qemu_savevm_state_cleanup(void);
46 void qemu_savevm_state_complete_postcopy(QEMUFile *f);
47 -int qemu_savevm_state_complete_precopy(MigrationState *s);
47 +int qemu_savevm_state_complete_precopy(MigrationState *s, Error **errp);
48 void qemu_savevm_query_pending(MigPendingData *pending, bool exact);
49 int qemu_savevm_state_complete_precopy_iterable(QEMUFile *f, bool in_postcopy);
50 bool qemu_savevm_state_postcopy_prepare(QEMUFile *f, Error **errp);