2011-09-02 19:34:48 +02:00
|
|
|
/*
|
|
|
|
* Human Monitor Interface
|
|
|
|
*
|
|
|
|
* Copyright IBM, Corp. 2011
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Anthony Liguori <aliguori@us.ibm.com>
|
|
|
|
*
|
|
|
|
* This work is licensed under the terms of the GNU GPL, version 2. See
|
|
|
|
* the COPYING file in the top-level directory.
|
|
|
|
*
|
2012-01-13 17:44:23 +01:00
|
|
|
* Contributions after 2012-01-13 are licensed under the terms of the
|
|
|
|
* GNU GPL, version 2 or (at your option) any later version.
|
2011-09-02 19:34:48 +02:00
|
|
|
*/
|
|
|
|
|
2016-01-29 18:50:05 +01:00
|
|
|
#include "qemu/osdep.h"
|
2011-09-02 19:34:48 +02:00
|
|
|
#include "hmp.h"
|
2012-10-24 08:43:34 +02:00
|
|
|
#include "net/net.h"
|
2015-06-11 03:21:21 +02:00
|
|
|
#include "net/eth.h"
|
2017-01-26 14:19:46 +01:00
|
|
|
#include "chardev/char.h"
|
2015-02-05 19:58:22 +01:00
|
|
|
#include "sysemu/block-backend.h"
|
2017-04-18 11:40:56 +02:00
|
|
|
#include "sysemu/sysemu.h"
|
2016-12-12 18:22:24 +01:00
|
|
|
#include "qemu/config-file.h"
|
2012-12-17 18:20:00 +01:00
|
|
|
#include "qemu/option.h"
|
|
|
|
#include "qemu/timer.h"
|
|
|
|
#include "qemu/sockets.h"
|
2012-12-17 18:19:49 +01:00
|
|
|
#include "monitor/monitor.h"
|
2015-03-05 17:24:48 +01:00
|
|
|
#include "monitor/qdev.h"
|
2018-02-01 12:18:31 +01:00
|
|
|
#include "qapi/error.h"
|
2013-12-20 23:21:10 +01:00
|
|
|
#include "qapi/opts-visitor.h"
|
2018-02-11 10:36:05 +01:00
|
|
|
#include "qapi/qapi-builtin-visit.h"
|
2018-02-27 00:13:27 +01:00
|
|
|
#include "qapi/qapi-commands-block.h"
|
|
|
|
#include "qapi/qapi-commands-char.h"
|
|
|
|
#include "qapi/qapi-commands-migration.h"
|
|
|
|
#include "qapi/qapi-commands-misc.h"
|
|
|
|
#include "qapi/qapi-commands-net.h"
|
|
|
|
#include "qapi/qapi-commands-rocker.h"
|
|
|
|
#include "qapi/qapi-commands-run-state.h"
|
|
|
|
#include "qapi/qapi-commands-tpm.h"
|
|
|
|
#include "qapi/qapi-commands-ui.h"
|
2018-02-01 12:18:39 +01:00
|
|
|
#include "qapi/qmp/qdict.h"
|
2015-03-17 17:22:46 +01:00
|
|
|
#include "qapi/qmp/qerror.h"
|
2017-05-16 11:37:45 +02:00
|
|
|
#include "qapi/string-input-visitor.h"
|
2014-05-14 11:43:35 +02:00
|
|
|
#include "qapi/string-output-visitor.h"
|
2016-02-10 19:40:59 +01:00
|
|
|
#include "qom/object_interfaces.h"
|
2012-11-28 12:06:30 +01:00
|
|
|
#include "ui/console.h"
|
2017-04-26 09:36:41 +02:00
|
|
|
#include "block/nbd.h"
|
2013-06-06 06:28:00 +02:00
|
|
|
#include "block/qapi.h"
|
2013-06-05 14:19:41 +02:00
|
|
|
#include "qemu-io.h"
|
2016-03-20 18:16:19 +01:00
|
|
|
#include "qemu/cutils.h"
|
migration: add reporting of errors for outgoing migration
Currently if an application initiates an outgoing migration,
it may or may not, get an error reported back on failure. If
the error occurs synchronously to the 'migrate' command
execution, the client app will see the error message. This
is the case for DNS lookup failures. If the error occurs
asynchronously to the monitor command though, the error
will be thrown away and the client left guessing about
what went wrong. This is the case for failure to connect
to the TCP server (eg due to wrong port, or firewall
rules, or other similar errors).
In the future we'll be adding more scope for errors to
happen asynchronously with the TLS protocol handshake.
TLS errors are hard to diagnose even when they are well
reported, so discarding errors entirely will make it
impossible to debug TLS connection problems.
Management apps which do migration are already using
'query-migrate' / 'info migrate' to check up on progress
of background migration operations and to see their end
status. This is a fine place to also include the error
message when things go wrong.
This patch thus adds an 'error-desc' field to the
MigrationInfo struct, which will be populated when
the 'status' is set to 'failed':
(qemu) migrate -d tcp:localhost:9001
(qemu) info migrate
capabilities: xbzrle: off rdma-pin-all: off auto-converge: off zero-blocks: off compress: off events: off x-postcopy-ram: off
Migration status: failed (Error connecting to socket: Connection refused)
total time: 0 milliseconds
In the HMP, when doing non-detached migration, it is
also possible to display this error message directly
to the app.
(qemu) migrate tcp:localhost:9001
Error connecting to socket: Connection refused
Or with QMP
{
"execute": "query-migrate",
"arguments": {}
}
{
"return": {
"status": "failed",
"error-desc": "address resolution failed for myhost:9000: No address associated with hostname"
}
}
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Message-Id: <1461751518-12128-11-git-send-email-berrange@redhat.com>
Signed-off-by: Amit Shah <amit.shah@redhat.com>
2016-04-27 12:05:00 +02:00
|
|
|
#include "qemu/error-report.h"
|
2017-05-12 06:17:41 +02:00
|
|
|
#include "exec/ramlist.h"
|
2016-09-26 22:23:27 +02:00
|
|
|
#include "hw/intc/intc.h"
|
2017-04-20 14:25:55 +02:00
|
|
|
#include "migration/snapshot.h"
|
2017-06-27 06:10:19 +02:00
|
|
|
#include "migration/misc.h"
|
2011-09-02 19:34:48 +02:00
|
|
|
|
2015-03-01 15:29:18 +01:00
|
|
|
#ifdef CONFIG_SPICE
|
|
|
|
#include <spice/enums.h>
|
|
|
|
#endif
|
|
|
|
|
2011-11-22 19:32:37 +01:00
|
|
|
static void hmp_handle_error(Monitor *mon, Error **errp)
|
|
|
|
{
|
2014-05-02 13:26:34 +02:00
|
|
|
assert(errp);
|
|
|
|
if (*errp) {
|
error: Use error_report_err() instead of monitor_printf()
Both error_report_err() and monitor_printf() print to the same
destination when monitor_printf() is used correctly, i.e. within an
HMP monitor. Elsewhere, monitor_printf() does nothing, while
error_report_err() reports to stderr.
Most changed functions are HMP command handlers. These should only
run within an HMP monitor. The one exception is bdrv_password_cb(),
which should also only run within an HMP monitor.
Four command handlers prefix the error message with the command name:
balloon, migrate_set_capability, migrate_set_parameter, migrate.
Pointless, drop.
Unlike monitor_printf(), error_report_err() uses the error whole
instead of just its message obtained with error_get_pretty(). This
avoids suppressing its hint (see commit 50b7b00). Example:
(qemu) device_add ivshmem,id=666
Parameter 'id' expects an identifier
Identifiers consist of letters, digits, '-', '.', '_', starting with a letter.
Try "help device_add" for more information
The "Identifiers consist of..." line is new with this patch.
Coccinelle semantic patch:
@@
expression M, E;
@@
- monitor_printf(M, "%s\n", error_get_pretty(E));
- error_free(E);
+ error_report_err(E);
@r1@
expression M, E;
format F;
position p;
@@
- monitor_printf(M, "...%@F@\n", error_get_pretty(E));@p
- error_free(E);
+ error_report_err(E);
@script:python@
p << r1.p;
@@
print "%s:%s:%s: prefix dropped" % (p[0].file, p[0].line, p[0].column)
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <1450452927-8346-4-git-send-email-armbru@redhat.com>
2015-12-18 16:35:06 +01:00
|
|
|
error_report_err(*errp);
|
2011-11-22 19:32:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_name(Monitor *mon, const QDict *qdict)
|
2011-09-02 19:34:48 +02:00
|
|
|
{
|
|
|
|
NameInfo *info;
|
|
|
|
|
|
|
|
info = qmp_query_name(NULL);
|
|
|
|
if (info->has_name) {
|
|
|
|
monitor_printf(mon, "%s\n", info->name);
|
|
|
|
}
|
|
|
|
qapi_free_NameInfo(info);
|
|
|
|
}
|
2011-08-26 22:38:13 +02:00
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_version(Monitor *mon, const QDict *qdict)
|
2011-08-26 22:38:13 +02:00
|
|
|
{
|
|
|
|
VersionInfo *info;
|
|
|
|
|
|
|
|
info = qmp_query_version(NULL);
|
|
|
|
|
|
|
|
monitor_printf(mon, "%" PRId64 ".%" PRId64 ".%" PRId64 "%s\n",
|
2015-05-04 17:05:31 +02:00
|
|
|
info->qemu->major, info->qemu->minor, info->qemu->micro,
|
2011-08-26 22:38:13 +02:00
|
|
|
info->package);
|
|
|
|
|
|
|
|
qapi_free_VersionInfo(info);
|
|
|
|
}
|
2011-09-12 20:10:53 +02:00
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_kvm(Monitor *mon, const QDict *qdict)
|
2011-09-12 20:10:53 +02:00
|
|
|
{
|
|
|
|
KvmInfo *info;
|
|
|
|
|
|
|
|
info = qmp_query_kvm(NULL);
|
|
|
|
monitor_printf(mon, "kvm support: ");
|
|
|
|
if (info->present) {
|
|
|
|
monitor_printf(mon, "%s\n", info->enabled ? "enabled" : "disabled");
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "not compiled\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_KvmInfo(info);
|
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_status(Monitor *mon, const QDict *qdict)
|
2011-09-12 22:54:20 +02:00
|
|
|
{
|
|
|
|
StatusInfo *info;
|
|
|
|
|
|
|
|
info = qmp_query_status(NULL);
|
|
|
|
|
|
|
|
monitor_printf(mon, "VM status: %s%s",
|
|
|
|
info->running ? "running" : "paused",
|
|
|
|
info->singlestep ? " (single step mode)" : "");
|
|
|
|
|
|
|
|
if (!info->running && info->status != RUN_STATE_PAUSED) {
|
2017-08-24 10:46:08 +02:00
|
|
|
monitor_printf(mon, " (%s)", RunState_str(info->status));
|
2011-09-12 22:54:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
|
|
|
|
qapi_free_StatusInfo(info);
|
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_uuid(Monitor *mon, const QDict *qdict)
|
2011-09-13 22:16:25 +02:00
|
|
|
{
|
|
|
|
UuidInfo *info;
|
|
|
|
|
|
|
|
info = qmp_query_uuid(NULL);
|
|
|
|
monitor_printf(mon, "%s\n", info->UUID);
|
|
|
|
qapi_free_UuidInfo(info);
|
|
|
|
}
|
2011-09-14 21:05:49 +02:00
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_chardev(Monitor *mon, const QDict *qdict)
|
2011-09-14 21:05:49 +02:00
|
|
|
{
|
|
|
|
ChardevInfoList *char_info, *info;
|
|
|
|
|
|
|
|
char_info = qmp_query_chardev(NULL);
|
|
|
|
for (info = char_info; info; info = info->next) {
|
|
|
|
monitor_printf(mon, "%s: filename=%s\n", info->value->label,
|
|
|
|
info->value->filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_ChardevInfoList(char_info);
|
|
|
|
}
|
2011-09-15 19:20:28 +02:00
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_mice(Monitor *mon, const QDict *qdict)
|
2011-09-21 20:29:55 +02:00
|
|
|
{
|
|
|
|
MouseInfoList *mice_list, *mouse;
|
|
|
|
|
|
|
|
mice_list = qmp_query_mice(NULL);
|
|
|
|
if (!mice_list) {
|
|
|
|
monitor_printf(mon, "No mouse devices connected\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (mouse = mice_list; mouse; mouse = mouse->next) {
|
|
|
|
monitor_printf(mon, "%c Mouse #%" PRId64 ": %s%s\n",
|
|
|
|
mouse->value->current ? '*' : ' ',
|
|
|
|
mouse->value->index, mouse->value->name,
|
|
|
|
mouse->value->absolute ? " (absolute)" : "");
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_MouseInfoList(mice_list);
|
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_migrate(Monitor *mon, const QDict *qdict)
|
2011-09-13 22:37:16 +02:00
|
|
|
{
|
|
|
|
MigrationInfo *info;
|
2012-08-06 20:42:47 +02:00
|
|
|
MigrationCapabilityStatusList *caps, *cap;
|
2011-09-13 22:37:16 +02:00
|
|
|
|
|
|
|
info = qmp_query_migrate(NULL);
|
2012-08-06 20:42:47 +02:00
|
|
|
caps = qmp_query_migrate_capabilities(NULL);
|
|
|
|
|
2017-06-27 06:10:19 +02:00
|
|
|
migration_global_dump(mon);
|
|
|
|
|
2012-08-06 20:42:47 +02:00
|
|
|
/* do not display parameters during setup */
|
|
|
|
if (info->has_status && caps) {
|
|
|
|
monitor_printf(mon, "capabilities: ");
|
|
|
|
for (cap = caps; cap; cap = cap->next) {
|
|
|
|
monitor_printf(mon, "%s: %s ",
|
2017-08-24 10:46:08 +02:00
|
|
|
MigrationCapability_str(cap->value->capability),
|
2012-08-06 20:42:47 +02:00
|
|
|
cap->value->state ? "on" : "off");
|
|
|
|
}
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
}
|
2011-09-13 22:37:16 +02:00
|
|
|
|
|
|
|
if (info->has_status) {
|
migration: add reporting of errors for outgoing migration
Currently if an application initiates an outgoing migration,
it may or may not, get an error reported back on failure. If
the error occurs synchronously to the 'migrate' command
execution, the client app will see the error message. This
is the case for DNS lookup failures. If the error occurs
asynchronously to the monitor command though, the error
will be thrown away and the client left guessing about
what went wrong. This is the case for failure to connect
to the TCP server (eg due to wrong port, or firewall
rules, or other similar errors).
In the future we'll be adding more scope for errors to
happen asynchronously with the TLS protocol handshake.
TLS errors are hard to diagnose even when they are well
reported, so discarding errors entirely will make it
impossible to debug TLS connection problems.
Management apps which do migration are already using
'query-migrate' / 'info migrate' to check up on progress
of background migration operations and to see their end
status. This is a fine place to also include the error
message when things go wrong.
This patch thus adds an 'error-desc' field to the
MigrationInfo struct, which will be populated when
the 'status' is set to 'failed':
(qemu) migrate -d tcp:localhost:9001
(qemu) info migrate
capabilities: xbzrle: off rdma-pin-all: off auto-converge: off zero-blocks: off compress: off events: off x-postcopy-ram: off
Migration status: failed (Error connecting to socket: Connection refused)
total time: 0 milliseconds
In the HMP, when doing non-detached migration, it is
also possible to display this error message directly
to the app.
(qemu) migrate tcp:localhost:9001
Error connecting to socket: Connection refused
Or with QMP
{
"execute": "query-migrate",
"arguments": {}
}
{
"return": {
"status": "failed",
"error-desc": "address resolution failed for myhost:9000: No address associated with hostname"
}
}
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Message-Id: <1461751518-12128-11-git-send-email-berrange@redhat.com>
Signed-off-by: Amit Shah <amit.shah@redhat.com>
2016-04-27 12:05:00 +02:00
|
|
|
monitor_printf(mon, "Migration status: %s",
|
2017-08-24 10:46:08 +02:00
|
|
|
MigrationStatus_str(info->status));
|
migration: add reporting of errors for outgoing migration
Currently if an application initiates an outgoing migration,
it may or may not, get an error reported back on failure. If
the error occurs synchronously to the 'migrate' command
execution, the client app will see the error message. This
is the case for DNS lookup failures. If the error occurs
asynchronously to the monitor command though, the error
will be thrown away and the client left guessing about
what went wrong. This is the case for failure to connect
to the TCP server (eg due to wrong port, or firewall
rules, or other similar errors).
In the future we'll be adding more scope for errors to
happen asynchronously with the TLS protocol handshake.
TLS errors are hard to diagnose even when they are well
reported, so discarding errors entirely will make it
impossible to debug TLS connection problems.
Management apps which do migration are already using
'query-migrate' / 'info migrate' to check up on progress
of background migration operations and to see their end
status. This is a fine place to also include the error
message when things go wrong.
This patch thus adds an 'error-desc' field to the
MigrationInfo struct, which will be populated when
the 'status' is set to 'failed':
(qemu) migrate -d tcp:localhost:9001
(qemu) info migrate
capabilities: xbzrle: off rdma-pin-all: off auto-converge: off zero-blocks: off compress: off events: off x-postcopy-ram: off
Migration status: failed (Error connecting to socket: Connection refused)
total time: 0 milliseconds
In the HMP, when doing non-detached migration, it is
also possible to display this error message directly
to the app.
(qemu) migrate tcp:localhost:9001
Error connecting to socket: Connection refused
Or with QMP
{
"execute": "query-migrate",
"arguments": {}
}
{
"return": {
"status": "failed",
"error-desc": "address resolution failed for myhost:9000: No address associated with hostname"
}
}
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Message-Id: <1461751518-12128-11-git-send-email-berrange@redhat.com>
Signed-off-by: Amit Shah <amit.shah@redhat.com>
2016-04-27 12:05:00 +02:00
|
|
|
if (info->status == MIGRATION_STATUS_FAILED &&
|
|
|
|
info->has_error_desc) {
|
|
|
|
monitor_printf(mon, " (%s)\n", info->error_desc);
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
}
|
|
|
|
|
2012-08-18 13:17:10 +02:00
|
|
|
monitor_printf(mon, "total time: %" PRIu64 " milliseconds\n",
|
|
|
|
info->total_time);
|
2012-08-13 09:53:12 +02:00
|
|
|
if (info->has_expected_downtime) {
|
|
|
|
monitor_printf(mon, "expected downtime: %" PRIu64 " milliseconds\n",
|
|
|
|
info->expected_downtime);
|
|
|
|
}
|
2012-08-13 09:35:16 +02:00
|
|
|
if (info->has_downtime) {
|
|
|
|
monitor_printf(mon, "downtime: %" PRIu64 " milliseconds\n",
|
|
|
|
info->downtime);
|
|
|
|
}
|
2013-07-22 16:01:58 +02:00
|
|
|
if (info->has_setup_time) {
|
|
|
|
monitor_printf(mon, "setup: %" PRIu64 " milliseconds\n",
|
|
|
|
info->setup_time);
|
|
|
|
}
|
2011-09-13 22:37:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (info->has_ram) {
|
|
|
|
monitor_printf(mon, "transferred ram: %" PRIu64 " kbytes\n",
|
|
|
|
info->ram->transferred >> 10);
|
2013-06-26 03:35:30 +02:00
|
|
|
monitor_printf(mon, "throughput: %0.2f mbps\n",
|
|
|
|
info->ram->mbps);
|
2011-09-13 22:37:16 +02:00
|
|
|
monitor_printf(mon, "remaining ram: %" PRIu64 " kbytes\n",
|
|
|
|
info->ram->remaining >> 10);
|
|
|
|
monitor_printf(mon, "total ram: %" PRIu64 " kbytes\n",
|
|
|
|
info->ram->total >> 10);
|
2012-08-06 20:42:56 +02:00
|
|
|
monitor_printf(mon, "duplicate: %" PRIu64 " pages\n",
|
|
|
|
info->ram->duplicate);
|
2013-03-26 10:58:37 +01:00
|
|
|
monitor_printf(mon, "skipped: %" PRIu64 " pages\n",
|
|
|
|
info->ram->skipped);
|
2012-08-06 20:42:56 +02:00
|
|
|
monitor_printf(mon, "normal: %" PRIu64 " pages\n",
|
|
|
|
info->ram->normal);
|
|
|
|
monitor_printf(mon, "normal bytes: %" PRIu64 " kbytes\n",
|
|
|
|
info->ram->normal_bytes >> 10);
|
2014-04-04 11:57:55 +02:00
|
|
|
monitor_printf(mon, "dirty sync count: %" PRIu64 "\n",
|
|
|
|
info->ram->dirty_sync_count);
|
2017-03-21 03:22:43 +01:00
|
|
|
monitor_printf(mon, "page size: %" PRIu64 " kbytes\n",
|
|
|
|
info->ram->page_size >> 10);
|
|
|
|
|
2012-08-13 12:31:25 +02:00
|
|
|
if (info->ram->dirty_pages_rate) {
|
|
|
|
monitor_printf(mon, "dirty pages rate: %" PRIu64 " pages\n",
|
|
|
|
info->ram->dirty_pages_rate);
|
|
|
|
}
|
2016-06-13 13:16:42 +02:00
|
|
|
if (info->ram->postcopy_requests) {
|
|
|
|
monitor_printf(mon, "postcopy request count: %" PRIu64 "\n",
|
|
|
|
info->ram->postcopy_requests);
|
|
|
|
}
|
2011-09-13 22:37:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (info->has_disk) {
|
|
|
|
monitor_printf(mon, "transferred disk: %" PRIu64 " kbytes\n",
|
|
|
|
info->disk->transferred >> 10);
|
|
|
|
monitor_printf(mon, "remaining disk: %" PRIu64 " kbytes\n",
|
|
|
|
info->disk->remaining >> 10);
|
|
|
|
monitor_printf(mon, "total disk: %" PRIu64 " kbytes\n",
|
|
|
|
info->disk->total >> 10);
|
|
|
|
}
|
|
|
|
|
2012-08-06 20:42:57 +02:00
|
|
|
if (info->has_xbzrle_cache) {
|
|
|
|
monitor_printf(mon, "cache size: %" PRIu64 " bytes\n",
|
|
|
|
info->xbzrle_cache->cache_size);
|
|
|
|
monitor_printf(mon, "xbzrle transferred: %" PRIu64 " kbytes\n",
|
|
|
|
info->xbzrle_cache->bytes >> 10);
|
|
|
|
monitor_printf(mon, "xbzrle pages: %" PRIu64 " pages\n",
|
|
|
|
info->xbzrle_cache->pages);
|
|
|
|
monitor_printf(mon, "xbzrle cache miss: %" PRIu64 "\n",
|
|
|
|
info->xbzrle_cache->cache_miss);
|
2014-04-04 11:57:56 +02:00
|
|
|
monitor_printf(mon, "xbzrle cache miss rate: %0.2f\n",
|
|
|
|
info->xbzrle_cache->cache_miss_rate);
|
2012-08-06 20:42:57 +02:00
|
|
|
monitor_printf(mon, "xbzrle overflow : %" PRIu64 "\n",
|
|
|
|
info->xbzrle_cache->overflow);
|
|
|
|
}
|
|
|
|
|
2016-04-21 20:07:18 +02:00
|
|
|
if (info->has_cpu_throttle_percentage) {
|
2015-09-08 19:12:36 +02:00
|
|
|
monitor_printf(mon, "cpu throttle percentage: %" PRIu64 "\n",
|
2016-04-21 20:07:18 +02:00
|
|
|
info->cpu_throttle_percentage);
|
2015-09-08 19:12:36 +02:00
|
|
|
}
|
|
|
|
|
2018-03-22 19:17:27 +01:00
|
|
|
if (info->has_postcopy_blocktime) {
|
|
|
|
monitor_printf(mon, "postcopy blocktime: %u\n",
|
|
|
|
info->postcopy_blocktime);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info->has_postcopy_vcpu_blocktime) {
|
|
|
|
Visitor *v;
|
|
|
|
char *str;
|
|
|
|
v = string_output_visitor_new(false, &str);
|
|
|
|
visit_type_uint32List(v, NULL, &info->postcopy_vcpu_blocktime, NULL);
|
|
|
|
visit_complete(v, &str);
|
|
|
|
monitor_printf(mon, "postcopy vcpu blocktime: %s\n", str);
|
|
|
|
g_free(str);
|
|
|
|
visit_free(v);
|
|
|
|
}
|
2011-09-13 22:37:16 +02:00
|
|
|
qapi_free_MigrationInfo(info);
|
2012-08-06 20:42:47 +02:00
|
|
|
qapi_free_MigrationCapabilityStatusList(caps);
|
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict)
|
2012-08-06 20:42:47 +02:00
|
|
|
{
|
|
|
|
MigrationCapabilityStatusList *caps, *cap;
|
|
|
|
|
|
|
|
caps = qmp_query_migrate_capabilities(NULL);
|
|
|
|
|
|
|
|
if (caps) {
|
|
|
|
for (cap = caps; cap; cap = cap->next) {
|
2017-04-01 10:18:44 +02:00
|
|
|
monitor_printf(mon, "%s: %s\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
MigrationCapability_str(cap->value->capability),
|
2012-08-06 20:42:47 +02:00
|
|
|
cap->value->state ? "on" : "off");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_MigrationCapabilityStatusList(caps);
|
2011-09-13 22:37:16 +02:00
|
|
|
}
|
|
|
|
|
2015-03-23 09:32:29 +01:00
|
|
|
void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
MigrationParameters *params;
|
|
|
|
|
|
|
|
params = qmp_query_migrate_parameters(NULL);
|
|
|
|
|
|
|
|
if (params) {
|
2016-09-09 05:14:15 +02:00
|
|
|
assert(params->has_compress_level);
|
2017-12-01 13:08:38 +01:00
|
|
|
monitor_printf(mon, "%s: %u\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_COMPRESS_LEVEL),
|
2015-03-23 09:32:29 +01:00
|
|
|
params->compress_level);
|
2016-09-09 05:14:15 +02:00
|
|
|
assert(params->has_compress_threads);
|
2017-12-01 13:08:38 +01:00
|
|
|
monitor_printf(mon, "%s: %u\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_COMPRESS_THREADS),
|
2015-03-23 09:32:29 +01:00
|
|
|
params->compress_threads);
|
2016-09-09 05:14:15 +02:00
|
|
|
assert(params->has_decompress_threads);
|
2017-12-01 13:08:38 +01:00
|
|
|
monitor_printf(mon, "%s: %u\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_DECOMPRESS_THREADS),
|
2015-03-23 09:32:29 +01:00
|
|
|
params->decompress_threads);
|
2016-09-09 05:14:15 +02:00
|
|
|
assert(params->has_cpu_throttle_initial);
|
2017-12-01 13:08:38 +01:00
|
|
|
monitor_printf(mon, "%s: %u\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL),
|
2016-04-21 20:07:18 +02:00
|
|
|
params->cpu_throttle_initial);
|
2016-09-09 05:14:15 +02:00
|
|
|
assert(params->has_cpu_throttle_increment);
|
2017-12-01 13:08:38 +01:00
|
|
|
monitor_printf(mon, "%s: %u\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT),
|
2016-04-21 20:07:18 +02:00
|
|
|
params->cpu_throttle_increment);
|
2017-07-18 12:04:54 +02:00
|
|
|
assert(params->has_tls_creds);
|
2017-04-01 10:18:45 +02:00
|
|
|
monitor_printf(mon, "%s: '%s'\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_TLS_CREDS),
|
2017-07-18 12:04:54 +02:00
|
|
|
params->tls_creds);
|
|
|
|
assert(params->has_tls_hostname);
|
2017-04-01 10:18:45 +02:00
|
|
|
monitor_printf(mon, "%s: '%s'\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_TLS_HOSTNAME),
|
2017-07-18 12:04:54 +02:00
|
|
|
params->tls_hostname);
|
2016-09-15 18:20:28 +02:00
|
|
|
assert(params->has_max_bandwidth);
|
2017-12-01 13:08:38 +01:00
|
|
|
monitor_printf(mon, "%s: %" PRIu64 " bytes/second\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_MAX_BANDWIDTH),
|
2016-09-15 18:20:28 +02:00
|
|
|
params->max_bandwidth);
|
|
|
|
assert(params->has_downtime_limit);
|
2017-12-01 13:08:38 +01:00
|
|
|
monitor_printf(mon, "%s: %" PRIu64 " milliseconds\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_DOWNTIME_LIMIT),
|
2016-09-15 18:20:28 +02:00
|
|
|
params->downtime_limit);
|
2016-11-02 08:42:09 +01:00
|
|
|
assert(params->has_x_checkpoint_delay);
|
2017-12-01 13:08:38 +01:00
|
|
|
monitor_printf(mon, "%s: %u\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_X_CHECKPOINT_DELAY),
|
2016-10-27 08:43:01 +02:00
|
|
|
params->x_checkpoint_delay);
|
2017-04-05 18:32:37 +02:00
|
|
|
assert(params->has_block_incremental);
|
|
|
|
monitor_printf(mon, "%s: %s\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_BLOCK_INCREMENTAL),
|
|
|
|
params->block_incremental ? "on" : "off");
|
2017-12-01 13:08:38 +01:00
|
|
|
monitor_printf(mon, "%s: %u\n",
|
2016-01-15 08:56:17 +01:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_X_MULTIFD_CHANNELS),
|
|
|
|
params->x_multifd_channels);
|
2017-12-01 13:08:38 +01:00
|
|
|
monitor_printf(mon, "%s: %u\n",
|
2017-04-27 10:48:25 +02:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_X_MULTIFD_PAGE_COUNT),
|
|
|
|
params->x_multifd_page_count);
|
2017-12-01 13:08:38 +01:00
|
|
|
monitor_printf(mon, "%s: %" PRIu64 "\n",
|
2017-10-05 21:30:10 +02:00
|
|
|
MigrationParameter_str(MIGRATION_PARAMETER_XBZRLE_CACHE_SIZE),
|
|
|
|
params->xbzrle_cache_size);
|
2015-03-23 09:32:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_MigrationParameters(params);
|
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_migrate_cache_size(Monitor *mon, const QDict *qdict)
|
2012-08-06 20:42:54 +02:00
|
|
|
{
|
|
|
|
monitor_printf(mon, "xbzrel cache size: %" PRId64 " kbytes\n",
|
|
|
|
qmp_query_migrate_cache_size(NULL) >> 10);
|
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_cpus(Monitor *mon, const QDict *qdict)
|
2011-09-21 21:38:35 +02:00
|
|
|
{
|
2018-02-16 17:08:41 +01:00
|
|
|
CpuInfoFastList *cpu_list, *cpu;
|
2011-09-21 21:38:35 +02:00
|
|
|
|
2018-02-16 17:08:41 +01:00
|
|
|
cpu_list = qmp_query_cpus_fast(NULL);
|
2011-09-21 21:38:35 +02:00
|
|
|
|
|
|
|
for (cpu = cpu_list; cpu; cpu = cpu->next) {
|
|
|
|
int active = ' ';
|
|
|
|
|
2018-02-16 17:08:41 +01:00
|
|
|
if (cpu->value->cpu_index == monitor_get_cpu_index()) {
|
2011-09-21 21:38:35 +02:00
|
|
|
active = '*';
|
|
|
|
}
|
|
|
|
|
2018-02-16 17:08:41 +01:00
|
|
|
monitor_printf(mon, "%c CPU #%" PRId64 ":", active,
|
|
|
|
cpu->value->cpu_index);
|
2018-03-27 14:38:00 +02:00
|
|
|
monitor_printf(mon, " thread_id=%" PRId64 "\n", cpu->value->thread_id);
|
2011-09-21 21:38:35 +02:00
|
|
|
}
|
|
|
|
|
2018-02-16 17:08:41 +01:00
|
|
|
qapi_free_CpuInfoFastList(cpu_list);
|
2011-09-21 21:38:35 +02:00
|
|
|
}
|
|
|
|
|
2014-09-15 12:06:39 +02:00
|
|
|
static void print_block_info(Monitor *mon, BlockInfo *info,
|
|
|
|
BlockDeviceInfo *inserted, bool verbose)
|
2011-09-21 22:16:47 +02:00
|
|
|
{
|
2013-06-06 06:28:00 +02:00
|
|
|
ImageInfo *image_info;
|
2011-09-21 22:16:47 +02:00
|
|
|
|
2014-09-15 12:12:52 +02:00
|
|
|
assert(!info || !info->has_inserted || info->inserted == inserted);
|
|
|
|
|
2017-07-11 14:00:57 +02:00
|
|
|
if (info && *info->device) {
|
2014-09-15 12:12:52 +02:00
|
|
|
monitor_printf(mon, "%s", info->device);
|
|
|
|
if (inserted && inserted->has_node_name) {
|
|
|
|
monitor_printf(mon, " (%s)", inserted->node_name);
|
|
|
|
}
|
|
|
|
} else {
|
2017-07-11 14:00:57 +02:00
|
|
|
assert(info || inserted);
|
2014-09-15 12:12:52 +02:00
|
|
|
monitor_printf(mon, "%s",
|
2017-07-11 14:00:57 +02:00
|
|
|
inserted && inserted->has_node_name ? inserted->node_name
|
|
|
|
: info && info->has_qdev ? info->qdev
|
2014-09-15 12:12:52 +02:00
|
|
|
: "<anonymous>");
|
|
|
|
}
|
|
|
|
|
2014-09-15 12:06:39 +02:00
|
|
|
if (inserted) {
|
|
|
|
monitor_printf(mon, ": %s (%s%s%s)\n",
|
|
|
|
inserted->file,
|
|
|
|
inserted->drv,
|
|
|
|
inserted->ro ? ", read-only" : "",
|
|
|
|
inserted->encrypted ? ", encrypted" : "");
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, ": [not inserted]\n");
|
|
|
|
}
|
2011-09-21 22:16:47 +02:00
|
|
|
|
2014-09-15 12:12:52 +02:00
|
|
|
if (info) {
|
2017-07-11 13:27:38 +02:00
|
|
|
if (info->has_qdev) {
|
|
|
|
monitor_printf(mon, " Attached to: %s\n", info->qdev);
|
|
|
|
}
|
2014-09-15 12:12:52 +02:00
|
|
|
if (info->has_io_status && info->io_status != BLOCK_DEVICE_IO_STATUS_OK) {
|
|
|
|
monitor_printf(mon, " I/O status: %s\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
BlockDeviceIoStatus_str(info->io_status));
|
2014-09-15 12:12:52 +02:00
|
|
|
}
|
2011-09-21 22:16:47 +02:00
|
|
|
|
2014-09-15 12:12:52 +02:00
|
|
|
if (info->removable) {
|
|
|
|
monitor_printf(mon, " Removable device: %slocked, tray %s\n",
|
|
|
|
info->locked ? "" : "not ",
|
|
|
|
info->tray_open ? "open" : "closed");
|
|
|
|
}
|
2014-09-15 12:06:39 +02:00
|
|
|
}
|
2013-06-19 16:10:55 +02:00
|
|
|
|
2011-09-21 22:16:47 +02:00
|
|
|
|
2014-09-15 12:06:39 +02:00
|
|
|
if (!inserted) {
|
|
|
|
return;
|
|
|
|
}
|
2011-09-21 22:16:47 +02:00
|
|
|
|
2014-09-15 12:06:39 +02:00
|
|
|
monitor_printf(mon, " Cache mode: %s%s%s\n",
|
|
|
|
inserted->cache->writeback ? "writeback" : "writethrough",
|
|
|
|
inserted->cache->direct ? ", direct" : "",
|
|
|
|
inserted->cache->no_flush ? ", ignore flushes" : "");
|
|
|
|
|
|
|
|
if (inserted->has_backing_file) {
|
|
|
|
monitor_printf(mon,
|
|
|
|
" Backing file: %s "
|
|
|
|
"(chain depth: %" PRId64 ")\n",
|
|
|
|
inserted->backing_file,
|
|
|
|
inserted->backing_file_depth);
|
|
|
|
}
|
2011-11-08 06:00:31 +01:00
|
|
|
|
2014-09-15 12:06:39 +02:00
|
|
|
if (inserted->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF) {
|
|
|
|
monitor_printf(mon, " Detect zeroes: %s\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
BlockdevDetectZeroesOptions_str(inserted->detect_zeroes));
|
2014-09-15 12:06:39 +02:00
|
|
|
}
|
2013-06-19 16:10:55 +02:00
|
|
|
|
2014-09-15 12:06:39 +02:00
|
|
|
if (inserted->bps || inserted->bps_rd || inserted->bps_wr ||
|
|
|
|
inserted->iops || inserted->iops_rd || inserted->iops_wr)
|
|
|
|
{
|
|
|
|
monitor_printf(mon, " I/O throttling: bps=%" PRId64
|
|
|
|
" bps_rd=%" PRId64 " bps_wr=%" PRId64
|
|
|
|
" bps_max=%" PRId64
|
|
|
|
" bps_rd_max=%" PRId64
|
|
|
|
" bps_wr_max=%" PRId64
|
|
|
|
" iops=%" PRId64 " iops_rd=%" PRId64
|
|
|
|
" iops_wr=%" PRId64
|
|
|
|
" iops_max=%" PRId64
|
|
|
|
" iops_rd_max=%" PRId64
|
|
|
|
" iops_wr_max=%" PRId64
|
2015-06-08 18:17:46 +02:00
|
|
|
" iops_size=%" PRId64
|
|
|
|
" group=%s\n",
|
2014-09-15 12:06:39 +02:00
|
|
|
inserted->bps,
|
|
|
|
inserted->bps_rd,
|
|
|
|
inserted->bps_wr,
|
|
|
|
inserted->bps_max,
|
|
|
|
inserted->bps_rd_max,
|
|
|
|
inserted->bps_wr_max,
|
|
|
|
inserted->iops,
|
|
|
|
inserted->iops_rd,
|
|
|
|
inserted->iops_wr,
|
|
|
|
inserted->iops_max,
|
|
|
|
inserted->iops_rd_max,
|
|
|
|
inserted->iops_wr_max,
|
2015-06-08 18:17:46 +02:00
|
|
|
inserted->iops_size,
|
|
|
|
inserted->group);
|
2014-09-15 12:06:39 +02:00
|
|
|
}
|
2013-06-19 16:10:55 +02:00
|
|
|
|
2015-04-22 12:15:10 +02:00
|
|
|
if (verbose) {
|
2014-09-15 12:06:39 +02:00
|
|
|
monitor_printf(mon, "\nImages:\n");
|
|
|
|
image_info = inserted->image;
|
|
|
|
while (1) {
|
|
|
|
bdrv_image_info_dump((fprintf_function)monitor_printf,
|
|
|
|
mon, image_info);
|
|
|
|
if (image_info->has_backing_image) {
|
|
|
|
image_info = image_info->backing_image;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-05-22 13:28:45 +02:00
|
|
|
|
2014-09-15 12:06:39 +02:00
|
|
|
void hmp_info_block(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
BlockInfoList *block_list, *info;
|
2014-09-15 12:19:14 +02:00
|
|
|
BlockDeviceInfoList *blockdev_list, *blockdev;
|
2014-09-15 12:06:39 +02:00
|
|
|
const char *device = qdict_get_try_str(qdict, "device");
|
2015-05-16 00:25:00 +02:00
|
|
|
bool verbose = qdict_get_try_bool(qdict, "verbose", false);
|
|
|
|
bool nodes = qdict_get_try_bool(qdict, "nodes", false);
|
2014-09-15 12:19:14 +02:00
|
|
|
bool printed = false;
|
2014-05-22 13:28:45 +02:00
|
|
|
|
2014-09-15 12:19:14 +02:00
|
|
|
/* Print BlockBackend information */
|
|
|
|
if (!nodes) {
|
2015-02-08 15:40:48 +01:00
|
|
|
block_list = qmp_query_block(NULL);
|
2014-09-15 12:19:14 +02:00
|
|
|
} else {
|
|
|
|
block_list = NULL;
|
|
|
|
}
|
2013-06-19 16:10:55 +02:00
|
|
|
|
2014-09-15 12:06:39 +02:00
|
|
|
for (info = block_list; info; info = info->next) {
|
|
|
|
if (device && strcmp(device, info->value->device)) {
|
|
|
|
continue;
|
2014-05-18 00:58:19 +02:00
|
|
|
}
|
|
|
|
|
2014-09-15 12:06:39 +02:00
|
|
|
if (info != block_list) {
|
|
|
|
monitor_printf(mon, "\n");
|
2013-06-19 16:10:55 +02:00
|
|
|
}
|
2013-06-06 06:28:00 +02:00
|
|
|
|
2014-09-15 12:06:39 +02:00
|
|
|
print_block_info(mon, info->value, info->value->has_inserted
|
|
|
|
? info->value->inserted : NULL,
|
|
|
|
verbose);
|
2014-09-15 12:19:14 +02:00
|
|
|
printed = true;
|
2011-09-21 22:16:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_BlockInfoList(block_list);
|
2014-09-15 12:19:14 +02:00
|
|
|
|
|
|
|
if ((!device && !nodes) || printed) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Print node information */
|
|
|
|
blockdev_list = qmp_query_named_block_nodes(NULL);
|
|
|
|
for (blockdev = blockdev_list; blockdev; blockdev = blockdev->next) {
|
|
|
|
assert(blockdev->value->has_node_name);
|
|
|
|
if (device && strcmp(device, blockdev->value->node_name)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (blockdev != blockdev_list) {
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
print_block_info(mon, NULL, blockdev->value, verbose);
|
|
|
|
}
|
|
|
|
qapi_free_BlockDeviceInfoList(blockdev_list);
|
2011-09-21 22:16:47 +02:00
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_blockstats(Monitor *mon, const QDict *qdict)
|
2011-09-22 20:56:36 +02:00
|
|
|
{
|
|
|
|
BlockStatsList *stats_list, *stats;
|
|
|
|
|
2014-10-31 04:32:57 +01:00
|
|
|
stats_list = qmp_query_blockstats(false, false, NULL);
|
2011-09-22 20:56:36 +02:00
|
|
|
|
|
|
|
for (stats = stats_list; stats; stats = stats->next) {
|
|
|
|
if (!stats->value->has_device) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "%s:", stats->value->device);
|
|
|
|
monitor_printf(mon, " rd_bytes=%" PRId64
|
|
|
|
" wr_bytes=%" PRId64
|
|
|
|
" rd_operations=%" PRId64
|
|
|
|
" wr_operations=%" PRId64
|
|
|
|
" flush_operations=%" PRId64
|
|
|
|
" wr_total_time_ns=%" PRId64
|
|
|
|
" rd_total_time_ns=%" PRId64
|
|
|
|
" flush_total_time_ns=%" PRId64
|
2015-02-02 14:52:18 +01:00
|
|
|
" rd_merged=%" PRId64
|
|
|
|
" wr_merged=%" PRId64
|
2015-10-28 16:33:02 +01:00
|
|
|
" idle_time_ns=%" PRId64
|
2011-09-22 20:56:36 +02:00
|
|
|
"\n",
|
|
|
|
stats->value->stats->rd_bytes,
|
|
|
|
stats->value->stats->wr_bytes,
|
|
|
|
stats->value->stats->rd_operations,
|
|
|
|
stats->value->stats->wr_operations,
|
|
|
|
stats->value->stats->flush_operations,
|
|
|
|
stats->value->stats->wr_total_time_ns,
|
|
|
|
stats->value->stats->rd_total_time_ns,
|
2015-02-02 14:52:18 +01:00
|
|
|
stats->value->stats->flush_total_time_ns,
|
|
|
|
stats->value->stats->rd_merged,
|
2015-10-28 16:33:02 +01:00
|
|
|
stats->value->stats->wr_merged,
|
|
|
|
stats->value->stats->idle_time_ns);
|
2011-09-22 20:56:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_BlockStatsList(stats_list);
|
|
|
|
}
|
|
|
|
|
2017-07-11 17:44:14 +02:00
|
|
|
/* Helper for hmp_info_vnc_clients, _servers */
|
|
|
|
static void hmp_info_VncBasicInfo(Monitor *mon, VncBasicInfo *info,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
monitor_printf(mon, " %s: %s:%s (%s%s)\n",
|
|
|
|
name,
|
|
|
|
info->host,
|
|
|
|
info->service,
|
2017-08-24 10:46:08 +02:00
|
|
|
NetworkAddressFamily_str(info->family),
|
2017-07-11 17:44:14 +02:00
|
|
|
info->websocket ? " (Websocket)" : "");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Helper displaying and auth and crypt info */
|
|
|
|
static void hmp_info_vnc_authcrypt(Monitor *mon, const char *indent,
|
|
|
|
VncPrimaryAuth auth,
|
|
|
|
VncVencryptSubAuth *vencrypt)
|
|
|
|
{
|
|
|
|
monitor_printf(mon, "%sAuth: %s (Sub: %s)\n", indent,
|
2017-08-24 10:46:08 +02:00
|
|
|
VncPrimaryAuth_str(auth),
|
|
|
|
vencrypt ? VncVencryptSubAuth_str(*vencrypt) : "none");
|
2017-07-11 17:44:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void hmp_info_vnc_clients(Monitor *mon, VncClientInfoList *client)
|
|
|
|
{
|
|
|
|
while (client) {
|
|
|
|
VncClientInfo *cinfo = client->value;
|
|
|
|
|
|
|
|
hmp_info_VncBasicInfo(mon, qapi_VncClientInfo_base(cinfo), "Client");
|
|
|
|
monitor_printf(mon, " x509_dname: %s\n",
|
|
|
|
cinfo->has_x509_dname ?
|
|
|
|
cinfo->x509_dname : "none");
|
|
|
|
monitor_printf(mon, " sasl_username: %s\n",
|
|
|
|
cinfo->has_sasl_username ?
|
|
|
|
cinfo->sasl_username : "none");
|
|
|
|
|
|
|
|
client = client->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void hmp_info_vnc_servers(Monitor *mon, VncServerInfo2List *server)
|
|
|
|
{
|
|
|
|
while (server) {
|
|
|
|
VncServerInfo2 *sinfo = server->value;
|
|
|
|
hmp_info_VncBasicInfo(mon, qapi_VncServerInfo2_base(sinfo), "Server");
|
|
|
|
hmp_info_vnc_authcrypt(mon, " ", sinfo->auth,
|
|
|
|
sinfo->has_vencrypt ? &sinfo->vencrypt : NULL);
|
|
|
|
server = server->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_vnc(Monitor *mon, const QDict *qdict)
|
2011-10-17 20:41:22 +02:00
|
|
|
{
|
2017-07-11 17:44:14 +02:00
|
|
|
VncInfo2List *info2l;
|
2011-10-17 20:41:22 +02:00
|
|
|
Error *err = NULL;
|
|
|
|
|
2017-07-11 17:44:14 +02:00
|
|
|
info2l = qmp_query_vnc_servers(&err);
|
2011-10-17 20:41:22 +02:00
|
|
|
if (err) {
|
2017-10-19 13:16:33 +02:00
|
|
|
hmp_handle_error(mon, &err);
|
2011-10-17 20:41:22 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-07-11 17:44:14 +02:00
|
|
|
if (!info2l) {
|
|
|
|
monitor_printf(mon, "None\n");
|
|
|
|
return;
|
2011-10-17 20:41:22 +02:00
|
|
|
}
|
|
|
|
|
2017-07-11 17:44:14 +02:00
|
|
|
while (info2l) {
|
|
|
|
VncInfo2 *info = info2l->value;
|
|
|
|
monitor_printf(mon, "%s:\n", info->id);
|
|
|
|
hmp_info_vnc_servers(mon, info->server);
|
|
|
|
hmp_info_vnc_clients(mon, info->clients);
|
|
|
|
if (!info->server) {
|
|
|
|
/* The server entry displays its auth, we only
|
|
|
|
* need to display in the case of 'reverse' connections
|
|
|
|
* where there's no server.
|
|
|
|
*/
|
|
|
|
hmp_info_vnc_authcrypt(mon, " ", info->auth,
|
|
|
|
info->has_vencrypt ? &info->vencrypt : NULL);
|
|
|
|
}
|
|
|
|
if (info->has_display) {
|
|
|
|
monitor_printf(mon, " Display: %s\n", info->display);
|
2011-10-17 20:41:22 +02:00
|
|
|
}
|
2017-07-11 17:44:14 +02:00
|
|
|
info2l = info2l->next;
|
2011-10-17 20:41:22 +02:00
|
|
|
}
|
|
|
|
|
2017-07-11 17:44:14 +02:00
|
|
|
qapi_free_VncInfo2List(info2l);
|
|
|
|
|
2011-10-17 20:41:22 +02:00
|
|
|
}
|
|
|
|
|
2015-01-13 15:46:39 +01:00
|
|
|
#ifdef CONFIG_SPICE
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_spice(Monitor *mon, const QDict *qdict)
|
2011-10-20 21:01:33 +02:00
|
|
|
{
|
|
|
|
SpiceChannelList *chan;
|
|
|
|
SpiceInfo *info;
|
2015-03-01 15:29:18 +01:00
|
|
|
const char *channel_name;
|
|
|
|
const char * const channel_names[] = {
|
|
|
|
[SPICE_CHANNEL_MAIN] = "main",
|
|
|
|
[SPICE_CHANNEL_DISPLAY] = "display",
|
|
|
|
[SPICE_CHANNEL_INPUTS] = "inputs",
|
|
|
|
[SPICE_CHANNEL_CURSOR] = "cursor",
|
|
|
|
[SPICE_CHANNEL_PLAYBACK] = "playback",
|
|
|
|
[SPICE_CHANNEL_RECORD] = "record",
|
|
|
|
[SPICE_CHANNEL_TUNNEL] = "tunnel",
|
|
|
|
[SPICE_CHANNEL_SMARTCARD] = "smartcard",
|
|
|
|
[SPICE_CHANNEL_USBREDIR] = "usbredir",
|
|
|
|
[SPICE_CHANNEL_PORT] = "port",
|
2015-03-03 09:27:28 +01:00
|
|
|
#if 0
|
|
|
|
/* minimum spice-protocol is 0.12.3, webdav was added in 0.12.7,
|
|
|
|
* no easy way to #ifdef (SPICE_CHANNEL_* is a enum). Disable
|
|
|
|
* as quick fix for build failures with older versions. */
|
2015-03-01 15:29:18 +01:00
|
|
|
[SPICE_CHANNEL_WEBDAV] = "webdav",
|
2015-03-03 09:27:28 +01:00
|
|
|
#endif
|
2015-03-01 15:29:18 +01:00
|
|
|
};
|
2011-10-20 21:01:33 +02:00
|
|
|
|
|
|
|
info = qmp_query_spice(NULL);
|
|
|
|
|
|
|
|
if (!info->enabled) {
|
|
|
|
monitor_printf(mon, "Server: disabled\n");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "Server:\n");
|
|
|
|
if (info->has_port) {
|
|
|
|
monitor_printf(mon, " address: %s:%" PRId64 "\n",
|
|
|
|
info->host, info->port);
|
|
|
|
}
|
|
|
|
if (info->has_tls_port) {
|
|
|
|
monitor_printf(mon, " address: %s:%" PRId64 " [tls]\n",
|
|
|
|
info->host, info->tls_port);
|
|
|
|
}
|
2012-08-21 10:51:58 +02:00
|
|
|
monitor_printf(mon, " migrated: %s\n",
|
|
|
|
info->migrated ? "true" : "false");
|
2011-10-20 21:01:33 +02:00
|
|
|
monitor_printf(mon, " auth: %s\n", info->auth);
|
|
|
|
monitor_printf(mon, " compiled: %s\n", info->compiled_version);
|
2012-03-29 23:23:14 +02:00
|
|
|
monitor_printf(mon, " mouse-mode: %s\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
SpiceQueryMouseMode_str(info->mouse_mode));
|
2011-10-20 21:01:33 +02:00
|
|
|
|
|
|
|
if (!info->has_channels || info->channels == NULL) {
|
|
|
|
monitor_printf(mon, "Channels: none\n");
|
|
|
|
} else {
|
|
|
|
for (chan = info->channels; chan; chan = chan->next) {
|
|
|
|
monitor_printf(mon, "Channel:\n");
|
|
|
|
monitor_printf(mon, " address: %s:%s%s\n",
|
qapi: Unbox base members
Rather than storing a base class as a pointer to a box, just
store the fields of that base class in the same order, so that
a child struct can be directly cast to its parent. This gives
less malloc overhead, less pointer dereferencing, and even less
generated code. Compare to the earlier commit 1e6c1616a "qapi:
Generate a nicer struct for flat unions" (although that patch
had fewer places to change, as less of qemu was directly using
qapi structs for flat unions). It also allows us to turn on
automatic type-safe wrappers for upcasting to the base class
of a struct.
Changes to the generated code look like this in qapi-types.h:
| struct SpiceChannel {
|- SpiceBasicInfo *base;
|+ /* Members inherited from SpiceBasicInfo: */
|+ char *host;
|+ char *port;
|+ NetworkAddressFamily family;
|+ /* Own members: */
| int64_t connection_id;
as well as additional upcast functions like qapi_SpiceChannel_base().
Meanwhile, changes to qapi-visit.c look like:
| static void visit_type_SpiceChannel_fields(Visitor *v, SpiceChannel **obj, Error **errp)
| {
| Error *err = NULL;
|
|- visit_type_implicit_SpiceBasicInfo(v, &(*obj)->base, &err);
|+ visit_type_SpiceBasicInfo_fields(v, (SpiceBasicInfo **)obj, &err);
| if (err) {
(the cast is necessary, since our upcast wrappers only deal with a
single pointer, not pointer-to-pointer); plus the wholesale
elimination of some now-unused visit_type_implicit_FOO() functions.
Without boxing, the corner case of one empty struct having
another empty struct as its base type now requires inserting a
dummy member (previously, the 'Base *base' member sufficed).
And now that we no longer consume a 'base' member in the generated
C struct, we can delete the former negative struct-base-clash-base
test.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1445898903-12082-11-git-send-email-eblake@redhat.com>
[Commit message tweaked slightly]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-10-26 23:34:49 +01:00
|
|
|
chan->value->host, chan->value->port,
|
2011-10-20 21:01:33 +02:00
|
|
|
chan->value->tls ? " [tls]" : "");
|
|
|
|
monitor_printf(mon, " session: %" PRId64 "\n",
|
|
|
|
chan->value->connection_id);
|
|
|
|
monitor_printf(mon, " channel: %" PRId64 ":%" PRId64 "\n",
|
|
|
|
chan->value->channel_type, chan->value->channel_id);
|
2015-03-01 15:29:18 +01:00
|
|
|
|
|
|
|
channel_name = "unknown";
|
|
|
|
if (chan->value->channel_type > 0 &&
|
|
|
|
chan->value->channel_type < ARRAY_SIZE(channel_names) &&
|
|
|
|
channel_names[chan->value->channel_type]) {
|
|
|
|
channel_name = channel_names[chan->value->channel_type];
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, " channel name: %s\n", channel_name);
|
2011-10-20 21:01:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
qapi_free_SpiceInfo(info);
|
|
|
|
}
|
2015-01-13 15:46:39 +01:00
|
|
|
#endif
|
2011-10-20 21:01:33 +02:00
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_balloon(Monitor *mon, const QDict *qdict)
|
2011-10-21 15:41:37 +02:00
|
|
|
{
|
|
|
|
BalloonInfo *info;
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
info = qmp_query_balloon(&err);
|
|
|
|
if (err) {
|
2017-10-19 13:16:33 +02:00
|
|
|
hmp_handle_error(mon, &err);
|
2011-10-21 15:41:37 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-12-03 18:56:41 +01:00
|
|
|
monitor_printf(mon, "balloon: actual=%" PRId64 "\n", info->actual >> 20);
|
2011-10-21 15:41:37 +02:00
|
|
|
|
|
|
|
qapi_free_BalloonInfo(info);
|
|
|
|
}
|
|
|
|
|
2011-10-21 18:15:33 +02:00
|
|
|
static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev)
|
|
|
|
{
|
|
|
|
PciMemoryRegionList *region;
|
|
|
|
|
|
|
|
monitor_printf(mon, " Bus %2" PRId64 ", ", dev->bus);
|
|
|
|
monitor_printf(mon, "device %3" PRId64 ", function %" PRId64 ":\n",
|
|
|
|
dev->slot, dev->function);
|
|
|
|
monitor_printf(mon, " ");
|
|
|
|
|
2015-05-04 17:05:32 +02:00
|
|
|
if (dev->class_info->has_desc) {
|
|
|
|
monitor_printf(mon, "%s", dev->class_info->desc);
|
2011-10-21 18:15:33 +02:00
|
|
|
} else {
|
2015-05-04 17:05:32 +02:00
|
|
|
monitor_printf(mon, "Class %04" PRId64, dev->class_info->q_class);
|
2011-10-21 18:15:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, ": PCI device %04" PRIx64 ":%04" PRIx64 "\n",
|
2015-05-04 17:05:32 +02:00
|
|
|
dev->id->vendor, dev->id->device);
|
2011-10-21 18:15:33 +02:00
|
|
|
|
|
|
|
if (dev->has_irq) {
|
|
|
|
monitor_printf(mon, " IRQ %" PRId64 ".\n", dev->irq);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dev->has_pci_bridge) {
|
|
|
|
monitor_printf(mon, " BUS %" PRId64 ".\n",
|
2015-05-04 17:05:32 +02:00
|
|
|
dev->pci_bridge->bus->number);
|
2011-10-21 18:15:33 +02:00
|
|
|
monitor_printf(mon, " secondary bus %" PRId64 ".\n",
|
2015-05-04 17:05:32 +02:00
|
|
|
dev->pci_bridge->bus->secondary);
|
2011-10-21 18:15:33 +02:00
|
|
|
monitor_printf(mon, " subordinate bus %" PRId64 ".\n",
|
2015-05-04 17:05:32 +02:00
|
|
|
dev->pci_bridge->bus->subordinate);
|
2011-10-21 18:15:33 +02:00
|
|
|
|
|
|
|
monitor_printf(mon, " IO range [0x%04"PRIx64", 0x%04"PRIx64"]\n",
|
2015-05-04 17:05:32 +02:00
|
|
|
dev->pci_bridge->bus->io_range->base,
|
|
|
|
dev->pci_bridge->bus->io_range->limit);
|
2011-10-21 18:15:33 +02:00
|
|
|
|
|
|
|
monitor_printf(mon,
|
|
|
|
" memory range [0x%08"PRIx64", 0x%08"PRIx64"]\n",
|
2015-05-04 17:05:32 +02:00
|
|
|
dev->pci_bridge->bus->memory_range->base,
|
|
|
|
dev->pci_bridge->bus->memory_range->limit);
|
2011-10-21 18:15:33 +02:00
|
|
|
|
|
|
|
monitor_printf(mon, " prefetchable memory range "
|
|
|
|
"[0x%08"PRIx64", 0x%08"PRIx64"]\n",
|
2015-05-04 17:05:32 +02:00
|
|
|
dev->pci_bridge->bus->prefetchable_range->base,
|
|
|
|
dev->pci_bridge->bus->prefetchable_range->limit);
|
2011-10-21 18:15:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for (region = dev->regions; region; region = region->next) {
|
|
|
|
uint64_t addr, size;
|
|
|
|
|
|
|
|
addr = region->value->address;
|
|
|
|
size = region->value->size;
|
|
|
|
|
|
|
|
monitor_printf(mon, " BAR%" PRId64 ": ", region->value->bar);
|
|
|
|
|
|
|
|
if (!strcmp(region->value->type, "io")) {
|
|
|
|
monitor_printf(mon, "I/O at 0x%04" PRIx64
|
|
|
|
" [0x%04" PRIx64 "].\n",
|
|
|
|
addr, addr + size - 1);
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "%d bit%s memory at 0x%08" PRIx64
|
|
|
|
" [0x%08" PRIx64 "].\n",
|
|
|
|
region->value->mem_type_64 ? 64 : 32,
|
|
|
|
region->value->prefetch ? " prefetchable" : "",
|
|
|
|
addr, addr + size - 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, " id \"%s\"\n", dev->qdev_id);
|
|
|
|
|
|
|
|
if (dev->has_pci_bridge) {
|
|
|
|
if (dev->pci_bridge->has_devices) {
|
|
|
|
PciDeviceInfoList *cdev;
|
|
|
|
for (cdev = dev->pci_bridge->devices; cdev; cdev = cdev->next) {
|
|
|
|
hmp_info_pci_device(mon, cdev->value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-26 22:23:27 +02:00
|
|
|
static int hmp_info_irq_foreach(Object *obj, void *opaque)
|
|
|
|
{
|
|
|
|
InterruptStatsProvider *intc;
|
|
|
|
InterruptStatsProviderClass *k;
|
|
|
|
Monitor *mon = 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) {
|
|
|
|
monitor_printf(mon, "IRQ statistics for %s:\n",
|
|
|
|
object_get_typename(obj));
|
|
|
|
for (i = 0; i < nb_irqs; i++) {
|
|
|
|
if (irq_counts[i] > 0) {
|
|
|
|
monitor_printf(mon, "%2d: %" PRId64 "\n", i,
|
|
|
|
irq_counts[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "IRQ statistics not available for %s.\n",
|
|
|
|
object_get_typename(obj));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_info_irq(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
object_child_foreach_recursive(object_get_root(),
|
|
|
|
hmp_info_irq_foreach, mon);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int hmp_info_pic_foreach(Object *obj, void *opaque)
|
|
|
|
{
|
|
|
|
InterruptStatsProvider *intc;
|
|
|
|
InterruptStatsProviderClass *k;
|
|
|
|
Monitor *mon = opaque;
|
|
|
|
|
|
|
|
if (object_dynamic_cast(obj, TYPE_INTERRUPT_STATS_PROVIDER)) {
|
|
|
|
intc = INTERRUPT_STATS_PROVIDER(obj);
|
|
|
|
k = INTERRUPT_STATS_PROVIDER_GET_CLASS(obj);
|
|
|
|
if (k->print_info) {
|
|
|
|
k->print_info(intc, mon);
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "Interrupt controller information not available for %s.\n",
|
|
|
|
object_get_typename(obj));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_info_pic(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
object_child_foreach_recursive(object_get_root(),
|
|
|
|
hmp_info_pic_foreach, mon);
|
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_pci(Monitor *mon, const QDict *qdict)
|
2011-10-21 18:15:33 +02:00
|
|
|
{
|
2012-01-11 16:51:52 +01:00
|
|
|
PciInfoList *info_list, *info;
|
2011-10-21 18:15:33 +02:00
|
|
|
Error *err = NULL;
|
|
|
|
|
2012-01-11 16:51:52 +01:00
|
|
|
info_list = qmp_query_pci(&err);
|
2011-10-21 18:15:33 +02:00
|
|
|
if (err) {
|
|
|
|
monitor_printf(mon, "PCI devices not supported\n");
|
|
|
|
error_free(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-01-11 16:51:52 +01:00
|
|
|
for (info = info_list; info; info = info->next) {
|
2011-10-21 18:15:33 +02:00
|
|
|
PciDeviceInfoList *dev;
|
|
|
|
|
|
|
|
for (dev = info->value->devices; dev; dev = dev->next) {
|
|
|
|
hmp_info_pci_device(mon, dev->value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-11 16:51:52 +01:00
|
|
|
qapi_free_PciInfoList(info_list);
|
2011-10-21 18:15:33 +02:00
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:25 +01:00
|
|
|
void hmp_info_block_jobs(Monitor *mon, const QDict *qdict)
|
2012-01-18 15:40:49 +01:00
|
|
|
{
|
|
|
|
BlockJobInfoList *list;
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
list = qmp_query_block_jobs(&err);
|
|
|
|
assert(!err);
|
|
|
|
|
|
|
|
if (!list) {
|
|
|
|
monitor_printf(mon, "No active jobs\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (list) {
|
|
|
|
if (strcmp(list->value->type, "stream") == 0) {
|
|
|
|
monitor_printf(mon, "Streaming device %s: Completed %" PRId64
|
|
|
|
" of %" PRId64 " bytes, speed limit %" PRId64
|
|
|
|
" bytes/s\n",
|
|
|
|
list->value->device,
|
|
|
|
list->value->offset,
|
|
|
|
list->value->len,
|
|
|
|
list->value->speed);
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "Type %s, device %s: Completed %" PRId64
|
|
|
|
" of %" PRId64 " bytes, speed limit %" PRId64
|
|
|
|
" bytes/s\n",
|
|
|
|
list->value->type,
|
|
|
|
list->value->device,
|
|
|
|
list->value->offset,
|
|
|
|
list->value->len,
|
|
|
|
list->value->speed);
|
|
|
|
}
|
|
|
|
list = list->next;
|
|
|
|
}
|
2014-09-16 15:36:55 +02:00
|
|
|
|
|
|
|
qapi_free_BlockJobInfoList(list);
|
2012-01-18 15:40:49 +01:00
|
|
|
}
|
|
|
|
|
Support for TPM command line options
This patch adds support for TPM command line options.
The command line options supported here are
./qemu-... -tpmdev passthrough,path=<path to TPM device>,id=<id>
-device tpm-tis,tpmdev=<id>,id=<other id>
and
./qemu-... -tpmdev help
where the latter works similar to -soundhw help and shows a list of
available TPM backends (for example 'passthrough').
Using the type parameter, the backend is chosen, i.e., 'passthrough' for the
passthrough driver. The interpretation of the other parameters along
with determining whether enough parameters were provided is pushed into
the backend driver, which needs to implement the interface function
'create' and return a TPMDriverOpts structure if the VM can be started or
'NULL' if not enough or bad parameters were provided.
Monitor support for 'info tpm' has been added. It for example prints the
following:
(qemu) info tpm
TPM devices:
tpm0: model=tpm-tis
\ tpm0: type=passthrough,path=/dev/tpm0,cancel-path=/sys/devices/pnp0/00:09/cancel
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Reviewed-by: Corey Bryant <coreyb@linux.vnet.ibm.com>
Reviewed-by: Joel Schopp <jschopp@linux.vnet.ibm.com>
Message-id: 1361987275-26289-2-git-send-email-stefanb@linux.vnet.ibm.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-02-27 18:47:49 +01:00
|
|
|
void hmp_info_tpm(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
TPMInfoList *info_list, *info;
|
|
|
|
Error *err = NULL;
|
|
|
|
unsigned int c = 0;
|
|
|
|
TPMPassthroughOptions *tpo;
|
2017-09-29 13:10:20 +02:00
|
|
|
TPMEmulatorOptions *teo;
|
Support for TPM command line options
This patch adds support for TPM command line options.
The command line options supported here are
./qemu-... -tpmdev passthrough,path=<path to TPM device>,id=<id>
-device tpm-tis,tpmdev=<id>,id=<other id>
and
./qemu-... -tpmdev help
where the latter works similar to -soundhw help and shows a list of
available TPM backends (for example 'passthrough').
Using the type parameter, the backend is chosen, i.e., 'passthrough' for the
passthrough driver. The interpretation of the other parameters along
with determining whether enough parameters were provided is pushed into
the backend driver, which needs to implement the interface function
'create' and return a TPMDriverOpts structure if the VM can be started or
'NULL' if not enough or bad parameters were provided.
Monitor support for 'info tpm' has been added. It for example prints the
following:
(qemu) info tpm
TPM devices:
tpm0: model=tpm-tis
\ tpm0: type=passthrough,path=/dev/tpm0,cancel-path=/sys/devices/pnp0/00:09/cancel
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Reviewed-by: Corey Bryant <coreyb@linux.vnet.ibm.com>
Reviewed-by: Joel Schopp <jschopp@linux.vnet.ibm.com>
Message-id: 1361987275-26289-2-git-send-email-stefanb@linux.vnet.ibm.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-02-27 18:47:49 +01:00
|
|
|
|
|
|
|
info_list = qmp_query_tpm(&err);
|
|
|
|
if (err) {
|
|
|
|
monitor_printf(mon, "TPM device not supported\n");
|
|
|
|
error_free(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info_list) {
|
|
|
|
monitor_printf(mon, "TPM device:\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (info = info_list; info; info = info->next) {
|
|
|
|
TPMInfo *ti = info->value;
|
|
|
|
monitor_printf(mon, " tpm%d: model=%s\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
c, TpmModel_str(ti->model));
|
Support for TPM command line options
This patch adds support for TPM command line options.
The command line options supported here are
./qemu-... -tpmdev passthrough,path=<path to TPM device>,id=<id>
-device tpm-tis,tpmdev=<id>,id=<other id>
and
./qemu-... -tpmdev help
where the latter works similar to -soundhw help and shows a list of
available TPM backends (for example 'passthrough').
Using the type parameter, the backend is chosen, i.e., 'passthrough' for the
passthrough driver. The interpretation of the other parameters along
with determining whether enough parameters were provided is pushed into
the backend driver, which needs to implement the interface function
'create' and return a TPMDriverOpts structure if the VM can be started or
'NULL' if not enough or bad parameters were provided.
Monitor support for 'info tpm' has been added. It for example prints the
following:
(qemu) info tpm
TPM devices:
tpm0: model=tpm-tis
\ tpm0: type=passthrough,path=/dev/tpm0,cancel-path=/sys/devices/pnp0/00:09/cancel
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Reviewed-by: Corey Bryant <coreyb@linux.vnet.ibm.com>
Reviewed-by: Joel Schopp <jschopp@linux.vnet.ibm.com>
Message-id: 1361987275-26289-2-git-send-email-stefanb@linux.vnet.ibm.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-02-27 18:47:49 +01:00
|
|
|
|
|
|
|
monitor_printf(mon, " \\ %s: type=%s",
|
2017-08-24 10:46:08 +02:00
|
|
|
ti->id, TpmTypeOptionsKind_str(ti->options->type));
|
Support for TPM command line options
This patch adds support for TPM command line options.
The command line options supported here are
./qemu-... -tpmdev passthrough,path=<path to TPM device>,id=<id>
-device tpm-tis,tpmdev=<id>,id=<other id>
and
./qemu-... -tpmdev help
where the latter works similar to -soundhw help and shows a list of
available TPM backends (for example 'passthrough').
Using the type parameter, the backend is chosen, i.e., 'passthrough' for the
passthrough driver. The interpretation of the other parameters along
with determining whether enough parameters were provided is pushed into
the backend driver, which needs to implement the interface function
'create' and return a TPMDriverOpts structure if the VM can be started or
'NULL' if not enough or bad parameters were provided.
Monitor support for 'info tpm' has been added. It for example prints the
following:
(qemu) info tpm
TPM devices:
tpm0: model=tpm-tis
\ tpm0: type=passthrough,path=/dev/tpm0,cancel-path=/sys/devices/pnp0/00:09/cancel
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Reviewed-by: Corey Bryant <coreyb@linux.vnet.ibm.com>
Reviewed-by: Joel Schopp <jschopp@linux.vnet.ibm.com>
Message-id: 1361987275-26289-2-git-send-email-stefanb@linux.vnet.ibm.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-02-27 18:47:49 +01:00
|
|
|
|
2015-10-26 23:35:00 +01:00
|
|
|
switch (ti->options->type) {
|
2013-03-20 17:34:48 +01:00
|
|
|
case TPM_TYPE_OPTIONS_KIND_PASSTHROUGH:
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-17 23:48:37 +01:00
|
|
|
tpo = ti->options->u.passthrough.data;
|
Support for TPM command line options
This patch adds support for TPM command line options.
The command line options supported here are
./qemu-... -tpmdev passthrough,path=<path to TPM device>,id=<id>
-device tpm-tis,tpmdev=<id>,id=<other id>
and
./qemu-... -tpmdev help
where the latter works similar to -soundhw help and shows a list of
available TPM backends (for example 'passthrough').
Using the type parameter, the backend is chosen, i.e., 'passthrough' for the
passthrough driver. The interpretation of the other parameters along
with determining whether enough parameters were provided is pushed into
the backend driver, which needs to implement the interface function
'create' and return a TPMDriverOpts structure if the VM can be started or
'NULL' if not enough or bad parameters were provided.
Monitor support for 'info tpm' has been added. It for example prints the
following:
(qemu) info tpm
TPM devices:
tpm0: model=tpm-tis
\ tpm0: type=passthrough,path=/dev/tpm0,cancel-path=/sys/devices/pnp0/00:09/cancel
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Reviewed-by: Corey Bryant <coreyb@linux.vnet.ibm.com>
Reviewed-by: Joel Schopp <jschopp@linux.vnet.ibm.com>
Message-id: 1361987275-26289-2-git-send-email-stefanb@linux.vnet.ibm.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-02-27 18:47:49 +01:00
|
|
|
monitor_printf(mon, "%s%s%s%s",
|
|
|
|
tpo->has_path ? ",path=" : "",
|
|
|
|
tpo->has_path ? tpo->path : "",
|
|
|
|
tpo->has_cancel_path ? ",cancel-path=" : "",
|
|
|
|
tpo->has_cancel_path ? tpo->cancel_path : "");
|
|
|
|
break;
|
2017-09-29 13:10:20 +02:00
|
|
|
case TPM_TYPE_OPTIONS_KIND_EMULATOR:
|
|
|
|
teo = ti->options->u.emulator.data;
|
|
|
|
monitor_printf(mon, ",chardev=%s", teo->chardev);
|
|
|
|
break;
|
qapi: Don't let implicit enum MAX member collide
Now that we guarantee the user doesn't have any enum values
beginning with a single underscore, we can use that for our
own purposes. Renaming ENUM_MAX to ENUM__MAX makes it obvious
that the sentinel is generated.
This patch was mostly generated by applying a temporary patch:
|diff --git a/scripts/qapi.py b/scripts/qapi.py
|index e6d014b..b862ec9 100644
|--- a/scripts/qapi.py
|+++ b/scripts/qapi.py
|@@ -1570,6 +1570,7 @@ const char *const %(c_name)s_lookup[] = {
| max_index = c_enum_const(name, 'MAX', prefix)
| ret += mcgen('''
| [%(max_index)s] = NULL,
|+// %(max_index)s
| };
| ''',
| max_index=max_index)
then running:
$ cat qapi-{types,event}.c tests/test-qapi-types.c |
sed -n 's,^// \(.*\)MAX,s|\1MAX|\1_MAX|g,p' > list
$ git grep -l _MAX | xargs sed -i -f list
The only things not generated are the changes in scripts/qapi.py.
Rejecting enum members named 'MAX' is now useless, and will be dropped
in the next patch.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-23-git-send-email-eblake@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
[Rebased to current master, commit message tweaked]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-11-18 09:52:57 +01:00
|
|
|
case TPM_TYPE_OPTIONS_KIND__MAX:
|
Support for TPM command line options
This patch adds support for TPM command line options.
The command line options supported here are
./qemu-... -tpmdev passthrough,path=<path to TPM device>,id=<id>
-device tpm-tis,tpmdev=<id>,id=<other id>
and
./qemu-... -tpmdev help
where the latter works similar to -soundhw help and shows a list of
available TPM backends (for example 'passthrough').
Using the type parameter, the backend is chosen, i.e., 'passthrough' for the
passthrough driver. The interpretation of the other parameters along
with determining whether enough parameters were provided is pushed into
the backend driver, which needs to implement the interface function
'create' and return a TPMDriverOpts structure if the VM can be started or
'NULL' if not enough or bad parameters were provided.
Monitor support for 'info tpm' has been added. It for example prints the
following:
(qemu) info tpm
TPM devices:
tpm0: model=tpm-tis
\ tpm0: type=passthrough,path=/dev/tpm0,cancel-path=/sys/devices/pnp0/00:09/cancel
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Reviewed-by: Corey Bryant <coreyb@linux.vnet.ibm.com>
Reviewed-by: Joel Schopp <jschopp@linux.vnet.ibm.com>
Message-id: 1361987275-26289-2-git-send-email-stefanb@linux.vnet.ibm.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-02-27 18:47:49 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
c++;
|
|
|
|
}
|
|
|
|
qapi_free_TPMInfoList(info_list);
|
|
|
|
}
|
|
|
|
|
2011-09-15 19:20:28 +02:00
|
|
|
void hmp_quit(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
monitor_suspend(mon);
|
|
|
|
qmp_quit(NULL);
|
|
|
|
}
|
2011-09-15 19:34:39 +02:00
|
|
|
|
|
|
|
void hmp_stop(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
qmp_stop(NULL);
|
|
|
|
}
|
2011-09-15 19:41:46 +02:00
|
|
|
|
|
|
|
void hmp_system_reset(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
qmp_system_reset(NULL);
|
|
|
|
}
|
2011-09-28 16:06:15 +02:00
|
|
|
|
|
|
|
void hmp_system_powerdown(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
qmp_system_powerdown(NULL);
|
|
|
|
}
|
2011-10-06 19:31:39 +02:00
|
|
|
|
|
|
|
void hmp_cpu(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
int64_t cpu_index;
|
|
|
|
|
|
|
|
/* XXX: drop the monitor_set_cpu() usage when all HMP commands that
|
|
|
|
use it are converted to the QAPI */
|
|
|
|
cpu_index = qdict_get_int(qdict, "index");
|
|
|
|
if (monitor_set_cpu(cpu_index) < 0) {
|
|
|
|
monitor_printf(mon, "invalid CPU index\n");
|
|
|
|
}
|
|
|
|
}
|
2011-11-22 19:32:37 +01:00
|
|
|
|
|
|
|
void hmp_memsave(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
uint32_t size = qdict_get_int(qdict, "size");
|
|
|
|
const char *filename = qdict_get_str(qdict, "filename");
|
|
|
|
uint64_t addr = qdict_get_int(qdict, "val");
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2017-01-13 13:12:35 +01:00
|
|
|
int cpu_index = monitor_get_cpu_index();
|
2011-11-22 19:32:37 +01:00
|
|
|
|
2017-01-13 13:12:35 +01:00
|
|
|
if (cpu_index < 0) {
|
|
|
|
monitor_printf(mon, "No CPU available\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
qmp_memsave(addr, size, filename, true, cpu_index, &err);
|
2014-05-02 13:26:29 +02:00
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-22 19:32:37 +01:00
|
|
|
}
|
2011-11-22 20:26:46 +01:00
|
|
|
|
|
|
|
void hmp_pmemsave(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
uint32_t size = qdict_get_int(qdict, "size");
|
|
|
|
const char *filename = qdict_get_str(qdict, "filename");
|
|
|
|
uint64_t addr = qdict_get_int(qdict, "val");
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2011-11-22 20:26:46 +01:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_pmemsave(addr, size, filename, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2013-01-24 17:03:20 +01:00
|
|
|
}
|
|
|
|
|
qemu-char: Saner naming of memchar stuff & doc fixes
New device, has never been released, so we can still improve things
without worrying about compatibility.
Naming is a mess. The code calls the device driver CirMemCharDriver,
the public API calls it "memory", "memchardev", or "memchar", and the
special commands are named like "memchar-FOO". "memory" is a
particularly unfortunate choice, because there's another character
device driver called MemoryDriver. Moreover, the device's distinctive
property is that it's a ring buffer, not that's in memory. Therefore:
* Rename CirMemCharDriver to RingBufCharDriver, and call the thing a
"ringbuf" in the API.
* Rename QMP and HMP commands from memchar-FOO to ringbuf-FOO.
* Rename device parameter from maxcapacity to size (simple words are
good for you).
* Clearly mark the parameter as optional in documentation.
* Fix error reporting so that chardev-add reports to current monitor,
not stderr.
* Replace cirmem in C identifiers by ringbuf.
* Rework documentation. Document the impact of our crappy UTF-8
handling on reading.
* QMP examples that even work.
I could split this up into multiple commits, but they'd change the
same documentation lines multiple times. Not worth it.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-02-06 21:27:24 +01:00
|
|
|
void hmp_ringbuf_write(Monitor *mon, const QDict *qdict)
|
2013-01-24 17:03:20 +01:00
|
|
|
{
|
|
|
|
const char *chardev = qdict_get_str(qdict, "device");
|
|
|
|
const char *data = qdict_get_str(qdict, "data");
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2013-01-24 17:03:20 +01:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_ringbuf_write(chardev, data, false, 0, &err);
|
2013-01-24 17:03:20 +01:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-22 20:26:46 +01:00
|
|
|
}
|
2011-11-22 20:58:31 +01:00
|
|
|
|
qemu-char: Saner naming of memchar stuff & doc fixes
New device, has never been released, so we can still improve things
without worrying about compatibility.
Naming is a mess. The code calls the device driver CirMemCharDriver,
the public API calls it "memory", "memchardev", or "memchar", and the
special commands are named like "memchar-FOO". "memory" is a
particularly unfortunate choice, because there's another character
device driver called MemoryDriver. Moreover, the device's distinctive
property is that it's a ring buffer, not that's in memory. Therefore:
* Rename CirMemCharDriver to RingBufCharDriver, and call the thing a
"ringbuf" in the API.
* Rename QMP and HMP commands from memchar-FOO to ringbuf-FOO.
* Rename device parameter from maxcapacity to size (simple words are
good for you).
* Clearly mark the parameter as optional in documentation.
* Fix error reporting so that chardev-add reports to current monitor,
not stderr.
* Replace cirmem in C identifiers by ringbuf.
* Rework documentation. Document the impact of our crappy UTF-8
handling on reading.
* QMP examples that even work.
I could split this up into multiple commits, but they'd change the
same documentation lines multiple times. Not worth it.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-02-06 21:27:24 +01:00
|
|
|
void hmp_ringbuf_read(Monitor *mon, const QDict *qdict)
|
2013-01-24 17:03:21 +01:00
|
|
|
{
|
|
|
|
uint32_t size = qdict_get_int(qdict, "size");
|
|
|
|
const char *chardev = qdict_get_str(qdict, "device");
|
2013-02-06 21:27:15 +01:00
|
|
|
char *data;
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2013-02-06 21:27:26 +01:00
|
|
|
int i;
|
2013-01-24 17:03:21 +01:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
data = qmp_ringbuf_read(chardev, size, false, 0, &err);
|
|
|
|
if (err) {
|
2017-10-19 13:16:33 +02:00
|
|
|
hmp_handle_error(mon, &err);
|
2013-01-24 17:03:21 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-02-06 21:27:26 +01:00
|
|
|
for (i = 0; data[i]; i++) {
|
|
|
|
unsigned char ch = data[i];
|
|
|
|
|
|
|
|
if (ch == '\\') {
|
|
|
|
monitor_printf(mon, "\\\\");
|
|
|
|
} else if ((ch < 0x20 && ch != '\n' && ch != '\t') || ch == 0x7F) {
|
|
|
|
monitor_printf(mon, "\\u%04X", ch);
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "%c", ch);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
monitor_printf(mon, "\n");
|
2013-02-06 21:27:15 +01:00
|
|
|
g_free(data);
|
2013-01-24 17:03:21 +01:00
|
|
|
}
|
|
|
|
|
2011-11-22 20:58:31 +01:00
|
|
|
void hmp_cont(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2011-11-22 20:58:31 +01:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_cont(&err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-22 20:58:31 +01:00
|
|
|
}
|
2011-11-23 15:55:53 +01:00
|
|
|
|
2012-02-23 13:45:21 +01:00
|
|
|
void hmp_system_wakeup(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
qmp_system_wakeup(NULL);
|
|
|
|
}
|
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 13:55:43 +01:00
|
|
|
void hmp_nmi(Monitor *mon, const QDict *qdict)
|
2011-11-23 15:55:53 +01:00
|
|
|
{
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2011-11-23 15:55:53 +01:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_inject_nmi(&err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-23 15:55:53 +01:00
|
|
|
}
|
2011-11-23 16:11:55 +01:00
|
|
|
|
|
|
|
void hmp_set_link(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *name = qdict_get_str(qdict, "name");
|
2015-05-16 00:25:00 +02:00
|
|
|
bool up = qdict_get_bool(qdict, "up");
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2011-11-23 16:11:55 +01:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_set_link(name, up, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-23 16:11:55 +01:00
|
|
|
}
|
2011-11-23 16:28:21 +01:00
|
|
|
|
|
|
|
void hmp_block_passwd(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
const char *password = qdict_get_str(qdict, "password");
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2011-11-23 16:28:21 +01:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_block_passwd(true, device, false, NULL, password, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-23 16:28:21 +01:00
|
|
|
}
|
2011-11-25 17:38:09 +01:00
|
|
|
|
|
|
|
void hmp_balloon(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
int64_t value = qdict_get_int(qdict, "value");
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2011-11-25 17:38:09 +01:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_balloon(value, &err);
|
2017-10-19 13:16:33 +02:00
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-25 17:38:09 +01:00
|
|
|
}
|
2011-11-25 17:57:10 +01:00
|
|
|
|
|
|
|
void hmp_block_resize(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
int64_t size = qdict_get_int(qdict, "size");
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2011-11-25 17:57:10 +01:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_block_resize(true, device, false, NULL, size, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-25 17:57:10 +01:00
|
|
|
}
|
2011-11-25 19:15:19 +01:00
|
|
|
|
2012-10-18 16:49:24 +02:00
|
|
|
void hmp_drive_mirror(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *filename = qdict_get_str(qdict, "target");
|
|
|
|
const char *format = qdict_get_try_str(qdict, "format");
|
2015-05-16 00:25:00 +02:00
|
|
|
bool reuse = qdict_get_try_bool(qdict, "reuse", false);
|
|
|
|
bool full = qdict_get_try_bool(qdict, "full", false);
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2016-07-15 00:37:58 +02:00
|
|
|
DriveMirror mirror = {
|
|
|
|
.device = (char *)qdict_get_str(qdict, "device"),
|
|
|
|
.target = (char *)filename,
|
|
|
|
.has_format = !!format,
|
|
|
|
.format = (char *)format,
|
|
|
|
.sync = full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
|
|
|
|
.has_mode = true,
|
|
|
|
.mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS,
|
|
|
|
.unmap = true,
|
|
|
|
};
|
2012-10-18 16:49:24 +02:00
|
|
|
|
|
|
|
if (!filename) {
|
2015-03-17 11:54:50 +01:00
|
|
|
error_setg(&err, QERR_MISSING_PARAMETER, "target");
|
2014-05-02 13:26:29 +02:00
|
|
|
hmp_handle_error(mon, &err);
|
2012-10-18 16:49:24 +02:00
|
|
|
return;
|
|
|
|
}
|
2016-07-15 00:37:58 +02:00
|
|
|
qmp_drive_mirror(&mirror, &err);
|
2014-05-02 13:26:29 +02:00
|
|
|
hmp_handle_error(mon, &err);
|
2012-10-18 16:49:24 +02:00
|
|
|
}
|
|
|
|
|
2013-06-26 14:11:58 +02:00
|
|
|
void hmp_drive_backup(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
const char *filename = qdict_get_str(qdict, "target");
|
|
|
|
const char *format = qdict_get_try_str(qdict, "format");
|
2015-05-16 00:25:00 +02:00
|
|
|
bool reuse = qdict_get_try_bool(qdict, "reuse", false);
|
|
|
|
bool full = qdict_get_try_bool(qdict, "full", false);
|
2016-07-22 10:17:52 +02:00
|
|
|
bool compress = qdict_get_try_bool(qdict, "compress", false);
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2016-07-22 10:17:50 +02:00
|
|
|
DriveBackup backup = {
|
|
|
|
.device = (char *)device,
|
|
|
|
.target = (char *)filename,
|
|
|
|
.has_format = !!format,
|
|
|
|
.format = (char *)format,
|
|
|
|
.sync = full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
|
|
|
|
.has_mode = true,
|
|
|
|
.mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS,
|
2016-07-22 10:17:52 +02:00
|
|
|
.has_compress = !!compress,
|
|
|
|
.compress = compress,
|
2016-07-22 10:17:50 +02:00
|
|
|
};
|
2013-06-26 14:11:58 +02:00
|
|
|
|
|
|
|
if (!filename) {
|
2015-03-17 11:54:50 +01:00
|
|
|
error_setg(&err, QERR_MISSING_PARAMETER, "target");
|
2014-05-02 13:26:29 +02:00
|
|
|
hmp_handle_error(mon, &err);
|
2013-06-26 14:11:58 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-07-22 10:17:50 +02:00
|
|
|
qmp_drive_backup(&backup, &err);
|
2014-05-02 13:26:29 +02:00
|
|
|
hmp_handle_error(mon, &err);
|
2013-06-26 14:11:58 +02:00
|
|
|
}
|
|
|
|
|
2011-11-25 19:15:19 +01:00
|
|
|
void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
const char *filename = qdict_get_try_str(qdict, "snapshot-file");
|
|
|
|
const char *format = qdict_get_try_str(qdict, "format");
|
2015-05-16 00:25:00 +02:00
|
|
|
bool reuse = qdict_get_try_bool(qdict, "reuse", false);
|
2012-03-06 18:55:59 +01:00
|
|
|
enum NewImageMode mode;
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2011-11-25 19:15:19 +01:00
|
|
|
|
|
|
|
if (!filename) {
|
|
|
|
/* In the future, if 'snapshot-file' is not specified, the snapshot
|
|
|
|
will be taken internally. Today it's actually required. */
|
2015-03-17 11:54:50 +01:00
|
|
|
error_setg(&err, QERR_MISSING_PARAMETER, "snapshot-file");
|
2014-05-02 13:26:29 +02:00
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-25 19:15:19 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-03-06 18:55:59 +01:00
|
|
|
mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS;
|
2014-01-23 21:31:38 +01:00
|
|
|
qmp_blockdev_snapshot_sync(true, device, false, NULL,
|
|
|
|
filename, false, NULL,
|
|
|
|
!!format, format,
|
2014-05-02 13:26:29 +02:00
|
|
|
true, mode, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2011-11-25 19:15:19 +01:00
|
|
|
}
|
2011-11-28 01:54:09 +01:00
|
|
|
|
2013-09-11 08:04:37 +02:00
|
|
|
void hmp_snapshot_blkdev_internal(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
const char *name = qdict_get_str(qdict, "name");
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2013-09-11 08:04:37 +02:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_blockdev_snapshot_internal_sync(device, name, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2013-09-11 08:04:37 +02:00
|
|
|
}
|
|
|
|
|
2013-09-11 08:04:38 +02:00
|
|
|
void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
const char *name = qdict_get_str(qdict, "name");
|
|
|
|
const char *id = qdict_get_try_str(qdict, "id");
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2013-09-11 08:04:38 +02:00
|
|
|
|
|
|
|
qmp_blockdev_snapshot_delete_internal_sync(device, !!id, id,
|
2014-05-02 13:26:29 +02:00
|
|
|
true, name, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2013-09-11 08:04:38 +02:00
|
|
|
}
|
|
|
|
|
2017-04-18 11:40:56 +02:00
|
|
|
void hmp_loadvm(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
int saved_vm_running = runstate_is_running();
|
|
|
|
const char *name = qdict_get_str(qdict, "name");
|
2017-04-18 18:12:35 +02:00
|
|
|
Error *err = NULL;
|
2017-04-18 11:40:56 +02:00
|
|
|
|
|
|
|
vm_stop(RUN_STATE_RESTORE_VM);
|
|
|
|
|
2017-04-20 14:25:55 +02:00
|
|
|
if (load_snapshot(name, &err) == 0 && saved_vm_running) {
|
2017-04-18 11:40:56 +02:00
|
|
|
vm_start();
|
|
|
|
}
|
2017-04-18 18:12:35 +02:00
|
|
|
hmp_handle_error(mon, &err);
|
2017-04-18 11:40:56 +02:00
|
|
|
}
|
|
|
|
|
2017-04-18 11:44:16 +02:00
|
|
|
void hmp_savevm(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2017-04-18 18:12:35 +02:00
|
|
|
Error *err = NULL;
|
|
|
|
|
2017-04-20 14:25:55 +02:00
|
|
|
save_snapshot(qdict_get_try_str(qdict, "name"), &err);
|
2017-04-18 18:12:35 +02:00
|
|
|
hmp_handle_error(mon, &err);
|
2017-04-18 11:44:16 +02:00
|
|
|
}
|
|
|
|
|
2017-04-18 11:46:23 +02:00
|
|
|
void hmp_delvm(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
BlockDriverState *bs;
|
2018-02-25 02:47:51 +01:00
|
|
|
Error *err = NULL;
|
2017-04-18 11:46:23 +02:00
|
|
|
const char *name = qdict_get_str(qdict, "name");
|
|
|
|
|
|
|
|
if (bdrv_all_delete_snapshot(name, &bs, &err) < 0) {
|
|
|
|
error_reportf_err(err,
|
|
|
|
"Error while deleting snapshot on device '%s': ",
|
|
|
|
bdrv_get_device_name(bs));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-18 11:51:06 +02:00
|
|
|
void hmp_info_snapshots(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
BlockDriverState *bs, *bs1;
|
|
|
|
BdrvNextIterator it1;
|
|
|
|
QEMUSnapshotInfo *sn_tab, *sn;
|
|
|
|
bool no_snapshot = true;
|
|
|
|
int nb_sns, i;
|
|
|
|
int total;
|
|
|
|
int *global_snapshots;
|
|
|
|
AioContext *aio_context;
|
|
|
|
|
|
|
|
typedef struct SnapshotEntry {
|
|
|
|
QEMUSnapshotInfo sn;
|
|
|
|
QTAILQ_ENTRY(SnapshotEntry) next;
|
|
|
|
} SnapshotEntry;
|
|
|
|
|
|
|
|
typedef struct ImageEntry {
|
|
|
|
const char *imagename;
|
|
|
|
QTAILQ_ENTRY(ImageEntry) next;
|
|
|
|
QTAILQ_HEAD(, SnapshotEntry) snapshots;
|
|
|
|
} ImageEntry;
|
|
|
|
|
|
|
|
QTAILQ_HEAD(, ImageEntry) image_list =
|
|
|
|
QTAILQ_HEAD_INITIALIZER(image_list);
|
|
|
|
|
|
|
|
ImageEntry *image_entry, *next_ie;
|
|
|
|
SnapshotEntry *snapshot_entry;
|
|
|
|
|
|
|
|
bs = bdrv_all_find_vmstate_bs();
|
|
|
|
if (!bs) {
|
|
|
|
monitor_printf(mon, "No available block device supports snapshots\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
aio_context = bdrv_get_aio_context(bs);
|
|
|
|
|
|
|
|
aio_context_acquire(aio_context);
|
|
|
|
nb_sns = bdrv_snapshot_list(bs, &sn_tab);
|
|
|
|
aio_context_release(aio_context);
|
|
|
|
|
|
|
|
if (nb_sns < 0) {
|
|
|
|
monitor_printf(mon, "bdrv_snapshot_list: error %d\n", nb_sns);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (bs1 = bdrv_first(&it1); bs1; bs1 = bdrv_next(&it1)) {
|
|
|
|
int bs1_nb_sns = 0;
|
|
|
|
ImageEntry *ie;
|
|
|
|
SnapshotEntry *se;
|
|
|
|
AioContext *ctx = bdrv_get_aio_context(bs1);
|
|
|
|
|
|
|
|
aio_context_acquire(ctx);
|
|
|
|
if (bdrv_can_snapshot(bs1)) {
|
|
|
|
sn = NULL;
|
|
|
|
bs1_nb_sns = bdrv_snapshot_list(bs1, &sn);
|
|
|
|
if (bs1_nb_sns > 0) {
|
|
|
|
no_snapshot = false;
|
|
|
|
ie = g_new0(ImageEntry, 1);
|
|
|
|
ie->imagename = bdrv_get_device_name(bs1);
|
|
|
|
QTAILQ_INIT(&ie->snapshots);
|
|
|
|
QTAILQ_INSERT_TAIL(&image_list, ie, next);
|
|
|
|
for (i = 0; i < bs1_nb_sns; i++) {
|
|
|
|
se = g_new0(SnapshotEntry, 1);
|
|
|
|
se->sn = sn[i];
|
|
|
|
QTAILQ_INSERT_TAIL(&ie->snapshots, se, next);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g_free(sn);
|
|
|
|
}
|
|
|
|
aio_context_release(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (no_snapshot) {
|
|
|
|
monitor_printf(mon, "There is no snapshot available.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
global_snapshots = g_new0(int, nb_sns);
|
|
|
|
total = 0;
|
|
|
|
for (i = 0; i < nb_sns; i++) {
|
|
|
|
SnapshotEntry *next_sn;
|
|
|
|
if (bdrv_all_find_snapshot(sn_tab[i].name, &bs1) == 0) {
|
|
|
|
global_snapshots[total] = i;
|
|
|
|
total++;
|
|
|
|
QTAILQ_FOREACH(image_entry, &image_list, next) {
|
|
|
|
QTAILQ_FOREACH_SAFE(snapshot_entry, &image_entry->snapshots,
|
|
|
|
next, next_sn) {
|
|
|
|
if (!strcmp(sn_tab[i].name, snapshot_entry->sn.name)) {
|
|
|
|
QTAILQ_REMOVE(&image_entry->snapshots, snapshot_entry,
|
|
|
|
next);
|
|
|
|
g_free(snapshot_entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "List of snapshots present on all disks:\n");
|
|
|
|
|
|
|
|
if (total > 0) {
|
|
|
|
bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, NULL);
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
for (i = 0; i < total; i++) {
|
|
|
|
sn = &sn_tab[global_snapshots[i]];
|
|
|
|
/* The ID is not guaranteed to be the same on all images, so
|
|
|
|
* overwrite it.
|
|
|
|
*/
|
|
|
|
pstrcpy(sn->id_str, sizeof(sn->id_str), "--");
|
|
|
|
bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, sn);
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "None\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
QTAILQ_FOREACH(image_entry, &image_list, next) {
|
|
|
|
if (QTAILQ_EMPTY(&image_entry->snapshots)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
monitor_printf(mon,
|
|
|
|
"\nList of partial (non-loadable) snapshots on '%s':\n",
|
|
|
|
image_entry->imagename);
|
|
|
|
bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, NULL);
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
QTAILQ_FOREACH(snapshot_entry, &image_entry->snapshots, next) {
|
|
|
|
bdrv_snapshot_dump((fprintf_function)monitor_printf, mon,
|
|
|
|
&snapshot_entry->sn);
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QTAILQ_FOREACH_SAFE(image_entry, &image_list, next, next_ie) {
|
|
|
|
SnapshotEntry *next_sn;
|
|
|
|
QTAILQ_FOREACH_SAFE(snapshot_entry, &image_entry->snapshots, next,
|
|
|
|
next_sn) {
|
|
|
|
g_free(snapshot_entry);
|
|
|
|
}
|
|
|
|
g_free(image_entry);
|
|
|
|
}
|
|
|
|
g_free(sn_tab);
|
|
|
|
g_free(global_snapshots);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2011-11-28 01:54:09 +01:00
|
|
|
void hmp_migrate_cancel(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
qmp_migrate_cancel(NULL);
|
|
|
|
}
|
2011-11-28 02:18:01 +01:00
|
|
|
|
2017-10-20 11:05:54 +02:00
|
|
|
void hmp_migrate_continue(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
const char *state = qdict_get_str(qdict, "state");
|
|
|
|
int val = qapi_enum_parse(&MigrationStatus_lookup, state, -1, &err);
|
|
|
|
|
|
|
|
if (val >= 0) {
|
|
|
|
qmp_migrate_continue(val, &err);
|
|
|
|
}
|
|
|
|
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
|
|
|
|
2015-02-19 12:40:28 +01:00
|
|
|
void hmp_migrate_incoming(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
const char *uri = qdict_get_str(qdict, "uri");
|
|
|
|
|
|
|
|
qmp_migrate_incoming(uri, &err);
|
|
|
|
|
2015-02-26 15:54:39 +01:00
|
|
|
hmp_handle_error(mon, &err);
|
2015-02-19 12:40:28 +01:00
|
|
|
}
|
|
|
|
|
2016-09-15 18:20:28 +02:00
|
|
|
/* Kept for backwards compatibility */
|
2011-11-28 02:18:01 +01:00
|
|
|
void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
double value = qdict_get_double(qdict, "value");
|
|
|
|
qmp_migrate_set_downtime(value, NULL);
|
|
|
|
}
|
2011-11-28 14:59:37 +01:00
|
|
|
|
2012-08-06 20:42:54 +02:00
|
|
|
void hmp_migrate_set_cache_size(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
int64_t value = qdict_get_int(qdict, "value");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_migrate_set_cache_size(value, &err);
|
2017-10-19 13:16:33 +02:00
|
|
|
hmp_handle_error(mon, &err);
|
2012-08-06 20:42:54 +02:00
|
|
|
}
|
|
|
|
|
2016-09-15 18:20:28 +02:00
|
|
|
/* Kept for backwards compatibility */
|
2011-11-28 14:59:37 +01:00
|
|
|
void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
int64_t value = qdict_get_int(qdict, "value");
|
|
|
|
qmp_migrate_set_speed(value, NULL);
|
|
|
|
}
|
2011-12-07 14:17:51 +01:00
|
|
|
|
2012-08-06 20:42:48 +02:00
|
|
|
void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *cap = qdict_get_str(qdict, "capability");
|
|
|
|
bool state = qdict_get_bool(qdict, "state");
|
|
|
|
Error *err = NULL;
|
|
|
|
MigrationCapabilityStatusList *caps = g_malloc0(sizeof(*caps));
|
2017-08-24 10:46:00 +02:00
|
|
|
int val;
|
2012-08-06 20:42:48 +02:00
|
|
|
|
2017-08-24 10:46:10 +02:00
|
|
|
val = qapi_enum_parse(&MigrationCapability_lookup, cap, -1, &err);
|
2017-08-24 10:46:00 +02:00
|
|
|
if (val < 0) {
|
|
|
|
goto end;
|
2012-08-06 20:42:48 +02:00
|
|
|
}
|
|
|
|
|
2017-08-24 10:46:00 +02:00
|
|
|
caps->value = g_malloc0(sizeof(*caps->value));
|
|
|
|
caps->value->capability = val;
|
|
|
|
caps->value->state = state;
|
|
|
|
caps->next = NULL;
|
|
|
|
qmp_migrate_set_capabilities(caps, &err);
|
2012-08-06 20:42:48 +02:00
|
|
|
|
2017-08-24 10:46:00 +02:00
|
|
|
end:
|
2012-08-06 20:42:48 +02:00
|
|
|
qapi_free_MigrationCapabilityStatusList(caps);
|
2017-10-19 13:16:33 +02:00
|
|
|
hmp_handle_error(mon, &err);
|
2012-08-06 20:42:48 +02:00
|
|
|
}
|
|
|
|
|
2015-03-23 09:32:29 +01:00
|
|
|
void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *param = qdict_get_str(qdict, "parameter");
|
2016-04-27 12:05:15 +02:00
|
|
|
const char *valuestr = qdict_get_str(qdict, "value");
|
2017-05-16 11:37:45 +02:00
|
|
|
Visitor *v = string_input_visitor_new(valuestr);
|
migration: Unshare MigrationParameters struct for now
Commit de63ab6 "migrate: Share common MigrationParameters struct"
reused MigrationParameters for the arguments of
migrate-set-parameters, with the following rationale:
It is rather verbose, and slightly error-prone, to repeat
the same set of parameters for input (migrate-set-parameters)
as for output (query-migrate-parameters), where the only
difference is whether the members are optional. We can just
document that the optional members will always be present
on output, and then share a common struct between both
commands. The next patch can then reduce the amount of
code needed on input.
I need to unshare them to correct a design flaw in a stupid, but
minimally invasive way, in the next commit. We can restore the
sharing when we redo that patch in a less stupid way. Add a suitable
TODO comment.
Note that I revert only the sharing part of commit de63ab6, not the
part that made the members of query-migrate-parameters' result
optional. The schema (and thus introspection) remains inaccurate for
query-migrate-parameters. If we decide not to restore the sharing, we
should revert that part, too.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2017-07-18 13:42:11 +02:00
|
|
|
MigrateSetParameters *p = g_new0(MigrateSetParameters, 1);
|
2017-02-21 21:14:07 +01:00
|
|
|
uint64_t valuebw = 0;
|
2017-10-05 21:30:10 +02:00
|
|
|
uint64_t cache_size;
|
2015-03-23 09:32:29 +01:00
|
|
|
Error *err = NULL;
|
2017-08-24 10:46:01 +02:00
|
|
|
int val, ret;
|
2016-04-27 12:05:15 +02:00
|
|
|
|
2017-08-24 10:46:10 +02:00
|
|
|
val = qapi_enum_parse(&MigrationParameter_lookup, param, -1, &err);
|
2017-08-24 10:46:01 +02:00
|
|
|
if (val < 0) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (val) {
|
|
|
|
case MIGRATION_PARAMETER_COMPRESS_LEVEL:
|
|
|
|
p->has_compress_level = true;
|
|
|
|
visit_type_int(v, param, &p->compress_level, &err);
|
|
|
|
break;
|
|
|
|
case MIGRATION_PARAMETER_COMPRESS_THREADS:
|
|
|
|
p->has_compress_threads = true;
|
|
|
|
visit_type_int(v, param, &p->compress_threads, &err);
|
|
|
|
break;
|
|
|
|
case MIGRATION_PARAMETER_DECOMPRESS_THREADS:
|
|
|
|
p->has_decompress_threads = true;
|
|
|
|
visit_type_int(v, param, &p->decompress_threads, &err);
|
|
|
|
break;
|
|
|
|
case MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL:
|
|
|
|
p->has_cpu_throttle_initial = true;
|
|
|
|
visit_type_int(v, param, &p->cpu_throttle_initial, &err);
|
|
|
|
break;
|
|
|
|
case MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT:
|
|
|
|
p->has_cpu_throttle_increment = true;
|
|
|
|
visit_type_int(v, param, &p->cpu_throttle_increment, &err);
|
|
|
|
break;
|
|
|
|
case MIGRATION_PARAMETER_TLS_CREDS:
|
|
|
|
p->has_tls_creds = true;
|
|
|
|
p->tls_creds = g_new0(StrOrNull, 1);
|
|
|
|
p->tls_creds->type = QTYPE_QSTRING;
|
|
|
|
visit_type_str(v, param, &p->tls_creds->u.s, &err);
|
|
|
|
break;
|
|
|
|
case MIGRATION_PARAMETER_TLS_HOSTNAME:
|
|
|
|
p->has_tls_hostname = true;
|
|
|
|
p->tls_hostname = g_new0(StrOrNull, 1);
|
|
|
|
p->tls_hostname->type = QTYPE_QSTRING;
|
|
|
|
visit_type_str(v, param, &p->tls_hostname->u.s, &err);
|
|
|
|
break;
|
|
|
|
case MIGRATION_PARAMETER_MAX_BANDWIDTH:
|
|
|
|
p->has_max_bandwidth = true;
|
|
|
|
/*
|
|
|
|
* Can't use visit_type_size() here, because it
|
|
|
|
* defaults to Bytes rather than Mebibytes.
|
|
|
|
*/
|
|
|
|
ret = qemu_strtosz_MiB(valuestr, NULL, &valuebw);
|
|
|
|
if (ret < 0 || valuebw > INT64_MAX
|
|
|
|
|| (size_t)valuebw != valuebw) {
|
|
|
|
error_setg(&err, "Invalid size %s", valuestr);
|
2015-03-23 09:32:29 +01:00
|
|
|
break;
|
|
|
|
}
|
2017-08-24 10:46:01 +02:00
|
|
|
p->max_bandwidth = valuebw;
|
|
|
|
break;
|
|
|
|
case MIGRATION_PARAMETER_DOWNTIME_LIMIT:
|
|
|
|
p->has_downtime_limit = true;
|
|
|
|
visit_type_int(v, param, &p->downtime_limit, &err);
|
|
|
|
break;
|
|
|
|
case MIGRATION_PARAMETER_X_CHECKPOINT_DELAY:
|
|
|
|
p->has_x_checkpoint_delay = true;
|
|
|
|
visit_type_int(v, param, &p->x_checkpoint_delay, &err);
|
|
|
|
break;
|
|
|
|
case MIGRATION_PARAMETER_BLOCK_INCREMENTAL:
|
|
|
|
p->has_block_incremental = true;
|
|
|
|
visit_type_bool(v, param, &p->block_incremental, &err);
|
|
|
|
break;
|
2016-01-15 08:56:17 +01:00
|
|
|
case MIGRATION_PARAMETER_X_MULTIFD_CHANNELS:
|
|
|
|
p->has_x_multifd_channels = true;
|
|
|
|
visit_type_int(v, param, &p->x_multifd_channels, &err);
|
|
|
|
break;
|
2017-04-27 10:48:25 +02:00
|
|
|
case MIGRATION_PARAMETER_X_MULTIFD_PAGE_COUNT:
|
|
|
|
p->has_x_multifd_page_count = true;
|
|
|
|
visit_type_int(v, param, &p->x_multifd_page_count, &err);
|
|
|
|
break;
|
2017-10-05 21:30:10 +02:00
|
|
|
case MIGRATION_PARAMETER_XBZRLE_CACHE_SIZE:
|
|
|
|
p->has_xbzrle_cache_size = true;
|
|
|
|
visit_type_size(v, param, &cache_size, &err);
|
|
|
|
if (err || cache_size > INT64_MAX
|
|
|
|
|| (size_t)cache_size != cache_size) {
|
|
|
|
error_setg(&err, "Invalid size %s", valuestr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
p->xbzrle_cache_size = cache_size;
|
|
|
|
break;
|
2017-08-24 10:46:01 +02:00
|
|
|
default:
|
|
|
|
assert(0);
|
2015-03-23 09:32:29 +01:00
|
|
|
}
|
|
|
|
|
2017-08-24 10:46:01 +02:00
|
|
|
if (err) {
|
|
|
|
goto cleanup;
|
2015-03-23 09:32:29 +01:00
|
|
|
}
|
|
|
|
|
2017-08-24 10:46:01 +02:00
|
|
|
qmp_migrate_set_parameters(p, &err);
|
|
|
|
|
2016-04-27 12:05:15 +02:00
|
|
|
cleanup:
|
migration: Unshare MigrationParameters struct for now
Commit de63ab6 "migrate: Share common MigrationParameters struct"
reused MigrationParameters for the arguments of
migrate-set-parameters, with the following rationale:
It is rather verbose, and slightly error-prone, to repeat
the same set of parameters for input (migrate-set-parameters)
as for output (query-migrate-parameters), where the only
difference is whether the members are optional. We can just
document that the optional members will always be present
on output, and then share a common struct between both
commands. The next patch can then reduce the amount of
code needed on input.
I need to unshare them to correct a design flaw in a stupid, but
minimally invasive way, in the next commit. We can restore the
sharing when we redo that patch in a less stupid way. Add a suitable
TODO comment.
Note that I revert only the sharing part of commit de63ab6, not the
part that made the members of query-migrate-parameters' result
optional. The schema (and thus introspection) remains inaccurate for
query-migrate-parameters. If we decide not to restore the sharing, we
should revert that part, too.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2017-07-18 13:42:11 +02:00
|
|
|
qapi_free_MigrateSetParameters(p);
|
2017-05-16 11:37:45 +02:00
|
|
|
visit_free(v);
|
2017-10-19 13:16:33 +02:00
|
|
|
hmp_handle_error(mon, &err);
|
2015-03-23 09:32:29 +01:00
|
|
|
}
|
|
|
|
|
2015-03-05 17:29:02 +01:00
|
|
|
void hmp_client_migrate_info(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
const char *protocol = qdict_get_str(qdict, "protocol");
|
|
|
|
const char *hostname = qdict_get_str(qdict, "hostname");
|
|
|
|
bool has_port = qdict_haskey(qdict, "port");
|
|
|
|
int port = qdict_get_try_int(qdict, "port", -1);
|
|
|
|
bool has_tls_port = qdict_haskey(qdict, "tls-port");
|
|
|
|
int tls_port = qdict_get_try_int(qdict, "tls-port", -1);
|
|
|
|
const char *cert_subject = qdict_get_try_str(qdict, "cert-subject");
|
|
|
|
|
|
|
|
qmp_client_migrate_info(protocol, hostname,
|
|
|
|
has_port, port, has_tls_port, tls_port,
|
|
|
|
!!cert_subject, cert_subject, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
|
|
|
|
2015-11-05 19:10:56 +01:00
|
|
|
void hmp_migrate_start_postcopy(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
qmp_migrate_start_postcopy(&err);
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
|
|
|
|
COLO: Add 'x-colo-lost-heartbeat' command to trigger failover
We leave users to choose whatever heartbeat solution they want,
if the heartbeat is lost, or other errors they detect, they can use
experimental command 'x_colo_lost_heartbeat' to tell COLO to do failover,
COLO will do operations accordingly.
For example, if the command is sent to the Primary side,
the Primary side will exit COLO mode, does cleanup work,
and then, PVM will take over the service work. If sent to the Secondary side,
the Secondary side will run failover work, then takes over PVM's service work.
Cc: Luiz Capitulino <lcapitulino@redhat.com>
Cc: Eric Blake <eblake@redhat.com>
Cc: Markus Armbruster <armbru@redhat.com>
Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com>
Signed-off-by: Li Zhijian <lizhijian@cn.fujitsu.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: Amit Shah <amit.shah@redhat.com>
Signed-off-by: Amit Shah <amit@amitshah.net>
2016-10-27 08:43:03 +02:00
|
|
|
void hmp_x_colo_lost_heartbeat(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_x_colo_lost_heartbeat(&err);
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
|
|
|
|
2011-12-07 14:17:51 +01:00
|
|
|
void hmp_set_password(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *protocol = qdict_get_str(qdict, "protocol");
|
|
|
|
const char *password = qdict_get_str(qdict, "password");
|
|
|
|
const char *connected = qdict_get_try_str(qdict, "connected");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_set_password(protocol, password, !!connected, connected, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2011-12-07 14:47:57 +01:00
|
|
|
|
|
|
|
void hmp_expire_password(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *protocol = qdict_get_str(qdict, "protocol");
|
|
|
|
const char *whenstr = qdict_get_str(qdict, "time");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_expire_password(protocol, whenstr, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2011-12-07 19:02:36 +01:00
|
|
|
|
|
|
|
void hmp_eject(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2015-05-16 00:25:00 +02:00
|
|
|
bool force = qdict_get_try_bool(qdict, "force", false);
|
2011-12-07 19:02:36 +01:00
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
2016-09-20 13:38:46 +02:00
|
|
|
qmp_eject(true, device, false, NULL, true, force, &err);
|
2011-12-07 19:02:36 +01:00
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2011-12-08 14:13:50 +01:00
|
|
|
|
2013-11-14 11:54:14 +01:00
|
|
|
static void hmp_change_read_arg(void *opaque, const char *password,
|
|
|
|
void *readline_opaque)
|
2011-12-08 14:13:50 +01:00
|
|
|
{
|
|
|
|
qmp_change_vnc_password(password, NULL);
|
2013-11-14 11:54:14 +01:00
|
|
|
monitor_read_command(opaque, 1);
|
2011-12-08 14:13:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_change(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
const char *target = qdict_get_str(qdict, "target");
|
|
|
|
const char *arg = qdict_get_try_str(qdict, "arg");
|
2015-10-26 21:39:18 +01:00
|
|
|
const char *read_only = qdict_get_try_str(qdict, "read-only-mode");
|
|
|
|
BlockdevChangeReadOnlyMode read_only_mode = 0;
|
2011-12-08 14:13:50 +01:00
|
|
|
Error *err = NULL;
|
|
|
|
|
2015-10-26 21:39:16 +01:00
|
|
|
if (strcmp(device, "vnc") == 0) {
|
2015-10-26 21:39:18 +01:00
|
|
|
if (read_only) {
|
|
|
|
monitor_printf(mon,
|
|
|
|
"Parameter 'read-only-mode' is invalid for VNC\n");
|
|
|
|
return;
|
|
|
|
}
|
2015-10-26 21:39:16 +01:00
|
|
|
if (strcmp(target, "passwd") == 0 ||
|
|
|
|
strcmp(target, "password") == 0) {
|
|
|
|
if (!arg) {
|
|
|
|
monitor_read_password(mon, hmp_change_read_arg, NULL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
qmp_change("vnc", target, !!arg, arg, &err);
|
|
|
|
} else {
|
2015-10-26 21:39:18 +01:00
|
|
|
if (read_only) {
|
|
|
|
read_only_mode =
|
2017-08-24 10:46:10 +02:00
|
|
|
qapi_enum_parse(&BlockdevChangeReadOnlyMode_lookup,
|
2017-08-24 10:45:57 +02:00
|
|
|
read_only,
|
2015-10-26 21:39:18 +01:00
|
|
|
BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN, &err);
|
|
|
|
if (err) {
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-20 13:38:47 +02:00
|
|
|
qmp_blockdev_change_medium(true, device, false, NULL, target,
|
|
|
|
!!arg, arg, !!read_only, read_only_mode,
|
|
|
|
&err);
|
2011-12-08 14:13:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2011-12-14 19:49:14 +01:00
|
|
|
|
|
|
|
void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
2018-03-09 15:11:07 +01:00
|
|
|
char *device = (char *) qdict_get_str(qdict, "device");
|
2016-07-14 05:50:21 +02:00
|
|
|
BlockIOThrottle throttle = {
|
|
|
|
.bps = qdict_get_int(qdict, "bps"),
|
|
|
|
.bps_rd = qdict_get_int(qdict, "bps_rd"),
|
|
|
|
.bps_wr = qdict_get_int(qdict, "bps_wr"),
|
|
|
|
.iops = qdict_get_int(qdict, "iops"),
|
|
|
|
.iops_rd = qdict_get_int(qdict, "iops_rd"),
|
|
|
|
.iops_wr = qdict_get_int(qdict, "iops_wr"),
|
|
|
|
};
|
2011-12-14 19:49:14 +01:00
|
|
|
|
2018-03-09 15:11:07 +01:00
|
|
|
/* qmp_block_set_io_throttle has separate parameters for the
|
|
|
|
* (deprecated) block device name and the qdev ID but the HMP
|
|
|
|
* version has only one, so we must decide which one to pass. */
|
|
|
|
if (blk_by_name(device)) {
|
|
|
|
throttle.has_device = true;
|
|
|
|
throttle.device = device;
|
|
|
|
} else {
|
|
|
|
throttle.has_id = true;
|
|
|
|
throttle.id = device;
|
|
|
|
}
|
|
|
|
|
2016-07-14 05:50:21 +02:00
|
|
|
qmp_block_set_io_throttle(&throttle, &err);
|
2011-12-14 19:49:14 +01:00
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2012-01-18 15:40:46 +01:00
|
|
|
|
|
|
|
void hmp_block_stream(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *error = NULL;
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
const char *base = qdict_get_try_str(qdict, "base");
|
2012-04-25 17:51:03 +02:00
|
|
|
int64_t speed = qdict_get_try_int(qdict, "speed", 0);
|
2012-01-18 15:40:46 +01:00
|
|
|
|
2016-11-04 14:44:43 +01:00
|
|
|
qmp_block_stream(true, device, device, base != NULL, base, false, NULL,
|
2016-10-28 09:08:19 +02:00
|
|
|
false, NULL, qdict_haskey(qdict, "speed"), speed,
|
2013-09-17 18:10:47 +02:00
|
|
|
true, BLOCKDEV_ON_ERROR_REPORT, &error);
|
2012-01-18 15:40:46 +01:00
|
|
|
|
|
|
|
hmp_handle_error(mon, &error);
|
|
|
|
}
|
2012-01-18 15:40:47 +01:00
|
|
|
|
|
|
|
void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *error = NULL;
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
2012-05-08 16:51:56 +02:00
|
|
|
int64_t value = qdict_get_int(qdict, "speed");
|
2012-01-18 15:40:47 +01:00
|
|
|
|
|
|
|
qmp_block_job_set_speed(device, value, &error);
|
|
|
|
|
|
|
|
hmp_handle_error(mon, &error);
|
|
|
|
}
|
2012-01-18 15:40:48 +01:00
|
|
|
|
|
|
|
void hmp_block_job_cancel(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *error = NULL;
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
2015-05-16 00:25:00 +02:00
|
|
|
bool force = qdict_get_try_bool(qdict, "force", false);
|
2012-01-18 15:40:48 +01:00
|
|
|
|
2012-09-28 17:22:51 +02:00
|
|
|
qmp_block_job_cancel(device, true, force, &error);
|
|
|
|
|
|
|
|
hmp_handle_error(mon, &error);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_block_job_pause(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *error = NULL;
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
|
|
|
|
qmp_block_job_pause(device, &error);
|
|
|
|
|
|
|
|
hmp_handle_error(mon, &error);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_block_job_resume(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *error = NULL;
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
|
|
|
|
qmp_block_job_resume(device, &error);
|
2012-01-18 15:40:48 +01:00
|
|
|
|
|
|
|
hmp_handle_error(mon, &error);
|
|
|
|
}
|
2011-12-05 17:48:01 +01:00
|
|
|
|
2012-10-18 16:49:21 +02:00
|
|
|
void hmp_block_job_complete(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *error = NULL;
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
|
|
|
|
|
|
|
qmp_block_job_complete(device, &error);
|
|
|
|
|
|
|
|
hmp_handle_error(mon, &error);
|
|
|
|
}
|
|
|
|
|
2015-03-13 09:08:39 +01:00
|
|
|
typedef struct HMPMigrationStatus
|
2011-12-05 17:48:01 +01:00
|
|
|
{
|
|
|
|
QEMUTimer *timer;
|
|
|
|
Monitor *mon;
|
|
|
|
bool is_block_migration;
|
2015-03-13 09:08:39 +01:00
|
|
|
} HMPMigrationStatus;
|
2011-12-05 17:48:01 +01:00
|
|
|
|
|
|
|
static void hmp_migrate_status_cb(void *opaque)
|
|
|
|
{
|
2015-03-13 09:08:39 +01:00
|
|
|
HMPMigrationStatus *status = opaque;
|
2011-12-05 17:48:01 +01:00
|
|
|
MigrationInfo *info;
|
|
|
|
|
|
|
|
info = qmp_query_migrate(NULL);
|
2015-03-13 09:08:40 +01:00
|
|
|
if (!info->has_status || info->status == MIGRATION_STATUS_ACTIVE ||
|
|
|
|
info->status == MIGRATION_STATUS_SETUP) {
|
2011-12-05 17:48:01 +01:00
|
|
|
if (info->has_disk) {
|
|
|
|
int progress;
|
|
|
|
|
|
|
|
if (info->disk->remaining) {
|
|
|
|
progress = info->disk->transferred * 100 / info->disk->total;
|
|
|
|
} else {
|
|
|
|
progress = 100;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(status->mon, "Completed %d %%\r", progress);
|
|
|
|
monitor_flush(status->mon);
|
|
|
|
}
|
|
|
|
|
2013-08-21 17:03:08 +02:00
|
|
|
timer_mod(status->timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
|
2011-12-05 17:48:01 +01:00
|
|
|
} else {
|
|
|
|
if (status->is_block_migration) {
|
|
|
|
monitor_printf(status->mon, "\n");
|
|
|
|
}
|
migration: add reporting of errors for outgoing migration
Currently if an application initiates an outgoing migration,
it may or may not, get an error reported back on failure. If
the error occurs synchronously to the 'migrate' command
execution, the client app will see the error message. This
is the case for DNS lookup failures. If the error occurs
asynchronously to the monitor command though, the error
will be thrown away and the client left guessing about
what went wrong. This is the case for failure to connect
to the TCP server (eg due to wrong port, or firewall
rules, or other similar errors).
In the future we'll be adding more scope for errors to
happen asynchronously with the TLS protocol handshake.
TLS errors are hard to diagnose even when they are well
reported, so discarding errors entirely will make it
impossible to debug TLS connection problems.
Management apps which do migration are already using
'query-migrate' / 'info migrate' to check up on progress
of background migration operations and to see their end
status. This is a fine place to also include the error
message when things go wrong.
This patch thus adds an 'error-desc' field to the
MigrationInfo struct, which will be populated when
the 'status' is set to 'failed':
(qemu) migrate -d tcp:localhost:9001
(qemu) info migrate
capabilities: xbzrle: off rdma-pin-all: off auto-converge: off zero-blocks: off compress: off events: off x-postcopy-ram: off
Migration status: failed (Error connecting to socket: Connection refused)
total time: 0 milliseconds
In the HMP, when doing non-detached migration, it is
also possible to display this error message directly
to the app.
(qemu) migrate tcp:localhost:9001
Error connecting to socket: Connection refused
Or with QMP
{
"execute": "query-migrate",
"arguments": {}
}
{
"return": {
"status": "failed",
"error-desc": "address resolution failed for myhost:9000: No address associated with hostname"
}
}
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Message-Id: <1461751518-12128-11-git-send-email-berrange@redhat.com>
Signed-off-by: Amit Shah <amit.shah@redhat.com>
2016-04-27 12:05:00 +02:00
|
|
|
if (info->has_error_desc) {
|
|
|
|
error_report("%s", info->error_desc);
|
|
|
|
}
|
2011-12-05 17:48:01 +01:00
|
|
|
monitor_resume(status->mon);
|
2013-08-21 17:03:08 +02:00
|
|
|
timer_del(status->timer);
|
2011-12-05 17:48:01 +01:00
|
|
|
g_free(status);
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_MigrationInfo(info);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_migrate(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2015-05-16 00:25:00 +02:00
|
|
|
bool detach = qdict_get_try_bool(qdict, "detach", false);
|
|
|
|
bool blk = qdict_get_try_bool(qdict, "blk", false);
|
|
|
|
bool inc = qdict_get_try_bool(qdict, "inc", false);
|
2011-12-05 17:48:01 +01:00
|
|
|
const char *uri = qdict_get_str(qdict, "uri");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_migrate(uri, !!blk, blk, !!inc, inc, false, false, &err);
|
|
|
|
if (err) {
|
2017-10-19 13:16:33 +02:00
|
|
|
hmp_handle_error(mon, &err);
|
2011-12-05 17:48:01 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!detach) {
|
2015-03-13 09:08:39 +01:00
|
|
|
HMPMigrationStatus *status;
|
2011-12-05 17:48:01 +01:00
|
|
|
|
|
|
|
if (monitor_suspend(mon) < 0) {
|
|
|
|
monitor_printf(mon, "terminal does not allow synchronous "
|
|
|
|
"migration, continuing detached\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
status = g_malloc0(sizeof(*status));
|
|
|
|
status->mon = mon;
|
|
|
|
status->is_block_migration = blk || inc;
|
2013-08-21 17:03:08 +02:00
|
|
|
status->timer = timer_new_ms(QEMU_CLOCK_REALTIME, hmp_migrate_status_cb,
|
2011-12-05 17:48:01 +01:00
|
|
|
status);
|
2013-08-21 17:03:08 +02:00
|
|
|
timer_mod(status->timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
|
2011-12-05 17:48:01 +01:00
|
|
|
}
|
|
|
|
}
|
2012-03-29 17:38:50 +02:00
|
|
|
|
2015-03-05 17:24:48 +01:00
|
|
|
void hmp_device_add(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
qmp: Wean off qerror_report()
The traditional QMP command handler interface
int qmp_FOO(Monitor *mon, const QDict *params, QObject **ret_data);
doesn't provide for returning an Error object. Instead, the handler
is expected to stash it in the monitor with qerror_report().
When we rebased QMP on top of QAPI, we didn't change this interface.
Instead, commit 776574d introduced "middle mode" as a temporary aid
for converting existing QMP commands to QAPI one by one. More than
three years later, we're still using it.
Middle mode has two effects:
* Instead of the native input marshallers
static void qmp_marshal_input_FOO(QDict *, QObject **, Error **)
it generates input marshallers conforming to the traditional QMP
command handler interface.
* It suppresses generation of code to register them with
qmp_register_command()
This permits giving them internal linkage.
As long as we need qmp-commands.hx, we can't use the registry behind
qmp_register_command(), so the latter has to stay for now.
The former has to go to get rid of qerror_report(). Changing all QMP
commands to fit the QAPI mold in one go was impractical back when we
started, but by now there are just a few stragglers left:
do_qmp_capabilities(), qmp_qom_set(), qmp_qom_get(), qmp_object_add(),
qmp_netdev_add(), do_device_add().
Switch middle mode to generate native input marshallers, and adapt the
stragglers. Simplifies both the monitor code and the stragglers.
Rename do_qmp_capabilities() to qmp_capabilities(), and
do_device_add() to qmp_device_add, because that's how QMP command
handlers are named today.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Luiz Capitulino <lcapitulino@redhat.com>
2015-03-13 17:25:50 +01:00
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_device_add((QDict *)qdict, NULL, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2015-03-05 17:24:48 +01:00
|
|
|
}
|
|
|
|
|
2012-03-29 17:38:50 +02:00
|
|
|
void hmp_device_del(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *id = qdict_get_str(qdict, "id");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_device_del(id, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2012-05-07 06:10:47 +02:00
|
|
|
|
|
|
|
void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2015-05-16 00:25:00 +02:00
|
|
|
bool paging = qdict_get_try_bool(qdict, "paging", false);
|
|
|
|
bool zlib = qdict_get_try_bool(qdict, "zlib", false);
|
|
|
|
bool lzo = qdict_get_try_bool(qdict, "lzo", false);
|
|
|
|
bool snappy = qdict_get_try_bool(qdict, "snappy", false);
|
2012-09-21 18:53:00 +02:00
|
|
|
const char *file = qdict_get_str(qdict, "filename");
|
2012-05-07 06:10:47 +02:00
|
|
|
bool has_begin = qdict_haskey(qdict, "begin");
|
|
|
|
bool has_length = qdict_haskey(qdict, "length");
|
2016-02-18 06:16:47 +01:00
|
|
|
bool has_detach = qdict_haskey(qdict, "detach");
|
2012-05-07 06:10:47 +02:00
|
|
|
int64_t begin = 0;
|
|
|
|
int64_t length = 0;
|
2016-02-18 06:16:47 +01:00
|
|
|
bool detach = false;
|
2014-02-18 07:11:36 +01:00
|
|
|
enum DumpGuestMemoryFormat dump_format = DUMP_GUEST_MEMORY_FORMAT_ELF;
|
2012-09-21 18:53:00 +02:00
|
|
|
char *prot;
|
2012-05-07 06:10:47 +02:00
|
|
|
|
2014-04-17 10:15:07 +02:00
|
|
|
if (zlib + lzo + snappy > 1) {
|
2014-05-02 13:26:29 +02:00
|
|
|
error_setg(&err, "only one of '-z|-l|-s' can be set");
|
|
|
|
hmp_handle_error(mon, &err);
|
2014-04-17 10:15:07 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (zlib) {
|
|
|
|
dump_format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_ZLIB;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lzo) {
|
|
|
|
dump_format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_LZO;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (snappy) {
|
|
|
|
dump_format = DUMP_GUEST_MEMORY_FORMAT_KDUMP_SNAPPY;
|
|
|
|
}
|
|
|
|
|
2012-05-07 06:10:47 +02:00
|
|
|
if (has_begin) {
|
|
|
|
begin = qdict_get_int(qdict, "begin");
|
|
|
|
}
|
|
|
|
if (has_length) {
|
|
|
|
length = qdict_get_int(qdict, "length");
|
|
|
|
}
|
2016-02-18 06:16:47 +01:00
|
|
|
if (has_detach) {
|
|
|
|
detach = qdict_get_bool(qdict, "detach");
|
|
|
|
}
|
2012-05-07 06:10:47 +02:00
|
|
|
|
2012-09-21 18:53:00 +02:00
|
|
|
prot = g_strconcat("file:", file, NULL);
|
|
|
|
|
2016-02-18 06:16:47 +01:00
|
|
|
qmp_dump_guest_memory(paging, prot, true, detach, has_begin, begin,
|
|
|
|
has_length, length, true, dump_format, &err);
|
2014-05-02 13:26:29 +02:00
|
|
|
hmp_handle_error(mon, &err);
|
2012-09-21 18:53:00 +02:00
|
|
|
g_free(prot);
|
2012-05-07 06:10:47 +02:00
|
|
|
}
|
2012-04-18 22:34:15 +02:00
|
|
|
|
|
|
|
void hmp_netdev_add(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
QemuOpts *opts;
|
|
|
|
|
|
|
|
opts = qemu_opts_from_qdict(qemu_find_opts("netdev"), qdict, &err);
|
2014-01-30 15:07:28 +01:00
|
|
|
if (err) {
|
2012-04-18 22:34:15 +02:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
netdev_add(opts, &err);
|
2014-01-30 15:07:28 +01:00
|
|
|
if (err) {
|
2012-04-18 22:34:15 +02:00
|
|
|
qemu_opts_del(opts);
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2012-04-16 19:36:32 +02:00
|
|
|
|
|
|
|
void hmp_netdev_del(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *id = qdict_get_str(qdict, "id");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qmp_netdev_del(id, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2012-06-22 20:36:09 +02:00
|
|
|
|
2013-12-20 23:21:10 +01:00
|
|
|
void hmp_object_add(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
QemuOpts *opts;
|
2016-02-10 19:40:59 +01:00
|
|
|
Object *obj = NULL;
|
2013-12-20 23:21:10 +01:00
|
|
|
|
|
|
|
opts = qemu_opts_from_qdict(qemu_find_opts("object"), qdict, &err);
|
|
|
|
if (err) {
|
2016-02-10 19:40:59 +01:00
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
return;
|
2013-12-20 23:21:10 +01:00
|
|
|
}
|
|
|
|
|
2017-01-10 13:53:14 +01:00
|
|
|
obj = user_creatable_add_opts(opts, &err);
|
2016-02-10 19:40:59 +01:00
|
|
|
qemu_opts_del(opts);
|
2013-12-20 23:21:10 +01:00
|
|
|
|
|
|
|
if (err) {
|
2016-02-10 19:40:59 +01:00
|
|
|
hmp_handle_error(mon, &err);
|
2013-12-20 23:21:10 +01:00
|
|
|
}
|
2016-02-10 19:40:59 +01:00
|
|
|
if (obj) {
|
|
|
|
object_unref(obj);
|
2013-12-20 23:21:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-22 20:36:09 +02:00
|
|
|
void hmp_getfd(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *fdname = qdict_get_str(qdict, "fdname");
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2012-06-22 20:36:09 +02:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_getfd(fdname, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2012-06-22 20:36:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_closefd(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *fdname = qdict_get_str(qdict, "fdname");
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2012-06-22 20:36:09 +02:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_closefd(fdname, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2012-06-22 20:36:09 +02:00
|
|
|
}
|
2012-08-31 04:56:26 +02:00
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 13:55:43 +01:00
|
|
|
void hmp_sendkey(Monitor *mon, const QDict *qdict)
|
2012-08-31 04:56:26 +02:00
|
|
|
{
|
|
|
|
const char *keys = qdict_get_str(qdict, "keys");
|
2012-09-20 19:19:47 +02:00
|
|
|
KeyValueList *keylist, *head = NULL, *tmp = NULL;
|
2012-08-31 04:56:26 +02:00
|
|
|
int has_hold_time = qdict_haskey(qdict, "hold-time");
|
|
|
|
int hold_time = qdict_get_try_int(qdict, "hold-time", -1);
|
|
|
|
Error *err = NULL;
|
|
|
|
char *separator;
|
2012-09-20 19:19:47 +02:00
|
|
|
int keyname_len;
|
2012-08-31 04:56:26 +02:00
|
|
|
|
|
|
|
while (1) {
|
|
|
|
separator = strchr(keys, '-');
|
|
|
|
keyname_len = separator ? separator - keys : strlen(keys);
|
|
|
|
|
|
|
|
/* Be compatible with old interface, convert user inputted "<" */
|
2016-01-13 09:09:58 +01:00
|
|
|
if (keys[0] == '<' && keyname_len == 1) {
|
|
|
|
keys = "less";
|
2012-08-31 04:56:26 +02:00
|
|
|
keyname_len = 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
keylist = g_malloc0(sizeof(*keylist));
|
2012-09-20 19:19:47 +02:00
|
|
|
keylist->value = g_malloc0(sizeof(*keylist->value));
|
2012-08-31 04:56:26 +02:00
|
|
|
|
|
|
|
if (!head) {
|
|
|
|
head = keylist;
|
|
|
|
}
|
|
|
|
if (tmp) {
|
|
|
|
tmp->next = keylist;
|
|
|
|
}
|
|
|
|
tmp = keylist;
|
|
|
|
|
2016-01-13 09:09:58 +01:00
|
|
|
if (strstart(keys, "0x", NULL)) {
|
2012-09-20 19:19:47 +02:00
|
|
|
char *endp;
|
2016-01-13 09:09:58 +01:00
|
|
|
int value = strtoul(keys, &endp, 0);
|
|
|
|
assert(endp <= keys + keyname_len);
|
|
|
|
if (endp != keys + keyname_len) {
|
2012-09-20 19:19:47 +02:00
|
|
|
goto err_out;
|
|
|
|
}
|
2015-10-26 23:34:58 +01:00
|
|
|
keylist->value->type = KEY_VALUE_KIND_NUMBER;
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-17 23:48:37 +01:00
|
|
|
keylist->value->u.number.data = value;
|
2012-09-20 19:19:47 +02:00
|
|
|
} else {
|
2016-01-13 09:09:58 +01:00
|
|
|
int idx = index_from_key(keys, keyname_len);
|
qapi: Don't let implicit enum MAX member collide
Now that we guarantee the user doesn't have any enum values
beginning with a single underscore, we can use that for our
own purposes. Renaming ENUM_MAX to ENUM__MAX makes it obvious
that the sentinel is generated.
This patch was mostly generated by applying a temporary patch:
|diff --git a/scripts/qapi.py b/scripts/qapi.py
|index e6d014b..b862ec9 100644
|--- a/scripts/qapi.py
|+++ b/scripts/qapi.py
|@@ -1570,6 +1570,7 @@ const char *const %(c_name)s_lookup[] = {
| max_index = c_enum_const(name, 'MAX', prefix)
| ret += mcgen('''
| [%(max_index)s] = NULL,
|+// %(max_index)s
| };
| ''',
| max_index=max_index)
then running:
$ cat qapi-{types,event}.c tests/test-qapi-types.c |
sed -n 's,^// \(.*\)MAX,s|\1MAX|\1_MAX|g,p' > list
$ git grep -l _MAX | xargs sed -i -f list
The only things not generated are the changes in scripts/qapi.py.
Rejecting enum members named 'MAX' is now useless, and will be dropped
in the next patch.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-23-git-send-email-eblake@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
[Rebased to current master, commit message tweaked]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-11-18 09:52:57 +01:00
|
|
|
if (idx == Q_KEY_CODE__MAX) {
|
2012-09-20 19:19:47 +02:00
|
|
|
goto err_out;
|
|
|
|
}
|
2015-10-26 23:34:58 +01:00
|
|
|
keylist->value->type = KEY_VALUE_KIND_QCODE;
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-17 23:48:37 +01:00
|
|
|
keylist->value->u.qcode.data = idx;
|
2012-09-20 19:19:47 +02:00
|
|
|
}
|
|
|
|
|
2012-08-31 04:56:26 +02:00
|
|
|
if (!separator) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
keys = separator + 1;
|
|
|
|
}
|
|
|
|
|
2012-09-20 19:19:47 +02:00
|
|
|
qmp_send_key(head, has_hold_time, hold_time, &err);
|
2012-08-31 04:56:26 +02:00
|
|
|
hmp_handle_error(mon, &err);
|
2012-09-20 19:19:47 +02:00
|
|
|
|
|
|
|
out:
|
|
|
|
qapi_free_KeyValueList(head);
|
|
|
|
return;
|
|
|
|
|
|
|
|
err_out:
|
2016-01-13 09:09:58 +01:00
|
|
|
monitor_printf(mon, "invalid parameter: %.*s\n", keyname_len, keys);
|
2012-09-20 19:19:47 +02:00
|
|
|
goto out;
|
2012-08-31 04:56:26 +02:00
|
|
|
}
|
2012-05-24 18:48:23 +02:00
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 13:55:43 +01:00
|
|
|
void hmp_screendump(Monitor *mon, const QDict *qdict)
|
2012-05-24 18:48:23 +02:00
|
|
|
{
|
|
|
|
const char *filename = qdict_get_str(qdict, "filename");
|
2018-03-05 17:37:48 +01:00
|
|
|
const char *id = qdict_get_try_str(qdict, "device");
|
|
|
|
int64_t head = qdict_get_try_int(qdict, "head", 0);
|
2012-05-24 18:48:23 +02:00
|
|
|
Error *err = NULL;
|
|
|
|
|
2018-03-05 17:37:48 +01:00
|
|
|
qmp_screendump(filename, id != NULL, id, id != NULL, head, &err);
|
2012-05-24 18:48:23 +02:00
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2012-08-23 11:53:04 +02:00
|
|
|
|
|
|
|
void hmp_nbd_server_start(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *uri = qdict_get_str(qdict, "uri");
|
2015-05-16 00:25:00 +02:00
|
|
|
bool writable = qdict_get_try_bool(qdict, "writable", false);
|
|
|
|
bool all = qdict_get_try_bool(qdict, "all", false);
|
2012-08-23 11:53:04 +02:00
|
|
|
Error *local_err = NULL;
|
|
|
|
BlockInfoList *block_list, *info;
|
2017-04-26 09:36:41 +02:00
|
|
|
SocketAddress *addr;
|
2012-08-23 11:53:04 +02:00
|
|
|
|
|
|
|
if (writable && !all) {
|
|
|
|
error_setg(&local_err, "-w only valid together with -a");
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* First check if the address is valid and start the server. */
|
|
|
|
addr = socket_parse(uri, &local_err);
|
|
|
|
if (local_err != NULL) {
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
2017-04-26 09:36:41 +02:00
|
|
|
nbd_server_start(addr, NULL, &local_err);
|
|
|
|
qapi_free_SocketAddress(addr);
|
2012-08-23 11:53:04 +02:00
|
|
|
if (local_err != NULL) {
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!all) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then try adding all block devices. If one fails, close all and
|
|
|
|
* exit.
|
|
|
|
*/
|
|
|
|
block_list = qmp_query_block(NULL);
|
|
|
|
|
|
|
|
for (info = block_list; info; info = info->next) {
|
|
|
|
if (!info->value->has_inserted) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-01-19 14:57:15 +01:00
|
|
|
qmp_nbd_server_add(info->value->device, false, NULL,
|
|
|
|
true, writable, &local_err);
|
2012-08-23 11:53:04 +02:00
|
|
|
|
|
|
|
if (local_err != NULL) {
|
|
|
|
qmp_nbd_server_stop(NULL);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_BlockInfoList(block_list);
|
|
|
|
|
|
|
|
exit:
|
|
|
|
hmp_handle_error(mon, &local_err);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_nbd_server_add(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *device = qdict_get_str(qdict, "device");
|
2018-01-09 20:28:02 +01:00
|
|
|
const char *name = qdict_get_try_str(qdict, "name");
|
2015-05-16 00:25:00 +02:00
|
|
|
bool writable = qdict_get_try_bool(qdict, "writable", false);
|
2012-08-23 11:53:04 +02:00
|
|
|
Error *local_err = NULL;
|
|
|
|
|
2018-01-09 20:28:02 +01:00
|
|
|
qmp_nbd_server_add(device, !!name, name, true, writable, &local_err);
|
2018-01-25 15:45:57 +01:00
|
|
|
hmp_handle_error(mon, &local_err);
|
|
|
|
}
|
2012-08-23 11:53:04 +02:00
|
|
|
|
2018-01-25 15:45:57 +01:00
|
|
|
void hmp_nbd_server_remove(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *name = qdict_get_str(qdict, "name");
|
|
|
|
bool force = qdict_get_try_bool(qdict, "force", false);
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
/* Rely on NBD_SERVER_REMOVE_MODE_SAFE being the default */
|
|
|
|
qmp_nbd_server_remove(name, force, NBD_SERVER_REMOVE_MODE_HARD, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2012-08-23 11:53:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2014-05-02 13:26:29 +02:00
|
|
|
Error *err = NULL;
|
2012-08-23 11:53:04 +02:00
|
|
|
|
2014-05-02 13:26:29 +02:00
|
|
|
qmp_nbd_server_stop(&err);
|
|
|
|
hmp_handle_error(mon, &err);
|
2012-08-23 11:53:04 +02:00
|
|
|
}
|
2012-12-19 10:33:40 +01:00
|
|
|
|
2013-12-11 19:24:14 +01:00
|
|
|
void hmp_cpu_add(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
int cpuid;
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
cpuid = qdict_get_int(qdict, "id");
|
|
|
|
qmp_cpu_add(cpuid, &err);
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
|
|
|
|
2012-12-19 10:33:40 +01:00
|
|
|
void hmp_chardev_add(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *args = qdict_get_str(qdict, "args");
|
|
|
|
Error *err = NULL;
|
|
|
|
QemuOpts *opts;
|
|
|
|
|
QemuOpts: Wean off qerror_report_err()
qerror_report_err() is a transitional interface to help with
converting existing monitor commands to QMP. It should not be used
elsewhere.
The only remaining user in qemu-option.c is qemu_opts_parse(). Is it
used in QMP context? If not, we can simply replace
qerror_report_err() by error_report_err().
The uses in qemu-img.c, qemu-io.c, qemu-nbd.c and under tests/ are
clearly not in QMP context.
The uses in vl.c aren't either, because the only QMP command handlers
there are qmp_query_status() and qmp_query_machines(), and they don't
call it.
Remaining uses:
* drive_def(): Command line -drive and such, HMP drive_add and pci_add
* hmp_chardev_add(): HMP chardev-add
* monitor_parse_command(): HMP core
* tmp_config_parse(): Command line -tpmdev
* net_host_device_add(): HMP host_net_add
* net_client_parse(): Command line -net and -netdev
* qemu_global_option(): Command line -global
* vnc_parse_func(): Command line -display, -vnc, default display, HMP
change, QMP change. Bummer.
* qemu_pci_hot_add_nic(): HMP pci_add
* usb_net_init(): Command line -usbdevice, HMP usb_add
Propagate errors through qemu_opts_parse(). Create a convenience
function qemu_opts_parse_noisily() that passes errors to
error_report_err(). Switch all non-QMP users outside tests to it.
That leaves vnc_parse_func(). Propagate errors through it. Since I'm
touching it anyway, rename it to vnc_parse().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Luiz Capitulino <lcapitulino@redhat.com>
2015-02-13 12:50:26 +01:00
|
|
|
opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"), args, true);
|
2012-12-19 10:33:40 +01:00
|
|
|
if (opts == NULL) {
|
error: Strip trailing '\n' from error string arguments (again)
Commit 6daf194d and be62a2eb got rid of a bunch, but they keep coming
back. Tracked down with this Coccinelle semantic patch:
@r@
expression err, eno, cls, fmt;
position p;
@@
(
error_report(fmt, ...)@p
|
error_set(err, cls, fmt, ...)@p
|
error_set_errno(err, eno, cls, fmt, ...)@p
|
error_setg(err, fmt, ...)@p
|
error_setg_errno(err, eno, fmt, ...)@p
)
@script:python@
fmt << r.fmt;
p << r.p;
@@
if "\\n" in str(fmt):
print "%s:%s:%s:%s" % (p[0].file, p[0].line, p[0].column, fmt)
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-id: 1360354939-10994-4-git-send-email-armbru@redhat.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-02-08 21:22:16 +01:00
|
|
|
error_setg(&err, "Parsing chardev args failed");
|
2012-12-19 10:33:40 +01:00
|
|
|
} else {
|
2016-10-22 11:52:46 +02:00
|
|
|
qemu_chr_new_from_opts(opts, &err);
|
net: don't poke at chardev internal QemuOpts
The vhost-user & colo code is poking at the QemuOpts instance
in the CharDriverState struct, not realizing that it is valid
for this to be NULL. e.g. the following crash shows a codepath
where it will be NULL:
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x000055baf6ab4adc in qemu_opt_foreach (opts=0x0, func=0x55baf696b650 <net_vhost_chardev_opts>, opaque=0x7ffc51368c00, errp=0x7ffc51368e48) at util/qemu-option.c:617
617 QTAILQ_FOREACH(opt, &opts->head, next) {
[Current thread is 1 (Thread 0x7f1d4970bb40 (LWP 6603))]
(gdb) bt
#0 0x000055baf6ab4adc in qemu_opt_foreach (opts=0x0, func=0x55baf696b650 <net_vhost_chardev_opts>, opaque=0x7ffc51368c00, errp=0x7ffc51368e48) at util/qemu-option.c:617
#1 0x000055baf696b7da in net_vhost_parse_chardev (opts=0x55baf8ff9260, errp=0x7ffc51368e48) at net/vhost-user.c:314
#2 0x000055baf696b985 in net_init_vhost_user (netdev=0x55baf8ff9250, name=0x55baf879d270 "hostnet2", peer=0x0, errp=0x7ffc51368e48) at net/vhost-user.c:360
#3 0x000055baf6960216 in net_client_init1 (object=0x55baf8ff9250, is_netdev=true, errp=0x7ffc51368e48) at net/net.c:1051
#4 0x000055baf6960518 in net_client_init (opts=0x55baf776e7e0, is_netdev=true, errp=0x7ffc51368f00) at net/net.c:1108
#5 0x000055baf696083f in netdev_add (opts=0x55baf776e7e0, errp=0x7ffc51368f00) at net/net.c:1186
#6 0x000055baf69608c7 in qmp_netdev_add (qdict=0x55baf7afaf60, ret=0x7ffc51368f50, errp=0x7ffc51368f48) at net/net.c:1205
#7 0x000055baf6622135 in handle_qmp_command (parser=0x55baf77fb590, tokens=0x7f1d24011960) at /path/to/qemu.git/monitor.c:3978
#8 0x000055baf6a9d099 in json_message_process_token (lexer=0x55baf77fb598, input=0x55baf75acd20, type=JSON_RCURLY, x=113, y=19) at qobject/json-streamer.c:105
#9 0x000055baf6abf7aa in json_lexer_feed_char (lexer=0x55baf77fb598, ch=125 '}', flush=false) at qobject/json-lexer.c:319
#10 0x000055baf6abf8f2 in json_lexer_feed (lexer=0x55baf77fb598, buffer=0x7ffc51369170 "}R\204\367\272U", size=1) at qobject/json-lexer.c:369
#11 0x000055baf6a9d13c in json_message_parser_feed (parser=0x55baf77fb590, buffer=0x7ffc51369170 "}R\204\367\272U", size=1) at qobject/json-streamer.c:124
#12 0x000055baf66221f7 in monitor_qmp_read (opaque=0x55baf77fb530, buf=0x7ffc51369170 "}R\204\367\272U", size=1) at /path/to/qemu.git/monitor.c:3994
#13 0x000055baf6757014 in qemu_chr_be_write_impl (s=0x55baf7610a40, buf=0x7ffc51369170 "}R\204\367\272U", len=1) at qemu-char.c:387
#14 0x000055baf6757076 in qemu_chr_be_write (s=0x55baf7610a40, buf=0x7ffc51369170 "}R\204\367\272U", len=1) at qemu-char.c:399
#15 0x000055baf675b3b0 in tcp_chr_read (chan=0x55baf90244b0, cond=G_IO_IN, opaque=0x55baf7610a40) at qemu-char.c:2927
#16 0x000055baf6a5d655 in qio_channel_fd_source_dispatch (source=0x55baf7610df0, callback=0x55baf675b25a <tcp_chr_read>, user_data=0x55baf7610a40) at io/channel-watch.c:84
#17 0x00007f1d3e80cbbd in g_main_context_dispatch () from /usr/lib64/libglib-2.0.so.0
#18 0x000055baf69d3720 in glib_pollfds_poll () at main-loop.c:213
#19 0x000055baf69d37fd in os_host_main_loop_wait (timeout=126000000) at main-loop.c:258
#20 0x000055baf69d38ad in main_loop_wait (nonblocking=0) at main-loop.c:506
#21 0x000055baf676587b in main_loop () at vl.c:1908
#22 0x000055baf676d3bf in main (argc=101, argv=0x7ffc5136a6c8, envp=0x7ffc5136a9f8) at vl.c:4604
(gdb) p opts
$1 = (QemuOpts *) 0x0
The crash occurred when attaching vhost-user net via QMP:
{
"execute": "chardev-add",
"arguments": {
"id": "charnet2",
"backend": {
"type": "socket",
"data": {
"addr": {
"type": "unix",
"data": {
"path": "/var/run/openvswitch/vhost-user1"
}
},
"wait": false,
"server": false
}
}
},
"id": "libvirt-19"
}
{
"return": {
},
"id": "libvirt-19"
}
{
"execute": "netdev_add",
"arguments": {
"type": "vhost-user",
"chardev": "charnet2",
"id": "hostnet2"
},
"id": "libvirt-20"
}
Code using chardevs should not be poking at the internals of the
CharDriverState struct. What vhost-user wants is a chardev that is
operating as reconnectable network service, along with the ability
to do FD passing over the connection. The colo code simply wants
a network service. Add a feature concept to the char drivers so
that chardev users can query the actual features they wish to have
supported. The QemuOpts member is removed to prevent future mistakes
in this area.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-10-07 14:18:34 +02:00
|
|
|
qemu_opts_del(opts);
|
2012-12-19 10:33:40 +01:00
|
|
|
}
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
|
|
|
|
2017-07-06 14:08:57 +02:00
|
|
|
void hmp_chardev_change(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *args = qdict_get_str(qdict, "args");
|
|
|
|
const char *id;
|
|
|
|
Error *err = NULL;
|
|
|
|
ChardevBackend *backend = NULL;
|
|
|
|
ChardevReturn *ret = NULL;
|
|
|
|
QemuOpts *opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"), args,
|
|
|
|
true);
|
|
|
|
if (!opts) {
|
|
|
|
error_setg(&err, "Parsing chardev args failed");
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
id = qdict_get_str(qdict, "id");
|
|
|
|
if (qemu_opts_id(opts)) {
|
|
|
|
error_setg(&err, "Unexpected 'id' parameter");
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
backend = qemu_chr_parse_opts(opts, &err);
|
|
|
|
if (!backend) {
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = qmp_chardev_change(id, backend, &err);
|
|
|
|
|
|
|
|
end:
|
|
|
|
qapi_free_ChardevReturn(ret);
|
|
|
|
qapi_free_ChardevBackend(backend);
|
|
|
|
qemu_opts_del(opts);
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
|
|
|
|
2012-12-19 10:33:40 +01:00
|
|
|
void hmp_chardev_remove(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *local_err = NULL;
|
|
|
|
|
|
|
|
qmp_chardev_remove(qdict_get_str(qdict, "id"), &local_err);
|
|
|
|
hmp_handle_error(mon, &local_err);
|
|
|
|
}
|
2013-06-05 14:19:41 +02:00
|
|
|
|
2017-06-11 09:48:17 +02:00
|
|
|
void hmp_chardev_send_break(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *local_err = NULL;
|
|
|
|
|
|
|
|
qmp_chardev_send_break(qdict_get_str(qdict, "id"), &local_err);
|
|
|
|
hmp_handle_error(mon, &local_err);
|
|
|
|
}
|
|
|
|
|
2013-06-05 14:19:41 +02:00
|
|
|
void hmp_qemu_io(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2015-02-05 19:58:22 +01:00
|
|
|
BlockBackend *blk;
|
2016-07-13 17:27:51 +02:00
|
|
|
BlockBackend *local_blk = NULL;
|
2013-06-05 14:19:41 +02:00
|
|
|
const char* device = qdict_get_str(qdict, "device");
|
|
|
|
const char* command = qdict_get_str(qdict, "command");
|
|
|
|
Error *err = NULL;
|
2017-01-13 19:02:32 +01:00
|
|
|
int ret;
|
2013-06-05 14:19:41 +02:00
|
|
|
|
2015-02-05 19:58:22 +01:00
|
|
|
blk = blk_by_name(device);
|
2016-07-13 17:27:51 +02:00
|
|
|
if (!blk) {
|
|
|
|
BlockDriverState *bs = bdrv_lookup_bs(NULL, device, &err);
|
|
|
|
if (bs) {
|
2017-01-20 17:07:26 +01:00
|
|
|
blk = local_blk = blk_new(0, BLK_PERM_ALL);
|
2017-01-13 19:02:32 +01:00
|
|
|
ret = blk_insert_bs(blk, bs, &err);
|
|
|
|
if (ret < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
2016-07-13 17:27:51 +02:00
|
|
|
} else {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-10 16:24:56 +01:00
|
|
|
/*
|
|
|
|
* Notably absent: Proper permission management. This is sad, but it seems
|
|
|
|
* almost impossible to achieve without changing the semantics and thereby
|
|
|
|
* limiting the use cases of the qemu-io HMP command.
|
|
|
|
*
|
|
|
|
* In an ideal world we would unconditionally create a new BlockBackend for
|
|
|
|
* qemuio_command(), but we have commands like 'reopen' and want them to
|
|
|
|
* take effect on the exact BlockBackend whose name the user passed instead
|
|
|
|
* of just on a temporary copy of it.
|
|
|
|
*
|
|
|
|
* Another problem is that deleting the temporary BlockBackend involves
|
|
|
|
* draining all requests on it first, but some qemu-iotests cases want to
|
|
|
|
* issue multiple aio_read/write requests and expect them to complete in
|
|
|
|
* the background while the monitor has already returned.
|
|
|
|
*
|
|
|
|
* This is also what prevents us from saving the original permissions and
|
|
|
|
* restoring them later: We can't revoke permissions until all requests
|
|
|
|
* have completed, and we don't know when that is nor can we really let
|
|
|
|
* anything else run before we have revoken them to avoid race conditions.
|
|
|
|
*
|
|
|
|
* What happens now is that command() in qemu-io-cmds.c can extend the
|
|
|
|
* permissions if necessary for the qemu-io command. And they simply stay
|
|
|
|
* extended, possibly resulting in a read-only guest device keeping write
|
|
|
|
* permissions. Ugly, but it appears to be the lesser evil.
|
|
|
|
*/
|
2016-09-15 17:44:16 +02:00
|
|
|
qemuio_command(blk, command);
|
2013-06-05 14:19:41 +02:00
|
|
|
|
2016-07-13 17:27:51 +02:00
|
|
|
fail:
|
|
|
|
blk_unref(local_blk);
|
2013-06-05 14:19:41 +02:00
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2013-12-20 23:21:09 +01:00
|
|
|
|
|
|
|
void hmp_object_del(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *id = qdict_get_str(qdict, "id");
|
|
|
|
Error *err = NULL;
|
|
|
|
|
2016-02-10 19:40:59 +01:00
|
|
|
user_creatable_del(id, &err);
|
2013-12-20 23:21:09 +01:00
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2014-05-14 11:43:35 +02:00
|
|
|
|
|
|
|
void hmp_info_memdev(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
MemdevList *memdev_list = qmp_query_memdev(&err);
|
|
|
|
MemdevList *m = memdev_list;
|
qapi: Add new visit_complete() function
Making each output visitor provide its own output collection
function was the only remaining reason for exposing visitor
sub-types to the rest of the code base. Add a polymorphic
visit_complete() function which is a no-op for input visitors,
and which populates an opaque pointer for output visitors. For
maximum type-safety, also add a parameter to the output visitor
constructors with a type-correct version of the output pointer,
and assert that the two uses match.
This approach was considered superior to either passing the
output parameter only during construction (action at a distance
during visit_free() feels awkward) or only during visit_complete()
(defeating type safety makes it easier to use incorrectly).
Most callers were function-local, and therefore a mechanical
conversion; the testsuite was a bit trickier, but the previous
cleanup patch minimized the churn here.
The visit_complete() function may be called at most once; doing
so lets us use transfer semantics rather than duplication or
ref-count semantics to get the just-built output back to the
caller, even though it means our behavior is not idempotent.
Generated code is simplified as follows for events:
|@@ -26,7 +26,7 @@ void qapi_event_send_acpi_device_ost(ACP
| QDict *qmp;
| Error *err = NULL;
| QMPEventFuncEmit emit;
|- QmpOutputVisitor *qov;
|+ QObject *obj;
| Visitor *v;
| q_obj_ACPI_DEVICE_OST_arg param = {
| info
|@@ -39,8 +39,7 @@ void qapi_event_send_acpi_device_ost(ACP
|
| qmp = qmp_event_build_dict("ACPI_DEVICE_OST");
|
|- qov = qmp_output_visitor_new();
|- v = qmp_output_get_visitor(qov);
|+ v = qmp_output_visitor_new(&obj);
|
| visit_start_struct(v, "ACPI_DEVICE_OST", NULL, 0, &err);
| if (err) {
|@@ -55,7 +54,8 @@ void qapi_event_send_acpi_device_ost(ACP
| goto out;
| }
|
|- qdict_put_obj(qmp, "data", qmp_output_get_qobject(qov));
|+ visit_complete(v, &obj);
|+ qdict_put_obj(qmp, "data", obj);
| emit(QAPI_EVENT_ACPI_DEVICE_OST, qmp, &err);
and for commands:
| {
| Error *err = NULL;
|- QmpOutputVisitor *qov = qmp_output_visitor_new();
| Visitor *v;
|
|- v = qmp_output_get_visitor(qov);
|+ v = qmp_output_visitor_new(ret_out);
| visit_type_AddfdInfo(v, "unused", &ret_in, &err);
|- if (err) {
|- goto out;
|+ if (!err) {
|+ visit_complete(v, ret_out);
| }
|- *ret_out = qmp_output_get_qobject(qov);
|-
|-out:
| error_propagate(errp, err);
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1465490926-28625-13-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-06-09 18:48:43 +02:00
|
|
|
Visitor *v;
|
2014-08-18 08:46:34 +02:00
|
|
|
char *str;
|
2014-05-14 11:43:35 +02:00
|
|
|
|
|
|
|
while (m) {
|
qapi: Add new visit_complete() function
Making each output visitor provide its own output collection
function was the only remaining reason for exposing visitor
sub-types to the rest of the code base. Add a polymorphic
visit_complete() function which is a no-op for input visitors,
and which populates an opaque pointer for output visitors. For
maximum type-safety, also add a parameter to the output visitor
constructors with a type-correct version of the output pointer,
and assert that the two uses match.
This approach was considered superior to either passing the
output parameter only during construction (action at a distance
during visit_free() feels awkward) or only during visit_complete()
(defeating type safety makes it easier to use incorrectly).
Most callers were function-local, and therefore a mechanical
conversion; the testsuite was a bit trickier, but the previous
cleanup patch minimized the churn here.
The visit_complete() function may be called at most once; doing
so lets us use transfer semantics rather than duplication or
ref-count semantics to get the just-built output back to the
caller, even though it means our behavior is not idempotent.
Generated code is simplified as follows for events:
|@@ -26,7 +26,7 @@ void qapi_event_send_acpi_device_ost(ACP
| QDict *qmp;
| Error *err = NULL;
| QMPEventFuncEmit emit;
|- QmpOutputVisitor *qov;
|+ QObject *obj;
| Visitor *v;
| q_obj_ACPI_DEVICE_OST_arg param = {
| info
|@@ -39,8 +39,7 @@ void qapi_event_send_acpi_device_ost(ACP
|
| qmp = qmp_event_build_dict("ACPI_DEVICE_OST");
|
|- qov = qmp_output_visitor_new();
|- v = qmp_output_get_visitor(qov);
|+ v = qmp_output_visitor_new(&obj);
|
| visit_start_struct(v, "ACPI_DEVICE_OST", NULL, 0, &err);
| if (err) {
|@@ -55,7 +54,8 @@ void qapi_event_send_acpi_device_ost(ACP
| goto out;
| }
|
|- qdict_put_obj(qmp, "data", qmp_output_get_qobject(qov));
|+ visit_complete(v, &obj);
|+ qdict_put_obj(qmp, "data", obj);
| emit(QAPI_EVENT_ACPI_DEVICE_OST, qmp, &err);
and for commands:
| {
| Error *err = NULL;
|- QmpOutputVisitor *qov = qmp_output_visitor_new();
| Visitor *v;
|
|- v = qmp_output_get_visitor(qov);
|+ v = qmp_output_visitor_new(ret_out);
| visit_type_AddfdInfo(v, "unused", &ret_in, &err);
|- if (err) {
|- goto out;
|+ if (!err) {
|+ visit_complete(v, ret_out);
| }
|- *ret_out = qmp_output_get_qobject(qov);
|-
|-out:
| error_propagate(errp, err);
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1465490926-28625-13-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-06-09 18:48:43 +02:00
|
|
|
v = string_output_visitor_new(false, &str);
|
|
|
|
visit_type_uint16List(v, NULL, &m->value->host_nodes, NULL);
|
2017-01-10 13:53:15 +01:00
|
|
|
monitor_printf(mon, "memory backend: %s\n", m->value->id);
|
2014-05-14 11:43:35 +02:00
|
|
|
monitor_printf(mon, " size: %" PRId64 "\n", m->value->size);
|
|
|
|
monitor_printf(mon, " merge: %s\n",
|
|
|
|
m->value->merge ? "true" : "false");
|
|
|
|
monitor_printf(mon, " dump: %s\n",
|
|
|
|
m->value->dump ? "true" : "false");
|
|
|
|
monitor_printf(mon, " prealloc: %s\n",
|
|
|
|
m->value->prealloc ? "true" : "false");
|
|
|
|
monitor_printf(mon, " policy: %s\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
HostMemPolicy_str(m->value->policy));
|
qapi: Add new visit_complete() function
Making each output visitor provide its own output collection
function was the only remaining reason for exposing visitor
sub-types to the rest of the code base. Add a polymorphic
visit_complete() function which is a no-op for input visitors,
and which populates an opaque pointer for output visitors. For
maximum type-safety, also add a parameter to the output visitor
constructors with a type-correct version of the output pointer,
and assert that the two uses match.
This approach was considered superior to either passing the
output parameter only during construction (action at a distance
during visit_free() feels awkward) or only during visit_complete()
(defeating type safety makes it easier to use incorrectly).
Most callers were function-local, and therefore a mechanical
conversion; the testsuite was a bit trickier, but the previous
cleanup patch minimized the churn here.
The visit_complete() function may be called at most once; doing
so lets us use transfer semantics rather than duplication or
ref-count semantics to get the just-built output back to the
caller, even though it means our behavior is not idempotent.
Generated code is simplified as follows for events:
|@@ -26,7 +26,7 @@ void qapi_event_send_acpi_device_ost(ACP
| QDict *qmp;
| Error *err = NULL;
| QMPEventFuncEmit emit;
|- QmpOutputVisitor *qov;
|+ QObject *obj;
| Visitor *v;
| q_obj_ACPI_DEVICE_OST_arg param = {
| info
|@@ -39,8 +39,7 @@ void qapi_event_send_acpi_device_ost(ACP
|
| qmp = qmp_event_build_dict("ACPI_DEVICE_OST");
|
|- qov = qmp_output_visitor_new();
|- v = qmp_output_get_visitor(qov);
|+ v = qmp_output_visitor_new(&obj);
|
| visit_start_struct(v, "ACPI_DEVICE_OST", NULL, 0, &err);
| if (err) {
|@@ -55,7 +54,8 @@ void qapi_event_send_acpi_device_ost(ACP
| goto out;
| }
|
|- qdict_put_obj(qmp, "data", qmp_output_get_qobject(qov));
|+ visit_complete(v, &obj);
|+ qdict_put_obj(qmp, "data", obj);
| emit(QAPI_EVENT_ACPI_DEVICE_OST, qmp, &err);
and for commands:
| {
| Error *err = NULL;
|- QmpOutputVisitor *qov = qmp_output_visitor_new();
| Visitor *v;
|
|- v = qmp_output_get_visitor(qov);
|+ v = qmp_output_visitor_new(ret_out);
| visit_type_AddfdInfo(v, "unused", &ret_in, &err);
|- if (err) {
|- goto out;
|+ if (!err) {
|+ visit_complete(v, ret_out);
| }
|- *ret_out = qmp_output_get_qobject(qov);
|-
|-out:
| error_propagate(errp, err);
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1465490926-28625-13-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-06-09 18:48:43 +02:00
|
|
|
visit_complete(v, &str);
|
2014-08-18 08:46:34 +02:00
|
|
|
monitor_printf(mon, " host nodes: %s\n", str);
|
2014-05-14 11:43:35 +02:00
|
|
|
|
2014-08-18 08:46:34 +02:00
|
|
|
g_free(str);
|
qapi: Add new visit_complete() function
Making each output visitor provide its own output collection
function was the only remaining reason for exposing visitor
sub-types to the rest of the code base. Add a polymorphic
visit_complete() function which is a no-op for input visitors,
and which populates an opaque pointer for output visitors. For
maximum type-safety, also add a parameter to the output visitor
constructors with a type-correct version of the output pointer,
and assert that the two uses match.
This approach was considered superior to either passing the
output parameter only during construction (action at a distance
during visit_free() feels awkward) or only during visit_complete()
(defeating type safety makes it easier to use incorrectly).
Most callers were function-local, and therefore a mechanical
conversion; the testsuite was a bit trickier, but the previous
cleanup patch minimized the churn here.
The visit_complete() function may be called at most once; doing
so lets us use transfer semantics rather than duplication or
ref-count semantics to get the just-built output back to the
caller, even though it means our behavior is not idempotent.
Generated code is simplified as follows for events:
|@@ -26,7 +26,7 @@ void qapi_event_send_acpi_device_ost(ACP
| QDict *qmp;
| Error *err = NULL;
| QMPEventFuncEmit emit;
|- QmpOutputVisitor *qov;
|+ QObject *obj;
| Visitor *v;
| q_obj_ACPI_DEVICE_OST_arg param = {
| info
|@@ -39,8 +39,7 @@ void qapi_event_send_acpi_device_ost(ACP
|
| qmp = qmp_event_build_dict("ACPI_DEVICE_OST");
|
|- qov = qmp_output_visitor_new();
|- v = qmp_output_get_visitor(qov);
|+ v = qmp_output_visitor_new(&obj);
|
| visit_start_struct(v, "ACPI_DEVICE_OST", NULL, 0, &err);
| if (err) {
|@@ -55,7 +54,8 @@ void qapi_event_send_acpi_device_ost(ACP
| goto out;
| }
|
|- qdict_put_obj(qmp, "data", qmp_output_get_qobject(qov));
|+ visit_complete(v, &obj);
|+ qdict_put_obj(qmp, "data", obj);
| emit(QAPI_EVENT_ACPI_DEVICE_OST, qmp, &err);
and for commands:
| {
| Error *err = NULL;
|- QmpOutputVisitor *qov = qmp_output_visitor_new();
| Visitor *v;
|
|- v = qmp_output_get_visitor(qov);
|+ v = qmp_output_visitor_new(ret_out);
| visit_type_AddfdInfo(v, "unused", &ret_in, &err);
|- if (err) {
|- goto out;
|+ if (!err) {
|+ visit_complete(v, ret_out);
| }
|- *ret_out = qmp_output_get_qobject(qov);
|-
|-out:
| error_propagate(errp, err);
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1465490926-28625-13-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-06-09 18:48:43 +02:00
|
|
|
visit_free(v);
|
2014-05-14 11:43:35 +02:00
|
|
|
m = m->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "\n");
|
2014-08-18 08:46:35 +02:00
|
|
|
|
|
|
|
qapi_free_MemdevList(memdev_list);
|
2017-08-17 12:42:15 +02:00
|
|
|
hmp_handle_error(mon, &err);
|
2014-05-14 11:43:35 +02:00
|
|
|
}
|
2014-09-23 07:35:19 +02:00
|
|
|
|
|
|
|
void hmp_info_memory_devices(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
MemoryDeviceInfoList *info_list = qmp_query_memory_devices(&err);
|
|
|
|
MemoryDeviceInfoList *info;
|
|
|
|
MemoryDeviceInfo *value;
|
|
|
|
PCDIMMDeviceInfo *di;
|
|
|
|
|
|
|
|
for (info = info_list; info; info = info->next) {
|
|
|
|
value = info->value;
|
|
|
|
|
|
|
|
if (value) {
|
2015-10-26 23:34:59 +01:00
|
|
|
switch (value->type) {
|
2014-09-23 07:35:19 +02:00
|
|
|
case MEMORY_DEVICE_INFO_KIND_DIMM:
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-17 23:48:37 +01:00
|
|
|
di = value->u.dimm.data;
|
2018-03-11 04:02:12 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MEMORY_DEVICE_INFO_KIND_NVDIMM:
|
|
|
|
di = value->u.nvdimm.data;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
di = NULL;
|
|
|
|
break;
|
|
|
|
}
|
2014-09-23 07:35:19 +02:00
|
|
|
|
2018-03-11 04:02:12 +01:00
|
|
|
if (di) {
|
2014-09-23 07:35:19 +02:00
|
|
|
monitor_printf(mon, "Memory device [%s]: \"%s\"\n",
|
2017-08-24 10:46:08 +02:00
|
|
|
MemoryDeviceInfoKind_str(value->type),
|
2014-09-23 07:35:19 +02:00
|
|
|
di->id ? di->id : "");
|
|
|
|
monitor_printf(mon, " addr: 0x%" PRIx64 "\n", di->addr);
|
|
|
|
monitor_printf(mon, " slot: %" PRId64 "\n", di->slot);
|
|
|
|
monitor_printf(mon, " node: %" PRId64 "\n", di->node);
|
|
|
|
monitor_printf(mon, " size: %" PRIu64 "\n", di->size);
|
|
|
|
monitor_printf(mon, " memdev: %s\n", di->memdev);
|
|
|
|
monitor_printf(mon, " hotplugged: %s\n",
|
|
|
|
di->hotplugged ? "true" : "false");
|
|
|
|
monitor_printf(mon, " hotpluggable: %s\n",
|
|
|
|
di->hotpluggable ? "true" : "false");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_MemoryDeviceInfoList(info_list);
|
2017-08-17 12:42:15 +02:00
|
|
|
hmp_handle_error(mon, &err);
|
2014-09-23 07:35:19 +02:00
|
|
|
}
|
2014-05-07 18:08:29 +02:00
|
|
|
|
2015-06-26 10:07:13 +02:00
|
|
|
void hmp_info_iothreads(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
IOThreadInfoList *info_list = qmp_query_iothreads(NULL);
|
|
|
|
IOThreadInfoList *info;
|
2017-02-10 10:41:17 +01:00
|
|
|
IOThreadInfo *value;
|
2015-06-26 10:07:13 +02:00
|
|
|
|
|
|
|
for (info = info_list; info; info = info->next) {
|
2017-02-10 10:41:17 +01:00
|
|
|
value = info->value;
|
|
|
|
monitor_printf(mon, "%s:\n", value->id);
|
|
|
|
monitor_printf(mon, " thread_id=%" PRId64 "\n", value->thread_id);
|
|
|
|
monitor_printf(mon, " poll-max-ns=%" PRId64 "\n", value->poll_max_ns);
|
|
|
|
monitor_printf(mon, " poll-grow=%" PRId64 "\n", value->poll_grow);
|
|
|
|
monitor_printf(mon, " poll-shrink=%" PRId64 "\n", value->poll_shrink);
|
2015-06-26 10:07:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_IOThreadInfoList(info_list);
|
|
|
|
}
|
|
|
|
|
2014-05-07 18:08:29 +02:00
|
|
|
void hmp_qom_list(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *path = qdict_get_try_str(qdict, "path");
|
|
|
|
ObjectPropertyInfoList *list;
|
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
if (path == NULL) {
|
|
|
|
monitor_printf(mon, "/\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
list = qmp_qom_list(path, &err);
|
|
|
|
if (err == NULL) {
|
|
|
|
ObjectPropertyInfoList *start = list;
|
|
|
|
while (list != NULL) {
|
|
|
|
ObjectPropertyInfo *value = list->value;
|
|
|
|
|
|
|
|
monitor_printf(mon, "%s (%s)\n",
|
|
|
|
value->name, value->type);
|
|
|
|
list = list->next;
|
|
|
|
}
|
|
|
|
qapi_free_ObjectPropertyInfoList(start);
|
|
|
|
}
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2014-05-07 19:48:15 +02:00
|
|
|
|
|
|
|
void hmp_qom_set(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *path = qdict_get_str(qdict, "path");
|
|
|
|
const char *property = qdict_get_str(qdict, "property");
|
|
|
|
const char *value = qdict_get_str(qdict, "value");
|
|
|
|
Error *err = NULL;
|
|
|
|
bool ambiguous = false;
|
|
|
|
Object *obj;
|
|
|
|
|
|
|
|
obj = object_resolve_path(path, &ambiguous);
|
|
|
|
if (obj == NULL) {
|
2015-03-16 08:57:47 +01:00
|
|
|
error_set(&err, ERROR_CLASS_DEVICE_NOT_FOUND,
|
|
|
|
"Device '%s' not found", path);
|
2014-05-07 19:48:15 +02:00
|
|
|
} else {
|
|
|
|
if (ambiguous) {
|
|
|
|
monitor_printf(mon, "Warning: Path '%s' is ambiguous\n", path);
|
|
|
|
}
|
|
|
|
object_property_parse(obj, value, property, &err);
|
|
|
|
}
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|
2015-06-11 03:21:21 +02:00
|
|
|
|
|
|
|
void hmp_rocker(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
const char *name = qdict_get_str(qdict, "name");
|
|
|
|
RockerSwitch *rocker;
|
2015-12-18 16:35:27 +01:00
|
|
|
Error *err = NULL;
|
2015-06-11 03:21:21 +02:00
|
|
|
|
2015-12-18 16:35:27 +01:00
|
|
|
rocker = qmp_query_rocker(name, &err);
|
|
|
|
if (err != NULL) {
|
|
|
|
hmp_handle_error(mon, &err);
|
2015-06-11 03:21:21 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "name: %s\n", rocker->name);
|
|
|
|
monitor_printf(mon, "id: 0x%" PRIx64 "\n", rocker->id);
|
|
|
|
monitor_printf(mon, "ports: %d\n", rocker->ports);
|
|
|
|
|
|
|
|
qapi_free_RockerSwitch(rocker);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_rocker_ports(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
RockerPortList *list, *port;
|
|
|
|
const char *name = qdict_get_str(qdict, "name");
|
2015-12-18 16:35:27 +01:00
|
|
|
Error *err = NULL;
|
2015-06-11 03:21:21 +02:00
|
|
|
|
2015-12-18 16:35:27 +01:00
|
|
|
list = qmp_query_rocker_ports(name, &err);
|
|
|
|
if (err != NULL) {
|
|
|
|
hmp_handle_error(mon, &err);
|
2015-06-11 03:21:21 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, " ena/ speed/ auto\n");
|
|
|
|
monitor_printf(mon, " port link duplex neg?\n");
|
|
|
|
|
|
|
|
for (port = list; port; port = port->next) {
|
|
|
|
monitor_printf(mon, "%10s %-4s %-3s %2s %-3s\n",
|
|
|
|
port->value->name,
|
|
|
|
port->value->enabled ? port->value->link_up ?
|
|
|
|
"up" : "down" : "!ena",
|
|
|
|
port->value->speed == 10000 ? "10G" : "??",
|
|
|
|
port->value->duplex ? "FD" : "HD",
|
|
|
|
port->value->autoneg ? "Yes" : "No");
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_RockerPortList(list);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_rocker_of_dpa_flows(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
RockerOfDpaFlowList *list, *info;
|
|
|
|
const char *name = qdict_get_str(qdict, "name");
|
|
|
|
uint32_t tbl_id = qdict_get_try_int(qdict, "tbl_id", -1);
|
2015-12-18 16:35:27 +01:00
|
|
|
Error *err = NULL;
|
2015-06-11 03:21:21 +02:00
|
|
|
|
2015-12-18 16:35:27 +01:00
|
|
|
list = qmp_query_rocker_of_dpa_flows(name, tbl_id != -1, tbl_id, &err);
|
|
|
|
if (err != NULL) {
|
|
|
|
hmp_handle_error(mon, &err);
|
2015-06-11 03:21:21 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "prio tbl hits key(mask) --> actions\n");
|
|
|
|
|
|
|
|
for (info = list; info; info = info->next) {
|
|
|
|
RockerOfDpaFlow *flow = info->value;
|
|
|
|
RockerOfDpaFlowKey *key = flow->key;
|
|
|
|
RockerOfDpaFlowMask *mask = flow->mask;
|
|
|
|
RockerOfDpaFlowAction *action = flow->action;
|
|
|
|
|
|
|
|
if (flow->hits) {
|
|
|
|
monitor_printf(mon, "%-4d %-3d %-4" PRIu64,
|
|
|
|
key->priority, key->tbl_id, flow->hits);
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "%-4d %-3d ",
|
|
|
|
key->priority, key->tbl_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key->has_in_pport) {
|
|
|
|
monitor_printf(mon, " pport %d", key->in_pport);
|
|
|
|
if (mask->has_in_pport) {
|
|
|
|
monitor_printf(mon, "(0x%x)", mask->in_pport);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key->has_vlan_id) {
|
|
|
|
monitor_printf(mon, " vlan %d",
|
|
|
|
key->vlan_id & VLAN_VID_MASK);
|
|
|
|
if (mask->has_vlan_id) {
|
|
|
|
monitor_printf(mon, "(0x%x)", mask->vlan_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key->has_tunnel_id) {
|
|
|
|
monitor_printf(mon, " tunnel %d", key->tunnel_id);
|
|
|
|
if (mask->has_tunnel_id) {
|
|
|
|
monitor_printf(mon, "(0x%x)", mask->tunnel_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key->has_eth_type) {
|
|
|
|
switch (key->eth_type) {
|
|
|
|
case 0x0806:
|
|
|
|
monitor_printf(mon, " ARP");
|
|
|
|
break;
|
|
|
|
case 0x0800:
|
|
|
|
monitor_printf(mon, " IP");
|
|
|
|
break;
|
|
|
|
case 0x86dd:
|
|
|
|
monitor_printf(mon, " IPv6");
|
|
|
|
break;
|
|
|
|
case 0x8809:
|
|
|
|
monitor_printf(mon, " LACP");
|
|
|
|
break;
|
|
|
|
case 0x88cc:
|
|
|
|
monitor_printf(mon, " LLDP");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
monitor_printf(mon, " eth type 0x%04x", key->eth_type);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key->has_eth_src) {
|
|
|
|
if ((strcmp(key->eth_src, "01:00:00:00:00:00") == 0) &&
|
|
|
|
(mask->has_eth_src) &&
|
|
|
|
(strcmp(mask->eth_src, "01:00:00:00:00:00") == 0)) {
|
|
|
|
monitor_printf(mon, " src <any mcast/bcast>");
|
|
|
|
} else if ((strcmp(key->eth_src, "00:00:00:00:00:00") == 0) &&
|
|
|
|
(mask->has_eth_src) &&
|
|
|
|
(strcmp(mask->eth_src, "01:00:00:00:00:00") == 0)) {
|
|
|
|
monitor_printf(mon, " src <any ucast>");
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, " src %s", key->eth_src);
|
|
|
|
if (mask->has_eth_src) {
|
|
|
|
monitor_printf(mon, "(%s)", mask->eth_src);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key->has_eth_dst) {
|
|
|
|
if ((strcmp(key->eth_dst, "01:00:00:00:00:00") == 0) &&
|
|
|
|
(mask->has_eth_dst) &&
|
|
|
|
(strcmp(mask->eth_dst, "01:00:00:00:00:00") == 0)) {
|
|
|
|
monitor_printf(mon, " dst <any mcast/bcast>");
|
|
|
|
} else if ((strcmp(key->eth_dst, "00:00:00:00:00:00") == 0) &&
|
|
|
|
(mask->has_eth_dst) &&
|
|
|
|
(strcmp(mask->eth_dst, "01:00:00:00:00:00") == 0)) {
|
|
|
|
monitor_printf(mon, " dst <any ucast>");
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, " dst %s", key->eth_dst);
|
|
|
|
if (mask->has_eth_dst) {
|
|
|
|
monitor_printf(mon, "(%s)", mask->eth_dst);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key->has_ip_proto) {
|
|
|
|
monitor_printf(mon, " proto %d", key->ip_proto);
|
|
|
|
if (mask->has_ip_proto) {
|
|
|
|
monitor_printf(mon, "(0x%x)", mask->ip_proto);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key->has_ip_tos) {
|
|
|
|
monitor_printf(mon, " TOS %d", key->ip_tos);
|
|
|
|
if (mask->has_ip_tos) {
|
|
|
|
monitor_printf(mon, "(0x%x)", mask->ip_tos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key->has_ip_dst) {
|
|
|
|
monitor_printf(mon, " dst %s", key->ip_dst);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (action->has_goto_tbl || action->has_group_id ||
|
|
|
|
action->has_new_vlan_id) {
|
|
|
|
monitor_printf(mon, " -->");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (action->has_new_vlan_id) {
|
|
|
|
monitor_printf(mon, " apply new vlan %d",
|
|
|
|
ntohs(action->new_vlan_id));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (action->has_group_id) {
|
|
|
|
monitor_printf(mon, " write group 0x%08x", action->group_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (action->has_goto_tbl) {
|
|
|
|
monitor_printf(mon, " goto tbl %d", action->goto_tbl);
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_RockerOfDpaFlowList(list);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
RockerOfDpaGroupList *list, *g;
|
|
|
|
const char *name = qdict_get_str(qdict, "name");
|
|
|
|
uint8_t type = qdict_get_try_int(qdict, "type", 9);
|
2015-12-18 16:35:27 +01:00
|
|
|
Error *err = NULL;
|
2015-06-11 03:21:21 +02:00
|
|
|
bool set = false;
|
|
|
|
|
2015-12-18 16:35:27 +01:00
|
|
|
list = qmp_query_rocker_of_dpa_groups(name, type != 9, type, &err);
|
|
|
|
if (err != NULL) {
|
|
|
|
hmp_handle_error(mon, &err);
|
2015-06-11 03:21:21 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "id (decode) --> buckets\n");
|
|
|
|
|
|
|
|
for (g = list; g; g = g->next) {
|
|
|
|
RockerOfDpaGroup *group = g->value;
|
|
|
|
|
|
|
|
monitor_printf(mon, "0x%08x", group->id);
|
|
|
|
|
|
|
|
monitor_printf(mon, " (type %s", group->type == 0 ? "L2 interface" :
|
|
|
|
group->type == 1 ? "L2 rewrite" :
|
|
|
|
group->type == 2 ? "L3 unicast" :
|
|
|
|
group->type == 3 ? "L2 multicast" :
|
|
|
|
group->type == 4 ? "L2 flood" :
|
|
|
|
group->type == 5 ? "L3 interface" :
|
|
|
|
group->type == 6 ? "L3 multicast" :
|
|
|
|
group->type == 7 ? "L3 ECMP" :
|
|
|
|
group->type == 8 ? "L2 overlay" :
|
|
|
|
"unknown");
|
|
|
|
|
|
|
|
if (group->has_vlan_id) {
|
|
|
|
monitor_printf(mon, " vlan %d", group->vlan_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (group->has_pport) {
|
|
|
|
monitor_printf(mon, " pport %d", group->pport);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (group->has_index) {
|
|
|
|
monitor_printf(mon, " index %d", group->index);
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, ") -->");
|
|
|
|
|
|
|
|
if (group->has_set_vlan_id && group->set_vlan_id) {
|
|
|
|
set = true;
|
|
|
|
monitor_printf(mon, " set vlan %d",
|
|
|
|
group->set_vlan_id & VLAN_VID_MASK);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (group->has_set_eth_src) {
|
|
|
|
if (!set) {
|
|
|
|
set = true;
|
|
|
|
monitor_printf(mon, " set");
|
|
|
|
}
|
|
|
|
monitor_printf(mon, " src %s", group->set_eth_src);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (group->has_set_eth_dst) {
|
|
|
|
if (!set) {
|
|
|
|
set = true;
|
|
|
|
monitor_printf(mon, " set");
|
|
|
|
}
|
|
|
|
monitor_printf(mon, " dst %s", group->set_eth_dst);
|
|
|
|
}
|
|
|
|
|
|
|
|
set = false;
|
|
|
|
|
|
|
|
if (group->has_ttl_check && group->ttl_check) {
|
|
|
|
monitor_printf(mon, " check TTL");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (group->has_group_id && group->group_id) {
|
|
|
|
monitor_printf(mon, " group id 0x%08x", group->group_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (group->has_pop_vlan && group->pop_vlan) {
|
|
|
|
monitor_printf(mon, " pop vlan");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (group->has_out_pport) {
|
|
|
|
monitor_printf(mon, " out pport %d", group->out_pport);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (group->has_group_ids) {
|
|
|
|
struct uint32List *id;
|
|
|
|
|
|
|
|
monitor_printf(mon, " groups [");
|
|
|
|
for (id = group->group_ids; id; id = id->next) {
|
|
|
|
monitor_printf(mon, "0x%08x", id->value);
|
|
|
|
if (id->next) {
|
|
|
|
monitor_printf(mon, ",");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
monitor_printf(mon, "]");
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_RockerOfDpaGroupList(list);
|
|
|
|
}
|
2016-02-18 06:16:55 +01:00
|
|
|
|
|
|
|
void hmp_info_dump(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
DumpQueryResult *result = qmp_query_dump(NULL);
|
|
|
|
|
|
|
|
assert(result && result->status < DUMP_STATUS__MAX);
|
2017-08-24 10:46:08 +02:00
|
|
|
monitor_printf(mon, "Status: %s\n", DumpStatus_str(result->status));
|
2016-02-18 06:16:55 +01:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2016-06-10 02:59:07 +02:00
|
|
|
|
2017-05-12 06:17:41 +02:00
|
|
|
void hmp_info_ramblock(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
ram_block_dump(mon);
|
|
|
|
}
|
|
|
|
|
2016-06-10 02:59:07 +02:00
|
|
|
void hmp_hotpluggable_cpus(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
HotpluggableCPUList *l = qmp_query_hotpluggable_cpus(&err);
|
|
|
|
HotpluggableCPUList *saved = l;
|
|
|
|
CpuInstanceProperties *c;
|
|
|
|
|
|
|
|
if (err != NULL) {
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "Hotpluggable CPUs:\n");
|
|
|
|
while (l) {
|
|
|
|
monitor_printf(mon, " type: \"%s\"\n", l->value->type);
|
|
|
|
monitor_printf(mon, " vcpus_count: \"%" PRIu64 "\"\n",
|
|
|
|
l->value->vcpus_count);
|
|
|
|
if (l->value->has_qom_path) {
|
|
|
|
monitor_printf(mon, " qom_path: \"%s\"\n", l->value->qom_path);
|
|
|
|
}
|
|
|
|
|
|
|
|
c = l->value->props;
|
|
|
|
monitor_printf(mon, " CPUInstance Properties:\n");
|
2016-06-23 23:23:34 +02:00
|
|
|
if (c->has_node_id) {
|
|
|
|
monitor_printf(mon, " node-id: \"%" PRIu64 "\"\n", c->node_id);
|
2016-06-10 02:59:07 +02:00
|
|
|
}
|
2016-06-23 23:23:34 +02:00
|
|
|
if (c->has_socket_id) {
|
|
|
|
monitor_printf(mon, " socket-id: \"%" PRIu64 "\"\n", c->socket_id);
|
2016-06-10 02:59:07 +02:00
|
|
|
}
|
2016-06-23 23:23:34 +02:00
|
|
|
if (c->has_core_id) {
|
|
|
|
monitor_printf(mon, " core-id: \"%" PRIu64 "\"\n", c->core_id);
|
2016-06-10 02:59:07 +02:00
|
|
|
}
|
2016-06-23 23:23:34 +02:00
|
|
|
if (c->has_thread_id) {
|
|
|
|
monitor_printf(mon, " thread-id: \"%" PRIu64 "\"\n", c->thread_id);
|
2016-06-10 02:59:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
l = l->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_HotpluggableCPUList(saved);
|
|
|
|
}
|
2017-02-17 00:15:37 +01:00
|
|
|
|
|
|
|
void hmp_info_vm_generation_id(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
2017-03-02 22:36:50 +01:00
|
|
|
Error *err = NULL;
|
|
|
|
GuidInfo *info = qmp_query_vm_generation_id(&err);
|
2017-02-17 00:15:37 +01:00
|
|
|
if (info) {
|
|
|
|
monitor_printf(mon, "%s\n", info->guid);
|
|
|
|
}
|
2017-03-02 22:36:50 +01:00
|
|
|
hmp_handle_error(mon, &err);
|
2017-02-17 00:15:37 +01:00
|
|
|
qapi_free_GuidInfo(info);
|
|
|
|
}
|
2017-08-29 17:30:22 +02:00
|
|
|
|
|
|
|
void hmp_info_memory_size_summary(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
Error *err = NULL;
|
|
|
|
MemoryInfo *info = qmp_query_memory_size_summary(&err);
|
|
|
|
if (info) {
|
|
|
|
monitor_printf(mon, "base memory: %" PRIu64 "\n",
|
|
|
|
info->base_memory);
|
|
|
|
|
|
|
|
if (info->has_plugged_memory) {
|
|
|
|
monitor_printf(mon, "plugged memory: %" PRIu64 "\n",
|
|
|
|
info->plugged_memory);
|
|
|
|
}
|
|
|
|
|
|
|
|
qapi_free_MemoryInfo(info);
|
|
|
|
}
|
|
|
|
hmp_handle_error(mon, &err);
|
|
|
|
}
|