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:
Stefano Stabellini 2012-01-25 12:24:51 +00:00
parent 695bb854e8
commit a7ae8355b4
4 changed files with 151 additions and 0 deletions

View 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

View File

@ -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'} }

View File

@ -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
{

View File

@ -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;