Introduce "xen-save-devices-state"
- add an "is_ram" flag to SaveStateEntry; - register_savevm_live sets is_ram for live_savevm devices; - introduce a "xen-save-devices-state" QAPI command that can be used to save the state of all devices, but not the RAM or the block devices of the VM. Changes in v8: - rename save-devices-state to xen-save-devices-state. Changes in v7: - rename save_devices to save-devices-state. Changes in v6: - remove the is_ram parameter from register_savevm_live and sets is_ram if the device is a live_savevm device; - introduce save_devices as a QAPI command, write a better description for it; - fix CODING_STYLE; - introduce a new doc to explain the save format used by save_devices. Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Reviewed-by: Anthony Liguori <aliguori@us.ibm.com> Acked-by: Luiz Capitulino <lcapitulino@redhat.com>
This commit is contained in:
parent
695bb854e8
commit
a7ae8355b4
34
docs/xen-save-devices-state.txt
Normal file
34
docs/xen-save-devices-state.txt
Normal file
@ -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
|
@ -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'} }
|
||||
|
||||
|
@ -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
savevm.c
71
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;
|
||||
|
Loading…
Reference in New Issue
Block a user