diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2012-06-18 10:35:13 -0500 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2012-06-18 10:35:13 -0500 |
commit | 664535c31c41d8dcd7756b579674a4a6f9eb6cd9 (patch) | |
tree | 654ffde68f284ef4d595920f5da646bfb92b20f4 | |
parent | 0b0cb9d310edfe2b2d108f18be4f013a1e552cfd (diff) | |
parent | 0cd23fcc0afe0a847e2e68797b64b297b20121f9 (diff) |
Merge remote-tracking branch 'qmp/queue/qmp' into staging
* qmp/queue/qmp:
build: install qmp-commands.txt
Add rate limiting of RTC_CHANGE, BALLOON_CHANGE & WATCHDOG events
Add event notification for guest balloon changes
Fix some more license versions (GPL2+ instead of GPL2)
monitor: Fix memory leak with readline completion
qmp: do not include monitor.h from qapi-types-core.h
qmp: include monitor.h when needed
kvm: add missing include files
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | QMP/qmp-events.txt | 18 | ||||
-rw-r--r-- | balloon.c | 14 | ||||
-rw-r--r-- | balloon.h | 2 | ||||
-rw-r--r-- | hmp.c | 1 | ||||
-rw-r--r-- | hw/virtio-balloon.c | 5 | ||||
-rw-r--r-- | kvm-all.c | 2 | ||||
-rw-r--r-- | monitor.c | 159 | ||||
-rw-r--r-- | monitor.h | 1 | ||||
-rw-r--r-- | net/tap.c | 1 | ||||
-rw-r--r-- | qapi/qapi-types-core.h | 4 | ||||
-rw-r--r-- | trace-events | 5 |
12 files changed, 204 insertions, 9 deletions
@@ -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" 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 } } @@ -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; @@ -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 @@ -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/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) @@ -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" @@ -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; @@ -443,9 +457,145 @@ 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) +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 * @@ -455,7 +605,6 @@ void monitor_protocol_event(MonitorEvent event, QObject *data) { QDict *qmp; const char *event_name; - Monitor *mon; assert(event < QEVENT_MAX); @@ -470,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); } @@ -4570,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; } @@ -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 */ @@ -34,6 +34,7 @@ #include <net/if.h> #include "net.h" +#include "monitor.h" #include "sysemu.h" #include "qemu-char.h" #include "qemu-common.h" 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 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" |