]> git.proxmox.com Git - qemu.git/blobdiff - savevm.c
pci: Implement BusInfo.get_dev_path()
[qemu.git] / savevm.c
index 1125ef2d5382829264ff0985089c8f4a72b5a92b..f1f450edc4e4105a3864093686f3801246eb4455 100644 (file)
--- a/savevm.c
+++ b/savevm.c
 #include "sysemu.h"
 #include "qemu-timer.h"
 #include "qemu-char.h"
-#include "block.h"
+#include "blockdev.h"
 #include "audio/audio.h"
 #include "migration.h"
 #include "qemu_socket.h"
 #include "qemu-queue.h"
 
-/* point to the block driver where the snapshots are managed */
-static BlockDriverState *bs_snapshots;
-
 #define SELF_ANNOUNCE_ROUNDS 5
 
 #ifndef ETH_P_RARP
-#define ETH_P_RARP 0x0835
+#define ETH_P_RARP 0x8035
 #endif
 #define ARP_HTYPE_ETH 0x0001
 #define ARP_PTYPE_IP 0x0800
@@ -235,9 +232,10 @@ static int stdio_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
 static int stdio_pclose(void *opaque)
 {
     QEMUFileStdio *s = opaque;
-    pclose(s->stdio_file);
+    int ret;
+    ret = pclose(s->stdio_file);
     qemu_free(s);
-    return 0;
+    return ret;
 }
 
 static int stdio_fclose(void *opaque)
@@ -339,8 +337,7 @@ static int file_put_buffer(void *opaque, const uint8_t *buf,
 {
     QEMUFileStdio *s = opaque;
     fseek(s->stdio_file, pos, SEEK_SET);
-    fwrite(buf, 1, size, s->stdio_file);
-    return size;
+    return fwrite(buf, 1, size, s->stdio_file);
 }
 
 static int file_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
@@ -357,7 +354,7 @@ QEMUFile *qemu_fopen(const char *filename, const char *mode)
     if (mode == NULL ||
        (mode[0] != 'r' && mode[0] != 'w') ||
        mode[1] != 'b' || mode[2] != 0) {
-        fprintf(stderr, "qemu_fdopen: Argument validity check failed\n");
+        fprintf(stderr, "qemu_fopen: Argument validity check failed\n");
         return NULL;
     }
 
@@ -992,6 +989,7 @@ typedef struct SaveStateEntry {
     QTAILQ_ENTRY(SaveStateEntry) entry;
     char idstr[256];
     int instance_id;
+    int alias_id;
     int version_id;
     int section_id;
     SaveSetParamsHandler *set_params;
@@ -1080,11 +1078,16 @@ void unregister_savevm(const char *idstr, void *opaque)
     }
 }
 
