Parcourir la source

Merge remote-tracking branch 'remotes/juanquintela/tags/migration/20170206' into staging

migration/next for 20170206

# gpg: Signature made Mon 06 Feb 2017 16:13:26 GMT
# gpg:                using RSA key 0xF487EF185872D723
# gpg: Good signature from "Juan Quintela <quintela@redhat.com>"
# gpg:                 aka "Juan Quintela <quintela@trasno.org>"
# Primary key fingerprint: 1899 FF8E DEBF 58CC EE03  4B82 F487 EF18 5872 D723

* remotes/juanquintela/tags/migration/20170206:
  postcopy: Recover block devices on early failure
  Postcopy: Reset state to avoid cleanup assert
  vmstate registration: check return values
  migration: Check for ID length
  vmstate_register_with_alias_id: Take an Error **
  migration: create Migration Incoming State at init time

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Peter Maydell il y a 8 ans
Parent
commit
d0dff238a8

+ 6 - 3
hw/core/qdev.c

@@ -933,9 +933,12 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
         }
         }
 
 
         if (qdev_get_vmsd(dev)) {
         if (qdev_get_vmsd(dev)) {
-            vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
-                                           dev->instance_id_alias,
-                                           dev->alias_required_for_version);
+            if (vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
+                                               dev->instance_id_alias,
+                                               dev->alias_required_for_version,
+                                               &local_err) < 0) {
+                goto post_realize_fail;
+            }
         }
         }
 
 
         QLIST_FOREACH(bus, &dev->child_bus, sibling) {
         QLIST_FOREACH(bus, &dev->child_bus, sibling) {

+ 1 - 1
hw/intc/apic_common.c

@@ -329,7 +329,7 @@ static void apic_common_realize(DeviceState *dev, Error **errp)
         instance_id = -1;
         instance_id = -1;
     }
     }
     vmstate_register_with_alias_id(NULL, instance_id, &vmstate_apic_common,
     vmstate_register_with_alias_id(NULL, instance_id, &vmstate_apic_common,
-                                   s, -1, 0);
+                                   s, -1, 0, NULL);
 }
 }
 
 
 static void apic_common_unrealize(DeviceState *dev, Error **errp)
 static void apic_common_unrealize(DeviceState *dev, Error **errp)

+ 0 - 1
include/migration/migration.h

@@ -122,7 +122,6 @@ struct MigrationIncomingState {
 };
 };
 
 
 MigrationIncomingState *migration_incoming_get_current(void);
 MigrationIncomingState *migration_incoming_get_current(void);
-MigrationIncomingState *migration_incoming_state_new(QEMUFile *f);
 void migration_incoming_state_destroy(void);
 void migration_incoming_state_destroy(void);
 
 
 /*
 /*

+ 5 - 2
include/migration/vmstate.h

@@ -985,17 +985,20 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
 
 
 bool vmstate_save_needed(const VMStateDescription *vmsd, void *opaque);
 bool vmstate_save_needed(const VMStateDescription *vmsd, void *opaque);
 
 
+/* Returns: 0 on success, -1 on failure */
 int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
 int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
                                    const VMStateDescription *vmsd,
                                    const VMStateDescription *vmsd,
                                    void *base, int alias_id,
                                    void *base, int alias_id,
-                                   int required_for_version);
+                                   int required_for_version,
+                                   Error **errp);
 
 
+/* Returns: 0 on success, -1 on failure */
 static inline int vmstate_register(DeviceState *dev, int instance_id,
 static inline int vmstate_register(DeviceState *dev, int instance_id,
                                    const VMStateDescription *vmsd,
                                    const VMStateDescription *vmsd,
                                    void *opaque)
                                    void *opaque)
 {
 {
     return vmstate_register_with_alias_id(dev, instance_id, vmsd,
     return vmstate_register_with_alias_id(dev, instance_id, vmsd,
-                                          opaque, -1, 0);
+                                          opaque, -1, 0, NULL);
 }
 }
 
 
 void vmstate_unregister(DeviceState *dev, const VMStateDescription *vmsd,
 void vmstate_unregister(DeviceState *dev, const VMStateDescription *vmsd,

+ 42 - 21
migration/migration.c

@@ -111,32 +111,28 @@ MigrationState *migrate_get_current(void)
     return &current_migration;
     return &current_migration;
 }
 }
 
 
