This ends up being pretty slick as we can store the JSON schema in the tree and then use a test wrapper to validate whether fields change.
Current schema will come with the test wrapper. Signed-off-by: Anthony Liguori <aligu...@us.ibm.com> --- hw/hw.h | 2 + qemu-options.hx | 10 ++++++++ savevm.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.c | 10 ++++++++ 4 files changed, 84 insertions(+), 0 deletions(-) diff --git a/hw/hw.h b/hw/hw.h index 9a9012f..531ee30 100644 --- a/hw/hw.h +++ b/hw/hw.h @@ -927,4 +927,6 @@ void vmstate_unregister(DeviceState *dev, const VMStateDescription *vmsd, void register_vmstate_description(const VMStateDescription *desc); +void vmstate_dump_schema(void); + #endif diff --git a/qemu-options.hx b/qemu-options.hx index ef60730..0faaea5 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2368,6 +2368,16 @@ Specify a trace file to log output traces to. ETEXI #endif +DEF("vmstate-dump", 0, QEMU_OPTION_vmstate_dump, + "-vmstate-dump output the current VMState schema and exit\n", + QEMU_ARCH_ALL) +STEXI +@item -vmstate-dump +@findex -vmstate-dump +This option is only used for an internal test suite. The output format may +change in the future. +ETEXI + HXCOMM This is the last statement. Insert new options before this line! STEXI @end table diff --git a/savevm.c b/savevm.c index 4a37917..d35ce8d 100644 --- a/savevm.c +++ b/savevm.c @@ -82,6 +82,7 @@ #include "migration.h" #include "qemu_socket.h" #include "qemu-queue.h" +#include "qemu-objects.h" #define SELF_ANNOUNCE_ROUNDS 5 @@ -1285,8 +1286,69 @@ void vmstate_unregister(DeviceState *dev, const VMStateDescription *vmsd, } } +typedef struct VmsdEntry +{ + const VMStateDescription *desc; + QTAILQ_ENTRY(VmsdEntry) node; +} VmsdEntry; + +static QTAILQ_HEAD(, VmsdEntry) vmsd_description_list = + QTAILQ_HEAD_INITIALIZER(vmsd_description_list); + void register_vmstate_description(const VMStateDescription *desc) { + VmsdEntry *e = qemu_mallocz(sizeof(*e)); + + e->desc = desc; + QTAILQ_INSERT_TAIL(&vmsd_description_list, e, node); +} + +static QDict *vmstate_dump_state(const VMStateDescription *desc) +{ + VMStateField *f; + QDict *ret; + + ret = qdict_new(); + + qdict_put(ret, "__version__", qint_from_int(desc->version_id)); + for (f = desc->fields; f && f->name; f++) { + if (qdict_haskey(ret, f->name)) { + fprintf(stderr, "vmstate: duplicate key `%s' in `%s'\n", + f->name, desc->name); + exit(1); + } + if (f->vmsd) { + qdict_put(ret, f->name, vmstate_dump_state(f->vmsd)); + } else { + qdict_put(ret, f->name, qstring_from_str(f->info->name)); + } + } + + return ret; +} + +void vmstate_dump_schema(void) +{ + QDict *items; + QString *str; + VmsdEntry *e; + + items = qdict_new(); + + QTAILQ_FOREACH(e, &vmsd_description_list, node) { + if (qdict_haskey(items, e->desc->name)) { + fprintf(stderr, "vmstate: duplicate devices of name `%s'\n", + e->desc->name); + exit(1); + } + qdict_put(items, e->desc->name, vmstate_dump_state(e->desc)); + } + + str = qobject_to_json_pretty(QOBJECT(items)); + printf("%s\n", qstring_get_str(str)); + + QDECREF(str); + QDECREF(items); } static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd, diff --git a/vl.c b/vl.c index dbb927d..f91875b 100644 --- a/vl.c +++ b/vl.c @@ -2038,6 +2038,7 @@ int main(int argc, char **argv, char **envp) #endif int defconfig = 1; const char *trace_file = NULL; + bool vmstate_dump = false; atexit(qemu_run_exit_notifiers); error_set_progname(argv[0]); @@ -2876,6 +2877,9 @@ int main(int argc, char **argv, char **envp) fclose(fp); break; } + case QEMU_OPTION_vmstate_dump: + vmstate_dump = true; + break; default: os_parse_cmd_args(popt->index, optarg); } @@ -3124,6 +3128,12 @@ int main(int argc, char **argv, char **envp) } qemu_add_globals(); + if (vmstate_dump) { + module_call_init(MODULE_INIT_VMSTATE); + vmstate_dump_schema(); + exit(0); + } + machine->init(ram_size, boot_devices, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); -- 1.7.0.4