@@ -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
@@ -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
@@ -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,
@@ -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);
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 <aliguori@us.ibm.com> --- hw/hw.h | 2 + qemu-options.hx | 10 ++++++++ savevm.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.c | 10 ++++++++ 4 files changed, 84 insertions(+), 0 deletions(-)