-int vmstate_register(int instance_id, const VMStateDescription *vmsd,
-                     void *opaque)
+int vmstate_register_with_alias_id(int instance_id,
+                                   const VMStateDescription *vmsd,
+                                   void *opaque, int alias_id,
+                                   int required_for_version)
 {
     SaveStateEntry *se;
 
+    /* If this triggers, alias support can be dropped for the vmsd. */
+    assert(alias_id == -1 || required_for_version >= vmsd->minimum_version_id);
+
     se = qemu_mallocz(sizeof(SaveStateEntry));
     pstrcpy(se->idstr, sizeof(se->idstr), vmsd->name);
     se->version_id = vmsd->version_id;
@@ -1094,6 +1097,7 @@ int vmstate_register(int instance_id, const VMStateDescription *vmsd,
     se->load_state = NULL;
     se->opaque = opaque;
     se->vmsd = vmsd;
+    se->alias_id = alias_id;
 
     if (instance_id == -1) {
         se->instance_id = calculate_new_instance_id(vmsd->name);
@@ -1105,6 +1109,12 @@ int vmstate_register(int instance_id, const VMStateDescription *vmsd,
     return 0;
 }
 
+int vmstate_register(int instance_id, const VMStateDescription *vmsd,
+                     void *opaque)
+{
+    return vmstate_register_with_alias_id(instance_id, vmsd, opaque, -1, 0);
+}
+
 void vmstate_unregister(const VMStateDescription *vmsd, void *opaque)
 {
     SaveStateEntry *se, *new_se;
@@ -1147,6 +1157,9 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
 
             if (field->flags & VMS_VBUFFER) {
                 size = *(int32_t *)(opaque+field->size_offset);
+                if (field->flags & VMS_MULTIPLY) {
+                    size *= field->size;
+                }
             }
             if (field->flags & VMS_ARRAY) {
                 n_elems = field->num;
@@ -1200,6 +1213,9 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
 
             if (field->flags & VMS_VBUFFER) {
                 size = *(int32_t *)(opaque+field->size_offset);
+                if (field->flags & VMS_MULTIPLY) {
+                    size *= field->size;
+                }
             }
             if (field->flags & VMS_ARRAY) {
                 n_elems = field->num;
@@ -1226,9 +1242,6 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
         }
         field++;
     }
-    if (vmsd->post_save) {
-        vmsd->post_save(opaque);
-    }
 }
 
 static int vmstate_load(QEMUFile *f, SaveStateEntry *se, int version_id)
@@ -1258,7 +1271,8 @@ static void vmstate_save(QEMUFile *f, SaveStateEntry *se)
 #define QEMU_VM_SECTION_END          0x03
 #define QEMU_VM_SECTION_FULL         0x04
 
-int qemu_savevm_state_begin(QEMUFile *f, int blk_enable, int shared)
+int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
+                            int shared)
 {
     SaveStateEntry *se;
 
@@ -1290,16 +1304,18 @@ int qemu_savevm_state_begin(QEMUFile *f, int blk_enable, int shared)
         qemu_put_be32(f, se->instance_id);
         qemu_put_be32(f, se->version_id);
 
-        se->save_live_state(f, QEMU_VM_SECTION_START, se->opaque);
+        se->save_live_state(mon, f, QEMU_VM_SECTION_START, se->opaque);
     }
 
-    if (qemu_file_has_error(f))
+    if (qemu_file_has_error(f)) {
+        qemu_savevm_state_cancel(mon, f);
         return -EIO;
+    }
 
     return 0;
 }
 
-int qemu_savevm_state_iterate(QEMUFile *f)
+int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f)
 {
     SaveStateEntry *se;
     int ret = 1;
@@ -1312,22 +1328,33 @@ int qemu_savevm_state_iterate(QEMUFile *f)
         qemu_put_byte(f, QEMU_VM_SECTION_PART);
         qemu_put_be32(f, se->section_id);
 
-        ret &= !!se->save_live_state(f, QEMU_VM_SECTION_PART, se->opaque);
+        ret = se->save_live_state(mon, f, QEMU_VM_SECTION_PART, se->opaque);
+        if (!ret) {
+            /* Do not proceed to the next vmstate before this one reported
+               completion of the current stage. This serializes the migration
+               and reduces the probability that a faster changing state is
+               synchronized over and over again. */
+            break;
+        }
     }
 
     if (ret)
         return 1;
 
-    if (qemu_file_has_error(f))
+    if (qemu_file_has_error(f)) {
+        qemu_savevm_state_cancel(mon, f);
         return -EIO;
+    }
 
     return 0;
 }
 
