提交 664535c3 编写于 作者: A Anthony Liguori

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
......@@ -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"
......
......@@ -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)
{
......
......@@ -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"
......
......@@ -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
......@@ -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"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册