*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "qemu/cutils.h"
#include "qemu/option.h"
#include "monitor/monitor.h"
#include "chardev/char.h"
#include "ui/qemu-spice.h"
#include "ui/console.h"
+#include "ui/dbus-display.h"
#include "sysemu/kvm.h"
#include "sysemu/runstate.h"
#include "sysemu/runstate-action.h"
-#include "sysemu/arch_init.h"
#include "sysemu/blockdev.h"
#include "sysemu/block-backend.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-control.h"
#include "qapi/qapi-commands-machine.h"
#include "qapi/qapi-commands-misc.h"
+#include "qapi/qapi-commands-stats.h"
#include "qapi/qapi-commands-ui.h"
+#include "qapi/type-helpers.h"
#include "qapi/qmp/qerror.h"
+#include "exec/ramlist.h"
#include "hw/mem/memory-device.h"
#include "hw/acpi/acpi_dev_interface.h"
+#include "hw/intc/intc.h"
+#include "hw/rdma/rdma.h"
+#include "monitor/stats.h"
NameInfo *qmp_query_name(Error **errp)
{
KvmInfo *info = g_malloc0(sizeof(*info));
info->enabled = kvm_enabled();
- info->present = kvm_available();
+ info->present = accel_find("kvm");
return info;
}
{
/* if there is a dump in background, we should wait until the dump
* finished */
- if (dump_in_progress()) {
+ if (qemu_system_dump_in_progress()) {
error_setg(errp, "There is a dump in process, please wait.");
return;
}
/* if there is a dump in background, we should wait until the dump
* finished */
- if (dump_in_progress()) {
+ if (qemu_system_dump_in_progress()) {
error_setg(errp, "There is a dump in process, please wait.");
return;
}
blk_iostatus_reset(blk);
}
- for (job = block_job_next(NULL); job; job = block_job_next(job)) {
- block_job_iostatus_reset(job);
+ WITH_JOB_LOCK_GUARD() {
+ for (job = block_job_next_locked(NULL); job;
+ job = block_job_next_locked(job)) {
+ block_job_iostatus_reset_locked(job);
+ }
}
/* Continuing after completed migration. Images have been inactivated to
* If there are no inactive block nodes (e.g. because the VM was just
* paused rather than completing a migration), bdrv_inactivate_all() simply
* doesn't do anything. */
- bdrv_invalidate_cache_all(&local_err);
+ bdrv_activate_all(&local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, errp);
}
-void qmp_set_password(const char *protocol, const char *password,
- bool has_connected, const char *connected, Error **errp)
+void qmp_set_password(SetPasswordOptions *opts, Error **errp)
{
- int disconnect_if_connected = 0;
- int fail_if_connected = 0;
int rc;
- if (has_connected) {
- if (strcmp(connected, "fail") == 0) {
- fail_if_connected = 1;
- } else if (strcmp(connected, "disconnect") == 0) {
- disconnect_if_connected = 1;
- } else if (strcmp(connected, "keep") == 0) {
- /* nothing */
- } else {
- error_setg(errp, QERR_INVALID_PARAMETER, "connected");
- return;
- }
- }
-
- if (strcmp(protocol, "spice") == 0) {
+ if (opts->protocol == DISPLAY_PROTOCOL_SPICE) {
if (!qemu_using_spice(errp)) {
return;
}
- rc = qemu_spice.set_passwd(password, fail_if_connected,
- disconnect_if_connected);
- } else if (strcmp(protocol, "vnc") == 0) {
- if (fail_if_connected || disconnect_if_connected) {
+ rc = qemu_spice.set_passwd(opts->password,
+ opts->connected == SET_PASSWORD_ACTION_FAIL,
+ opts->connected == SET_PASSWORD_ACTION_DISCONNECT);
+ } else {
+ assert(opts->protocol == DISPLAY_PROTOCOL_VNC);
+ if (opts->connected != SET_PASSWORD_ACTION_KEEP) {
/* vnc supports "connected=keep" only */
error_setg(errp, QERR_INVALID_PARAMETER, "connected");
return;
}
/* Note that setting an empty password will not disable login through
* this interface. */
- rc = vnc_display_password(NULL, password);
- } else {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "protocol",
- "'vnc' or 'spice'");
- return;
+ rc = vnc_display_password(opts->u.vnc.display, opts->password);
}
if (rc != 0) {
}
}
-void qmp_expire_password(const char *protocol, const char *whenstr,
- Error **errp)
+void qmp_expire_password(ExpirePasswordOptions *opts, Error **errp)
{
time_t when;
int rc;
+ const char *whenstr = opts->time;
if (strcmp(whenstr, "now") == 0) {
when = 0;
when = strtoull(whenstr, NULL, 10);
}
- if (strcmp(protocol, "spice") == 0) {
+ if (opts->protocol == DISPLAY_PROTOCOL_SPICE) {
if (!qemu_using_spice(errp)) {
return;
}
rc = qemu_spice.set_pw_expire(when);
- } else if (strcmp(protocol, "vnc") == 0) {
- rc = vnc_display_pw_expire(NULL, when);
} else {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "protocol",
- "'vnc' or 'spice'");
- return;
+ assert(opts->protocol == DISPLAY_PROTOCOL_VNC);
+ rc = vnc_display_pw_expire(opts->u.vnc.display, when);
}
if (rc != 0) {
skipauth = has_skipauth ? skipauth : false;
vnc_display_add_client(NULL, fd, skipauth);
return;
+#endif
+#ifdef CONFIG_DBUS_DISPLAY
+ } else if (strcmp(protocol, "@dbus-display") == 0) {
+ if (!qemu_using_dbus_display(errp)) {
+ close(fd);
+ return;
+ }
+ if (!qemu_dbus_display.add_client(fd, errp)) {
+ close(fd);
+ return;
+ }
+ return;
#endif
} else if ((s = qemu_chr_find(protocol)) != NULL) {
if (qemu_chr_add_client(s, fd) < 0) {
MemoryInfo *qmp_query_memory_size_summary(Error **errp)
{
- MemoryInfo *mem_info = g_malloc0(sizeof(MemoryInfo));
+ MemoryInfo *mem_info = g_new0(MemoryInfo, 1);
MachineState *ms = MACHINE(qdev_get_machine());
mem_info->base_memory = ms->ram_size;
abort();
}
}
+
+void qmp_display_update(DisplayUpdateOptions *arg, Error **errp)
+{
+ switch (arg->type) {
+ case DISPLAY_UPDATE_TYPE_VNC:
+#ifdef CONFIG_VNC
+ vnc_display_update(&arg->u.vnc, errp);
+#else
+ error_setg(errp, "vnc is invalid, missing 'CONFIG_VNC'");
+#endif
+ break;
+ default:
+ abort();
+ }
+}
+
+static int qmp_x_query_rdma_foreach(Object *obj, void *opaque)
+{
+ RdmaProvider *rdma;
+ RdmaProviderClass *k;
+ GString *buf = opaque;
+
+ if (object_dynamic_cast(obj, INTERFACE_RDMA_PROVIDER)) {
+ rdma = RDMA_PROVIDER(obj);
+ k = RDMA_PROVIDER_GET_CLASS(obj);
+ if (k->format_statistics) {
+ k->format_statistics(rdma, buf);
+ } else {
+ g_string_append_printf(buf,
+ "RDMA statistics not available for %s.\n",
+ object_get_typename(obj));
+ }
+ }
+
+ return 0;
+}
+
+HumanReadableText *qmp_x_query_rdma(Error **errp)
+{
+ g_autoptr(GString) buf = g_string_new("");
+
+ object_child_foreach_recursive(object_get_root(),
+ qmp_x_query_rdma_foreach, buf);
+
+ return human_readable_text_from_str(buf);
+}
+
+HumanReadableText *qmp_x_query_ramblock(Error **errp)
+{
+ g_autoptr(GString) buf = ram_block_format();
+
+ return human_readable_text_from_str(buf);
+}
+
+static int qmp_x_query_irq_foreach(Object *obj, void *opaque)
+{
+ InterruptStatsProvider *intc;
+ InterruptStatsProviderClass *k;
+ GString *buf = opaque;
+
+ if (object_dynamic_cast(obj, TYPE_INTERRUPT_STATS_PROVIDER)) {
+ intc = INTERRUPT_STATS_PROVIDER(obj);
+ k = INTERRUPT_STATS_PROVIDER_GET_CLASS(obj);
+ uint64_t *irq_counts;
+ unsigned int nb_irqs, i;
+ if (k->get_statistics &&
+ k->get_statistics(intc, &irq_counts, &nb_irqs)) {
+ if (nb_irqs > 0) {
+ g_string_append_printf(buf, "IRQ statistics for %s:\n",
+ object_get_typename(obj));
+ for (i = 0; i < nb_irqs; i++) {
+ if (irq_counts[i] > 0) {
+ g_string_append_printf(buf, "%2d: %" PRId64 "\n", i,
+ irq_counts[i]);
+ }
+ }
+ }
+ } else {
+ g_string_append_printf(buf,
+ "IRQ statistics not available for %s.\n",
+ object_get_typename(obj));
+ }
+ }
+
+ return 0;
+}
+
+HumanReadableText *qmp_x_query_irq(Error **errp)
+{
+ g_autoptr(GString) buf = g_string_new("");
+
+ object_child_foreach_recursive(object_get_root(),
+ qmp_x_query_irq_foreach, buf);
+
+ return human_readable_text_from_str(buf);
+}
+
+typedef struct StatsCallbacks {
+ StatsProvider provider;
+ StatRetrieveFunc *stats_cb;
+ SchemaRetrieveFunc *schemas_cb;
+ QTAILQ_ENTRY(StatsCallbacks) next;
+} StatsCallbacks;
+
+static QTAILQ_HEAD(, StatsCallbacks) stats_callbacks =
+ QTAILQ_HEAD_INITIALIZER(stats_callbacks);
+
+void add_stats_callbacks(StatsProvider provider,
+ StatRetrieveFunc *stats_fn,
+ SchemaRetrieveFunc *schemas_fn)
+{
+ StatsCallbacks *entry = g_new(StatsCallbacks, 1);
+ entry->provider = provider;
+ entry->stats_cb = stats_fn;
+ entry->schemas_cb = schemas_fn;
+
+ QTAILQ_INSERT_TAIL(&stats_callbacks, entry, next);
+}
+
+static bool invoke_stats_cb(StatsCallbacks *entry,
+ StatsResultList **stats_results,
+ StatsFilter *filter, StatsRequest *request,
+ Error **errp)
+{
+ strList *targets = NULL;
+ strList *names = NULL;
+ ERRP_GUARD();
+
+ if (request) {
+ if (request->provider != entry->provider) {
+ return true;
+ }
+ if (request->has_names && !request->names) {
+ return true;
+ }
+ names = request->has_names ? request->names : NULL;
+ }
+
+ switch (filter->target) {
+ case STATS_TARGET_VM:
+ break;
+ case STATS_TARGET_VCPU:
+ if (filter->u.vcpu.has_vcpus) {
+ if (!filter->u.vcpu.vcpus) {
+ /* No targets allowed? Return no statistics. */
+ return true;
+ }
+ targets = filter->u.vcpu.vcpus;
+ }
+ break;
+ default:
+ abort();
+ }
+
+ entry->stats_cb(stats_results, filter->target, names, targets, errp);
+ if (*errp) {
+ qapi_free_StatsResultList(*stats_results);
+ *stats_results = NULL;
+ return false;
+ }
+ return true;
+}
+
+StatsResultList *qmp_query_stats(StatsFilter *filter, Error **errp)
+{
+ StatsResultList *stats_results = NULL;
+ StatsCallbacks *entry;
+ StatsRequestList *request;
+
+ QTAILQ_FOREACH(entry, &stats_callbacks, next) {
+ if (filter->has_providers) {
+ for (request = filter->providers; request; request = request->next) {
+ if (!invoke_stats_cb(entry, &stats_results, filter,
+ request->value, errp)) {
+ break;
+ }
+ }
+ } else {
+ if (!invoke_stats_cb(entry, &stats_results, filter, NULL, errp)) {
+ break;
+ }
+ }
+ }
+
+ return stats_results;
+}
+
+StatsSchemaList *qmp_query_stats_schemas(bool has_provider,
+ StatsProvider provider,
+ Error **errp)
+{
+ StatsSchemaList *stats_results = NULL;
+ StatsCallbacks *entry;
+ ERRP_GUARD();
+
+ QTAILQ_FOREACH(entry, &stats_callbacks, next) {
+ if (!has_provider || provider == entry->provider) {
+ entry->schemas_cb(&stats_results, errp);
+ if (*errp) {
+ qapi_free_StatsSchemaList(stats_results);
+ return NULL;
+ }
+ }
+ }
+
+ return stats_results;
+}
+
+void add_stats_entry(StatsResultList **stats_results, StatsProvider provider,
+ const char *qom_path, StatsList *stats_list)
+{
+ StatsResult *entry = g_new0(StatsResult, 1);
+
+ entry->provider = provider;
+ if (qom_path) {
+ entry->has_qom_path = true;
+ entry->qom_path = g_strdup(qom_path);
+ }
+ entry->stats = stats_list;
+
+ QAPI_LIST_PREPEND(*stats_results, entry);
+}
+
+void add_stats_schema(StatsSchemaList **schema_results,
+ StatsProvider provider, StatsTarget target,
+ StatsSchemaValueList *stats_list)
+{
+ StatsSchema *entry = g_new0(StatsSchema, 1);
+
+ entry->provider = provider;
+ entry->target = target;
+ entry->stats = stats_list;
+ QAPI_LIST_PREPEND(*schema_results, entry);
+}
+
+bool apply_str_list_filter(const char *string, strList *list)
+{
+ strList *str_list = NULL;
+
+ if (!list) {
+ return true;
+ }
+ for (str_list = list; str_list; str_list = str_list->next) {
+ if (g_str_equal(string, str_list->value)) {
+ return true;
+ }
+ }
+ return false;
+}