aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/xen-save-devices-state.txt34
-rw-r--r--qapi-schema.json19
-rw-r--r--qmp-commands.hx27
-rw-r--r--savevm.c71
4 files changed, 151 insertions, 0 deletions
diff --git a/docs/xen-save-devices-state.txt b/docs/xen-save-devices-state.txt
new file mode 100644
index 0000000..92e08db
--- /dev/null
+++ b/docs/xen-save-devices-state.txt
@@ -0,0 +1,34 @@
+= 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
diff --git a/qapi-schema.json b/qapi-schema.json
index d0b6792..def69a9 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1593,3 +1593,22 @@
{ 'command': 'qom-list-types',
'data': { '*implements': 'str', '*abstract': 'bool' },
'returns': [ 'ObjectTypeInfo' ] }
+
+##
+# @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'} }
+
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 705f704..dbb6236 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -444,6 +444,33 @@ Note: inject-nmi is only supported for x86 guest currently, it will
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
+
+ {
.name = "migrate",
.args_type = "detach:-d,blk:-b,inc:-i,uri:s",
.params = "[-d] [-b] [-i] uri",
diff --git a/savevm.c b/savevm.c
index 80be1ff..0e61eb0 100644
--- a/savevm.c
+++ b/savevm.c
@@ -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;