#include "cpus.h"
#include "memory.h"
#include "qmp-commands.h"
+#include "trace.h"
#define SELF_ANNOUNCE_ROUNDS 5
static int bdrv_fclose(void *opaque)
{
- return 0;
+ return bdrv_flush(opaque);
}
static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable)
int alias_id;
int version_id;
int section_id;
- SaveSetParamsHandler *set_params;
- SaveLiveStateHandler *save_live_state;
- SaveStateHandler *save_state;
- LoadStateHandler *load_state;
+ SaveVMHandlers *ops;
const VMStateDescription *vmsd;
void *opaque;
CompatEntry *compat;
const char *idstr,
int instance_id,
int version_id,
- SaveSetParamsHandler *set_params,
- SaveLiveStateHandler *save_live_state,
- SaveStateHandler *save_state,
- LoadStateHandler *load_state,
+ SaveVMHandlers *ops,
void *opaque)
{
SaveStateEntry *se;
se = g_malloc0(sizeof(SaveStateEntry));
se->version_id = version_id;
se->section_id = global_section_id++;
- se->set_params = set_params;
- se->save_live_state = save_live_state;
- se->save_state = save_state;
- se->load_state = load_state;
+ se->ops = ops;
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) {
+ if (ops->save_live_setup != NULL) {
se->is_ram = 1;
}
LoadStateHandler *load_state,
void *opaque)
{
+ SaveVMHandlers *ops = g_malloc0(sizeof(SaveVMHandlers));
+ ops->save_state = save_state;
+ ops->load_state = load_state;
return register_savevm_live(dev, idstr, instance_id, version_id,
- NULL, NULL, save_state, load_state, opaque);
+ ops, opaque);
}
void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque)
if (se->compat) {
g_free(se->compat);
}
+ g_free(se->ops);
g_free(se);
}
}
se = g_malloc0(sizeof(SaveStateEntry));
se->version_id = vmsd->version_id;
se->section_id = global_section_id++;
- se->save_live_state = NULL;
- se->save_state = NULL;
- se->load_state = NULL;
se->opaque = opaque;
se->vmsd = vmsd;
se->alias_id = alias_id;
static int vmstate_load(QEMUFile *f, SaveStateEntry *se, int version_id)
{
if (!se->vmsd) { /* Old style */
- return se->load_state(f, se->opaque, version_id);
+ return se->ops->load_state(f, se->opaque, version_id);
}
return vmstate_load_state(f, se->vmsd, se->opaque, version_id);
}
static void vmstate_save(QEMUFile *f, SaveStateEntry *se)
{
if (!se->vmsd) { /* Old style */
- se->save_state(f, se->opaque);
+ se->ops->save_state(f, se->opaque);
return;
}
vmstate_save_state(f,se->vmsd, se->opaque);
return false;
}
-int qemu_savevm_state_begin(QEMUFile *f, int blk_enable, int shared)
+int qemu_savevm_state_begin(QEMUFile *f,
+ const MigrationParams *params)
{
SaveStateEntry *se;
int ret;
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
- if(se->set_params == NULL) {
+ if (!se->ops || !se->ops->set_params) {
continue;
- }
- se->set_params(blk_enable, shared, se->opaque);
+ }
+ se->ops->set_params(params, se->opaque);
}
qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
int len;
- if (se->save_live_state == NULL)
+ if (!se->ops || !se->ops->save_live_setup) {
continue;
-
+ }
+ if (se->ops && se->ops->is_active) {
+ if (!se->ops->is_active(se->opaque)) {
+ continue;
+ }
+ }
/* Section type */
qemu_put_byte(f, QEMU_VM_SECTION_START);
qemu_put_be32(f, se->section_id);
qemu_put_be32(f, se->instance_id);
qemu_put_be32(f, se->version_id);
- ret = se->save_live_state(f, QEMU_VM_SECTION_START, se->opaque);
+ ret = se->ops->save_live_setup(f, se->opaque);
if (ret < 0) {
qemu_savevm_state_cancel(f);
return ret;
int ret = 1;
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
- if (se->save_live_state == NULL)
+ if (!se->ops || !se->ops->save_live_iterate) {
continue;
-
+ }
+ if (se->ops && se->ops->is_active) {
+ if (!se->ops->is_active(se->opaque)) {
+ continue;
+ }
+ }
+ if (qemu_file_rate_limit(f)) {
+ return 0;
+ }
+ trace_savevm_section_start();
/* Section type */
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->ops->save_live_iterate(f, se->opaque);
+ trace_savevm_section_end(se->section_id);
+
if (ret <= 0) {
/* Do not proceed to the next vmstate before this one reported
completion of the current stage. This serializes the migration
cpu_synchronize_all_states();
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
- if (se->save_live_state == NULL)
+ if (!se->ops || !se->ops->save_live_complete) {
continue;
-
+ }
+ if (se->ops && se->ops->is_active) {
+ if (!se->ops->is_active(se->opaque)) {
+ continue;
+ }
+ }
+ trace_savevm_section_start();
/* Section type */
qemu_put_byte(f, QEMU_VM_SECTION_END);
qemu_put_be32(f, se->section_id);
- ret = se->save_live_state(f, QEMU_VM_SECTION_END, se->opaque);
+ ret = se->ops->save_live_complete(f, se->opaque);
+ trace_savevm_section_end(se->section_id);
if (ret < 0) {
return ret;
}
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
int len;
- if (se->save_state == NULL && se->vmsd == NULL)
+ if ((!se->ops || !se->ops->save_state) && !se->vmsd) {
continue;
-
+ }
+ trace_savevm_section_start();
/* Section type */
qemu_put_byte(f, QEMU_VM_SECTION_FULL);
qemu_put_be32(f, se->section_id);
qemu_put_be32(f, se->version_id);
vmstate_save(f, se);
+ trace_savevm_section_end(se->section_id);
}
qemu_put_byte(f, QEMU_VM_EOF);
SaveStateEntry *se;
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
- if (se->save_live_state) {
- se->save_live_state(f, -1, se->opaque);
+ if (se->ops && se->ops->cancel) {
+ se->ops->cancel(se->opaque);
}
}
}
static int qemu_savevm_state(QEMUFile *f)
{
int ret;
+ MigrationParams params = {
+ .blk = 0,
+ .shared = 0
+ };
if (qemu_savevm_state_blocked(NULL)) {
ret = -EINVAL;
goto out;
}
- ret = qemu_savevm_state_begin(f, 0, 0);
+ ret = qemu_savevm_state_begin(f, ¶ms);
if (ret < 0)
goto out;
if (se->is_ram) {
continue;
}
- if (se->save_state == NULL && se->vmsd == NULL) {
+ if ((!se->ops || !se->ops->save_state) && !se->vmsd) {
continue;
}