From: Amit Shah <amit.shah@redhat.com>
To: qemu list <qemu-devel@nongnu.org>
Cc: "Juan Quintela" <quintela@redhat.com>,
"Markus Armbruster" <armbru@redhat.com>,
"Alexander Graf" <agraf@suse.de>,
"\\\"Dr. David Alan Gilbert\\\"" <dgilbert@redhat.com>,
"Amit Shah" <amit.shah@redhat.com>,
"Paolo Bonzini" <pbonzini@redhat.com>,
"Andreas Färber" <afaerber@suse.de>
Subject: [Qemu-devel] [PATCH 01/18] migration: dump vmstate info as a json file for static analysis
Date: Mon, 12 May 2014 16:46:01 +0530 [thread overview]
Message-ID: <f75cb6f1f65dc9fb91e63db3fbe49711dea35060.1399892389.git.amit.shah@redhat.com> (raw)
In-Reply-To: <cover.1399892389.git.amit.shah@redhat.com>
In-Reply-To: <cover.1399892389.git.amit.shah@redhat.com>
This commit adds a new command, '-dump-vmstate', that takes a filename
as a parameter. When executed, QEMU will dump the vmstate information
for the machine type it's invoked with to the file, and quit.
The JSON-format output can then be used to compare the vmstate info for
different QEMU versions, specifically to test whether live migration
would break due to changes in the vmstate data.
This is based on a version from Andreas Färber posted here:
https://lists.gnu.org/archive/html/qemu-devel/2013-10/msg03095.html
A Python script that compares the output of such JSON dumps is included
in the following commit.
Signed-off-by: Amit Shah <amit.shah@redhat.com>
---
include/migration/vmstate.h | 2 +
qemu-options.hx | 9 +++
savevm.c | 134 ++++++++++++++++++++++++++++++++++++++++++++
vl.c | 14 +++++
4 files changed, 159 insertions(+)
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 7e45048..9829c0e 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -778,4 +778,6 @@ void vmstate_register_ram(struct MemoryRegion *memory, DeviceState *dev);
void vmstate_unregister_ram(struct MemoryRegion *memory, DeviceState *dev);
void vmstate_register_ram_global(struct MemoryRegion *memory);
+void dump_vmstate_json_to_file(FILE *out_fp);
+
#endif
diff --git a/qemu-options.hx b/qemu-options.hx
index 781af14..d376227 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3146,6 +3146,15 @@ STEXI
prepend a timestamp to each log message.(default:on)
ETEXI
+DEF("dump-vmstate", HAS_ARG, QEMU_OPTION_dump_vmstate,
+ "-dump-vmstate <file>\n" "", QEMU_ARCH_ALL)
+STEXI
+@item -dump-vmstate @var{file}
+@findex -dump-vmstate
+Dump json-encoded vmstate information for current machine type to file
+in @var{file}
+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 da8aa24..a4ce279 100644
--- a/savevm.c
+++ b/savevm.c
@@ -24,6 +24,7 @@
#include "config-host.h"
#include "qemu-common.h"
+#include "hw/boards.h"
#include "hw/hw.h"
#include "hw/qdev.h"
#include "net/net.h"
@@ -241,6 +242,139 @@ static QTAILQ_HEAD(savevm_handlers, SaveStateEntry) savevm_handlers =
QTAILQ_HEAD_INITIALIZER(savevm_handlers);
static int global_section_id;
+static void dump_vmstate_vmsd(FILE *out_file,
+ const VMStateDescription *vmsd, int indent,
+ bool is_subsection);
+
+static void dump_vmstate_vmsf(FILE *out_file, const VMStateField *field,
+ int indent)
+{
+ fprintf(out_file, "%*s{\n", indent, "");
+ indent += 2;
+ fprintf(out_file, "%*s\"field\": \"%s\",\n", indent, "", field->name);
+ fprintf(out_file, "%*s\"version_id\": %d,\n", indent, "",
+ field->version_id);
+ fprintf(out_file, "%*s\"field_exists\": %s,\n", indent, "",
+ field->field_exists ? "true" : "false");
+ fprintf(out_file, "%*s\"size\": %zu", indent, "", field->size);
+ if (field->vmsd != NULL) {
+ fprintf(out_file, ",\n");
+ dump_vmstate_vmsd(out_file, field->vmsd, indent, false);
+ }
+ fprintf(out_file, "\n%*s}", indent - 2, "");
+}
+
+static void dump_vmstate_vmss(FILE *out_file,
+ const VMStateSubsection *subsection,
+ int indent)
+{
+ if (subsection->vmsd != NULL) {
+ dump_vmstate_vmsd(out_file, subsection->vmsd, indent, true);
+ }
+}
+
+static void dump_vmstate_vmsd(FILE *out_file,
+ const VMStateDescription *vmsd, int indent,
+ bool is_subsection)
+{
+ if (is_subsection) {
+ fprintf(out_file, "%*s{\n", indent, "");
+ } else {
+ fprintf(out_file, "%*s\"%s\": {\n", indent, "", "Description");
+ }
+ indent += 2;
+ fprintf(out_file, "%*s\"name\": \"%s\",\n", indent, "", vmsd->name);
+ fprintf(out_file, "%*s\"version_id\": %d,\n", indent, "",
+ vmsd->version_id);
+ fprintf(out_file, "%*s\"minimum_version_id\": %d", indent, "",
+ vmsd->minimum_version_id);
+ if (vmsd->fields != NULL) {
+ const VMStateField *field = vmsd->fields;
+ bool first;
+
+ fprintf(out_file, ",\n%*s\"Fields\": [\n", indent, "");
+ first = true;
+ while (field->name != NULL) {
+ if (!first) {
+ fprintf(out_file, ",\n");
+ }
+ dump_vmstate_vmsf(out_file, field, indent + 2);
+ field++;
+ first = false;
+ }
+ fprintf(out_file, "\n%*s]", indent, "");
+ }
+ if (vmsd->subsections != NULL) {
+ const VMStateSubsection *subsection = vmsd->subsections;
+ bool first;
+
+ fprintf(out_file, ",\n%*s\"Subsections\": [\n", indent, "");
+ first = true;
+ while (subsection->vmsd != NULL) {
+ if (!first) {
+ fprintf(out_file, ",\n");
+ }
+ dump_vmstate_vmss(out_file, subsection, indent + 2);
+ subsection++;
+ first = false;
+ }
+ fprintf(out_file, "\n%*s]", indent, "");
+ }
+ fprintf(out_file, "\n%*s}", indent - 2, "");
+}
+
+static void dump_machine_type(FILE *out_file)
+{
+ MachineClass *mc;
+
+ mc = MACHINE_GET_CLASS(current_machine);
+
+ fprintf(out_file, " \"vmschkmachine\": {\n");
+ fprintf(out_file, " \"Name\": \"%s\"\n", mc->name);
+ fprintf(out_file, " },\n");
+}
+
+void dump_vmstate_json_to_file(FILE *out_file)
+{
+ GSList *list, *elt;
+ bool first;
+
+ fprintf(out_file, "{\n");
+ dump_machine_type(out_file);
+
+ first = true;
+ list = object_class_get_list(TYPE_DEVICE, true);
+ for (elt = list; elt; elt = elt->next) {
+ DeviceClass *dc = OBJECT_CLASS_CHECK(DeviceClass, elt->data,
+ TYPE_DEVICE);
+ const char *name;
+ int indent = 2;
+
+ if (!dc->vmsd) {
+ continue;
+ }
+
+ if (!first) {
+ fprintf(out_file, ",\n");
+ }
+ name = object_class_get_name(OBJECT_CLASS(dc));
+ fprintf(out_file, "%*s\"%s\": {\n", indent, "", name);
+ indent += 2;
+ fprintf(out_file, "%*s\"Name\": \"%s\",\n", indent, "", name);
+ fprintf(out_file, "%*s\"version_id\": %d,\n", indent, "",
+ dc->vmsd->version_id);
+ fprintf(out_file, "%*s\"minimum_version_id\": %d,\n", indent, "",
+ dc->vmsd->minimum_version_id);
+
+ dump_vmstate_vmsd(out_file, dc->vmsd, indent, false);
+
+ fprintf(out_file, "\n%*s}", indent - 2, "");
+ first = false;
+ }
+ fprintf(out_file, "\n}\n");
+ fclose(out_file);
+}
+
static int calculate_new_instance_id(const char *idstr)
{
SaveStateEntry *se;
diff --git a/vl.c b/vl.c
index 73e0661..165ec3e 100644
--- a/vl.c
+++ b/vl.c
@@ -2988,6 +2988,7 @@ int main(int argc, char **argv, char **envp)
const char *trace_file = NULL;
const ram_addr_t default_ram_size = (ram_addr_t)DEFAULT_RAM_SIZE *
1024 * 1024;
+ FILE *vmstate_dump_file = NULL;
atexit(qemu_run_exit_notifiers);
error_set_progname(argv[0]);
@@ -3956,6 +3957,13 @@ int main(int argc, char **argv, char **envp)
}
configure_msg(opts);
break;
+ case QEMU_OPTION_dump_vmstate:
+ vmstate_dump_file = fopen(optarg, "w");
+ if (vmstate_dump_file == NULL) {
+ fprintf(stderr, "open %s: %s\n", optarg, strerror(errno));
+ exit(1);
+ }
+ break;
default:
os_parse_cmd_args(popt->index, optarg);
}
@@ -4533,6 +4541,12 @@ int main(int argc, char **argv, char **envp)
}
}
+ if (vmstate_dump_file) {
+ /* dump and exit */
+ dump_vmstate_json_to_file(vmstate_dump_file);
+ return 0;
+ }
+
if (incoming) {
Error *local_err = NULL;
qemu_start_incoming_migration(incoming, &local_err);
--
1.9.0
next prev parent reply other threads:[~2014-05-12 11:16 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-05-12 11:16 [Qemu-devel] [PATCH 00/18] migration: add static analysis tool to check vmstate compat between versions Amit Shah
2014-05-12 11:16 ` Amit Shah [this message]
2014-05-12 12:51 ` [Qemu-devel] [PATCH 01/18] migration: dump vmstate info as a json file for static analysis Eric Blake
2014-05-13 4:12 ` Amit Shah
2014-05-21 11:45 ` Eric Blake
2014-05-21 9:44 ` Dr. David Alan Gilbert
2014-05-21 9:55 ` Amit Shah
2014-05-21 10:03 ` Dr. David Alan Gilbert
2014-05-21 10:12 ` Amit Shah
2014-05-21 11:47 ` Markus Armbruster
2014-05-21 11:45 ` Markus Armbruster
2014-05-12 11:16 ` [Qemu-devel] [PATCH 02/18] vmstate-static-checker: script to validate vmstate changes Amit Shah
2014-05-12 11:16 ` [Qemu-devel] [PATCH 03/18] tests: vmstate static checker: add dump1 and dump2 files Amit Shah
2014-05-12 11:16 ` [Qemu-devel] [PATCH 04/18] tests: vmstate static checker: incompat machine types Amit Shah
2014-05-12 11:16 ` [Qemu-devel] [PATCH 05/18] tests: vmstate static checker: add version error in main section Amit Shah
2014-05-12 11:16 ` [Qemu-devel] [PATCH 06/18] tests: vmstate static checker: version mismatch inside a Description Amit Shah
2014-05-12 11:16 ` [Qemu-devel] [PATCH 07/18] tests: vmstate static checker: minimum_version_id check Amit Shah
2014-05-12 11:16 ` [Qemu-devel] [PATCH 08/18] tests: vmstate static checker: remove a section Amit Shah
2014-05-12 11:16 ` [Qemu-devel] [PATCH 09/18] tests: vmstate static checker: remove a field Amit Shah
2014-05-12 11:16 ` [Qemu-devel] [PATCH 10/18] tests: vmstate static checker: remove last field in a struct Amit Shah
2014-05-12 11:16 ` [Qemu-devel] [PATCH 11/18] tests: vmstate static checker: change description name Amit Shah
2014-05-12 11:16 ` [Qemu-devel] [PATCH 12/18] tests: vmstate static checker: remove Fields Amit Shah
2014-05-12 11:16 ` [Qemu-devel] [PATCH 13/18] tests: vmstate static checker: remove Description Amit Shah
2014-05-12 11:16 ` [Qemu-devel] [PATCH 14/18] tests: vmstate static checker: remove Description inside Fields Amit Shah
2014-05-12 11:16 ` [Qemu-devel] [PATCH 15/18] tests: vmstate static checker: remove a subsection Amit Shah
2014-05-12 11:16 ` [Qemu-devel] [PATCH 16/18] tests: vmstate static checker: remove Subsections Amit Shah
2014-05-12 11:16 ` [Qemu-devel] [PATCH 17/18] tests: vmstate static checker: add substructure for usb-kbd for hid section Amit Shah
2014-05-12 11:16 ` [Qemu-devel] [PATCH 18/18] tests: vmstate static checker: add size mismatch inside substructure Amit Shah
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=f75cb6f1f65dc9fb91e63db3fbe49711dea35060.1399892389.git.amit.shah@redhat.com \
--to=amit.shah@redhat.com \
--cc=afaerber@suse.de \
--cc=agraf@suse.de \
--cc=armbru@redhat.com \
--cc=dgilbert@redhat.com \
--cc=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=quintela@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).