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@xxxxxxxxxx> --- 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; } -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html