Commit 33cf629a authored by Anthony Liguori's avatar Anthony Liguori
Browse files

Merge remote-tracking branch 'sstabellini/saverestore-8' into staging



* sstabellini/saverestore-8:
  xen: do not allocate RAM during INMIGRATE runstate
  xen mapcache: check if memory region has moved.
  xen: record physmap changes to xenstore
  Set runstate to INMIGRATE earlier
  Introduce "xen-save-devices-state"
  cirrus_vga: do not reset videoram

Conflicts:
	qapi-schema.json

Signed-off-by: default avatarAnthony Liguori <aliguori@us.ibm.com>
parents b85a4ec8 c234572d
Loading
Loading
Loading
Loading
+34 −0
Original line number Diff line number Diff line
= Save Devices =

QEMU has code to load/save the state of the guest that it is running.
These are two complementary operations.  Saving the state just does
that, saves the state for each device that the guest is running.

These operations are normally used with migration (see migration.txt),
however it is also possible to save the state of all devices to file,
without saving the RAM or the block devices of the VM.

This operation is called "xen-save-devices-state" (see
QMP/qmp-commands.txt)


The binary format used in the file is the following:


-------------------------------------------

32 bit big endian: QEMU_VM_FILE_MAGIC
32 bit big endian: QEMU_VM_FILE_VERSION

for_each_device
{
    8 bit:              QEMU_VM_SECTION_FULL
    32 bit big endian:  section_id
    8 bit:              idstr (ID string) length
    string:             idstr (ID string)
    32 bit big endian:  instance_id
    32 bit big endian:  version_id
    buffer:             device specific data
}

8 bit: QEMU_VM_EOF
+0 −4
Original line number Diff line number Diff line
@@ -2767,10 +2767,6 @@ static void cirrus_reset(void *opaque)
    }
    s->vga.cr[0x27] = s->device_id;

    /* Win2K seems to assume that the pattern buffer is at 0xff
       initially ! */
    memset(s->vga.vram_ptr, 0xff, s->real_vram_size);

    s->cirrus_hidden_dac_lockindex = 5;
    s->cirrus_hidden_dac_data = 0;
}
+17 −0
Original line number Diff line number Diff line
@@ -1684,3 +1684,20 @@
##
{ 'command': 'migrate',
  'data': {'uri': 'str', '*blk': 'bool', '*inc': 'bool', '*detach': 'bool' } }

# @xen-save-devices-state:
#
# Save the state of all devices to file. The RAM and the block devices
# of the VM are not saved by this command.
#
# @filename: the file to save the state of the devices to as binary
# data. See xen-save-devices-state.txt for a description of the binary
# format.
#
# Returns: Nothing on success
#          If @filename cannot be opened, OpenFileFailed
#          If an I/O error occurs while writing the file, IOError
#
# Since: 1.1
##
{ 'command': 'xen-save-devices-state', 'data': {'filename': 'str'} }
+27 −0
Original line number Diff line number Diff line
@@ -441,6 +441,33 @@ Example:
Note: inject-nmi is only supported for x86 guest currently, it will
      returns "Unsupported" error for non-x86 guest.

EQMP

    {
        .name       = "xen-save-devices-state",
        .args_type  = "filename:F",
    .mhandler.cmd_new = qmp_marshal_input_xen_save_devices_state,
    },

SQMP
xen-save-devices-state
-------

Save the state of all devices to file. The RAM and the block devices
of the VM are not saved by this command.

Arguments:

- "filename": the file to save the state of the devices to as binary
data. See xen-save-devices-state.txt for a description of the binary
format.

Example:

-> { "execute": "xen-save-devices-state",
     "arguments": { "filename": "/tmp/save" } }
<- { "return": {} }

EQMP

    {
+71 −0
Original line number Diff line number Diff line
@@ -84,6 +84,7 @@
#include "qemu-timer.h"
#include "cpus.h"
#include "memory.h"
#include "qmp-commands.h"

#define SELF_ANNOUNCE_ROUNDS 5

@@ -1177,6 +1178,7 @@ typedef struct SaveStateEntry {
    void *opaque;
    CompatEntry *compat;
    int no_migrate;
    int is_ram;
} SaveStateEntry;


@@ -1241,6 +1243,10 @@ int register_savevm_live(DeviceState *dev,
    se->opaque = opaque;
    se->vmsd = NULL;
    se->no_migrate = 0;
    /* if this is a live_savem then set is_ram */
    if (save_live_state != NULL) {
        se->is_ram = 1;
    }

    if (dev && dev->parent_bus && dev->parent_bus->info->get_dev_path) {
        char *id = dev->parent_bus->info->get_dev_path(dev);
@@ -1728,6 +1734,45 @@ out:
    return ret;
}

static int qemu_save_device_state(QEMUFile *f)
{
    SaveStateEntry *se;

    qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
    qemu_put_be32(f, QEMU_VM_FILE_VERSION);

    cpu_synchronize_all_states();

    QTAILQ_FOREACH(se, &savevm_handlers, entry) {
        int len;

        if (se->is_ram) {
            continue;
        }
        if (se->save_state == NULL && se->vmsd == NULL) {
            continue;
        }

        /* Section type */
        qemu_put_byte(f, QEMU_VM_SECTION_FULL);
        qemu_put_be32(f, se->section_id);

        /* ID string */
        len = strlen(se->idstr);
        qemu_put_byte(f, len);
        qemu_put_buffer(f, (uint8_t *)se->idstr, len);

        qemu_put_be32(f, se->instance_id);
        qemu_put_be32(f, se->version_id);

        vmstate_save(f, se);
    }

    qemu_put_byte(f, QEMU_VM_EOF);

    return qemu_file_get_error(f);
}

static SaveStateEntry *find_se(const char *idstr, int instance_id)
{
    SaveStateEntry *se;
@@ -2109,6 +2154,32 @@ void do_savevm(Monitor *mon, const QDict *qdict)
        vm_start();
}

void qmp_xen_save_devices_state(const char *filename, Error **errp)
{
    QEMUFile *f;
    int saved_vm_running;
    int ret;

    saved_vm_running = runstate_is_running();
    vm_stop(RUN_STATE_SAVE_VM);

    f = qemu_fopen(filename, "wb");
    if (!f) {
        error_set(errp, QERR_OPEN_FILE_FAILED, filename);
        goto the_end;
    }
    ret = qemu_save_device_state(f);
    qemu_fclose(f);
    if (ret < 0) {
        error_set(errp, QERR_IO_ERROR);
    }

 the_end:
    if (saved_vm_running)
        vm_start();
    return;
}

int load_vmstate(const char *name)
{
    BlockDriverState *bs, *bs_vm_state;
Loading