-int qemu_savevm_state_complete(QEMUFile *f)
+int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f)
 {
     SaveStateEntry *se;
 
+    cpu_synchronize_all_states();
+
     QTAILQ_FOREACH(se, &savevm_handlers, entry) {
         if (se->save_live_state == NULL)
             continue;
@@ -1336,7 +1363,7 @@ int qemu_savevm_state_complete(QEMUFile *f)
         qemu_put_byte(f, QEMU_VM_SECTION_END);
         qemu_put_be32(f, se->section_id);
 
-        se->save_live_state(f, QEMU_VM_SECTION_END, se->opaque);
+        se->save_live_state(mon, f, QEMU_VM_SECTION_END, se->opaque);
     }
 
     QTAILQ_FOREACH(se, &savevm_handlers, entry) {
@@ -1368,7 +1395,18 @@ int qemu_savevm_state_complete(QEMUFile *f)
     return 0;
 }
 
-int qemu_savevm_state(QEMUFile *f)
+void qemu_savevm_state_cancel(Monitor *mon, QEMUFile *f)
+{
+    SaveStateEntry *se;
+
+    QTAILQ_FOREACH(se, &savevm_handlers, entry) {
+        if (se->save_live_state) {
+            se->save_live_state(mon, f, -1, se->opaque);
+        }
+    }
+}
+
+static int qemu_savevm_state(Monitor *mon, QEMUFile *f)
 {
     int saved_vm_running;
     int ret;
@@ -1378,17 +1416,17 @@ int qemu_savevm_state(QEMUFile *f)
 
     bdrv_flush_all();
 
-    ret = qemu_savevm_state_begin(f, 0, 0);
+    ret = qemu_savevm_state_begin(mon, f, 0, 0);
     if (ret < 0)
         goto out;
 
     do {
-        ret = qemu_savevm_state_iterate(f);
+        ret = qemu_savevm_state_iterate(mon, f);
         if (ret < 0)
             goto out;
     } while (ret == 0);
 
-    ret = qemu_savevm_state_complete(f);
+    ret = qemu_savevm_state_complete(mon, f);
 
 out:
     if (qemu_file_has_error(f))
@@ -1406,7 +1444,8 @@ static SaveStateEntry *find_se(const char *idstr, int instance_id)
 
     QTAILQ_FOREACH(se, &savevm_handlers, entry) {
         if (!strcmp(se->idstr, idstr) &&
-            instance_id == se->instance_id)
+            (instance_id == se->instance_id ||
+             instance_id == se->alias_id))
             return se;
     }
     return NULL;
@@ -1517,6 +1556,8 @@ int qemu_loadvm_state(QEMUFile *f)
         }
     }
 
+    cpu_synchronize_all_post_init();
+
     ret = 0;
 
 out:
@@ -1531,40 +1572,6 @@ out:
     return ret;
 }
 