-/* For incoming */
-static MigrationIncomingState *mis_current;
-
 MigrationIncomingState *migration_incoming_get_current(void)
 MigrationIncomingState *migration_incoming_get_current(void)
 {
 {
-    return mis_current;
-}
-
-MigrationIncomingState *migration_incoming_state_new(QEMUFile* f)
-{
-    mis_current = g_new0(MigrationIncomingState, 1);
-    mis_current->from_src_file = f;
-    mis_current->state = MIGRATION_STATUS_NONE;
-    QLIST_INIT(&mis_current->loadvm_handlers);
-    qemu_mutex_init(&mis_current->rp_mutex);
-    qemu_event_init(&mis_current->main_thread_load_event, false);
+    static bool once;
+    static MigrationIncomingState mis_current;
 
 
-    return mis_current;
+    if (!once) {
+        mis_current.state = MIGRATION_STATUS_NONE;
+        memset(&mis_current, 0, sizeof(MigrationIncomingState));
+        QLIST_INIT(&mis_current.loadvm_handlers);
+        qemu_mutex_init(&mis_current.rp_mutex);
+        qemu_event_init(&mis_current.main_thread_load_event, false);
+        once = true;
+    }
+    return &mis_current;
 }
 }
 
 
 void migration_incoming_state_destroy(void)
 void migration_incoming_state_destroy(void)
 {
 {
-    qemu_event_destroy(&mis_current->main_thread_load_event);
-    loadvm_free_handlers(mis_current);
-    g_free(mis_current);
-    mis_current = NULL;
+    struct MigrationIncomingState *mis = migration_incoming_get_current();
+
+    qemu_event_destroy(&mis->main_thread_load_event);
+    loadvm_free_handlers(mis);
 }
 }
 
 
 
 
