From a40db1b36ba3cf4c8599178740511d7d5c0c9641 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Feb 2016 17:28:58 +0000 Subject: qemu-options.hx: Improve documentation of chardev multiplexing mode The current documentation of chardev mux=on is rather brief and opaque; expand it to hopefully be a bit more helpful. Signed-off-by: Peter Maydell Message-Id: <1455643738-6068-1-git-send-email-peter.maydell@linaro.org> Signed-off-by: Paolo Bonzini --- qemu-doc.texi | 30 ++++++++++++++++++++---------- qemu-options.hx | 45 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 12 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index c324da8..bc9dd13 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -158,7 +158,8 @@ TODO (no longer available) * pcsys_introduction:: Introduction * pcsys_quickstart:: Quick Start * sec_invocation:: Invocation -* pcsys_keys:: Keys +* pcsys_keys:: Keys in the graphical frontends +* mux_keys:: Keys in the character backend multiplexer * pcsys_monitor:: QEMU Monitor * disk_images:: Disk Images * pcsys_network:: Network emulation @@ -272,7 +273,7 @@ targets do not need a disk image. @c man end @node pcsys_keys -@section Keys +@section Keys in the graphical frontends @c man begin OPTIONS @@ -322,15 +323,23 @@ Toggle mouse and keyboard grab. In the virtual consoles, you can use @key{Ctrl-Up}, @key{Ctrl-Down}, @key{Ctrl-PageUp} and @key{Ctrl-PageDown} to move in the back log. -@kindex Ctrl-a h -During emulation, if you are using the @option{-nographic} option, use -@key{Ctrl-a h} to get terminal commands: +@c man end + +@node mux_keys +@section Keys in the character backend multiplexer + +@c man begin OPTIONS + +During emulation, if you are using a character backend multiplexer +(which is the default if you are using @option{-nographic}) then +several commands are available via an escape sequence. These +key sequences all start with an escape character, which is @key{Ctrl-a} +by default, but can be changed with @option{-echr}. The list below assumes +you're using the default. @table @key @item Ctrl-a h @kindex Ctrl-a h -@item Ctrl-a ? -@kindex Ctrl-a ? Print this help @item Ctrl-a x @kindex Ctrl-a x @@ -346,10 +355,11 @@ Toggle console timestamps Send break (magic sysrq in Linux) @item Ctrl-a c @kindex Ctrl-a c -Switch between console and monitor +Rotate between the frontends connected to the multiplexer (usually +this switches between the monitor and the console) @item Ctrl-a Ctrl-a -@kindex Ctrl-a a -Send Ctrl-a +@kindex Ctrl-a Ctrl-a +Send the escape character to the frontend @end table @c man end diff --git a/qemu-options.hx b/qemu-options.hx index 2f0465e..7e6762e 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2162,8 +2162,49 @@ All devices must have an id, which can be any string up to 127 characters long. It is used to uniquely identify this device in other command line directives. A character device may be used in multiplexing mode by multiple front-ends. -The key sequence of @key{Control-a} and @key{c} will rotate the input focus -between attached front-ends. Specify @option{mux=on} to enable this mode. +Specify @option{mux=on} to enable this mode. +A multiplexer is a "1:N" device, and here the "1" end is your specified chardev +backend, and the "N" end is the various parts of QEMU that can talk to a chardev. +If you create a chardev with @option{id=myid} and @option{mux=on}, QEMU will +create a multiplexer with your specified ID, and you can then configure multiple +front ends to use that chardev ID for their input/output. Up to four different +front ends can be connected to a single multiplexed chardev. (Without +multiplexing enabled, a chardev can only be used by a single front end.) +For instance you could use this to allow a single stdio chardev to be used by +two serial ports and the QEMU monitor: + +@example +-chardev stdio,mux=on,id=char0 \ +-mon chardev=char0,mode=readline,default \ +-serial chardev:char0 \ +-serial chardev:char0 +@end example + +You can have more than one multiplexer in a system configuration; for instance +you could have a TCP port multiplexed between UART 0 and UART 1, and stdio +multiplexed between the QEMU monitor and a parallel port: + +@example +-chardev stdio,mux=on,id=char0 \ +-mon chardev=char0,mode=readline,default \ +-parallel chardev:char0 \ +-chardev tcp,...,mux=on,id=char1 \ +-serial chardev:char1 \ +-serial chardev:char1 +@end example + +When you're using a multiplexed character device, some escape sequences are +interpreted in the input. @xref{mux_keys, Keys in the character backend +multiplexer}. + +Note that some other command line options may implicitly create multiplexed +character backends; for instance @option{-serial mon:stdio} creates a +multiplexed stdio backend connected to the serial port and the QEMU monitor, +and @option{-nographic} also multiplexes the console and the monitor to +stdio. + +There is currently no support for multiplexing in the other direction +(where a single QEMU front end takes input and output from multiple chardevs). Every backend supports the @option{logfile} option, which supplies the path to a file to record all data transmitted via the backend. The @option{logappend} -- cgit v1.1 From cf7ea1e60c4280bc037d8eee8cdbba67dfbc7825 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Fri, 19 Feb 2016 10:20:16 +0800 Subject: scripts/kvm/kvm_stat: Fix missing right parantheses and ".format(...)" They seem to have snuck in when applying Janosch Frank 's previous patch. Signed-off-by: Fam Zheng Message-Id: <1455848416-13177-1-git-send-email-famz@redhat.com> Reviewed-by: Janosch Frank Tested-by: Janosch Frank Signed-off-by: Paolo Bonzini --- scripts/kvm/kvm_stat | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat index 3cf1181..769d884 100755 --- a/scripts/kvm/kvm_stat +++ b/scripts/kvm/kvm_stat @@ -796,11 +796,12 @@ def check_access(options): sys.stderr.write("Please enable CONFIG_TRACING in your kernel " "when using the option -t (default).\n" "If it is enabled, make {0} readable by the " - "current user.\n") + "current user.\n" + .format(PATH_DEBUGFS_TRACING)) if options.tracepoints: sys.exit(1) - sys.stderr.write("Falling back to debugfs statistics!\n" + sys.stderr.write("Falling back to debugfs statistics!\n") options.debugfs = True sleep(5) -- cgit v1.1 From e3517a529913a2a48c12ba8eef4975ad561af97c Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Thu, 18 Feb 2016 13:16:46 +0800 Subject: dump-guest-memory: cleanup: removing dump_{error|cleanup}(). It might be a little bit confusing and error prone to do dump_cleanup() in these two functions. A better way is to do dump_cleanup() before dump finish, no matter whether dump has succeeded or not. Signed-off-by: Peter Xu Reviewed-by: Fam Zheng Message-Id: <1455772616-8668-2-git-send-email-peterx@redhat.com> Signed-off-by: Paolo Bonzini --- dump.c | 78 +++++++++++++++++++++++++++--------------------------------------- 1 file changed, 32 insertions(+), 46 deletions(-) diff --git a/dump.c b/dump.c index 96e1fc1..769c5f9 100644 --- a/dump.c +++ b/dump.c @@ -82,12 +82,6 @@ static int dump_cleanup(DumpState *s) return 0; } -static void dump_error(DumpState *s, const char *reason, Error **errp) -{ - dump_cleanup(s); - error_setg(errp, "%s", reason); -} - static int fd_write_vmcore(const void *buf, size_t size, void *opaque) { DumpState *s = opaque; @@ -128,7 +122,7 @@ static void write_elf64_header(DumpState *s, Error **errp) ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s); if (ret < 0) { - dump_error(s, "dump: failed to write elf header", errp); + error_setg(errp, "dump: failed to write elf header"); } } @@ -159,7 +153,7 @@ static void write_elf32_header(DumpState *s, Error **errp) ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s); if (ret < 0) { - dump_error(s, "dump: failed to write elf header", errp); + error_setg(errp, "dump: failed to write elf header"); } } @@ -182,7 +176,7 @@ static void write_elf64_load(DumpState *s, MemoryMapping *memory_mapping, ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s); if (ret < 0) { - dump_error(s, "dump: failed to write program header table", errp); + error_setg(errp, "dump: failed to write program header table"); } } @@ -205,7 +199,7 @@ static void write_elf32_load(DumpState *s, MemoryMapping *memory_mapping, ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s); if (ret < 0) { - dump_error(s, "dump: failed to write program header table", errp); + error_setg(errp, "dump: failed to write program header table"); } } @@ -225,7 +219,7 @@ static void write_elf64_note(DumpState *s, Error **errp) ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s); if (ret < 0) { - dump_error(s, "dump: failed to write program header table", errp); + error_setg(errp, "dump: failed to write program header table"); } } @@ -245,7 +239,7 @@ static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s, id = cpu_index(cpu); ret = cpu_write_elf64_note(f, cpu, id, s); if (ret < 0) { - dump_error(s, "dump: failed to write elf notes", errp); + error_setg(errp, "dump: failed to write elf notes"); return; } } @@ -253,7 +247,7 @@ static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s, CPU_FOREACH(cpu) { ret = cpu_write_elf64_qemunote(f, cpu, s); if (ret < 0) { - dump_error(s, "dump: failed to write CPU status", errp); + error_setg(errp, "dump: failed to write CPU status"); return; } } @@ -275,7 +269,7 @@ static void write_elf32_note(DumpState *s, Error **errp) ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s); if (ret < 0) { - dump_error(s, "dump: failed to write program header table", errp); + error_setg(errp, "dump: failed to write program header table"); } } @@ -290,7 +284,7 @@ static void write_elf32_notes(WriteCoreDumpFunction f, DumpState *s, id = cpu_index(cpu); ret = cpu_write_elf32_note(f, cpu, id, s); if (ret < 0) { - dump_error(s, "dump: failed to write elf notes", errp); + error_setg(errp, "dump: failed to write elf notes"); return; } } @@ -298,7 +292,7 @@ static void write_elf32_notes(WriteCoreDumpFunction f, DumpState *s, CPU_FOREACH(cpu) { ret = cpu_write_elf32_qemunote(f, cpu, s); if (ret < 0) { - dump_error(s, "dump: failed to write CPU status", errp); + error_setg(errp, "dump: failed to write CPU status"); return; } } @@ -326,7 +320,7 @@ static void write_elf_section(DumpState *s, int type, Error **errp) ret = fd_write_vmcore(&shdr, shdr_size, s); if (ret < 0) { - dump_error(s, "dump: failed to write section header table", errp); + error_setg(errp, "dump: failed to write section header table"); } } @@ -336,7 +330,7 @@ static void write_data(DumpState *s, void *buf, int length, Error **errp) ret = fd_write_vmcore(buf, length, s); if (ret < 0) { - dump_error(s, "dump: failed to save memory", errp); + error_setg(errp, "dump: failed to save memory"); } } @@ -568,11 +562,6 @@ static void dump_begin(DumpState *s, Error **errp) } } -static void dump_completed(DumpState *s) -{ - dump_cleanup(s); -} - static int get_next_block(DumpState *s, GuestPhysBlock *block) { while (1) { @@ -624,8 +613,6 @@ static void dump_iterate(DumpState *s, Error **errp) } } while (!get_next_block(s, block)); - - dump_completed(s); } static void create_vmcore(DumpState *s, Error **errp) @@ -765,7 +752,7 @@ static void create_header32(DumpState *s, Error **errp) dh->status = cpu_to_dump32(s, status); if (write_buffer(s->fd, 0, dh, size) < 0) { - dump_error(s, "dump: failed to write disk dump header", errp); + error_setg(errp, "dump: failed to write disk dump header"); goto out; } @@ -784,7 +771,7 @@ static void create_header32(DumpState *s, Error **errp) if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS * block_size, kh, size) < 0) { - dump_error(s, "dump: failed to write kdump sub header", errp); + error_setg(errp, "dump: failed to write kdump sub header"); goto out; } @@ -800,7 +787,7 @@ static void create_header32(DumpState *s, Error **errp) } if (write_buffer(s->fd, offset_note, s->note_buf, s->note_size) < 0) { - dump_error(s, "dump: failed to write notes", errp); + error_setg(errp, "dump: failed to write notes"); goto out; } @@ -865,7 +852,7 @@ static void create_header64(DumpState *s, Error **errp) dh->status = cpu_to_dump32(s, status); if (write_buffer(s->fd, 0, dh, size) < 0) { - dump_error(s, "dump: failed to write disk dump header", errp); + error_setg(errp, "dump: failed to write disk dump header"); goto out; } @@ -884,7 +871,7 @@ static void create_header64(DumpState *s, Error **errp) if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS * block_size, kh, size) < 0) { - dump_error(s, "dump: failed to write kdump sub header", errp); + error_setg(errp, "dump: failed to write kdump sub header"); goto out; } @@ -901,7 +888,7 @@ static void create_header64(DumpState *s, Error **errp) if (write_buffer(s->fd, offset_note, s->note_buf, s->note_size) < 0) { - dump_error(s, "dump: failed to write notes", errp); + error_setg(errp, "dump: failed to write notes"); goto out; } @@ -1087,7 +1074,7 @@ static void write_dump_bitmap(DumpState *s, Error **errp) while (get_next_page(&block_iter, &pfn, NULL, s)) { ret = set_dump_bitmap(last_pfn, pfn, true, dump_bitmap_buf, s); if (ret < 0) { - dump_error(s, "dump: failed to set dump_bitmap", errp); + error_setg(errp, "dump: failed to set dump_bitmap"); goto out; } @@ -1104,7 +1091,7 @@ static void write_dump_bitmap(DumpState *s, Error **errp) ret = set_dump_bitmap(last_pfn, last_pfn + bits_per_buf, false, dump_bitmap_buf, s); if (ret < 0) { - dump_error(s, "dump: failed to sync dump_bitmap", errp); + error_setg(errp, "dump: failed to sync dump_bitmap"); goto out; } } @@ -1237,7 +1224,7 @@ static void write_dump_pages(DumpState *s, Error **errp) ret = write_cache(&page_data, buf, s->dump_info.page_size, false); g_free(buf); if (ret < 0) { - dump_error(s, "dump: failed to write page data (zero page)", errp); + error_setg(errp, "dump: failed to write page data (zero page)"); goto out; } @@ -1253,7 +1240,7 @@ static void write_dump_pages(DumpState *s, Error **errp) ret = write_cache(&page_desc, &pd_zero, sizeof(PageDescriptor), false); if (ret < 0) { - dump_error(s, "dump: failed to write page desc", errp); + error_setg(errp, "dump: failed to write page desc"); goto out; } } else { @@ -1278,7 +1265,7 @@ static void write_dump_pages(DumpState *s, Error **errp) ret = write_cache(&page_data, buf_out, size_out, false); if (ret < 0) { - dump_error(s, "dump: failed to write page data", errp); + error_setg(errp, "dump: failed to write page data"); goto out; } #ifdef CONFIG_LZO @@ -1291,7 +1278,7 @@ static void write_dump_pages(DumpState *s, Error **errp) ret = write_cache(&page_data, buf_out, size_out, false); if (ret < 0) { - dump_error(s, "dump: failed to write page data", errp); + error_setg(errp, "dump: failed to write page data"); goto out; } #endif @@ -1305,7 +1292,7 @@ static void write_dump_pages(DumpState *s, Error **errp) ret = write_cache(&page_data, buf_out, size_out, false); if (ret < 0) { - dump_error(s, "dump: failed to write page data", errp); + error_setg(errp, "dump: failed to write page data"); goto out; } #endif @@ -1321,7 +1308,7 @@ static void write_dump_pages(DumpState *s, Error **errp) ret = write_cache(&page_data, buf, s->dump_info.page_size, false); if (ret < 0) { - dump_error(s, "dump: failed to write page data", errp); + error_setg(errp, "dump: failed to write page data"); goto out; } } @@ -1333,7 +1320,7 @@ static void write_dump_pages(DumpState *s, Error **errp) ret = write_cache(&page_desc, &pd, sizeof(PageDescriptor), false); if (ret < 0) { - dump_error(s, "dump: failed to write page desc", errp); + error_setg(errp, "dump: failed to write page desc"); goto out; } } @@ -1341,12 +1328,12 @@ static void write_dump_pages(DumpState *s, Error **errp) ret = write_cache(&page_desc, NULL, 0, true); if (ret < 0) { - dump_error(s, "dump: failed to sync cache for page_desc", errp); + error_setg(errp, "dump: failed to sync cache for page_desc"); goto out; } ret = write_cache(&page_data, NULL, 0, true); if (ret < 0) { - dump_error(s, "dump: failed to sync cache for page_data", errp); + error_setg(errp, "dump: failed to sync cache for page_data"); goto out; } @@ -1390,7 +1377,7 @@ static void create_kdump_vmcore(DumpState *s, Error **errp) ret = write_start_flat_header(s->fd); if (ret < 0) { - dump_error(s, "dump: failed to write start flat header", errp); + error_setg(errp, "dump: failed to write start flat header"); return; } @@ -1414,11 +1401,9 @@ static void create_kdump_vmcore(DumpState *s, Error **errp) ret = write_end_flat_header(s->fd); if (ret < 0) { - dump_error(s, "dump: failed to write end flat header", errp); + error_setg(errp, "dump: failed to write end flat header"); return; } - - dump_completed(s); } static ram_addr_t get_start_block(DumpState *s) @@ -1706,6 +1691,7 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin, create_vmcore(s, errp); } + dump_cleanup(s); g_free(s); } -- cgit v1.1 From 228de9cf1d9607d7eb73445c1656cc3834826606 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Thu, 18 Feb 2016 13:16:47 +0800 Subject: dump-guest-memory: add "detach" flag for QMP/HMP interfaces. This patch only adds the interfaces, but does not implement them. "detach" parameter is made optional, to make sure that all the old dump-guest-memory requests will still be able to work. Signed-off-by: Peter Xu Reviewed-by: Fam Zheng Message-Id: <1455772616-8668-3-git-send-email-peterx@redhat.com> Signed-off-by: Paolo Bonzini --- dump.c | 5 +++-- hmp-commands.hx | 5 +++-- hmp.c | 9 +++++++-- qapi-schema.json | 8 ++++++-- qmp-commands.hx | 6 ++++-- 5 files changed, 23 insertions(+), 10 deletions(-) diff --git a/dump.c b/dump.c index 769c5f9..c4a62d9 100644 --- a/dump.c +++ b/dump.c @@ -1609,8 +1609,9 @@ cleanup: dump_cleanup(s); } -void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin, - int64_t begin, bool has_length, +void qmp_dump_guest_memory(bool paging, const char *file, + bool has_detach, bool detach, + bool has_begin, int64_t begin, bool has_length, int64_t length, bool has_format, DumpGuestMemoryFormat format, Error **errp) { diff --git a/hmp-commands.hx b/hmp-commands.hx index bb52e4d..664d794 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1056,10 +1056,11 @@ ETEXI { .name = "dump-guest-memory", - .args_type = "paging:-p,zlib:-z,lzo:-l,snappy:-s,filename:F,begin:i?,length:i?", - .params = "[-p] [-z|-l|-s] filename [begin length]", + .args_type = "paging:-p,detach:-d,zlib:-z,lzo:-l,snappy:-s,filename:F,begin:i?,length:i?", + .params = "[-p] [-d] [-z|-l|-s] filename [begin length]", .help = "dump guest memory into file 'filename'.\n\t\t\t" "-p: do paging to get guest's memory mapping.\n\t\t\t" + "-d: return immediately (do not wait for completion).\n\t\t\t" "-z: dump in kdump-compressed format, with zlib compression.\n\t\t\t" "-l: dump in kdump-compressed format, with lzo compression.\n\t\t\t" "-s: dump in kdump-compressed format, with snappy compression.\n\t\t\t" diff --git a/hmp.c b/hmp.c index 996cb91..7f65b32 100644 --- a/hmp.c +++ b/hmp.c @@ -1587,8 +1587,10 @@ void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict) const char *file = qdict_get_str(qdict, "filename"); bool has_begin = qdict_haskey(qdict, "begin"); bool has_length = qdict_haskey(qdict, "length"); + bool has_detach = qdict_haskey(qdict, "detach"); int64_t begin = 0; int64_t length = 0; + bool detach = false; enum DumpGuestMemoryFormat dump_format = DUMP_GUEST_MEMORY_FORMAT_ELF; char *prot; @@ -1616,11 +1618,14 @@ void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict) if (has_length) { length = qdict_get_int(qdict, "length"); } + if (has_detach) { + detach = qdict_get_bool(qdict, "detach"); + } prot = g_strconcat("file:", file, NULL); - qmp_dump_guest_memory(paging, prot, has_begin, begin, has_length, length, - true, dump_format, &err); + qmp_dump_guest_memory(paging, prot, true, detach, has_begin, begin, + has_length, length, true, dump_format, &err); hmp_handle_error(mon, &err); g_free(prot); } diff --git a/qapi-schema.json b/qapi-schema.json index 8d04897..caff580 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -2195,6 +2195,9 @@ # 2. fd: the protocol starts with "fd:", and the following string # is the fd's name. # +# @detach: #optional if true, QMP will return immediately rather than +# waiting for the dump to finish. (since 2.6). +# # @begin: #optional if specified, the starting physical address. # # @length: #optional if specified, the memory size, in bytes. If you don't @@ -2211,8 +2214,9 @@ # Since: 1.2 ## { 'command': 'dump-guest-memory', - 'data': { 'paging': 'bool', 'protocol': 'str', '*begin': 'int', - '*length': 'int', '*format': 'DumpGuestMemoryFormat' } } + 'data': { 'paging': 'bool', 'protocol': 'str', '*detach': 'bool', + '*begin': 'int', '*length': 'int', + '*format': 'DumpGuestMemoryFormat'} } ## # @DumpGuestMemoryCapability: diff --git a/qmp-commands.hx b/qmp-commands.hx index 9fb0d78..d30b1eb 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -838,8 +838,8 @@ EQMP { .name = "dump-guest-memory", - .args_type = "paging:b,protocol:s,begin:i?,end:i?,format:s?", - .params = "-p protocol [begin] [length] [format]", + .args_type = "paging:b,protocol:s,detach:b?,begin:i?,end:i?,format:s?", + .params = "-p protocol [-d] [begin] [length] [format]", .help = "dump guest memory to file", .mhandler.cmd_new = qmp_marshal_dump_guest_memory, }, @@ -855,6 +855,8 @@ Arguments: - "paging": do paging to get guest's memory mapping (json-bool) - "protocol": destination file(started with "file:") or destination file descriptor (started with "fd:") (json-string) +- "detach": if specified, command will return immediately, without waiting + for the dump to finish (json-bool) - "begin": the starting physical address. It's optional, and should be specified with length together (json-int) - "length": the memory size, in bytes. It's optional, and should be specified -- cgit v1.1 From baf28f57e2dec63eebfcd3c00f8d4dea9fcde21e Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Thu, 18 Feb 2016 13:16:48 +0800 Subject: dump-guest-memory: using static DumpState, add DumpStatus Instead of malloc/free each time for DumpState, make it static. Added DumpStatus to show status for dump. This is to be used for detached dump. Signed-off-by: Peter Xu Reviewed-by: Fam Zheng Message-Id: <1455772616-8668-4-git-send-email-peterx@redhat.com> Signed-off-by: Paolo Bonzini --- dump.c | 21 ++++++++++++++++----- include/sysemu/dump.h | 2 ++ qapi-schema.json | 18 ++++++++++++++++++ 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/dump.c b/dump.c index c4a62d9..434bc60 100644 --- a/dump.c +++ b/dump.c @@ -1442,6 +1442,14 @@ static void get_max_mapnr(DumpState *s) s->max_mapnr = dump_paddr_to_pfn(s, last_block->target_end); } +static DumpState dump_state_global = { .status = DUMP_STATUS_NONE }; + +static void dump_state_prepare(DumpState *s) +{ + /* zero the struct, setting status to active */ + *s = (DumpState) { .status = DUMP_STATUS_ACTIVE }; +} + static void dump_init(DumpState *s, int fd, bool has_format, DumpGuestMemoryFormat format, bool paging, bool has_filter, int64_t begin, int64_t length, Error **errp) @@ -1676,24 +1684,27 @@ void qmp_dump_guest_memory(bool paging, const char *file, return; } - s = g_malloc0(sizeof(DumpState)); + s = &dump_state_global; + dump_state_prepare(s); dump_init(s, fd, has_format, format, paging, has_begin, begin, length, &local_err); if (local_err) { - g_free(s); error_propagate(errp, local_err); + s->status = DUMP_STATUS_FAILED; return; } if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) { - create_kdump_vmcore(s, errp); + create_kdump_vmcore(s, &local_err); } else { - create_vmcore(s, errp); + create_vmcore(s, &local_err); } + s->status = (local_err ? DUMP_STATUS_FAILED : DUMP_STATUS_COMPLETED); + error_propagate(errp, local_err); + dump_cleanup(s); - g_free(s); } DumpGuestMemoryCapability *qmp_query_dump_guest_memory_capability(Error **errp) diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h index 2f04b24..21fc02d 100644 --- a/include/sysemu/dump.h +++ b/include/sysemu/dump.h @@ -38,6 +38,7 @@ #include "sysemu/dump-arch.h" #include "sysemu/memory_mapping.h" +#include "qapi-types.h" typedef struct QEMU_PACKED MakedumpfileHeader { char signature[16]; /* = "makedumpfile" */ @@ -176,6 +177,7 @@ typedef struct DumpState { off_t offset_page; /* offset of page part in vmcore */ size_t num_dumpable; /* number of page that can be dumped */ uint32_t flag_compress; /* indicate the compression format */ + DumpStatus status; /* current dump status */ } DumpState; uint16_t cpu_to_dump16(DumpState *s, uint16_t val); diff --git a/qapi-schema.json b/qapi-schema.json index caff580..ccd30c8 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -2219,6 +2219,24 @@ '*format': 'DumpGuestMemoryFormat'} } ## +# @DumpStatus +# +# Describe the status of a long-running background guest memory dump. +# +# @none: no dump-guest-memory has started yet. +# +# @active: there is one dump running in background. +# +# @completed: the last dump has finished successfully. +# +# @failed: the last dump has failed. +# +# Since 2.6 +## +{ 'enum': 'DumpStatus', + 'data': [ 'none', 'active', 'completed', 'failed' ] } + +## # @DumpGuestMemoryCapability: # # A list of the available formats for dump-guest-memory -- cgit v1.1 From 65d64f362326a57b590b8b76e3422030a2aa5c44 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Thu, 18 Feb 2016 13:16:49 +0800 Subject: dump-guest-memory: add dump_in_progress() helper function For now, it has no effect. It will be used in dump detach support. Signed-off-by: Peter Xu Reviewed-by: Fam Zheng Message-Id: <1455772616-8668-5-git-send-email-peterx@redhat.com> Signed-off-by: Paolo Bonzini --- dump.c | 13 +++++++++++++ include/qemu-common.h | 4 ++++ qmp.c | 14 ++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/dump.c b/dump.c index 434bc60..158d6ea 100644 --- a/dump.c +++ b/dump.c @@ -1450,6 +1450,12 @@ static void dump_state_prepare(DumpState *s) *s = (DumpState) { .status = DUMP_STATUS_ACTIVE }; } +bool dump_in_progress(void) +{ + DumpState *state = &dump_state_global; + return (state->status == DUMP_STATUS_ACTIVE); +} + static void dump_init(DumpState *s, int fd, bool has_format, DumpGuestMemoryFormat format, bool paging, bool has_filter, int64_t begin, int64_t length, Error **errp) @@ -1628,6 +1634,13 @@ void qmp_dump_guest_memory(bool paging, const char *file, DumpState *s; Error *local_err = NULL; + /* if there is a dump in background, we should wait until the dump + * finished */ + if (dump_in_progress()) { + error_setg(errp, "There is a dump in process, please wait."); + return; + } + /* * kdump-compressed format need the whole memory dumped, so paging or * filter is not supported here. diff --git a/include/qemu-common.h b/include/qemu-common.h index f557be7..59ab759 100644 --- a/include/qemu-common.h +++ b/include/qemu-common.h @@ -494,4 +494,8 @@ int parse_debug_env(const char *name, int max, int initial); const char *qemu_ether_ntoa(const MACAddr *mac); void page_size_init(void); +/* returns non-zero if dump is in progress, otherwise zero is + * returned. */ +bool dump_in_progress(void); + #endif diff --git a/qmp.c b/qmp.c index 9a93d5e..3f16a77 100644 --- a/qmp.c +++ b/qmp.c @@ -103,6 +103,13 @@ void qmp_quit(Error **errp) void qmp_stop(Error **errp) { + /* if there is a dump in background, we should wait until the dump + * finished */ + if (dump_in_progress()) { + error_setg(errp, "There is a dump in process, please wait."); + return; + } + if (runstate_check(RUN_STATE_INMIGRATE)) { autostart = 0; } else { @@ -175,6 +182,13 @@ void qmp_cont(Error **errp) BlockBackend *blk; BlockDriverState *bs; + /* if there is a dump in background, we should wait until the dump + * finished */ + if (dump_in_progress()) { + error_setg(errp, "There is a dump in process, please wait."); + return; + } + if (runstate_needs_reset()) { error_setg(errp, "Resetting the Virtual Machine is required"); return; -- cgit v1.1 From ca1fc8c97e9f26690b1ddbbbced5bafb3d65f6b5 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Thu, 18 Feb 2016 13:16:50 +0800 Subject: dump-guest-memory: introduce dump_process() helper function. No functional change. Cleanup only. Signed-off-by: Peter Xu Reviewed-by: Fam Zheng Message-Id: <1455772616-8668-6-git-send-email-peterx@redhat.com> Signed-off-by: Paolo Bonzini --- dump.c | 31 +++++++++++++++++++++---------- include/sysemu/dump.h | 3 +++ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/dump.c b/dump.c index 158d6ea..fed84a6 100644 --- a/dump.c +++ b/dump.c @@ -1465,6 +1465,9 @@ static void dump_init(DumpState *s, int fd, bool has_format, Error *err = NULL; int ret; + s->has_format = has_format; + s->format = format; + /* kdump-compressed is conflict with paging and filter */ if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) { assert(!paging && !has_filter); @@ -1623,6 +1626,23 @@ cleanup: dump_cleanup(s); } +/* this operation might be time consuming. */ +static void dump_process(DumpState *s, Error **errp) +{ + Error *local_err = NULL; + + if (s->has_format && s->format != DUMP_GUEST_MEMORY_FORMAT_ELF) { + create_kdump_vmcore(s, &local_err); + } else { + create_vmcore(s, &local_err); + } + + s->status = (local_err ? DUMP_STATUS_FAILED : DUMP_STATUS_COMPLETED); + error_propagate(errp, local_err); + + dump_cleanup(s); +} + void qmp_dump_guest_memory(bool paging, const char *file, bool has_detach, bool detach, bool has_begin, int64_t begin, bool has_length, @@ -1708,16 +1728,7 @@ void qmp_dump_guest_memory(bool paging, const char *file, return; } - if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) { - create_kdump_vmcore(s, &local_err); - } else { - create_vmcore(s, &local_err); - } - - s->status = (local_err ? DUMP_STATUS_FAILED : DUMP_STATUS_COMPLETED); - error_propagate(errp, local_err); - - dump_cleanup(s); + dump_process(s, errp); } DumpGuestMemoryCapability *qmp_query_dump_guest_memory_capability(Error **errp) diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h index 21fc02d..1da3ddb 100644 --- a/include/sysemu/dump.h +++ b/include/sysemu/dump.h @@ -178,6 +178,9 @@ typedef struct DumpState { size_t num_dumpable; /* number of page that can be dumped */ uint32_t flag_compress; /* indicate the compression format */ DumpStatus status; /* current dump status */ + + bool has_format; /* whether format is provided */ + DumpGuestMemoryFormat format; /* valid only if has_format == true */ } DumpState; uint16_t cpu_to_dump16(DumpState *s, uint16_t val); -- cgit v1.1 From 63e27f28f281986de791f099efa4fa15cc47f4fc Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Thu, 18 Feb 2016 13:16:51 +0800 Subject: dump-guest-memory: disable dump when in INMIGRATE state Signed-off-by: Peter Xu Reviewed-by: Fam Zheng Message-Id: <1455772616-8668-7-git-send-email-peterx@redhat.com> Signed-off-by: Paolo Bonzini --- dump.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dump.c b/dump.c index fed84a6..923e3a5 100644 --- a/dump.c +++ b/dump.c @@ -1654,6 +1654,11 @@ void qmp_dump_guest_memory(bool paging, const char *file, DumpState *s; Error *local_err = NULL; + if (runstate_check(RUN_STATE_INMIGRATE)) { + error_setg(errp, "Dump not allowed during incoming migration."); + return; + } + /* if there is a dump in background, we should wait until the dump * finished */ if (dump_in_progress()) { -- cgit v1.1 From 1fbeff72c2ba17aedfbf0d57caf8945862725c54 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Thu, 18 Feb 2016 13:16:52 +0800 Subject: dump-guest-memory: add "detach" support If "detach" is provided, one thread is created to do the dump work, while main thread will return immediately. For each GuestPhysBlock, adding one more field "mr" to points to MemoryRegion that it belongs, also ref the mr before use. Signed-off-by: Peter Xu Reviewed-by: Fam Zheng Message-Id: <1455772616-8668-8-git-send-email-peterx@redhat.com> Signed-off-by: Paolo Bonzini --- dump.c | 27 ++++++++++++++++++++++++++- include/sysemu/dump.h | 1 + include/sysemu/memory_mapping.h | 4 ++++ memory_mapping.c | 3 +++ 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/dump.c b/dump.c index 923e3a5..9210a72 100644 --- a/dump.c +++ b/dump.c @@ -1643,6 +1643,20 @@ static void dump_process(DumpState *s, Error **errp) dump_cleanup(s); } +static void *dump_thread(void *data) +{ + Error *err = NULL; + DumpState *s = (DumpState *)data; + + dump_process(s, &err); + + if (err) { + /* TODO: notify user the error */ + error_free(err); + } + return NULL; +} + void qmp_dump_guest_memory(bool paging, const char *file, bool has_detach, bool detach, bool has_begin, int64_t begin, bool has_length, @@ -1653,6 +1667,7 @@ void qmp_dump_guest_memory(bool paging, const char *file, int fd = -1; DumpState *s; Error *local_err = NULL; + bool detach_p = false; if (runstate_check(RUN_STATE_INMIGRATE)) { error_setg(errp, "Dump not allowed during incoming migration."); @@ -1684,6 +1699,9 @@ void qmp_dump_guest_memory(bool paging, const char *file, error_setg(errp, QERR_MISSING_PARAMETER, "begin"); return; } + if (has_detach) { + detach_p = detach; + } /* check whether lzo/snappy is supported */ #ifndef CONFIG_LZO @@ -1733,7 +1751,14 @@ void qmp_dump_guest_memory(bool paging, const char *file, return; } - dump_process(s, errp); + if (detach_p) { + /* detached dump */ + qemu_thread_create(&s->dump_thread, "dump_thread", dump_thread, + s, QEMU_THREAD_DETACHED); + } else { + /* sync dump */ + dump_process(s, errp); + } } DumpGuestMemoryCapability *qmp_query_dump_guest_memory_capability(Error **errp) diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h index 1da3ddb..06393c3 100644 --- a/include/sysemu/dump.h +++ b/include/sysemu/dump.h @@ -181,6 +181,7 @@ typedef struct DumpState { bool has_format; /* whether format is provided */ DumpGuestMemoryFormat format; /* valid only if has_format == true */ + QemuThread dump_thread; /* thread for detached dump */ } DumpState; uint16_t cpu_to_dump16(DumpState *s, uint16_t val); diff --git a/include/sysemu/memory_mapping.h b/include/sysemu/memory_mapping.h index a75d59a..d46d879 100644 --- a/include/sysemu/memory_mapping.h +++ b/include/sysemu/memory_mapping.h @@ -16,6 +16,7 @@ #include "qemu/queue.h" #include "qemu/typedefs.h" +#include "exec/memory.h" typedef struct GuestPhysBlock { /* visible to guest, reflects PCI hole, etc */ @@ -27,6 +28,9 @@ typedef struct GuestPhysBlock { /* points into host memory */ uint8_t *host_addr; + /* points to the MemoryRegion that this block belongs to */ + MemoryRegion *mr; + QTAILQ_ENTRY(GuestPhysBlock) next; } GuestPhysBlock; diff --git a/memory_mapping.c b/memory_mapping.c index 04db3ac..c8855de 100644 --- a/memory_mapping.c +++ b/memory_mapping.c @@ -178,6 +178,7 @@ void guest_phys_blocks_free(GuestPhysBlockList *list) QTAILQ_FOREACH_SAFE(p, &list->head, next, q) { QTAILQ_REMOVE(&list->head, p, next); + memory_region_unref(p->mr); g_free(p); } list->num = 0; @@ -241,6 +242,8 @@ static void guest_phys_blocks_region_add(MemoryListener *listener, block->target_start = target_start; block->target_end = target_end; block->host_addr = host_addr; + block->mr = section->mr; + memory_region_ref(section->mr); QTAILQ_INSERT_TAIL(&g->list->head, block, next); ++g->list->num; -- cgit v1.1 From 2264c2c96e0a1f0913412da73e9bcaf9f8fa4427 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Thu, 18 Feb 2016 13:16:53 +0800 Subject: DumpState: adding total_size and written_size fields Here, total_size is the size in bytes to be dumped (raw data, which means before compression), while written_size are bytes handled (raw size too). Signed-off-by: Peter Xu Message-Id: <1455772616-8668-9-git-send-email-peterx@redhat.com> Signed-off-by: Paolo Bonzini --- dump.c | 32 ++++++++++++++++++++++++++++++++ include/sysemu/dump.h | 9 +++++++++ 2 files changed, 41 insertions(+) diff --git a/dump.c b/dump.c index 9210a72..cd4ae5e 100644 --- a/dump.c +++ b/dump.c @@ -331,6 +331,8 @@ static void write_data(DumpState *s, void *buf, int length, Error **errp) ret = fd_write_vmcore(buf, length, s); if (ret < 0) { error_setg(errp, "dump: failed to save memory"); + } else { + s->written_size += length; } } @@ -1324,6 +1326,7 @@ static void write_dump_pages(DumpState *s, Error **errp) goto out; } } + s->written_size += s->dump_info.page_size; } ret = write_cache(&page_desc, NULL, 0, true); @@ -1456,6 +1459,30 @@ bool dump_in_progress(void) return (state->status == DUMP_STATUS_ACTIVE); } +/* calculate total size of memory to be dumped (taking filter into + * acoount.) */ +static int64_t dump_calculate_size(DumpState *s) +{ + GuestPhysBlock *block; + int64_t size = 0, total = 0, left = 0, right = 0; + + QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) { + if (s->has_filter) { + /* calculate the overlapped region. */ + left = MAX(s->begin, block->target_start); + right = MIN(s->begin + s->length, block->target_end); + size = right - left; + size = size > 0 ? size : 0; + } else { + /* count the whole region in */ + size = (block->target_end - block->target_start); + } + total += size; + } + + return total; +} + static void dump_init(DumpState *s, int fd, bool has_format, DumpGuestMemoryFormat format, bool paging, bool has_filter, int64_t begin, int64_t length, Error **errp) @@ -1467,6 +1494,7 @@ static void dump_init(DumpState *s, int fd, bool has_format, s->has_format = has_format; s->format = format; + s->written_size = 0; /* kdump-compressed is conflict with paging and filter */ if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) { @@ -1498,6 +1526,10 @@ static void dump_init(DumpState *s, int fd, bool has_format, guest_phys_blocks_init(&s->guest_phys_blocks); guest_phys_blocks_append(&s->guest_phys_blocks); + s->total_size = dump_calculate_size(s); +#ifdef DEBUG_DUMP_GUEST_MEMORY + fprintf(stderr, "DUMP: total memory to dump: %lu\n", s->total_size); +#endif s->start = get_start_block(s); if (s->start == -1) { diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h index 06393c3..ef931be 100644 --- a/include/sysemu/dump.h +++ b/include/sysemu/dump.h @@ -182,6 +182,15 @@ typedef struct DumpState { bool has_format; /* whether format is provided */ DumpGuestMemoryFormat format; /* valid only if has_format == true */ QemuThread dump_thread; /* thread for detached dump */ + + int64_t total_size; /* total memory size (in bytes) to + * be dumped. When filter is + * enabled, this will only count + * those to be written. */ + int64_t written_size; /* written memory size (in bytes), + * this could be used to calculate + * how much work we have + * finished. */ } DumpState; uint16_t cpu_to_dump16(DumpState *s, uint16_t val); -- cgit v1.1 From 39ba2ea61f510512764e6f9063a8396d05fe57fe Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Thu, 18 Feb 2016 13:16:54 +0800 Subject: Dump: add qmp command "query-dump" When dump-guest-memory is requested with detach flag, after its return, user could query its status using "query-dump" command (with no argument). The result contains: - status: current dump status - completed: bytes written in the latest dump - total: bytes to write in the latest dump From completed and total, we could know how much work finished by calculating: 100.0 * completed / total (%) Reviewed-by: Fam Zheng Signed-off-by: Peter Xu Message-Id: <1455772616-8668-10-git-send-email-peterx@redhat.com> Signed-off-by: Paolo Bonzini --- dump.c | 23 +++++++++++++++++++---- qapi-schema.json | 32 +++++++++++++++++++++++++++++++- qmp-commands.hx | 27 ++++++++++++++++++++++++++- 3 files changed, 76 insertions(+), 6 deletions(-) diff --git a/dump.c b/dump.c index cd4ae5e..9dc4946 100644 --- a/dump.c +++ b/dump.c @@ -1456,7 +1456,7 @@ static void dump_state_prepare(DumpState *s) bool dump_in_progress(void) { DumpState *state = &dump_state_global; - return (state->status == DUMP_STATUS_ACTIVE); + return (atomic_read(&state->status) == DUMP_STATUS_ACTIVE); } /* calculate total size of memory to be dumped (taking filter into @@ -1669,9 +1669,12 @@ static void dump_process(DumpState *s, Error **errp) create_vmcore(s, &local_err); } - s->status = (local_err ? DUMP_STATUS_FAILED : DUMP_STATUS_COMPLETED); - error_propagate(errp, local_err); + /* make sure status is written after written_size updates */ + smp_wmb(); + atomic_set(&s->status, + (local_err ? DUMP_STATUS_FAILED : DUMP_STATUS_COMPLETED)); + error_propagate(errp, local_err); dump_cleanup(s); } @@ -1689,6 +1692,18 @@ static void *dump_thread(void *data) return NULL; } +DumpQueryResult *qmp_query_dump(Error **errp) +{ + DumpQueryResult *result = g_new(DumpQueryResult, 1); + DumpState *state = &dump_state_global; + result->status = atomic_read(&state->status); + /* make sure we are reading status and written_size in order */ + smp_rmb(); + result->completed = state->written_size; + result->total = state->total_size; + return result; +} + void qmp_dump_guest_memory(bool paging, const char *file, bool has_detach, bool detach, bool has_begin, int64_t begin, bool has_length, @@ -1779,7 +1794,7 @@ void qmp_dump_guest_memory(bool paging, const char *file, begin, length, &local_err); if (local_err) { error_propagate(errp, local_err); - s->status = DUMP_STATUS_FAILED; + atomic_set(&s->status, DUMP_STATUS_FAILED); return; } diff --git a/qapi-schema.json b/qapi-schema.json index ccd30c8..7b8f2a1 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -2196,7 +2196,8 @@ # is the fd's name. # # @detach: #optional if true, QMP will return immediately rather than -# waiting for the dump to finish. (since 2.6). +# waiting for the dump to finish. The user can track progress +# using "query-dump". (since 2.6). # # @begin: #optional if specified, the starting physical address. # @@ -2237,6 +2238,35 @@ 'data': [ 'none', 'active', 'completed', 'failed' ] } ## +# @DumpQueryResult +# +# The result format for 'query-dump'. +# +# @status: enum of @DumpStatus, which shows current dump status +# +# @completed: bytes written in latest dump (uncompressed) +# +# @total: total bytes to be written in latest dump (uncompressed) +# +# Since 2.6 +## +{ 'struct': 'DumpQueryResult', + 'data': { 'status': 'DumpStatus', + 'completed': 'int', + 'total': 'int' } } + +## +# @query-dump +# +# Query latest dump status. +# +# Returns: A @DumpStatus object showing the dump status. +# +# Since: 2.6 +## +{ 'command': 'query-dump', 'returns': 'DumpQueryResult' } + +## # @DumpGuestMemoryCapability: # # A list of the available formats for dump-guest-memory diff --git a/qmp-commands.hx b/qmp-commands.hx index d30b1eb..daaafe5 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -856,7 +856,8 @@ Arguments: - "protocol": destination file(started with "file:") or destination file descriptor (started with "fd:") (json-string) - "detach": if specified, command will return immediately, without waiting - for the dump to finish (json-bool) + for the dump to finish. The user can track progress using + "query-dump". (json-bool) - "begin": the starting physical address. It's optional, and should be specified with length together (json-int) - "length": the memory size, in bytes. It's optional, and should be specified @@ -896,6 +897,30 @@ Example: EQMP + { + .name = "query-dump", + .args_type = "", + .params = "", + .help = "query background dump status", + .mhandler.cmd_new = qmp_marshal_query_dump, + }, + +SQMP +query-dump +---------- + +Query background dump status. + +Arguments: None. + +Example: + +-> { "execute": "query-dump" } +<- { "return": { "status": "active", "completed": 1024000, + "total": 2048000 } } + +EQMP + #if defined TARGET_S390X { .name = "dump-skeys", -- cgit v1.1 From 4a6b52d67e36486ae3d695170a2a7eb39f7a032e Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Thu, 18 Feb 2016 13:16:55 +0800 Subject: Dump: add hmp command "info dump" It will calculate percentage of finished work from completed and total. Signed-off-by: Peter Xu Message-Id: <1455772616-8668-11-git-send-email-peterx@redhat.com> Signed-off-by: Paolo Bonzini --- hmp-commands-info.hx | 14 ++++++++++++++ hmp.c | 17 +++++++++++++++++ hmp.h | 1 + 3 files changed, 32 insertions(+) diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx index 9b71351..52539c3 100644 --- a/hmp-commands-info.hx +++ b/hmp-commands-info.hx @@ -786,6 +786,20 @@ STEXI Display the value of a storage key (s390 only) ETEXI + { + .name = "dump", + .args_type = "", + .params = "", + .help = "Display the latest dump status", + .mhandler.cmd = hmp_info_dump, + }, + +STEXI +@item info dump +@findex dump +Display the latest dump status. +ETEXI + STEXI @end table ETEXI diff --git a/hmp.c b/hmp.c index 7f65b32..d0d0557 100644 --- a/hmp.c +++ b/hmp.c @@ -2351,3 +2351,20 @@ void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict) qapi_free_RockerOfDpaGroupList(list); } + +void hmp_info_dump(Monitor *mon, const QDict *qdict) +{ + DumpQueryResult *result = qmp_query_dump(NULL); + + assert(result && result->status < DUMP_STATUS__MAX); + monitor_printf(mon, "Status: %s\n", DumpStatus_lookup[result->status]); + + if (result->status == DUMP_STATUS_ACTIVE) { + float percent = 0; + assert(result->total != 0); + percent = 100.0 * result->completed / result->total; + monitor_printf(mon, "Finished: %.2f %%\n", percent); + } + + qapi_free_DumpQueryResult(result); +} diff --git a/hmp.h b/hmp.h index a8c5b5a..093d65f 100644 --- a/hmp.h +++ b/hmp.h @@ -131,5 +131,6 @@ void hmp_rocker(Monitor *mon, const QDict *qdict); void hmp_rocker_ports(Monitor *mon, const QDict *qdict); void hmp_rocker_of_dpa_flows(Monitor *mon, const QDict *qdict); void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict); +void hmp_info_dump(Monitor *mon, const QDict *qdict); #endif -- cgit v1.1 From d42a0d1484f03d05184ed9bb867fee42476a588f Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Thu, 18 Feb 2016 13:16:56 +0800 Subject: dump-guest-memory: add qmp event DUMP_COMPLETED One new QMP event DUMP_COMPLETED is added. When a dump finishes, one DUMP_COMPLETED event will occur to notify the user. Signed-off-by: Peter Xu Reviewed-by: Fam Zheng Message-Id: <1455772616-8668-12-git-send-email-peterx@redhat.com> Signed-off-by: Paolo Bonzini --- docs/qmp-events.txt | 18 ++++++++++++++++++ dump.c | 18 ++++++++++++------ qapi/event.json | 16 ++++++++++++++++ 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/docs/qmp-events.txt b/docs/qmp-events.txt index 52eb7e2..4e3eb9e 100644 --- a/docs/qmp-events.txt +++ b/docs/qmp-events.txt @@ -220,6 +220,24 @@ Data: }, "timestamp": { "seconds": 1265044230, "microseconds": 450486 } } +DUMP_COMPLETED +-------------- + +Emitted when the guest has finished one memory dump. + +Data: + +- "result": DumpQueryResult type described in qapi-schema.json +- "error": Error message when dump failed. This is only a + human-readable string provided when dump failed. It should not be + parsed in any way (json-string, optional) + +Example: + +{ "event": "DUMP_COMPLETED", + "data": {"result": {"total": 1090650112, "status": "completed", + "completed": 1090650112} } } + GUEST_PANICKED -------------- diff --git a/dump.c b/dump.c index 9dc4946..81d2d4f 100644 --- a/dump.c +++ b/dump.c @@ -25,6 +25,7 @@ #include "sysemu/cpus.h" #include "qapi/qmp/qerror.h" #include "qmp-commands.h" +#include "qapi-event.h" #include #ifdef CONFIG_LZO @@ -1662,6 +1663,7 @@ cleanup: static void dump_process(DumpState *s, Error **errp) { Error *local_err = NULL; + DumpQueryResult *result = NULL; if (s->has_format && s->format != DUMP_GUEST_MEMORY_FORMAT_ELF) { create_kdump_vmcore(s, &local_err); @@ -1674,6 +1676,15 @@ static void dump_process(DumpState *s, Error **errp) atomic_set(&s->status, (local_err ? DUMP_STATUS_FAILED : DUMP_STATUS_COMPLETED)); + /* send DUMP_COMPLETED message (unconditionally) */ + result = qmp_query_dump(NULL); + /* should never fail */ + assert(result); + qapi_event_send_dump_completed(result, !!local_err, (local_err ? \ + error_get_pretty(local_err) : NULL), + &error_abort); + qapi_free_DumpQueryResult(result); + error_propagate(errp, local_err); dump_cleanup(s); } @@ -1682,13 +1693,8 @@ static void *dump_thread(void *data) { Error *err = NULL; DumpState *s = (DumpState *)data; - dump_process(s, &err); - - if (err) { - /* TODO: notify user the error */ - error_free(err); - } + error_free(err); return NULL; } diff --git a/qapi/event.json b/qapi/event.json index 390fd45..1a45a6c 100644 --- a/qapi/event.json +++ b/qapi/event.json @@ -369,3 +369,19 @@ ## { 'event': 'MEM_UNPLUG_ERROR', 'data': { 'device': 'str', 'msg': 'str' } } + +## +# @DUMP_COMPLETED +# +# Emitted when background dump has completed +# +# @result: DumpQueryResult type described in qapi-schema.json. +# +# @error: #optional human-readable error string that provides +# hint on why dump failed. Only presents on failure. The +# user should not try to interpret the error string. +# +# Since: 2.6 +## +{ 'event': 'DUMP_COMPLETED' , + 'data': { 'result': 'DumpQueryResult', '*error': 'str' } } -- cgit v1.1 From 96c33a4523ee1abe382ce4ff3e82b90ba78aa186 Mon Sep 17 00:00:00 2001 From: Dimitris Aragiorgis Date: Thu, 18 Feb 2016 13:38:38 +0200 Subject: log: Redirect stderr to logfile if deamonized In case of daemonize, use the logfile passed with the -D option in order to redirect stderr to it instead of /dev/null. Also remove some unused code in log.h. Signed-off-by: Dimitris Aragiorgis Message-Id: <1455795518-19205-1-git-send-email-dimara@arrikto.com> Signed-off-by: Paolo Bonzini --- include/qemu/log.h | 6 ------ os-posix.c | 6 +++++- util/log.c | 11 +++++++++-- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/include/qemu/log.h b/include/qemu/log.h index 30817f7..dda65fd 100644 --- a/include/qemu/log.h +++ b/include/qemu/log.h @@ -94,12 +94,6 @@ static inline void qemu_log_close(void) } } -/* Set up a new log file */ -static inline void qemu_log_set_file(FILE *f) -{ - qemu_logfile = f; -} - /* define log items */ typedef struct QEMULogItem { int mask; diff --git a/os-posix.c b/os-posix.c index cce62ed..92fa3ba 100644 --- a/os-posix.c +++ b/os-posix.c @@ -37,6 +37,7 @@ #include "qemu-options.h" #include "qemu/rcu.h" #include "qemu/error-report.h" +#include "qemu/log.h" #ifdef CONFIG_LINUX #include @@ -275,7 +276,10 @@ void os_setup_post(void) dup2(fd, 0); dup2(fd, 1); - dup2(fd, 2); + /* In case -D is given do not redirect stderr to /dev/null */ + if (!qemu_logfile) { + dup2(fd, 2); + } close(fd); diff --git a/util/log.c b/util/log.c index 2709e98..a7ddc7e 100644 --- a/util/log.c +++ b/util/log.c @@ -56,13 +56,20 @@ void do_qemu_set_log(int log_flags, bool use_own_buffers) #ifdef CONFIG_TRACE_LOG qemu_loglevel |= LOG_TRACE; #endif - if (qemu_loglevel && !qemu_logfile) { + if ((qemu_loglevel || is_daemonized()) && !qemu_logfile) { if (logfilename) { qemu_logfile = fopen(logfilename, log_append ? "a" : "w"); if (!qemu_logfile) { perror(logfilename); _exit(1); } + /* In case we are a daemon redirect stderr to logfile */ + if (is_daemonized()) { + dup2(fileno(qemu_logfile), STDERR_FILENO); + fclose(qemu_logfile); + /* This will skip closing logfile in qemu_log_close() */ + qemu_logfile = stderr; + } } else { /* Default to stderr if no log file specified */ qemu_logfile = stderr; @@ -82,7 +89,7 @@ void do_qemu_set_log(int log_flags, bool use_own_buffers) log_append = 1; } } - if (!qemu_loglevel && qemu_logfile) { + if (!qemu_loglevel && !is_daemonized() && qemu_logfile) { qemu_log_close(); } } -- cgit v1.1 From 58eaa2174e99d9a05172d03fd2799ab8fd9e6f60 Mon Sep 17 00:00:00 2001 From: Gonglei Date: Mon, 22 Feb 2016 16:34:55 +0800 Subject: exec: store RAMBlock pointer into memory region Each RAM memory region has a unique corresponding RAMBlock. In the current realization, the memory region only stored the ram_addr which means the offset of RAM address space, We need to qurey the global ram.list to find the ram block by ram_addr if we want to get the ram block, which is very expensive. Now, we store the RAMBlock pointer into memory region structure. So, if we know the mr, we can easily get the RAMBlock. Signed-off-by: Gonglei Message-Id: <1456130097-4208-2-git-send-email-arei.gonglei@huawei.com> Signed-off-by: Paolo Bonzini --- exec.c | 2 ++ include/exec/memory.h | 2 ++ memory.c | 1 + 3 files changed, 5 insertions(+) diff --git a/exec.c b/exec.c index 1f24500..4c0114a 100644 --- a/exec.c +++ b/exec.c @@ -1717,6 +1717,8 @@ ram_addr_t qemu_ram_alloc_internal(ram_addr_t size, ram_addr_t max_size, error_propagate(errp, local_err); return -1; } + + mr->ram_block = new_block; return addr; } diff --git a/include/exec/memory.h b/include/exec/memory.h index c92734a..683be46 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -34,6 +34,7 @@ #include "qapi/error.h" #include "qom/object.h" #include "qemu/rcu.h" +#include "qemu/typedefs.h" #define MAX_PHYS_ADDR_SPACE_BITS 62 #define MAX_PHYS_ADDR (((hwaddr)1 << MAX_PHYS_ADDR_SPACE_BITS) - 1) @@ -172,6 +173,7 @@ struct MemoryRegion { bool global_locking; uint8_t dirty_log_mask; ram_addr_t ram_addr; + RAMBlock *ram_block; Object *owner; const MemoryRegionIOMMUOps *iommu_ops; diff --git a/memory.c b/memory.c index 09041ed..b4451dd 100644 --- a/memory.c +++ b/memory.c @@ -912,6 +912,7 @@ void memory_region_init(MemoryRegion *mr, } mr->name = g_strdup(name); mr->owner = owner; + mr->ram_block = NULL; if (name) { char *escaped_name = memory_region_escape_name(name); -- cgit v1.1 From 3655cb9c7375a595a8051ec677c515b24d5c1fe6 Mon Sep 17 00:00:00 2001 From: Gonglei Date: Sat, 20 Feb 2016 10:35:20 +0800 Subject: memory: optimize qemu_get_ram_ptr and qemu_ram_ptr_length these two functions consume too much cpu overhead to find the RAMBlock by ram address. After this patch, we can pass the RAMBlock pointer to them so that they don't need to find the RAMBlock anymore most of the time. We can get better performance in address translation processing. Signed-off-by: Gonglei Message-Id: <1455935721-8804-3-git-send-email-arei.gonglei@huawei.com> Signed-off-by: Paolo Bonzini --- exec.c | 46 ++++++++++++++++++++++++++++------------------ include/exec/memory.h | 4 ++-- memory.c | 2 +- 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/exec.c b/exec.c index 4c0114a..c62c439 100644 --- a/exec.c +++ b/exec.c @@ -1868,9 +1868,13 @@ void *qemu_get_ram_block_host_ptr(ram_addr_t addr) * * Called within RCU critical section. */ -void *qemu_get_ram_ptr(ram_addr_t addr) +void *qemu_get_ram_ptr(RAMBlock *ram_block, ram_addr_t addr) { - RAMBlock *block = qemu_get_ram_block(addr); + RAMBlock *block = ram_block; + + if (block == NULL) { + block = qemu_get_ram_block(addr); + } if (xen_enabled() && block->host == NULL) { /* We need to check if the requested address is in the RAM @@ -1891,15 +1895,18 @@ void *qemu_get_ram_ptr(ram_addr_t addr) * * Called within RCU critical section. */ -static void *qemu_ram_ptr_length(ram_addr_t addr, hwaddr *size) +static void *qemu_ram_ptr_length(RAMBlock *ram_block, ram_addr_t addr, + hwaddr *size) { - RAMBlock *block; + RAMBlock *block = ram_block; ram_addr_t offset_inside_block; if (*size == 0) { return NULL; } - block = qemu_get_ram_block(addr); + if (block == NULL) { + block = qemu_get_ram_block(addr); + } offset_inside_block = addr - block->offset; *size = MIN(*size, block->max_length - offset_inside_block); @@ -2027,13 +2034,13 @@ static void notdirty_mem_write(void *opaque, hwaddr ram_addr, } switch (size) { case 1: - stb_p(qemu_get_ram_ptr(ram_addr), val); + stb_p(qemu_get_ram_ptr(NULL, ram_addr), val); break; case 2: - stw_p(qemu_get_ram_ptr(ram_addr), val); + stw_p(qemu_get_ram_ptr(NULL, ram_addr), val); break; case 4: - stl_p(qemu_get_ram_ptr(ram_addr), val); + stl_p(qemu_get_ram_ptr(NULL, ram_addr), val); break; default: abort(); @@ -2609,7 +2616,7 @@ static MemTxResult address_space_write_continue(AddressSpace *as, hwaddr addr, } else { addr1 += memory_region_get_ram_addr(mr); /* RAM case */ - ptr = qemu_get_ram_ptr(addr1); + ptr = qemu_get_ram_ptr(mr->ram_block, addr1); memcpy(ptr, buf, l); invalidate_and_set_dirty(mr, addr1, l); } @@ -2700,7 +2707,7 @@ MemTxResult address_space_read_continue(AddressSpace *as, hwaddr addr, } } else { /* RAM case */ - ptr = qemu_get_ram_ptr(mr->ram_addr + addr1); + ptr = qemu_get_ram_ptr(mr->ram_block, mr->ram_addr + addr1); memcpy(buf, ptr, l); } @@ -2785,7 +2792,7 @@ static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as, } else { addr1 += memory_region_get_ram_addr(mr); /* ROM/RAM case */ - ptr = qemu_get_ram_ptr(addr1); + ptr = qemu_get_ram_ptr(mr->ram_block, addr1); switch (type) { case WRITE_DATA: memcpy(ptr, buf, l); @@ -2997,7 +3004,7 @@ void *address_space_map(AddressSpace *as, memory_region_ref(mr); *plen = done; - ptr = qemu_ram_ptr_length(raddr + base, plen); + ptr = qemu_ram_ptr_length(mr->ram_block, raddr + base, plen); rcu_read_unlock(); return ptr; @@ -3081,7 +3088,8 @@ static inline uint32_t address_space_ldl_internal(AddressSpace *as, hwaddr addr, #endif } else { /* RAM case */ - ptr = qemu_get_ram_ptr((memory_region_get_ram_addr(mr) + ptr = qemu_get_ram_ptr(mr->ram_block, + (memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK) + addr1); switch (endian) { @@ -3176,7 +3184,8 @@ static inline uint64_t address_space_ldq_internal(AddressSpace *as, hwaddr addr, #endif } else { /* RAM case */ - ptr = qemu_get_ram_ptr((memory_region_get_ram_addr(mr) + ptr = qemu_get_ram_ptr(mr->ram_block, + (memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK) + addr1); switch (endian) { @@ -3291,7 +3300,8 @@ static inline uint32_t address_space_lduw_internal(AddressSpace *as, #endif } else { /* RAM case */ - ptr = qemu_get_ram_ptr((memory_region_get_ram_addr(mr) + ptr = qemu_get_ram_ptr(mr->ram_block, + (memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK) + addr1); switch (endian) { @@ -3376,7 +3386,7 @@ void address_space_stl_notdirty(AddressSpace *as, hwaddr addr, uint32_t val, r = memory_region_dispatch_write(mr, addr1, val, 4, attrs); } else { addr1 += memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK; - ptr = qemu_get_ram_ptr(addr1); + ptr = qemu_get_ram_ptr(mr->ram_block, addr1); stl_p(ptr, val); dirty_log_mask = memory_region_get_dirty_log_mask(mr); @@ -3431,7 +3441,7 @@ static inline void address_space_stl_internal(AddressSpace *as, } else { /* RAM case */ addr1 += memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK; - ptr = qemu_get_ram_ptr(addr1); + ptr = qemu_get_ram_ptr(mr->ram_block, addr1); switch (endian) { case DEVICE_LITTLE_ENDIAN: stl_le_p(ptr, val); @@ -3541,7 +3551,7 @@ static inline void address_space_stw_internal(AddressSpace *as, } else { /* RAM case */ addr1 += memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK; - ptr = qemu_get_ram_ptr(addr1); + ptr = qemu_get_ram_ptr(mr->ram_block, addr1); switch (endian) { case DEVICE_LITTLE_ENDIAN: stw_le_p(ptr, val); diff --git a/include/exec/memory.h b/include/exec/memory.h index 683be46..34f21f1 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -1391,7 +1391,7 @@ MemTxResult address_space_read_continue(AddressSpace *as, hwaddr addr, MemoryRegion *mr); MemTxResult address_space_read_full(AddressSpace *as, hwaddr addr, MemTxAttrs attrs, uint8_t *buf, int len); -void *qemu_get_ram_ptr(ram_addr_t addr); +void *qemu_get_ram_ptr(RAMBlock *ram_block, ram_addr_t addr); static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write) { @@ -1432,7 +1432,7 @@ MemTxResult address_space_read(AddressSpace *as, hwaddr addr, MemTxAttrs attrs, mr = address_space_translate(as, addr, &addr1, &l, false); if (len == l && memory_access_is_direct(mr, false)) { addr1 += memory_region_get_ram_addr(mr); - ptr = qemu_get_ram_ptr(addr1); + ptr = qemu_get_ram_ptr(mr->ram_block, addr1); memcpy(buf, ptr, len); } else { result = address_space_read_continue(as, addr, attrs, buf, len, diff --git a/memory.c b/memory.c index b4451dd..0dd9695 100644 --- a/memory.c +++ b/memory.c @@ -1570,7 +1570,7 @@ void *memory_region_get_ram_ptr(MemoryRegion *mr) mr = mr->alias; } assert(mr->ram_addr != RAM_ADDR_INVALID); - ptr = qemu_get_ram_ptr(mr->ram_addr & TARGET_PAGE_MASK); + ptr = qemu_get_ram_ptr(mr->ram_block, mr->ram_addr & TARGET_PAGE_MASK); rcu_read_unlock(); return ptr + offset; -- cgit v1.1 From d61524486c6e503e502241a2ea834f930f98a6a1 Mon Sep 17 00:00:00 2001 From: Gonglei Date: Sat, 20 Feb 2016 10:35:21 +0800 Subject: memory: Remove unreachable return statement Signed-off-by: Gonglei Message-Id: <1455935721-8804-4-git-send-email-arei.gonglei@huawei.com> Signed-off-by: Paolo Bonzini --- include/exec/memory.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/exec/memory.h b/include/exec/memory.h index 34f21f1..032400a 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -1400,8 +1400,6 @@ static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write) } else { return memory_region_is_ram(mr) || memory_region_is_romd(mr); } - - return false; } /** -- cgit v1.1 From 21a933ea33c820515f331c162c9f7053ca6f4129 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 19 Feb 2016 17:19:31 -0700 Subject: chardev: Properly initialize ChardevCommon components Commit d0d7708b forgot to parse logging for spice chardevs and virtual consoles. This requires making qemu_chr_parse_common() non-static. While at it, use a temporary variable to make the code shorter, as well as reduce the churn when a later patch alters the layout of simple unions. Signed-off-by: Eric Blake CC: Daniel P. Berrange Message-Id: <1455927587-28033-2-git-send-email-eblake@redhat.com> Signed-off-by: Paolo Bonzini --- include/sysemu/char.h | 10 ++++++++++ qemu-char.c | 2 +- spice-qemu-char.c | 12 ++++++++---- ui/console.c | 20 +++++++++++--------- 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/include/sysemu/char.h b/include/sysemu/char.h index e035d1c..e46884f 100644 --- a/include/sysemu/char.h +++ b/include/sysemu/char.h @@ -115,6 +115,16 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, Error **errp); /** + * @qemu_chr_parse_common: + * + * Parse the common options available to all character backends. + * + * @opts the options that still need parsing + * @backend a new backend + */ +void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend); + +/** * @qemu_chr_new: * * Create a new character backend from a URI. diff --git a/qemu-char.c b/qemu-char.c index ad11b75..fc8ffda 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -3490,7 +3490,7 @@ fail: return NULL; } -static void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend) +void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend) { const char *logfile = qemu_opt_get(opts, "logfile"); diff --git a/spice-qemu-char.c b/spice-qemu-char.c index 7c1f438..21885c5 100644 --- a/spice-qemu-char.c +++ b/spice-qemu-char.c @@ -366,26 +366,30 @@ static void qemu_chr_parse_spice_vmc(QemuOpts *opts, ChardevBackend *backend, Error **errp) { const char *name = qemu_opt_get(opts, "name"); + ChardevSpiceChannel *spicevmc; if (name == NULL) { error_setg(errp, "chardev: spice channel: no name given"); return; } - backend->u.spicevmc = g_new0(ChardevSpiceChannel, 1); - backend->u.spicevmc->type = g_strdup(name); + spicevmc = backend->u.spicevmc = g_new0(ChardevSpiceChannel, 1); + qemu_chr_parse_common(opts, qapi_ChardevSpiceChannel_base(spicevmc)); + spicevmc->type = g_strdup(name); } static void qemu_chr_parse_spice_port(QemuOpts *opts, ChardevBackend *backend, Error **errp) { const char *name = qemu_opt_get(opts, "name"); + ChardevSpicePort *spiceport; if (name == NULL) { error_setg(errp, "chardev: spice port: no name given"); return; } - backend->u.spiceport = g_new0(ChardevSpicePort, 1); - backend->u.spiceport->fqdn = g_strdup(name); + spiceport = backend->u.spiceport = g_new0(ChardevSpicePort, 1); + qemu_chr_parse_common(opts, qapi_ChardevSpicePort_base(spiceport)); + spiceport->fqdn = g_strdup(name); } static void register_types(void) diff --git a/ui/console.c b/ui/console.c index b739ae9..7db0fd2 100644 --- a/ui/console.c +++ b/ui/console.c @@ -2060,31 +2060,33 @@ static void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend, Error **errp) { int val; + ChardevVC *vc; - backend->u.vc = g_new0(ChardevVC, 1); + vc = backend->u.vc = g_new0(ChardevVC, 1); + qemu_chr_parse_common(opts, qapi_ChardevVC_base(vc)); val = qemu_opt_get_number(opts, "width", 0); if (val != 0) { - backend->u.vc->has_width = true; - backend->u.vc->width = val; + vc->has_width = true; + vc->width = val; } val = qemu_opt_get_number(opts, "height", 0); if (val != 0) { - backend->u.vc->has_height = true; - backend->u.vc->height = val; + vc->has_height = true; + vc->height = val; } val = qemu_opt_get_number(opts, "cols", 0); if (val != 0) { - backend->u.vc->has_cols = true; - backend->u.vc->cols = val; + vc->has_cols = true; + vc->cols = val; } val = qemu_opt_get_number(opts, "rows", 0); if (val != 0) { - backend->u.vc->has_rows = true; - backend->u.vc->rows = val; + vc->has_rows = true; + vc->rows = val; } } -- cgit v1.1 From cfc3b074de4b4ccee2540edbf8cfdb026dc19943 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 17 Feb 2016 10:54:53 +0100 Subject: target-i386: fix confusion in xcr0 bit position vs. mask The xsave and xrstor helpers are accessing the x86_ext_save_areas array using a bit mask instead of a bit position. Provide two sets of XSTATE_* definitions and use XSTATE_*_BIT when a bit position is requested. Reviewed-by: Richard Henderson Acked-by: Eduardo Habkost Signed-off-by: Paolo Bonzini --- target-i386/cpu.c | 29 ++++++++++++++++++----------- target-i386/cpu.h | 29 +++++++++++++++++++---------- target-i386/fpu_helper.c | 41 +++++++++++++++++++++-------------------- target-i386/mpx_helper.c | 2 +- 4 files changed, 59 insertions(+), 42 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 0af43a3..912a376 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -473,19 +473,26 @@ static const X86RegisterInfo32 x86_reg_info_32[CPU_NB_REGS32] = { #undef REGISTER const ExtSaveArea x86_ext_save_areas[] = { - [2] = { .feature = FEAT_1_ECX, .bits = CPUID_EXT_AVX, + [XSTATE_YMM_BIT] = + { .feature = FEAT_1_ECX, .bits = CPUID_EXT_AVX, .offset = 0x240, .size = 0x100 }, - [3] = { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_MPX, + [XSTATE_BNDREGS_BIT] = + { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_MPX, .offset = 0x3c0, .size = 0x40 }, - [4] = { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_MPX, + [XSTATE_BNDCSR_BIT] = + { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_MPX, .offset = 0x400, .size = 0x40 }, - [5] = { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F, + [XSTATE_OPMASK_BIT] = + { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F, .offset = 0x440, .size = 0x40 }, - [6] = { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F, + [XSTATE_ZMM_Hi256_BIT] = + { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F, .offset = 0x480, .size = 0x200 }, - [7] = { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F, + [XSTATE_Hi16_ZMM_BIT] = + { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F, .offset = 0x680, .size = 0x400 }, - [9] = { .feature = FEAT_7_0_ECX, .bits = CPUID_7_0_ECX_PKU, + [XSTATE_PKRU_BIT] = + { .feature = FEAT_7_0_ECX, .bits = CPUID_7_0_ECX_PKU, .offset = 0xA80, .size = 0x8 }, }; @@ -2483,7 +2490,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, *ecx = MAX(*ecx, esa->offset + esa->size); } } - *eax |= ena_mask & (XSTATE_FP | XSTATE_SSE); + *eax |= ena_mask & (XSTATE_FP_MASK | XSTATE_SSE_MASK); *ebx = *ecx; } else if (count == 1) { *eax = env->features[FEAT_XSAVE]; @@ -2717,15 +2724,15 @@ static void x86_cpu_reset(CPUState *s) cpu_watchpoint_remove_all(s, BP_CPU); cr4 = 0; - xcr0 = XSTATE_FP; + xcr0 = XSTATE_FP_MASK; #ifdef CONFIG_USER_ONLY /* Enable all the features for user-mode. */ if (env->features[FEAT_1_EDX] & CPUID_SSE) { - xcr0 |= XSTATE_SSE; + xcr0 |= XSTATE_SSE_MASK; } if (env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_MPX) { - xcr0 |= XSTATE_BNDREGS | XSTATE_BNDCSR; + xcr0 |= XSTATE_BNDREGS_MASK | XSTATE_BNDCSR_MASK; } if (env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE) { cr4 |= CR4_OSFXSR_MASK | CR4_OSXSAVE_MASK; diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 94cb4db..03c00d5 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -405,16 +405,25 @@ #define MSR_IA32_BNDCFGS 0x00000d90 #define MSR_IA32_XSS 0x00000da0 -#define XSTATE_FP (1ULL << 0) -#define XSTATE_SSE (1ULL << 1) -#define XSTATE_YMM (1ULL << 2) -#define XSTATE_BNDREGS (1ULL << 3) -#define XSTATE_BNDCSR (1ULL << 4) -#define XSTATE_OPMASK (1ULL << 5) -#define XSTATE_ZMM_Hi256 (1ULL << 6) -#define XSTATE_Hi16_ZMM (1ULL << 7) -#define XSTATE_PKRU (1ULL << 9) - +#define XSTATE_FP_BIT 0 +#define XSTATE_SSE_BIT 1 +#define XSTATE_YMM_BIT 2 +#define XSTATE_BNDREGS_BIT 3 +#define XSTATE_BNDCSR_BIT 4 +#define XSTATE_OPMASK_BIT 5 +#define XSTATE_ZMM_Hi256_BIT 6 +#define XSTATE_Hi16_ZMM_BIT 7 +#define XSTATE_PKRU_BIT 9 + +#define XSTATE_FP_MASK (1ULL << XSTATE_FP_BIT) +#define XSTATE_SSE_MASK (1ULL << XSTATE_SSE_BIT) +#define XSTATE_YMM_MASK (1ULL << XSTATE_YMM_BIT) +#define XSTATE_BNDREGS_MASK (1ULL << XSTATE_BNDREGS_BIT) +#define XSTATE_BNDCSR_MASK (1ULL << XSTATE_BNDCSR_BIT) +#define XSTATE_OPMASK_MASK (1ULL << XSTATE_OPMASK_BIT) +#define XSTATE_ZMM_Hi256_MASK (1ULL << XSTATE_ZMM_Hi256_BIT) +#define XSTATE_Hi16_ZMM_MASK (1ULL << XSTATE_Hi16_ZMM_BIT) +#define XSTATE_PKRU_MASK (1ULL << XSTATE_PKRU_BIT) /* CPUID feature words */ typedef enum FeatureWord { diff --git a/target-i386/fpu_helper.c b/target-i386/fpu_helper.c index 9dfbc4c..d1a7f4c 100644 --- a/target-i386/fpu_helper.c +++ b/target-i386/fpu_helper.c @@ -1215,7 +1215,7 @@ static uint64_t get_xinuse(CPUX86State *env) indicate in use. That said, the state of BNDREGS is important enough to track in HFLAGS, so we might as well use that here. */ if ((env->hflags & HF_MPX_IU_MASK) == 0) { - inuse &= ~XSTATE_BNDREGS; + inuse &= ~XSTATE_BNDREGS_MASK; } return inuse; } @@ -1239,22 +1239,22 @@ static void do_xsave(CPUX86State *env, target_ulong ptr, uint64_t rfbm, rfbm &= env->xcr0; opt &= rfbm; - if (opt & XSTATE_FP) { + if (opt & XSTATE_FP_MASK) { do_xsave_fpu(env, ptr, ra); } - if (rfbm & XSTATE_SSE) { + if (rfbm & XSTATE_SSE_MASK) { /* Note that saving MXCSR is not suppressed by XSAVEOPT. */ do_xsave_mxcsr(env, ptr, ra); } - if (opt & XSTATE_SSE) { + if (opt & XSTATE_SSE_MASK) { do_xsave_sse(env, ptr, ra); } - if (opt & XSTATE_BNDREGS) { - target_ulong off = x86_ext_save_areas[XSTATE_BNDREGS].offset; + if (opt & XSTATE_BNDREGS_MASK) { + target_ulong off = x86_ext_save_areas[XSTATE_BNDREGS_BIT].offset; do_xsave_bndregs(env, ptr + off, ra); } - if (opt & XSTATE_BNDCSR) { - target_ulong off = x86_ext_save_areas[XSTATE_BNDCSR].offset; + if (opt & XSTATE_BNDCSR_MASK) { + target_ulong off = x86_ext_save_areas[XSTATE_BNDCSR_BIT].offset; do_xsave_bndcsr(env, ptr + off, ra); } @@ -1399,19 +1399,19 @@ void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm) raise_exception_ra(env, EXCP0D_GPF, ra); } - if (rfbm & XSTATE_FP) { - if (xstate_bv & XSTATE_FP) { + if (rfbm & XSTATE_FP_MASK) { + if (xstate_bv & XSTATE_FP_MASK) { do_xrstor_fpu(env, ptr, ra); } else { helper_fninit(env); memset(env->fpregs, 0, sizeof(env->fpregs)); } } - if (rfbm & XSTATE_SSE) { + if (rfbm & XSTATE_SSE_MASK) { /* Note that the standard form of XRSTOR loads MXCSR from memory whether or not the XSTATE_BV bit is set. */ do_xrstor_mxcsr(env, ptr, ra); - if (xstate_bv & XSTATE_SSE) { + if (xstate_bv & XSTATE_SSE_MASK) { do_xrstor_sse(env, ptr, ra); } else { /* ??? When AVX is implemented, we may have to be more @@ -1419,9 +1419,9 @@ void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm) memset(env->xmm_regs, 0, sizeof(env->xmm_regs)); } } - if (rfbm & XSTATE_BNDREGS) { - if (xstate_bv & XSTATE_BNDREGS) { - target_ulong off = x86_ext_save_areas[XSTATE_BNDREGS].offset; + if (rfbm & XSTATE_BNDREGS_MASK) { + if (xstate_bv & XSTATE_BNDREGS_MASK) { + target_ulong off = x86_ext_save_areas[XSTATE_BNDREGS_BIT].offset; do_xrstor_bndregs(env, ptr + off, ra); env->hflags |= HF_MPX_IU_MASK; } else { @@ -1429,9 +1429,9 @@ void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm) env->hflags &= ~HF_MPX_IU_MASK; } } - if (rfbm & XSTATE_BNDCSR) { - if (xstate_bv & XSTATE_BNDCSR) { - target_ulong off = x86_ext_save_areas[XSTATE_BNDCSR].offset; + if (rfbm & XSTATE_BNDCSR_MASK) { + if (xstate_bv & XSTATE_BNDCSR_MASK) { + target_ulong off = x86_ext_save_areas[XSTATE_BNDCSR_BIT].offset; do_xrstor_bndcsr(env, ptr + off, ra); } else { memset(&env->bndcs_regs, 0, sizeof(env->bndcs_regs)); @@ -1470,7 +1470,7 @@ void helper_xsetbv(CPUX86State *env, uint32_t ecx, uint64_t mask) } /* Only XCR0 is defined at present; the FPU may not be disabled. */ - if (ecx != 0 || (mask & XSTATE_FP) == 0) { + if (ecx != 0 || (mask & XSTATE_FP_MASK) == 0) { goto do_gpf; } @@ -1482,7 +1482,8 @@ void helper_xsetbv(CPUX86State *env, uint32_t ecx, uint64_t mask) } /* Disallow enabling only half of MPX. */ - if ((mask ^ (mask * (XSTATE_BNDCSR / XSTATE_BNDREGS))) & XSTATE_BNDCSR) { + if ((mask ^ (mask * (XSTATE_BNDCSR_MASK / XSTATE_BNDREGS_MASK))) + & XSTATE_BNDCSR_MASK) { goto do_gpf; } diff --git a/target-i386/mpx_helper.c b/target-i386/mpx_helper.c index 1bf717a..8c6c2e7 100644 --- a/target-i386/mpx_helper.c +++ b/target-i386/mpx_helper.c @@ -35,7 +35,7 @@ void cpu_sync_bndcs_hflags(CPUX86State *env) } if ((env->cr[4] & CR4_OSXSAVE_MASK) - && (env->xcr0 & XSTATE_BNDCSR) + && (env->xcr0 & XSTATE_BNDCSR_MASK) && (bndcsr & BNDCFG_ENABLE)) { hflags |= HF_MPX_EN_MASK; } else { -- cgit v1.1