-/* device can contain snapshots */
-static int bdrv_can_snapshot(BlockDriverState *bs)
-{
-    return (bs &&
-            !bdrv_is_removable(bs) &&
-            !bdrv_is_read_only(bs));
-}
-
-/* device must be snapshots in order to have a reliable snapshot */
-static int bdrv_has_snapshot(BlockDriverState *bs)
-{
-    return (bs &&
-            !bdrv_is_removable(bs) &&
-            !bdrv_is_read_only(bs));
-}
-
-static BlockDriverState *get_bs_snapshots(void)
-{
-    BlockDriverState *bs;
-    DriveInfo *dinfo;
-
-    if (bs_snapshots)
-        return bs_snapshots;
-    QTAILQ_FOREACH(dinfo, &drives, next) {
-        bs = dinfo->bdrv;
-        if (bdrv_can_snapshot(bs))
-            goto ok;
-    }
-    return NULL;
- ok:
-    bs_snapshots = bs;
-    return bs;
-}
-
 static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
                               const char *name)
 {
@@ -1593,12 +1600,11 @@ static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
 static int del_existing_snapshots(Monitor *mon, const char *name)
 {
     BlockDriverState *bs;
-    DriveInfo *dinfo;
     QEMUSnapshotInfo sn1, *snapshot = &sn1;
     int ret;
 
-    QTAILQ_FOREACH(dinfo, &drives, next) {
-        bs = dinfo->bdrv;
+    bs = NULL;
+    while ((bs = bdrv_next(bs))) {
         if (bdrv_can_snapshot(bs) &&
             bdrv_snapshot_find(bs, snapshot, name) >= 0)
         {
@@ -1617,7 +1623,6 @@ static int del_existing_snapshots(Monitor *mon, const char *name)
 
 void do_savevm(Monitor *mon, const QDict *qdict)
 {
-    DriveInfo *dinfo;
     BlockDriverState *bs, *bs1;
     QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1;
     int ret;
@@ -1631,12 +1636,26 @@ void do_savevm(Monitor *mon, const QDict *qdict)
 #endif
     const char *name = qdict_get_try_str(qdict, "name");
 
-    bs = get_bs_snapshots();
+    /* Verify if there is a device that doesn't support snapshots and is writable */
+    bs = NULL;
+    while ((bs = bdrv_next(bs))) {
+
+        if (bdrv_is_removable(bs) || bdrv_is_read_only(bs)) {
+            continue;
+        }
+
+        if (!bdrv_can_snapshot(bs)) {
+            monitor_printf(mon, "Device '%s' is writable but does not support snapshots.\n",
+                               bdrv_get_device_name(bs));
+            return;
+        }
+    }
+
+    bs = bdrv_snapshots();
     if (!bs) {
         monitor_printf(mon, "No block device can accept snapshots\n");
         return;
     }
-
     /* ??? Should this occur after vm_stop?  */
     qemu_aio_flush();
 
@@ -1667,7 +1686,7 @@ void do_savevm(Monitor *mon, const QDict *qdict)
     sn->vm_clock_nsec = qemu_get_clock(vm_clock);
 
     /* Delete old snapshots of the same name */
-    if (del_existing_snapshots(mon, name) < 0) {
+    if (name && del_existing_snapshots(mon, name) < 0) {
         goto the_end;
     }
 
@@ -1677,7 +1696,7 @@ void do_savevm(Monitor *mon, const QDict *qdict)
         monitor_printf(mon, "Could not open VM state file\n");
         goto the_end;
     }
-    ret = qemu_savevm_state(f);
+    ret = qemu_savevm_state(mon, f);
     vm_state_size = qemu_ftell(f);
     qemu_fclose(f);
     if (ret < 0) {
@@ -1687,9 +1706,9 @@ void do_savevm(Monitor *mon, const QDict *qdict)
 
     /* create the snapshots */
 
-    QTAILQ_FOREACH(dinfo, &drives, next) {
-        bs1 = dinfo->bdrv;
-        if (bdrv_has_snapshot(bs1)) {
+    bs1 = NULL;
+    while ((bs1 = bdrv_next(bs1))) {
+        if (bdrv_can_snapshot(bs1)) {
             /* Write VM state size only to the image that contains the state */
             sn->vm_state_size = (bs == bs1 ? vm_state_size : 0);
             ret = bdrv_snapshot_create(bs1, sn);
@@ -1705,44 +1724,57 @@ void do_savevm(Monitor *mon, const QDict *qdict)
         vm_start();
 }
 
-int load_vmstate(Monitor *mon, const char *name)
+int load_vmstate(const char *name)
 {
-    DriveInfo *dinfo;
     BlockDriverState *bs, *bs1;
     QEMUSnapshotInfo sn;
     QEMUFile *f;
     int ret;
 
-    bs = get_bs_snapshots();
+    /* Verify if there is a device that doesn't support snapshots and is writable */
+    bs = NULL;
+    while ((bs = bdrv_next(bs))) {
+
+        if (bdrv_is_removable(bs) || bdrv_is_read_only(bs)) {
+            continue;
+        }
+
+        if (!bdrv_can_snapshot(bs)) {
+            error_report("Device '%s' is writable but does not support snapshots.",
+                               bdrv_get_device_name(bs));
+            return -ENOTSUP;
+        }
+    }
+
+    bs = bdrv_snapshots();
     if (!bs) {
-        monitor_printf(mon, "No block device supports snapshots\n");
+        error_report("No block device supports snapshots");
         return -EINVAL;
     }
 
     /* Flush all IO requests so they don't interfere with the new state.  */
     qemu_aio_flush();
 
-    QTAILQ_FOREACH(dinfo, &drives, next) {
-        bs1 = dinfo->bdrv;
-        if (bdrv_has_snapshot(bs1)) {
+    bs1 = NULL;
+    while ((bs1 = bdrv_next(bs1))) {
+        if (bdrv_can_snapshot(bs1)) {
             ret = bdrv_snapshot_goto(bs1, name);
             if (ret < 0) {
-                if (bs != bs1)
-                    monitor_printf(mon, "Warning: ");
                 switch(ret) {
                 case -ENOTSUP:
-                    monitor_printf(mon,
-                                   "Snapshots not supported on device '%s'\n",
-                                   bdrv_get_device_name(bs1));
+                    error_report("%sSnapshots not supported on device '%s'",
+                                 bs != bs1 ? "Warning: " : "",
+                                 bdrv_get_device_name(bs1));
                     break;
                 case -ENOENT:
-                    monitor_printf(mon, "Could not find snapshot '%s' on "
-                                   "device '%s'\n",
-                                   name, bdrv_get_device_name(bs1));
+                    error_report("%sCould not find snapshot '%s' on device '%s'",
+                                 bs != bs1 ? "Warning: " : "",
+                                 name, bdrv_get_device_name(bs1));
                     break;
                 default:
-                    monitor_printf(mon, "Error %d while activating snapshot on"
-                                   " '%s'\n", ret, bdrv_get_device_name(bs1));
+                    error_report("%sError %d while activating snapshot on '%s'",
+                                 bs != bs1 ? "Warning: " : "",
+                                 ret, bdrv_get_device_name(bs1));
                     break;
                 }
                 /* fatal on snapshot block device */
@@ -1760,13 +1792,13 @@ int load_vmstate(Monitor *mon, const char *name)
     /* restore the VM state */
     f = qemu_fopen_bdrv(bs, 0);
     if (!f) {
-        monitor_printf(mon, "Could not open VM state file\n");
+        error_report("Could not open VM state file");
         return -EINVAL;
     }
     ret = qemu_loadvm_state(f);
     qemu_fclose(f);
     if (ret < 0) {
-        monitor_printf(mon, "Error %d while loading VM state\n", ret);
+        error_report("Error %d while loading VM state", ret);
         return ret;
     }
     return 0;
@@ -1774,20 +1806,19 @@ int load_vmstate(Monitor *mon, const char *name)
 
 void do_delvm(Monitor *mon, const QDict *qdict)
 {
-    DriveInfo *dinfo;
     BlockDriverState *bs, *bs1;
     int ret;
     const char *name = qdict_get_str(qdict, "name");
 
-    bs = get_bs_snapshots();
+    bs = bdrv_snapshots();
     if (!bs) {
         monitor_printf(mon, "No block device supports snapshots\n");
         return;
     }
 
-    QTAILQ_FOREACH(dinfo, &drives, next) {
-        bs1 = dinfo->bdrv;
-        if (bdrv_has_snapshot(bs1)) {
+    bs1 = NULL;
+    while ((bs1 = bdrv_next(bs1))) {
+        if (bdrv_can_snapshot(bs1)) {
             ret = bdrv_snapshot_delete(bs1, name);
             if (ret < 0) {
                 if (ret == -ENOTSUP)
@@ -1804,21 +1835,20 @@ void do_delvm(Monitor *mon, const QDict *qdict)
 
 void do_info_snapshots(Monitor *mon)
 {
-    DriveInfo *dinfo;
     BlockDriverState *bs, *bs1;
     QEMUSnapshotInfo *sn_tab, *sn;
     int nb_sns, i;
     char buf[256];
 
-    bs = get_bs_snapshots();
+    bs = bdrv_snapshots();
     if (!bs) {
         monitor_printf(mon, "No available block device supports snapshots\n");
         return;
     }
     monitor_printf(mon, "Snapshot devices:");
-    QTAILQ_FOREACH(dinfo, &drives, next) {
-        bs1 = dinfo->bdrv;
-        if (bdrv_has_snapshot(bs1)) {
+    bs1 = NULL;
+    while ((bs1 = bdrv_next(bs1))) {
+        if (bdrv_can_snapshot(bs1)) {
             if (bs == bs1)
                 monitor_printf(mon, " %s", bdrv_get_device_name(bs1));
         }