From ebd063d15015d372b5ebd36cdd9fe212b0d5334d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 7 Jun 2012 04:02:20 +0200 Subject: [PATCH 1/8] kvm: add missing include files These are included via monitor.h right now, add them explicitly. Signed-off-by: Paolo Bonzini Signed-off-by: Luiz Capitulino --- kvm-all.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kvm-all.c b/kvm-all.c index 4ea7d85fe2..f8e432841f 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -22,6 +22,8 @@ #include "qemu-common.h" #include "qemu-barrier.h" +#include "qemu-option.h" +#include "qemu-config.h" #include "sysemu.h" #include "hw/hw.h" #include "hw/msi.h" From 37003adf96c3e4d3de08247f0199055994d881de Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 7 Jun 2012 04:02:21 +0200 Subject: [PATCH 2/8] qmp: include monitor.h when needed This is needed to get file descriptors from SCM_RIGHTS. Signed-off-by: Paolo Bonzini Signed-off-by: Luiz Capitulino --- hmp.c | 1 + net/tap.c | 1 + 2 files changed, 2 insertions(+) diff --git a/hmp.c b/hmp.c index 2ce8cb9df1..b9cec1dafb 100644 --- a/hmp.c +++ b/hmp.c @@ -18,6 +18,7 @@ #include "qemu-option.h" #include "qemu-timer.h" #include "qmp-commands.h" +#include "monitor.h" static void hmp_handle_error(Monitor *mon, Error **errp) { diff --git a/net/tap.c b/net/tap.c index 5ac4ba3343..17e91355ce 100644 --- a/net/tap.c +++ b/net/tap.c @@ -34,6 +34,7 @@ #include #include "net.h" +#include "monitor.h" #include "sysemu.h" #include "qemu-char.h" #include "qemu-common.h" From ad608da51d59aed20905138bc4cc524bc77f42de Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 7 Jun 2012 04:02:22 +0200 Subject: [PATCH 3/8] qmp: do not include monitor.h from qapi-types-core.h The comment is stale, monitor.h is not needed anymore (only qerror.h is, because it contains the schema for errors). Signed-off-by: Paolo Bonzini Signed-off-by: Luiz Capitulino --- qapi/qapi-types-core.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/qapi/qapi-types-core.h b/qapi/qapi-types-core.h index 27e6be0a87..f781fc3ab7 100644 --- a/qapi/qapi-types-core.h +++ b/qapi/qapi-types-core.h @@ -16,8 +16,6 @@ #include "qemu-common.h" #include "error.h" - -/* FIXME this is temporary until we remove middle mode */ -#include "monitor.h" +#include "qerror.h" #endif From 7618be6230efebab643513eb92fd93c79da36e4d Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Mon, 14 May 2012 21:47:20 +0200 Subject: [PATCH 4/8] monitor: Fix memory leak with readline completion Each string which is shown during readline completion in the QEMU monitor is allocated dynamically but currently never deallocated. Add the missing loop which calls g_free for the allocated strings. Signed-off-by: Stefan Weil Reviewed-by: Stefan Hajnoczi Signed-off-by: Luiz Capitulino --- readline.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/readline.c b/readline.c index a6c0039ad2..540cd8a025 100644 --- a/readline.c +++ b/readline.c @@ -337,6 +337,9 @@ static void readline_completion(ReadLineState *rs) } readline_show_prompt(rs); } + for (i = 0; i < rs->nb_completions; i++) { + g_free(rs->completions[i]); + } } /* return true if command handled */ From 395c3b80bb48c0e1cbce3436e63af3650cc46d1a Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Mon, 11 Jun 2012 07:49:18 +0200 Subject: [PATCH 5/8] Fix some more license versions (GPL2+ instead of GPL2) Cc: Wen Congyang Signed-off-by: Stefan Weil Signed-off-by: Wen Congyang Signed-off-by: Luiz Capitulino --- memory_mapping-stub.c | 4 ++-- memory_mapping.c | 4 ++-- memory_mapping.h | 4 ++-- target-i386/arch_dump.c | 4 ++-- target-i386/arch_memory_mapping.c | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/memory_mapping-stub.c b/memory_mapping-stub.c index 104281d78e..76be34d89f 100644 --- a/memory_mapping-stub.c +++ b/memory_mapping-stub.c @@ -6,8 +6,8 @@ * Authors: * Wen Congyang * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. * */ diff --git a/memory_mapping.c b/memory_mapping.c index 1125e3fccf..6f5a2e3f71 100644 --- a/memory_mapping.c +++ b/memory_mapping.c @@ -6,8 +6,8 @@ * Authors: * Wen Congyang * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. * */ diff --git a/memory_mapping.h b/memory_mapping.h index 3f003586d4..ef72b0abad 100644 --- a/memory_mapping.h +++ b/memory_mapping.h @@ -6,8 +6,8 @@ * Authors: * Wen Congyang * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. * */ diff --git a/target-i386/arch_dump.c b/target-i386/arch_dump.c index 7c2b514383..4240278edd 100644 --- a/target-i386/arch_dump.c +++ b/target-i386/arch_dump.c @@ -6,8 +6,8 @@ * Authors: * Wen Congyang * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. * */ diff --git a/target-i386/arch_memory_mapping.c b/target-i386/arch_memory_mapping.c index efb0211fdc..8e5a56a3a8 100644 --- a/target-i386/arch_memory_mapping.c +++ b/target-i386/arch_memory_mapping.c @@ -6,8 +6,8 @@ * Authors: * Wen Congyang * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. * */ From 973603a813c5d60534b4fa0313f83be40e2b9c47 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Thu, 14 Jun 2012 18:12:56 +0100 Subject: [PATCH 6/8] Add event notification for guest balloon changes After setting a balloon target value, applications have to continually poll 'query-balloon' to determine whether the guest has reacted to this request. The virtio-balloon backend knows exactly when the guest has reacted though, and thus it is possible to emit a JSON event to tell the mgmt application whenever the guest balloon changes. This introduces a new 'qemu_balloon_changed()' API which is to be called by balloon driver backends, whenever they have a change in balloon value. This takes the 'actual' balloon value, as would be found in the BalloonInfo struct. The qemu_balloon_change API emits a JSON monitor event which looks like: {"timestamp": {"seconds": 1337162462, "microseconds": 814521}, "event": "BALLOON_CHANGE", "data": {"actual": 944766976}} * balloon.c, balloon.h: Introduce qemu_balloon_changed() for emitting balloon change events on the monitor * hw/virtio-balloon.c: Invoke qemu_balloon_changed() whenever the guest changes the balloon actual value * monitor.c, monitor.h: Define QEVENT_BALLOON_CHANGE Signed-off-by: Daniel P. Berrange Acked-by: Amit Shah Signed-off-by: Luiz Capitulino --- QMP/qmp-events.txt | 18 ++++++++++++++++++ balloon.c | 14 ++++++++++++++ balloon.h | 2 ++ hw/virtio-balloon.c | 5 +++++ monitor.c | 1 + monitor.h | 1 + 6 files changed, 41 insertions(+) diff --git a/QMP/qmp-events.txt b/QMP/qmp-events.txt index 9286af569d..9ba7079589 100644 --- a/QMP/qmp-events.txt +++ b/QMP/qmp-events.txt @@ -335,3 +335,21 @@ Example: "len": 10737418240, "offset": 134217728, "speed": 0 }, "timestamp": { "seconds": 1267061043, "microseconds": 959568 } } + + +BALLOON_CHANGE +---------- + +Emitted when the guest changes the actual BALLOON level. This +value is equivalent to the 'actual' field return by the +'query-balloon' command + +Data: + +- "actual": actual level of the guest memory balloon in bytes (json-number) + +Example: + +{ "event": "BALLOON_CHANGE", + "data": { "actual": 944766976 }, + "timestamp": { "seconds": 1267020223, "microseconds": 435656 } } diff --git a/balloon.c b/balloon.c index aa354f7554..e02ab1c884 100644 --- a/balloon.c +++ b/balloon.c @@ -30,6 +30,7 @@ #include "balloon.h" #include "trace.h" #include "qmp-commands.h" +#include "qjson.h" static QEMUBalloonEvent *balloon_event_fn; static QEMUBalloonStatus *balloon_stat_fn; @@ -80,6 +81,19 @@ static int qemu_balloon_status(BalloonInfo *info) return 1; } +void qemu_balloon_changed(int64_t actual) +{ + QObject *data; + + data = qobject_from_jsonf("{ 'actual': %" PRId64 " }", + actual); + + monitor_protocol_event(QEVENT_BALLOON_CHANGE, data); + + qobject_decref(data); +} + + BalloonInfo *qmp_query_balloon(Error **errp) { BalloonInfo *info; diff --git a/balloon.h b/balloon.h index b60fd5d9f2..b803a00741 100644 --- a/balloon.h +++ b/balloon.h @@ -24,4 +24,6 @@ int qemu_add_balloon_handler(QEMUBalloonEvent *event_func, QEMUBalloonStatus *stat_func, void *opaque); void qemu_remove_balloon_handler(void *opaque); +void qemu_balloon_changed(int64_t actual); + #endif diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c index 075ed87e37..d048cef50f 100644 --- a/hw/virtio-balloon.c +++ b/hw/virtio-balloon.c @@ -146,8 +146,13 @@ static void virtio_balloon_set_config(VirtIODevice *vdev, { VirtIOBalloon *dev = to_virtio_balloon(vdev); struct virtio_balloon_config config; + uint32_t oldactual = dev->actual; memcpy(&config, config_data, 8); dev->actual = le32_to_cpu(config.actual); + if (dev->actual != oldactual) { + qemu_balloon_changed(ram_size - + (dev->actual << VIRTIO_BALLOON_PFN_SHIFT)); + } } static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f) diff --git a/monitor.c b/monitor.c index a3bc2c7253..75fd4cf5e1 100644 --- a/monitor.c +++ b/monitor.c @@ -443,6 +443,7 @@ static const char *monitor_event_names[] = { [QEVENT_DEVICE_TRAY_MOVED] = "DEVICE_TRAY_MOVED", [QEVENT_SUSPEND] = "SUSPEND", [QEVENT_WAKEUP] = "WAKEUP", + [QEVENT_BALLOON_CHANGE] = "BALLOON_CHANGE", }; QEMU_BUILD_BUG_ON(ARRAY_SIZE(monitor_event_names) != QEVENT_MAX) diff --git a/monitor.h b/monitor.h index cd1d8786d1..5f4de1b3da 100644 --- a/monitor.h +++ b/monitor.h @@ -41,6 +41,7 @@ typedef enum MonitorEvent { QEVENT_DEVICE_TRAY_MOVED, QEVENT_SUSPEND, QEVENT_WAKEUP, + QEVENT_BALLOON_CHANGE, /* Add to 'monitor_event_names' array in monitor.c when * defining new events here */ From afeecec2e8e99ba184c487633d5d0dde68a002ac Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Thu, 14 Jun 2012 18:12:57 +0100 Subject: [PATCH 7/8] Add rate limiting of RTC_CHANGE, BALLOON_CHANGE & WATCHDOG events Allow certain event types to be rate limited to avoid flooding monitor clients. The monitor_protocol_event() method is changed such that instead of immediately emitting the event to Monitor instances, it will call a new monitor_protocol_event_queue() method. This will check to see if the rate limit for the event has been exceeded, and if so schedule a timer to wakeup at the end of the rate limit period. If further events arrive before the timer fires, the previously queued event will be discarded in favour of the new event. The event will eventually be emitted when the timer fires. This logic is applied to RTC_CHANGE, BALLOON_CHANGE & WATCHDOG events, since the data associated with these events is stateless * monitor.c: Add support for rate limiting * monitor.h: Define monitor_global_init for one-time setup tasks * vl.c: Invoke monitor_global_init * trace-events: Add hooks for monitor event tracing Signed-off-by: Daniel P. Berrange Acked-by: Amit Shah Signed-off-by: Luiz Capitulino --- monitor.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++-- trace-events | 5 ++ 2 files changed, 157 insertions(+), 6 deletions(-) diff --git a/monitor.c b/monitor.c index 75fd4cf5e1..f6107badb6 100644 --- a/monitor.c +++ b/monitor.c @@ -66,6 +66,7 @@ #include "memory.h" #include "qmp-commands.h" #include "hmp.h" +#include "qemu-thread.h" /* for pic/irq_info */ #if defined(TARGET_SPARC) @@ -145,6 +146,19 @@ typedef struct MonitorControl { int command_mode; } MonitorControl; +/* + * To prevent flooding clients, events can be throttled. The + * throttling is calculated globally, rather than per-Monitor + * instance. + */ +typedef struct MonitorEventState { + MonitorEvent event; /* Event being tracked */ + int64_t rate; /* Period over which to throttle. 0 to disable */ + int64_t last; /* Time at which event was last emitted */ + QEMUTimer *timer; /* Timer for handling delayed events */ + QObject *data; /* Event pending delayed dispatch */ +} MonitorEventState; + struct Monitor { CharDriverState *chr; int mux_out; @@ -447,6 +461,141 @@ static const char *monitor_event_names[] = { }; QEMU_BUILD_BUG_ON(ARRAY_SIZE(monitor_event_names) != QEVENT_MAX) +MonitorEventState monitor_event_state[QEVENT_MAX]; +QemuMutex monitor_event_state_lock; + +/* + * Emits the event to every monitor instance + */ +static void +monitor_protocol_event_emit(MonitorEvent event, + QObject *data) +{ + Monitor *mon; + + trace_monitor_protocol_event_emit(event, data); + QLIST_FOREACH(mon, &mon_list, entry) { + if (monitor_ctrl_mode(mon) && qmp_cmd_mode(mon)) { + monitor_json_emitter(mon, data); + } + } +} + + +/* + * Queue a new event for emission to Monitor instances, + * applying any rate limiting if required. + */ +static void +monitor_protocol_event_queue(MonitorEvent event, + QObject *data) +{ + MonitorEventState *evstate; + int64_t now = qemu_get_clock_ns(rt_clock); + assert(event < QEVENT_MAX); + + qemu_mutex_lock(&monitor_event_state_lock); + evstate = &(monitor_event_state[event]); + trace_monitor_protocol_event_queue(event, + data, + evstate->rate, + evstate->last, + now); + + /* Rate limit of 0 indicates no throttling */ + if (!evstate->rate) { + monitor_protocol_event_emit(event, data); + evstate->last = now; + } else { + int64_t delta = now - evstate->last; + if (evstate->data || + delta < evstate->rate) { + /* If there's an existing event pending, replace + * it with the new event, otherwise schedule a + * timer for delayed emission + */ + if (evstate->data) { + qobject_decref(evstate->data); + } else { + int64_t then = evstate->last + evstate->rate; + qemu_mod_timer_ns(evstate->timer, then); + } + evstate->data = data; + qobject_incref(evstate->data); + } else { + monitor_protocol_event_emit(event, data); + evstate->last = now; + } + } + qemu_mutex_unlock(&monitor_event_state_lock); +} + + +/* + * The callback invoked by QemuTimer when a delayed + * event is ready to be emitted + */ +static void monitor_protocol_event_handler(void *opaque) +{ + MonitorEventState *evstate = opaque; + int64_t now = qemu_get_clock_ns(rt_clock); + + qemu_mutex_lock(&monitor_event_state_lock); + + trace_monitor_protocol_event_handler(evstate->event, + evstate->data, + evstate->last, + now); + if (evstate->data) { + monitor_protocol_event_emit(evstate->event, evstate->data); + qobject_decref(evstate->data); + evstate->data = NULL; + } + evstate->last = now; + qemu_mutex_unlock(&monitor_event_state_lock); +} + + +/* + * @event: the event ID to be limited + * @rate: the rate limit in milliseconds + * + * Sets a rate limit on a particular event, so no + * more than 1 event will be emitted within @rate + * milliseconds + */ +static void +monitor_protocol_event_throttle(MonitorEvent event, + int64_t rate) +{ + MonitorEventState *evstate; + assert(event < QEVENT_MAX); + + evstate = &(monitor_event_state[event]); + + trace_monitor_protocol_event_throttle(event, rate); + evstate->event = event; + evstate->rate = rate * SCALE_MS; + evstate->timer = qemu_new_timer(rt_clock, + SCALE_MS, + monitor_protocol_event_handler, + evstate); + evstate->last = 0; + evstate->data = NULL; +} + + +/* Global, one-time initializer to configure the rate limiting + * and initialize state */ +static void monitor_protocol_event_init(void) +{ + qemu_mutex_init(&monitor_event_state_lock); + /* Limit RTC & BALLOON events to 1 per second */ + monitor_protocol_event_throttle(QEVENT_RTC_CHANGE, 1000); + monitor_protocol_event_throttle(QEVENT_BALLOON_CHANGE, 1000); + monitor_protocol_event_throttle(QEVENT_WATCHDOG, 1000); +} + /** * monitor_protocol_event(): Generate a Monitor event * @@ -456,7 +605,6 @@ void monitor_protocol_event(MonitorEvent event, QObject *data) { QDict *qmp; const char *event_name; - Monitor *mon; assert(event < QEVENT_MAX); @@ -471,11 +619,8 @@ void monitor_protocol_event(MonitorEvent event, QObject *data) qdict_put_obj(qmp, "data", data); } - QLIST_FOREACH(mon, &mon_list, entry) { - if (monitor_ctrl_mode(mon) && qmp_cmd_mode(mon)) { - monitor_json_emitter(mon, QOBJECT(qmp)); - } - } + trace_monitor_protocol_event(event, event_name, qmp); + monitor_protocol_event_queue(event, QOBJECT(qmp)); QDECREF(qmp); } @@ -4571,6 +4716,7 @@ void monitor_init(CharDriverState *chr, int flags) if (is_first_init) { key_timer = qemu_new_timer_ns(vm_clock, release_keys, NULL); + monitor_protocol_event_init(); is_first_init = 0; } diff --git a/trace-events b/trace-events index f70523c47e..5c82b3acf2 100644 --- a/trace-events +++ b/trace-events @@ -677,6 +677,11 @@ esp_mem_writeb_cmd_ensel(uint32_t val) "Enable selection (%2.2x)" # monitor.c handle_qmp_command(void *mon, const char *cmd_name) "mon %p cmd_name \"%s\"" monitor_protocol_emitter(void *mon) "mon %p" +monitor_protocol_event(uint32_t event, const char *evname, void *data) "event=%d name \"%s\" data %p" +monitor_protocol_event_handler(uint32_t event, void *data, uint64_t last, uint64_t now) "event=%d data=%p last=%" PRId64 " now=%" PRId64 +monitor_protocol_event_emit(uint32_t event, void *data) "event=%d data=%p" +monitor_protocol_event_queue(uint32_t event, void *data, uint64_t rate, uint64_t last, uint64_t now) "event=%d data=%p rate=%" PRId64 " last=%" PRId64 " now=%" PRId64 +monitor_protocol_event_throttle(uint32_t event, uint64_t rate) "event=%d rate=%" PRId64 # hw/opencores_eth.c open_eth_mii_write(unsigned idx, uint16_t v) "MII[%02x] <- %04x" From 0cd23fcc0afe0a847e2e68797b64b297b20121f9 Mon Sep 17 00:00:00 2001 From: Bruce Rogers Date: Wed, 13 Jun 2012 16:29:17 -0600 Subject: [PATCH 8/8] build: install qmp-commands.txt File is targeted for install, but is never installed. Signed-off-by: Bruce Rogers Signed-off-by: Luiz Capitulino --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 32550cbfaf..74f5c5fbc5 100644 --- a/Makefile +++ b/Makefile @@ -272,6 +272,7 @@ endif install-doc: $(DOCS) $(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)" $(INSTALL_DATA) qemu-doc.html qemu-tech.html "$(DESTDIR)$(qemu_docdir)" + $(INSTALL_DATA) QMP/qmp-commands.txt "$(DESTDIR)$(qemu_docdir)" ifdef CONFIG_POSIX $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1" $(INSTALL_DATA) qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1"