[RFC PATCH 3/5] savevm: Make use of the new DeviceState param

Alex Williamson
2010-06-14T05:51:36Z

Use the now passed in DeviceState along with qdev_get_dev_path() to
create meaningful id strings for the SaveStateEntry. We append the
driver provided string so we can differentiate multiple savevm
handlers per device:

"/main-system-bus/pci.0,addr=03.0/i82551,mac=52:54:00:12:34:56/eeprom"
"/main-system-bus/pci.0,addr=03.0/i82551,mac=52:54:00:12:34:56/i82551"

We also introduce compatibility fields so that we can attempt to
import savevm data from an older VM. These should be deprecated and
removed at some point.

Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
---

savevm.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 76 insertions(+), 7 deletions(-)

diff --git a/savevm.c b/savevm.c
index 81d544f..4cc542b 100644
--- a/savevm.c
+++ b/savevm.c
@@ -1002,6 +1002,8 @@ typedef struct SaveStateEntry {
LoadStateHandler *load_state;
const VMStateDescription *vmsd;
void *opaque;
+ char compat_idstr[256];
+ int compat_instance_id;
} SaveStateEntry;

@@ -1023,6 +1025,20 @@ static int calculate_new_instance_id(const char *idstr)
return instance_id;
}

+static int calculate_new_compat_instance_id(const char *idstr)
+{
+ SaveStateEntry *se;
+ int instance_id = 0;
+
+ QTAILQ_FOREACH(se, &savevm_handlers, entry) {
+ if (strcmp(idstr, se->compat_idstr) == 0
+ && instance_id <= se->compat_instance_id) {
+ instance_id = se->compat_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
@@ -1040,7 +1056,16 @@ int register_savevm_live(DeviceState *dev,
SaveStateEntry *se;

se = qemu_mallocz(sizeof(SaveStateEntry));
- pstrcpy(se->idstr, sizeof(se->idstr), idstr);
+
+ if (dev) {
+ char *path = qdev_get_dev_path(dev);
+ pstrcpy(se->idstr, sizeof(se->idstr), path);
+ pstrcat(se->idstr, sizeof(se->idstr), "/");
+ pstrcat(se->idstr, sizeof(se->idstr), idstr);
+ qemu_free(path);
+ } else {
+ pstrcpy(se->idstr, sizeof(se->idstr), idstr);
+ }
se->version_id = version_id;
se->section_id = global_section_id++;
se->set_params = set_params;
@@ -1050,11 +1075,19 @@ int register_savevm_live(DeviceState *dev,
se->opaque = opaque;
se->vmsd = NULL;

+ pstrcpy(se->compat_idstr, sizeof(se->idstr), idstr);
if (instance_id == -1) {
- se->instance_id = calculate_new_instance_id(idstr);
+ se->instance_id = calculate_new_instance_id(se->idstr);
+ se->compat_instance_id = calculate_new_compat_instance_id(idstr);
} else {
- se->instance_id = instance_id;
+ se->instance_id = se->compat_instance_id = instance_id;
+ }
+
+ if (dev && instance_id == -1 && se->instance_id != 0) {
+ fprintf(stderr, "%s: Failed to create unqiue path \"%s\"\n",
+ __FUNCTION__, se->idstr);
}
+
/* add at the end of list */
QTAILQ_INSERT_TAIL(&savevm_handlers, se, entry);
return 0;
@@ -1075,13 +1108,25 @@ int register_savevm(DeviceState *dev,
void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque)
{
SaveStateEntry *se, *new_se;
+ char *path;
+
+ if (dev) {
+ int len;
+ path = qdev_get_dev_path(dev);
+ len = strlen(path);
+ path = qemu_realloc(path, len + strlen(idstr) + 2);
+ sprintf(path + len, "/%s", idstr);
+ } else {
+ path = qemu_strdup(idstr);
+ }

QTAILQ_FOREACH_SAFE(se, &savevm_handlers, entry, new_se) {
- if (strcmp(se->idstr, idstr) == 0 && se->opaque == opaque) {
+ if (strcmp(se->idstr, path) == 0 && se->opaque == opaque) {
QTAILQ_REMOVE(&savevm_handlers, se, entry);
qemu_free(se);
}
}
+ qemu_free(path);
}

int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
@@ -1095,7 +1140,16 @@ int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
assert(alias_id == -1 || required_for_version >= vmsd->minimum_version_id);

se = qemu_mallocz(sizeof(SaveStateEntry));
- pstrcpy(se->idstr, sizeof(se->idstr), vmsd->name);
+
+ if (dev) {
+ char *path = qdev_get_dev_path(dev);
+ pstrcpy(se->idstr, sizeof(se->idstr), path);
+ pstrcat(se->idstr, sizeof(se->idstr), "/");
+ pstrcat(se->idstr, sizeof(se->idstr), vmsd->name);
+ qemu_free(path);
+ } else {
+ pstrcpy(se->idstr, sizeof(se->idstr), vmsd->name);
+ }
se->version_id = vmsd->version_id;
se->section_id = global_section_id++;
se->save_live_state = NULL;
@@ -1105,11 +1159,19 @@ int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
se->vmsd = vmsd;
se->alias_id = alias_id;

+ pstrcpy(se->compat_idstr, sizeof(se->idstr), vmsd->name);
if (instance_id == -1) {
- se->instance_id = calculate_new_instance_id(vmsd->name);
+ se->instance_id = calculate_new_instance_id(se->idstr);
+ se->compat_instance_id = calculate_new_compat_instance_id(vmsd->name);
} else {
- se->instance_id = instance_id;
+ se->instance_id = se->compat_instance_id = instance_id;
}
+
+ if (dev && instance_id == -1 && se->instance_id != 0) {
+ fprintf(stderr, "%s: Failed to create unqiue path \"%s\"\n",
+ __FUNCTION__, se->idstr);
+ }
+
/* add at the end of list */
QTAILQ_INSERT_TAIL(&savevm_handlers, se, entry);
return 0;
@@ -1456,6 +1518,13 @@ static SaveStateEntry *find_se(const char *idstr, int instance_id)
instance_id == se->alias_id))
return se;
}
+
+ QTAILQ_FOREACH(se, &savevm_handlers, entry) {
+ if (!strcmp(se->compat_idstr, idstr) &&
+ (instance_id == se->compat_instance_id ||
+ instance_id == se->alias_id))
+ return se;
+ }
return NULL;
}