#include "audio/audio.h"
#include "migration.h"
#include "qemu_socket.h"
+#include "qemu-queue.h"
/* point to the block driver where the snapshots are managed */
static BlockDriverState *bs_snapshots;
.put = put_uint64,
};
+/* 8 bit int. See that the received value is the same than the one
+ in the field */
+
+static int get_uint8_equal(QEMUFile *f, void *pv, size_t size)
+{
+ uint8_t *v = pv;
+ uint8_t v2;
+ qemu_get_8s(f, &v2);
+
+ if (*v == v2)
+ return 0;
+ return -EINVAL;
+}
+
+const VMStateInfo vmstate_info_uint8_equal = {
+ .name = "int32 equal",
+ .get = get_uint8_equal,
+ .put = put_uint8,
+};
+
/* timers */
static int get_timer(QEMUFile *f, void *pv, size_t size)
};
typedef struct SaveStateEntry {
+ QTAILQ_ENTRY(SaveStateEntry) entry;
char idstr[256];
int instance_id;
int version_id;
LoadStateHandler *load_state;
const VMStateDescription *vmsd;
void *opaque;
- struct SaveStateEntry *next;
} SaveStateEntry;
-static SaveStateEntry *first_se;
+static QTAILQ_HEAD(savevm_handlers, SaveStateEntry) savevm_handlers =
+ QTAILQ_HEAD_INITIALIZER(savevm_handlers);
static int global_section_id;
+static int calculate_new_instance_id(const char *idstr)
+{
+ SaveStateEntry *se;
+ int instance_id = 0;
+
+ QTAILQ_FOREACH(se, &savevm_handlers, entry) {
+ if (strcmp(idstr, se->idstr) == 0
+ && instance_id <= se->instance_id) {
+ instance_id = se->instance_id + 1;
+ }
+ }
+ return instance_id;
+}
+
/* TODO: Individual devices generally have very little idea about the rest
of the system, so instance_id should be removed/replaced.
Meanwhile pass -1 as instance_id if you do not already have a clearly
LoadStateHandler *load_state,
void *opaque)
{
- SaveStateEntry *se, **pse;
+ SaveStateEntry *se;
se = qemu_malloc(sizeof(SaveStateEntry));
pstrcpy(se->idstr, sizeof(se->idstr), idstr);
- se->instance_id = (instance_id == -1) ? 0 : instance_id;
se->version_id = version_id;
se->section_id = global_section_id++;
se->save_live_state = save_live_state;
se->load_state = load_state;
se->opaque = opaque;
se->vmsd = NULL;
- se->next = NULL;
- /* add at the end of list */
- pse = &first_se;
- while (*pse != NULL) {
- if (instance_id == -1
- && strcmp(se->idstr, (*pse)->idstr) == 0
- && se->instance_id <= (*pse)->instance_id)
- se->instance_id = (*pse)->instance_id + 1;
- pse = &(*pse)->next;
+ if (instance_id == -1) {
+ se->instance_id = calculate_new_instance_id(idstr);
+ } else {
+ se->instance_id = instance_id;
}
- *pse = se;
+ /* add at the end of list */
+ QTAILQ_INSERT_TAIL(&savevm_handlers, se, entry);
return 0;
}
void unregister_savevm(const char *idstr, void *opaque)
{
- SaveStateEntry **pse;
+ SaveStateEntry *se, *new_se;
- pse = &first_se;
- while (*pse != NULL) {
- if (strcmp((*pse)->idstr, idstr) == 0 && (*pse)->opaque == opaque) {
- SaveStateEntry *next = (*pse)->next;
- qemu_free(*pse);
- *pse = next;
- continue;
+ QTAILQ_FOREACH_SAFE(se, &savevm_handlers, entry, new_se) {
+ if (strcmp(se->idstr, idstr) == 0 && se->opaque == opaque) {
+ QTAILQ_REMOVE(&savevm_handlers, se, entry);
+ qemu_free(se);
}
- pse = &(*pse)->next;
}
}
int vmstate_register(int instance_id, const VMStateDescription *vmsd,
void *opaque)
{
- SaveStateEntry *se, **pse;
+ SaveStateEntry *se;
se = qemu_malloc(sizeof(SaveStateEntry));
pstrcpy(se->idstr, sizeof(se->idstr), vmsd->name);
- se->instance_id = (instance_id == -1) ? 0 : instance_id;
se->version_id = vmsd->version_id;
se->section_id = global_section_id++;
se->save_live_state = NULL;
se->load_state = NULL;
se->opaque = opaque;
se->vmsd = vmsd;
- se->next = NULL;
- /* add at the end of list */
- pse = &first_se;
- while (*pse != NULL) {
- if (instance_id == -1
- && strcmp(se->idstr, (*pse)->idstr) == 0
- && se->instance_id <= (*pse)->instance_id)
- se->instance_id = (*pse)->instance_id + 1;
- pse = &(*pse)->next;
+ if (instance_id == -1) {
+ se->instance_id = calculate_new_instance_id(vmsd->name);
+ } else {
+ se->instance_id = instance_id;
}
- *pse = se;
+ /* add at the end of list */
+ QTAILQ_INSERT_TAIL(&savevm_handlers, se, entry);
return 0;
}
-void vmstate_unregister(const char *idstr, void *opaque)
+void vmstate_unregister(const VMStateDescription *vmsd, void *opaque)
{
- SaveStateEntry **pse;
+ SaveStateEntry *se, *new_se;
- pse = &first_se;
- while (*pse != NULL) {
- if (strcmp((*pse)->idstr, idstr) == 0 && (*pse)->opaque == opaque) {
- SaveStateEntry *next = (*pse)->next;
- qemu_free(*pse);
- *pse = next;
- continue;
+ QTAILQ_FOREACH_SAFE(se, &savevm_handlers, entry, new_se) {
+ if (se->vmsd == vmsd && se->opaque == opaque) {
+ QTAILQ_REMOVE(&savevm_handlers, se, entry);
+ qemu_free(se);
}
- pse = &(*pse)->next;
}
}
if (version_id < vmsd->minimum_version_id) {
return vmsd->load_state_old(f, opaque, version_id);
}
+ if (vmsd->pre_load) {
+ int ret = vmsd->pre_load(opaque);
+ if (ret)
+ return ret;
+ }
while(field->name) {
if (field->version_id <= version_id) {
void *base_addr = opaque + field->offset;
void *addr = base_addr + field->size * i;
if (field->flags & VMS_STRUCT) {
- ret = vmstate_load_state(f, field->vmsd, addr, version_id);
+ ret = vmstate_load_state(f, field->vmsd, addr, field->vmsd->version_id);
} else {
ret = field->info->get(f, addr, field->size);
}
field++;
}
- if (vmsd->run_after_load)
- return vmsd->run_after_load(opaque);
+ if (vmsd->post_load) {
+ return vmsd->post_load(opaque);
+ }
return 0;
}
{
VMStateField *field = vmsd->fields;
+ if (vmsd->pre_save) {
+ vmsd->pre_save(opaque);
+ }
while(field->name) {
const void *base_addr = opaque + field->offset;
int i, n_elems = 1;
}
field++;
}
+ if (vmsd->post_save) {
+ vmsd->post_save(opaque);
+ }
}
static int vmstate_load(QEMUFile *f, SaveStateEntry *se, int version_id)
qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
qemu_put_be32(f, QEMU_VM_FILE_VERSION);
- for (se = first_se; se != NULL; se = se->next) {
+ QTAILQ_FOREACH(se, &savevm_handlers, entry) {
int len;
if (se->save_live_state == NULL)
SaveStateEntry *se;
int ret = 1;
- for (se = first_se; se != NULL; se = se->next) {
+ QTAILQ_FOREACH(se, &savevm_handlers, entry) {
if (se->save_live_state == NULL)
continue;
{
SaveStateEntry *se;
- for (se = first_se; se != NULL; se = se->next) {
+ QTAILQ_FOREACH(se, &savevm_handlers, entry) {
if (se->save_live_state == NULL)
continue;
se->save_live_state(f, QEMU_VM_SECTION_END, se->opaque);
}
- for(se = first_se; se != NULL; se = se->next) {
+ QTAILQ_FOREACH(se, &savevm_handlers, entry) {
int len;
if (se->save_state == NULL && se->vmsd == NULL)
{
SaveStateEntry *se;
- for(se = first_se; se != NULL; se = se->next) {
+ QTAILQ_FOREACH(se, &savevm_handlers, entry) {
if (!strcmp(se->idstr, idstr) &&
instance_id == se->instance_id)
return se;
}
typedef struct LoadStateEntry {
+ QLIST_ENTRY(LoadStateEntry) entry;
SaveStateEntry *se;
int section_id;
int version_id;
- struct LoadStateEntry *next;
} LoadStateEntry;
-static int qemu_loadvm_state_v2(QEMUFile *f)
-{
- SaveStateEntry *se;
- int len, ret, instance_id, record_len, version_id;
- int64_t total_len, end_pos, cur_pos;
- char idstr[256];
-
- total_len = qemu_get_be64(f);
- end_pos = total_len + qemu_ftell(f);
- for(;;) {
- if (qemu_ftell(f) >= end_pos)
- break;
- len = qemu_get_byte(f);
- qemu_get_buffer(f, (uint8_t *)idstr, len);
- idstr[len] = '\0';
- instance_id = qemu_get_be32(f);
- version_id = qemu_get_be32(f);
- record_len = qemu_get_be32(f);
- cur_pos = qemu_ftell(f);
- se = find_se(idstr, instance_id);
- if (!se) {
- fprintf(stderr, "qemu: warning: instance 0x%x of device '%s' not present in current VM\n",
- instance_id, idstr);
- } else {
- ret = vmstate_load(f, se, version_id);
- if (ret < 0) {
- fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n",
- instance_id, idstr);
- return ret;
- }
- }
- /* always seek to exact end of record */
- qemu_fseek(f, cur_pos + record_len, SEEK_SET);
- }
-
- if (qemu_file_has_error(f))
- return -EIO;
-
- return 0;
-}
-
int qemu_loadvm_state(QEMUFile *f)
{
- LoadStateEntry *first_le = NULL;
+ QLIST_HEAD(, LoadStateEntry) loadvm_handlers =
+ QLIST_HEAD_INITIALIZER(loadvm_handlers);
+ LoadStateEntry *le, *new_le;
uint8_t section_type;
unsigned int v;
int ret;
return -EINVAL;
v = qemu_get_be32(f);
- if (v == QEMU_VM_FILE_VERSION_COMPAT)
- return qemu_loadvm_state_v2(f);
+ if (v == QEMU_VM_FILE_VERSION_COMPAT) {
+ fprintf(stderr, "SaveVM v2 format is obsolete and don't work anymore\n");
+ return -ENOTSUP;
+ }
if (v != QEMU_VM_FILE_VERSION)
return -ENOTSUP;
while ((section_type = qemu_get_byte(f)) != QEMU_VM_EOF) {
uint32_t instance_id, version_id, section_id;
- LoadStateEntry *le;
SaveStateEntry *se;
char idstr[257];
int len;
le->se = se;
le->section_id = section_id;
le->version_id = version_id;
- le->next = first_le;
- first_le = le;
+ QLIST_INSERT_HEAD(&loadvm_handlers, le, entry);
ret = vmstate_load(f, le->se, le->version_id);
if (ret < 0) {
case QEMU_VM_SECTION_END:
section_id = qemu_get_be32(f);
- for (le = first_le; le && le->section_id != section_id; le = le->next);
+ QLIST_FOREACH(le, &loadvm_handlers, entry) {
+ if (le->section_id == section_id) {
+ break;
+ }
+ }
if (le == NULL) {
fprintf(stderr, "Unknown savevm section %d\n", section_id);
ret = -EINVAL;
ret = 0;
out:
- while (first_le) {
- LoadStateEntry *le = first_le;
- first_le = first_le->next;
+ QLIST_FOREACH_SAFE(le, &loadvm_handlers, entry, new_le) {
+ QLIST_REMOVE(le, entry);
qemu_free(le);
}
if (bs_snapshots)
return bs_snapshots;
- TAILQ_FOREACH(dinfo, &drives, next) {
+ QTAILQ_FOREACH(dinfo, &drives, next) {
bs = dinfo->bdrv;
if (bdrv_can_snapshot(bs))
goto ok;
return ret;
}
-void do_savevm(Monitor *mon, const char *name)
+void do_savevm(Monitor *mon, const QDict *qdict)
{
DriveInfo *dinfo;
BlockDriverState *bs, *bs1;
#else
struct timeval tv;
#endif
+ const char *name = qdict_get_try_str(qdict, "name");
bs = get_bs_snapshots();
if (!bs) {
/* create the snapshots */
- TAILQ_FOREACH(dinfo, &drives, next) {
+ QTAILQ_FOREACH(dinfo, &drives, next) {
bs1 = dinfo->bdrv;
if (bdrv_has_snapshot(bs1)) {
if (must_delete) {
/* Flush all IO requests so they don't interfere with the new state. */
qemu_aio_flush();
- TAILQ_FOREACH(dinfo, &drives, next) {
+ QTAILQ_FOREACH(dinfo, &drives, next) {
bs1 = dinfo->bdrv;
if (bdrv_has_snapshot(bs1)) {
ret = bdrv_snapshot_goto(bs1, name);
return 0;
}
-void do_delvm(Monitor *mon, const char *name)
+void do_delvm(Monitor *mon, const QDict *qdict)
{
DriveInfo *dinfo;
BlockDriverState *bs, *bs1;
int ret;
+ const char *name = qdict_get_str(qdict, "name");
bs = get_bs_snapshots();
if (!bs) {
return;
}
- TAILQ_FOREACH(dinfo, &drives, next) {
+ QTAILQ_FOREACH(dinfo, &drives, next) {
bs1 = dinfo->bdrv;
if (bdrv_has_snapshot(bs1)) {
ret = bdrv_snapshot_delete(bs1, name);
return;
}
monitor_printf(mon, "Snapshot devices:");
- TAILQ_FOREACH(dinfo, &drives, next) {
+ QTAILQ_FOREACH(dinfo, &drives, next) {
bs1 = dinfo->bdrv;
if (bdrv_has_snapshot(bs1)) {
if (bs == bs1)