aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Kiszka <jan.kiszka@siemens.com>2010-05-15 13:32:40 +0200
committerBlue Swirl <blauwirbel@gmail.com>2010-05-15 14:23:31 +0000
commit4d2ffa08b601bdd40d9ccf225480c0a7e90ca078 (patch)
treec58243f040336217efae96032a3fb666d5bcae98
parentec86f3e1af558a9a6f8476b9c1903cb6f152b771 (diff)
vmstate: Add support for alias ID
Some legacy users (mostly PC devices) of vmstate_register manage instance IDs on their own, and that unfortunately in a way that is incompatible with automatically generated ones. This so far prevents switching those users to vmstates that are registered by qdev. To establish a migration path, this patch introduces the concept of alias IDs. They can be passed to an extended vmstate registration service, and qdev provides a set service to be used during device init. find_se will consider the alias in addition to the default ID. We can then start generating the default ID automatically and writing it on vmsave, thus converting that format without breaking support for upward migration. The user is required specify the highest vmstate version for which the alias is required. Once this version falls behind the minimum required for a specific vmstate, an assertion triggers to motivate cleaning up the obsolete alias. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
-rw-r--r--hw/hw.h4
-rw-r--r--hw/qdev.c16
-rw-r--r--hw/qdev.h4
-rw-r--r--savevm.c20
4 files changed, 39 insertions, 5 deletions
diff --git a/hw/hw.h b/hw/hw.h
index 2d397243d1..fc2d1849d7 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -758,5 +758,9 @@ extern void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
void *opaque);
extern int vmstate_register(int instance_id, const VMStateDescription *vmsd,
void *base);
+extern int vmstate_register_with_alias_id(int instance_id,
+ const VMStateDescription *vmsd,
+ void *base, int alias_id,
+ int required_for_version);
void vmstate_unregister(const VMStateDescription *vmsd, void *opaque);
#endif
diff --git a/hw/qdev.c b/hw/qdev.c
index d3bf0fa43d..af17486976 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -93,6 +93,7 @@ static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
assert(bus->allow_hotplug);
dev->hotplugged = 1;
}
+ dev->instance_id_alias = -1;
dev->state = DEV_STATE_CREATED;
return dev;
}
@@ -278,12 +279,23 @@ int qdev_init(DeviceState *dev)
return rc;
}
qemu_register_reset(qdev_reset, dev);
- if (dev->info->vmsd)
- vmstate_register(-1, dev->info->vmsd, dev);
+ if (dev->info->vmsd) {
+ vmstate_register_with_alias_id(-1, dev->info->vmsd, dev,
+ dev->instance_id_alias,
+ dev->alias_required_for_version);
+ }
dev->state = DEV_STATE_INITIALIZED;
return 0;
}
+void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
+ int required_for_version)
+{
+ assert(dev->state == DEV_STATE_CREATED);
+ dev->instance_id_alias = alias_id;
+ dev->alias_required_for_version = required_for_version;
+}
+
int qdev_unplug(DeviceState *dev)
{
if (!dev->parent_bus->allow_hotplug) {
diff --git a/hw/qdev.h b/hw/qdev.h
index d8fbc739a0..a44060e54c 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -44,6 +44,8 @@ struct DeviceState {
QLIST_HEAD(, BusState) child_bus;
int num_child_bus;
QLIST_ENTRY(DeviceState) sibling;
+ int instance_id_alias;
+ int alias_required_for_version;
};
typedef void (*bus_dev_printfn)(Monitor *mon, DeviceState *dev, int indent);
@@ -112,6 +114,8 @@ int qdev_device_help(QemuOpts *opts);
DeviceState *qdev_device_add(QemuOpts *opts);
int qdev_init(DeviceState *dev) QEMU_WARN_UNUSED_RESULT;
void qdev_init_nofail(DeviceState *dev);
+void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
+ int required_for_version);
int qdev_unplug(DeviceState *dev);
void qdev_free(DeviceState *dev);
int qdev_simple_unplug_cb(DeviceState *dev);
diff --git a/savevm.c b/savevm.c
index 74e553c53d..dc20390b8f 100644
--- a/savevm.c
+++ b/savevm.c
@@ -991,6 +991,7 @@ typedef struct SaveStateEntry {
QTAILQ_ENTRY(SaveStateEntry) entry;
char idstr[256];
int instance_id;
+ int alias_id;
int version_id;
int section_id;
SaveSetParamsHandler *set_params;
@@ -1079,11 +1080,16 @@ void unregister_savevm(const char *idstr, void *opaque)
}
}
-int vmstate_register(int instance_id, const VMStateDescription *vmsd,
- void *opaque)
+int vmstate_register_with_alias_id(int instance_id,
+ const VMStateDescription *vmsd,
+ void *opaque, int alias_id,
+ int required_for_version)
{
SaveStateEntry *se;
+ /* If this triggers, alias support can be dropped for the vmsd. */
+ assert(alias_id == -1 || required_for_version >= vmsd->minimum_version_id);
+
se = qemu_mallocz(sizeof(SaveStateEntry));
pstrcpy(se->idstr, sizeof(se->idstr), vmsd->name);
se->version_id = vmsd->version_id;
@@ -1093,6 +1099,7 @@ int vmstate_register(int instance_id, const VMStateDescription *vmsd,
se->load_state = NULL;
se->opaque = opaque;
se->vmsd = vmsd;
+ se->alias_id = alias_id;
if (instance_id == -1) {
se->instance_id = calculate_new_instance_id(vmsd->name);
@@ -1104,6 +1111,12 @@ int vmstate_register(int instance_id, const VMStateDescription *vmsd,
return 0;
}
+int vmstate_register(int instance_id, const VMStateDescription *vmsd,
+ void *opaque)
+{
+ return vmstate_register_with_alias_id(instance_id, vmsd, opaque, -1, 0);
+}
+
void vmstate_unregister(const VMStateDescription *vmsd, void *opaque)
{
SaveStateEntry *se, *new_se;
@@ -1433,7 +1446,8 @@ static SaveStateEntry *find_se(const char *idstr, int instance_id)
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
if (!strcmp(se->idstr, idstr) &&
- instance_id == se->instance_id)
+ (instance_id == se->instance_id ||
+ instance_id == se->alias_id))
return se;
}
return NULL;