@@ -382,11 +378,11 @@ static void process_incoming_migration_bh(void *opaque)
 static void process_incoming_migration_co(void *opaque)
 static void process_incoming_migration_co(void *opaque)
 {
 {
     QEMUFile *f = opaque;
     QEMUFile *f = opaque;
-    MigrationIncomingState *mis;
+    MigrationIncomingState *mis = migration_incoming_get_current();
     PostcopyState ps;
     PostcopyState ps;
     int ret;
     int ret;
 
 
-    mis = migration_incoming_state_new(f);
+    mis->from_src_file = f;
     postcopy_state_set(POSTCOPY_INCOMING_NONE);
     postcopy_state_set(POSTCOPY_INCOMING_NONE);
     migrate_set_state(&mis->state, MIGRATION_STATUS_NONE,
     migrate_set_state(&mis->state, MIGRATION_STATUS_NONE,
                       MIGRATION_STATUS_ACTIVE);
                       MIGRATION_STATUS_ACTIVE);
@@ -1605,6 +1601,7 @@ static int postcopy_start(MigrationState *ms, bool *old_vm_running)
     QIOChannelBuffer *bioc;
     QIOChannelBuffer *bioc;
     QEMUFile *fb;
     QEMUFile *fb;
     int64_t time_at_stop = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
     int64_t time_at_stop = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
+    bool restart_block = false;
     migrate_set_state(&ms->state, MIGRATION_STATUS_ACTIVE,
     migrate_set_state(&ms->state, MIGRATION_STATUS_ACTIVE,
                       MIGRATION_STATUS_POSTCOPY_ACTIVE);
                       MIGRATION_STATUS_POSTCOPY_ACTIVE);
 
 
@@ -1624,6 +1621,7 @@ static int postcopy_start(MigrationState *ms, bool *old_vm_running)
     if (ret < 0) {
     if (ret < 0) {
         goto fail;
         goto fail;
     }
     }
+    restart_block = true;
 
 
     /*
     /*
      * Cause any non-postcopiable, but iterative devices to
      * Cause any non-postcopiable, but iterative devices to
@@ -1680,6 +1678,18 @@ static int postcopy_start(MigrationState *ms, bool *old_vm_running)
 
 
     /* <><> end of stuff going into the package */
     /* <><> end of stuff going into the package */
 
 
+    /* Last point of recovery; as soon as we send the package the destination
+     * can open devices and potentially start running.
+     * Lets just check again we've not got any errors.
+     */
+    ret = qemu_file_get_error(ms->to_dst_file);
+    if (ret) {
+        error_report("postcopy_start: Migration stream errored (pre package)");
+        goto fail_closefb;
+    }
+
+    restart_block = false;
+
     /* Now send that blob */
     /* Now send that blob */
     if (qemu_savevm_send_packaged(ms->to_dst_file, bioc->data, bioc->usage)) {
     if (qemu_savevm_send_packaged(ms->to_dst_file, bioc->data, bioc->usage)) {
         goto fail_closefb;
         goto fail_closefb;
@@ -1717,6 +1727,17 @@ fail_closefb:
 fail:
 fail:
     migrate_set_state(&ms->state, MIGRATION_STATUS_POSTCOPY_ACTIVE,
     migrate_set_state(&ms->state, MIGRATION_STATUS_POSTCOPY_ACTIVE,
                           MIGRATION_STATUS_FAILED);
                           MIGRATION_STATUS_FAILED);
+    if (restart_block) {
+        /* A failure happened early enough that we know the destination hasn't
+         * accessed block devices, so we're safe to recover.
+         */
+        Error *local_err = NULL;
+
+        bdrv_invalidate_cache_all(&local_err);
+        if (local_err) {
+            error_report_err(local_err);
+        }
+    }
     qemu_mutex_unlock_iothread();
     qemu_mutex_unlock_iothread();
     return -1;
     return -1;
 }
 }

+ 21 - 8
migration/savevm.c

@@ -590,8 +590,14 @@ int register_savevm_live(DeviceState *dev,
     if (dev) {
     if (dev) {
         char *id = qdev_get_dev_path(dev);
         char *id = qdev_get_dev_path(dev);
         if (id) {
         if (id) {
-            pstrcpy(se->idstr, sizeof(se->idstr), id);
-            pstrcat(se->idstr, sizeof(se->idstr), "/");
+            if (snprintf(se->idstr, sizeof(se->idstr), "%s/", id) >=
+                sizeof(se->idstr)) {
+                error_report("Path too long for VMState (%s)", id);
+                g_free(id);
+                g_free(se);
+
+                return -1;
+            }
             g_free(id);
             g_free(id);
 
 
             se->compat = g_new0(CompatEntry, 1);
             se->compat = g_new0(CompatEntry, 1);
@@ -656,7 +662,8 @@ void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque)
 int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
 int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
                                    const VMStateDescription *vmsd,
                                    const VMStateDescription *vmsd,
                                    void *opaque, int alias_id,
                                    void *opaque, int alias_id,
-                                   int required_for_version)
+                                   int required_for_version,
+                                   Error **errp)
 {
 {
     SaveStateEntry *se;
     SaveStateEntry *se;
 
 
@@ -673,9 +680,14 @@ int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
     if (dev) {
     if (dev) {
         char *id = qdev_get_dev_path(dev);
         char *id = qdev_get_dev_path(dev);
         if (id) {
         if (id) {
-            pstrcpy(se->idstr, sizeof(se->idstr), id);
-            pstrcat(se->idstr, sizeof(se->idstr), "/");
-            g_free(id);
+            if (snprintf(se->idstr, sizeof(se->idstr), "%s/", id) >=
+                sizeof(se->idstr)) {
+                error_setg(errp, "Path too long for VMState (%s)", id);
+                g_free(id);
+                g_free(se);
+
+                return -1;
+            }
 
 
             se->compat = g_new0(CompatEntry, 1);
             se->compat = g_new0(CompatEntry, 1);
             pstrcpy(se->compat->idstr, sizeof(se->compat->idstr), vmsd->name);
             pstrcpy(se->compat->idstr, sizeof(se->compat->idstr), vmsd->name);
@@ -1343,6 +1355,7 @@ static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis)
     }
     }
 
 
     if (!postcopy_ram_supported_by_host()) {
     if (!postcopy_ram_supported_by_host()) {
+        postcopy_state_set(POSTCOPY_INCOMING_NONE);
         return -1;
         return -1;
     }
     }
 
 
@@ -2199,7 +2212,6 @@ void qmp_xen_load_devices_state(const char *filename, Error **errp)
     qio_channel_set_name(QIO_CHANNEL(ioc), "migration-xen-load-state");
     qio_channel_set_name(QIO_CHANNEL(ioc), "migration-xen-load-state");
     f = qemu_fopen_channel_input(QIO_CHANNEL(ioc));
     f = qemu_fopen_channel_input(QIO_CHANNEL(ioc));
 
 
-    migration_incoming_state_new(f);
     ret = qemu_loadvm_state(f);
     ret = qemu_loadvm_state(f);
     qemu_fclose(f);
     qemu_fclose(f);
     if (ret < 0) {
     if (ret < 0) {
@@ -2215,6 +2227,7 @@ int load_vmstate(const char *name)
     QEMUFile *f;
     QEMUFile *f;
     int ret;
     int ret;
     AioContext *aio_context;
     AioContext *aio_context;
+    MigrationIncomingState *mis = migration_incoming_get_current();
 
 
     if (!bdrv_all_can_snapshot(&bs)) {
     if (!bdrv_all_can_snapshot(&bs)) {
         error_report("Device '%s' is writable but does not support snapshots.",
         error_report("Device '%s' is writable but does not support snapshots.",
@@ -2265,7 +2278,7 @@ int load_vmstate(const char *name)
     }
     }
 
 
     qemu_system_reset(VMRESET_SILENT);
     qemu_system_reset(VMRESET_SILENT);
-    migration_incoming_state_new(f);
+    mis->from_src_file = f;
 
 
     aio_context_acquire(aio_context);
     aio_context_acquire(aio_context);
     ret = qemu_loadvm_state(f);
     ret = qemu_loadvm_state(f);

+ 2 - 1
stubs/vmstate.c

@@ -8,7 +8,8 @@ int vmstate_register_with_alias_id(DeviceState *dev,
                                    int instance_id,
                                    int instance_id,
                                    const VMStateDescription *vmsd,
                                    const VMStateDescription *vmsd,
                                    void *base, int alias_id,
                                    void *base, int alias_id,
-                                   int required_for_version)
+                                   int required_for_version,
+                                   Error **errp)
 {
 {
     return 0;
     return 0;
 }
 }