#include "net/eth.h"
#include "sysemu/char.h"
#include "sysemu/block-backend.h"
+#include "sysemu/sysemu.h"
+#include "qemu/config-file.h"
#include "qemu/option.h"
#include "qemu/timer.h"
#include "qmp-commands.h"
#include "monitor/qdev.h"
#include "qapi/opts-visitor.h"
#include "qapi/qmp/qerror.h"
+#include "qapi/string-input-visitor.h"
#include "qapi/string-output-visitor.h"
#include "qapi/util.h"
#include "qapi-visit.h"
#include "qom/object_interfaces.h"
#include "ui/console.h"
+#include "block/nbd.h"
#include "block/qapi.h"
#include "qemu-io.h"
#include "qemu/cutils.h"
+#include "qemu/error-report.h"
+#include "exec/ramlist.h"
+#include "hw/intc/intc.h"
#ifdef CONFIG_SPICE
#include <spice/enums.h>
}
if (info->has_status) {
- monitor_printf(mon, "Migration status: %s\n",
+ monitor_printf(mon, "Migration status: %s",
MigrationStatus_lookup[info->status]);
+ if (info->status == MIGRATION_STATUS_FAILED &&
+ info->has_error_desc) {
+ monitor_printf(mon, " (%s)\n", info->error_desc);
+ } else {
+ monitor_printf(mon, "\n");
+ }
+
monitor_printf(mon, "total time: %" PRIu64 " milliseconds\n",
info->total_time);
if (info->has_expected_downtime) {
info->ram->normal_bytes >> 10);
monitor_printf(mon, "dirty sync count: %" PRIu64 "\n",
info->ram->dirty_sync_count);
+ monitor_printf(mon, "page size: %" PRIu64 " kbytes\n",
+ info->ram->page_size >> 10);
+
if (info->ram->dirty_pages_rate) {
monitor_printf(mon, "dirty pages rate: %" PRIu64 " pages\n",
info->ram->dirty_pages_rate);
}
+ if (info->ram->postcopy_requests) {
+ monitor_printf(mon, "postcopy request count: %" PRIu64 "\n",
+ info->ram->postcopy_requests);
+ }
}
if (info->has_disk) {
info->xbzrle_cache->overflow);
}
- if (info->has_x_cpu_throttle_percentage) {
+ if (info->has_cpu_throttle_percentage) {
monitor_printf(mon, "cpu throttle percentage: %" PRIu64 "\n",
- info->x_cpu_throttle_percentage);
+ info->cpu_throttle_percentage);
}
qapi_free_MigrationInfo(info);
caps = qmp_query_migrate_capabilities(NULL);
if (caps) {
- monitor_printf(mon, "capabilities: ");
for (cap = caps; cap; cap = cap->next) {
- monitor_printf(mon, "%s: %s ",
+ monitor_printf(mon, "%s: %s\n",
MigrationCapability_lookup[cap->value->capability],
cap->value->state ? "on" : "off");
}
- monitor_printf(mon, "\n");
}
qapi_free_MigrationCapabilityStatusList(caps);
params = qmp_query_migrate_parameters(NULL);
if (params) {
- monitor_printf(mon, "parameters:");
- monitor_printf(mon, " %s: %" PRId64,
+ assert(params->has_compress_level);
+ monitor_printf(mon, "%s: %" PRId64 "\n",
MigrationParameter_lookup[MIGRATION_PARAMETER_COMPRESS_LEVEL],
params->compress_level);
- monitor_printf(mon, " %s: %" PRId64,
+ assert(params->has_compress_threads);
+ monitor_printf(mon, "%s: %" PRId64 "\n",
MigrationParameter_lookup[MIGRATION_PARAMETER_COMPRESS_THREADS],
params->compress_threads);
- monitor_printf(mon, " %s: %" PRId64,
+ assert(params->has_decompress_threads);
+ monitor_printf(mon, "%s: %" PRId64 "\n",
MigrationParameter_lookup[MIGRATION_PARAMETER_DECOMPRESS_THREADS],
params->decompress_threads);
- monitor_printf(mon, " %s: %" PRId64,
- MigrationParameter_lookup[MIGRATION_PARAMETER_X_CPU_THROTTLE_INITIAL],
- params->x_cpu_throttle_initial);
- monitor_printf(mon, " %s: %" PRId64,
- MigrationParameter_lookup[MIGRATION_PARAMETER_X_CPU_THROTTLE_INCREMENT],
- params->x_cpu_throttle_increment);
- monitor_printf(mon, "\n");
+ assert(params->has_cpu_throttle_initial);
+ monitor_printf(mon, "%s: %" PRId64 "\n",
+ MigrationParameter_lookup[MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL],
+ params->cpu_throttle_initial);
+ assert(params->has_cpu_throttle_increment);
+ monitor_printf(mon, "%s: %" PRId64 "\n",
+ MigrationParameter_lookup[MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT],
+ params->cpu_throttle_increment);
+ monitor_printf(mon, "%s: '%s'\n",
+ MigrationParameter_lookup[MIGRATION_PARAMETER_TLS_CREDS],
+ params->has_tls_creds ? params->tls_creds : "");
+ monitor_printf(mon, "%s: '%s'\n",
+ MigrationParameter_lookup[MIGRATION_PARAMETER_TLS_HOSTNAME],
+ params->has_tls_hostname ? params->tls_hostname : "");
+ assert(params->has_max_bandwidth);
+ monitor_printf(mon, "%s: %" PRId64 " bytes/second\n",
+ MigrationParameter_lookup[MIGRATION_PARAMETER_MAX_BANDWIDTH],
+ params->max_bandwidth);
+ assert(params->has_downtime_limit);
+ monitor_printf(mon, "%s: %" PRId64 " milliseconds\n",
+ MigrationParameter_lookup[MIGRATION_PARAMETER_DOWNTIME_LIMIT],
+ params->downtime_limit);
+ assert(params->has_x_checkpoint_delay);
+ monitor_printf(mon, "%s: %" PRId64 "\n",
+ MigrationParameter_lookup[MIGRATION_PARAMETER_X_CHECKPOINT_DELAY],
+ params->x_checkpoint_delay);
+ assert(params->has_block_incremental);
+ monitor_printf(mon, "%s: %s\n",
+ MigrationParameter_lookup[MIGRATION_PARAMETER_BLOCK_INCREMENTAL],
+ params->block_incremental ? "on" : "off");
}
qapi_free_MigrationParameters(params);
}
}
+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);
+}
+
void hmp_info_pci(Monitor *mon, const QDict *qdict)
{
PciInfoList *info_list, *info;
const char *filename = qdict_get_str(qdict, "filename");
uint64_t addr = qdict_get_int(qdict, "val");
Error *err = NULL;
+ int cpu_index = monitor_get_cpu_index();
+
+ if (cpu_index < 0) {
+ monitor_printf(mon, "No CPU available\n");
+ return;
+ }
- qmp_memsave(addr, size, filename, true, monitor_get_cpu_index(), &err);
+ qmp_memsave(addr, size, filename, true, cpu_index, &err);
hmp_handle_error(mon, &err);
}
void hmp_drive_mirror(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");
bool reuse = qdict_get_try_bool(qdict, "reuse", false);
bool full = qdict_get_try_bool(qdict, "full", false);
- enum NewImageMode mode;
Error *err = NULL;
+ 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,
+ };
if (!filename) {
error_setg(&err, QERR_MISSING_PARAMETER, "target");
hmp_handle_error(mon, &err);
return;
}
-
- if (reuse) {
- mode = NEW_IMAGE_MODE_EXISTING;
- } else {
- mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
- }
-
- qmp_drive_mirror(device, filename, !!format, format,
- false, NULL, false, NULL,
- full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
- true, mode, false, 0, false, 0, false, 0,
- false, 0, false, 0, false, true, &err);
+ qmp_drive_mirror(&mirror, &err);
hmp_handle_error(mon, &err);
}
const char *format = qdict_get_try_str(qdict, "format");
bool reuse = qdict_get_try_bool(qdict, "reuse", false);
bool full = qdict_get_try_bool(qdict, "full", false);
- enum NewImageMode mode;
+ bool compress = qdict_get_try_bool(qdict, "compress", false);
Error *err = NULL;
+ 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,
+ .has_compress = !!compress,
+ .compress = compress,
+ };
if (!filename) {
error_setg(&err, QERR_MISSING_PARAMETER, "target");
return;
}
- if (reuse) {
- mode = NEW_IMAGE_MODE_EXISTING;
- } else {
- mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
- }
-
- qmp_drive_backup(device, filename, !!format, format,
- full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
- true, mode, false, 0, false, NULL,
- false, 0, false, 0, &err);
+ qmp_drive_backup(&backup, &err);
hmp_handle_error(mon, &err);
}
hmp_handle_error(mon, &err);
}
+void hmp_loadvm(Monitor *mon, const QDict *qdict)
+{
+ int saved_vm_running = runstate_is_running();
+ const char *name = qdict_get_str(qdict, "name");
+ Error *err = NULL;
+
+ vm_stop(RUN_STATE_RESTORE_VM);
+
+ if (load_vmstate(name, &err) == 0 && saved_vm_running) {
+ vm_start();
+ }
+ hmp_handle_error(mon, &err);
+}
+
+void hmp_savevm(Monitor *mon, const QDict *qdict)
+{
+ Error *err = NULL;
+
+ save_vmstate(qdict_get_try_str(qdict, "name"), &err);
+ hmp_handle_error(mon, &err);
+}
+
+void hmp_delvm(Monitor *mon, const QDict *qdict)
+{
+ BlockDriverState *bs;
+ Error *err;
+ 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));
+ }
+}
+
+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);
+
+}
+
void hmp_migrate_cancel(Monitor *mon, const QDict *qdict)
{
qmp_migrate_cancel(NULL);
hmp_handle_error(mon, &err);
}
+/* Kept for backwards compatibility */
void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict)
{
double value = qdict_get_double(qdict, "value");
}
}
+/* Kept for backwards compatibility */
void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict)
{
int64_t value = qdict_get_int(qdict, "value");
void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
{
const char *param = qdict_get_str(qdict, "parameter");
- int value = qdict_get_int(qdict, "value");
+ const char *valuestr = qdict_get_str(qdict, "value");
+ Visitor *v = string_input_visitor_new(valuestr);
+ uint64_t valuebw = 0;
+ int64_t valueint = 0;
+ bool valuebool = false;
Error *err = NULL;
- bool has_compress_level = false;
- bool has_compress_threads = false;
- bool has_decompress_threads = false;
- bool has_x_cpu_throttle_initial = false;
- bool has_x_cpu_throttle_increment = false;
- int i;
+ bool use_int_value = false;
+ int i, ret;
for (i = 0; i < MIGRATION_PARAMETER__MAX; i++) {
if (strcmp(param, MigrationParameter_lookup[i]) == 0) {
+ MigrationParameters p = { 0 };
switch (i) {
case MIGRATION_PARAMETER_COMPRESS_LEVEL:
- has_compress_level = true;
+ p.has_compress_level = true;
+ use_int_value = true;
break;
case MIGRATION_PARAMETER_COMPRESS_THREADS:
- has_compress_threads = true;
+ p.has_compress_threads = true;
+ use_int_value = true;
break;
case MIGRATION_PARAMETER_DECOMPRESS_THREADS:
- has_decompress_threads = true;
+ p.has_decompress_threads = true;
+ use_int_value = true;
+ break;
+ case MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL:
+ p.has_cpu_throttle_initial = true;
+ use_int_value = true;
+ break;
+ case MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT:
+ p.has_cpu_throttle_increment = true;
+ use_int_value = true;
+ break;
+ case MIGRATION_PARAMETER_TLS_CREDS:
+ p.has_tls_creds = true;
+ p.tls_creds = (char *) valuestr;
+ break;
+ case MIGRATION_PARAMETER_TLS_HOSTNAME:
+ p.has_tls_hostname = true;
+ p.tls_hostname = (char *) valuestr;
break;
- case MIGRATION_PARAMETER_X_CPU_THROTTLE_INITIAL:
- has_x_cpu_throttle_initial = true;
+ case MIGRATION_PARAMETER_MAX_BANDWIDTH:
+ p.has_max_bandwidth = true;
+ ret = qemu_strtosz_MiB(valuestr, NULL, &valuebw);
+ if (ret < 0 || valuebw > INT64_MAX
+ || (size_t)valuebw != valuebw) {
+ error_setg(&err, "Invalid size %s", valuestr);
+ goto cleanup;
+ }
+ p.max_bandwidth = valuebw;
+ break;
+ case MIGRATION_PARAMETER_DOWNTIME_LIMIT:
+ p.has_downtime_limit = true;
+ use_int_value = true;
+ break;
+ case MIGRATION_PARAMETER_X_CHECKPOINT_DELAY:
+ p.has_x_checkpoint_delay = true;
+ use_int_value = true;
break;
- case MIGRATION_PARAMETER_X_CPU_THROTTLE_INCREMENT:
- has_x_cpu_throttle_increment = true;
+ case MIGRATION_PARAMETER_BLOCK_INCREMENTAL:
+ p.has_block_incremental = true;
+ visit_type_bool(v, param, &valuebool, &err);
+ if (err) {
+ goto cleanup;
+ }
+ p.block_incremental = valuebool;
break;
}
- qmp_migrate_set_parameters(has_compress_level, value,
- has_compress_threads, value,
- has_decompress_threads, value,
- has_x_cpu_throttle_initial, value,
- has_x_cpu_throttle_increment, value,
- &err);
+
+ if (use_int_value) {
+ visit_type_int(v, param, &valueint, &err);
+ if (err) {
+ goto cleanup;
+ }
+ /* Set all integers; only one has_FOO will be set, and
+ * the code ignores the remaining values */
+ p.compress_level = valueint;
+ p.compress_threads = valueint;
+ p.decompress_threads = valueint;
+ p.cpu_throttle_initial = valueint;
+ p.cpu_throttle_increment = valueint;
+ p.downtime_limit = valueint;
+ p.x_checkpoint_delay = valueint;
+ }
+
+ qmp_migrate_set_parameters(&p, &err);
break;
}
}
error_setg(&err, QERR_INVALID_PARAMETER, param);
}
+ cleanup:
+ visit_free(v);
if (err) {
error_report_err(err);
}
hmp_handle_error(mon, &err);
}
+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);
+}
+
void hmp_set_password(Monitor *mon, const QDict *qdict)
{
const char *protocol = qdict_get_str(qdict, "protocol");
const char *device = qdict_get_str(qdict, "device");
Error *err = NULL;
- qmp_eject(device, true, force, &err);
+ qmp_eject(true, device, false, NULL, true, force, &err);
hmp_handle_error(mon, &err);
}
}
}
- qmp_blockdev_change_medium(device, target, !!arg, arg,
- !!read_only, read_only_mode, &err);
+ qmp_blockdev_change_medium(true, device, false, NULL, target,
+ !!arg, arg, !!read_only, read_only_mode,
+ &err);
if (err &&
error_get_class(err) == ERROR_CLASS_DEVICE_ENCRYPTED) {
error_free(err);
void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict)
{
Error *err = NULL;
+ BlockIOThrottle throttle = {
+ .has_device = true,
+ .device = (char *) qdict_get_str(qdict, "device"),
+ .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"),
+ };
- qmp_block_set_io_throttle(qdict_get_str(qdict, "device"),
- qdict_get_int(qdict, "bps"),
- qdict_get_int(qdict, "bps_rd"),
- qdict_get_int(qdict, "bps_wr"),
- qdict_get_int(qdict, "iops"),
- qdict_get_int(qdict, "iops_rd"),
- qdict_get_int(qdict, "iops_wr"),
- false, /* no burst max via HMP */
- 0,
- false,
- 0,
- false,
- 0,
- false,
- 0,
- false,
- 0,
- false,
- 0,
- false, /* no burst length via HMP */
- 0,
- false,
- 0,
- false,
- 0,
- false,
- 0,
- false,
- 0,
- false,
- 0,
- false, /* No default I/O size */
- 0,
- false,
- NULL, &err);
+ qmp_block_set_io_throttle(&throttle, &err);
hmp_handle_error(mon, &err);
}
const char *base = qdict_get_try_str(qdict, "base");
int64_t speed = qdict_get_try_int(qdict, "speed", 0);
- qmp_block_stream(device, base != NULL, base, false, NULL,
- qdict_haskey(qdict, "speed"), speed,
+ qmp_block_stream(true, device, device, base != NULL, base, false, NULL,
+ false, NULL, qdict_haskey(qdict, "speed"), speed,
true, BLOCKDEV_ON_ERROR_REPORT, &error);
hmp_handle_error(mon, &error);
if (status->is_block_migration) {
monitor_printf(status->mon, "\n");
}
+ if (info->has_error_desc) {
+ error_report("%s", info->error_desc);
+ }
monitor_resume(status->mon);
timer_del(status->timer);
g_free(status);
{
Error *err = NULL;
QemuOpts *opts;
- OptsVisitor *ov;
Object *obj = NULL;
opts = qemu_opts_from_qdict(qemu_find_opts("object"), qdict, &err);
return;
}
- ov = opts_visitor_new(opts);
- obj = user_creatable_add(qdict, opts_get_visitor(ov), &err);
- opts_visitor_cleanup(ov);
+ obj = user_creatable_add_opts(opts, &err);
qemu_opts_del(opts);
if (err) {
goto exit;
}
- qmp_nbd_server_start(addr, false, NULL, &local_err);
+ nbd_server_start(addr, NULL, &local_err);
qapi_free_SocketAddress(addr);
if (local_err != NULL) {
goto exit;
if (opts == NULL) {
error_setg(&err, "Parsing chardev args failed");
} else {
- qemu_chr_new_from_opts(opts, NULL, &err);
+ qemu_chr_new_from_opts(opts, &err);
+ qemu_opts_del(opts);
}
hmp_handle_error(mon, &err);
}
void hmp_qemu_io(Monitor *mon, const QDict *qdict)
{
BlockBackend *blk;
+ BlockBackend *local_blk = NULL;
+ AioContext *aio_context;
const char* device = qdict_get_str(qdict, "device");
const char* command = qdict_get_str(qdict, "command");
Error *err = NULL;
+ int ret;
blk = blk_by_name(device);
- if (blk) {
- qemuio_command(blk, command);
- } else {
- error_set(&err, ERROR_CLASS_DEVICE_NOT_FOUND,
- "Device '%s' not found", device);
- }
+ if (!blk) {
+ BlockDriverState *bs = bdrv_lookup_bs(NULL, device, &err);
+ if (bs) {
+ blk = local_blk = blk_new(0, BLK_PERM_ALL);
+ ret = blk_insert_bs(blk, bs, &err);
+ if (ret < 0) {
+ goto fail;
+ }
+ } else {
+ goto fail;
+ }
+ }
+
+ aio_context = blk_get_aio_context(blk);
+ aio_context_acquire(aio_context);
+
+ /*
+ * 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.
+ */
+ qemuio_command(blk, command);
+
+ aio_context_release(aio_context);
+fail:
+ blk_unref(local_blk);
hmp_handle_error(mon, &err);
}
Error *err = NULL;
MemdevList *memdev_list = qmp_query_memdev(&err);
MemdevList *m = memdev_list;
- StringOutputVisitor *ov;
+ Visitor *v;
char *str;
- int i = 0;
-
while (m) {
- ov = string_output_visitor_new(false);
- visit_type_uint16List(string_output_get_visitor(ov), NULL,
- &m->value->host_nodes, NULL);
- monitor_printf(mon, "memory backend: %d\n", i);
+ v = string_output_visitor_new(false, &str);
+ visit_type_uint16List(v, NULL, &m->value->host_nodes, NULL);
+ monitor_printf(mon, "memory backend: %s\n", m->value->id);
monitor_printf(mon, " size: %" PRId64 "\n", m->value->size);
monitor_printf(mon, " merge: %s\n",
m->value->merge ? "true" : "false");
m->value->prealloc ? "true" : "false");
monitor_printf(mon, " policy: %s\n",
HostMemPolicy_lookup[m->value->policy]);
- str = string_output_get_string(ov);
+ visit_complete(v, &str);
monitor_printf(mon, " host nodes: %s\n", str);
g_free(str);
- string_output_visitor_cleanup(ov);
+ visit_free(v);
m = m->next;
- i++;
}
monitor_printf(mon, "\n");
{
IOThreadInfoList *info_list = qmp_query_iothreads(NULL);
IOThreadInfoList *info;
+ IOThreadInfo *value;
for (info = info_list; info; info = info->next) {
- monitor_printf(mon, "%s: thread_id=%" PRId64 "\n",
- info->value->id, info->value->thread_id);
+ 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);
}
qapi_free_IOThreadInfoList(info_list);
qapi_free_DumpQueryResult(result);
}
+
+void hmp_info_ramblock(Monitor *mon, const QDict *qdict)
+{
+ ram_block_dump(mon);
+}
+
+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");
+ if (c->has_node_id) {
+ monitor_printf(mon, " node-id: \"%" PRIu64 "\"\n", c->node_id);
+ }
+ if (c->has_socket_id) {
+ monitor_printf(mon, " socket-id: \"%" PRIu64 "\"\n", c->socket_id);
+ }
+ if (c->has_core_id) {
+ monitor_printf(mon, " core-id: \"%" PRIu64 "\"\n", c->core_id);
+ }
+ if (c->has_thread_id) {
+ monitor_printf(mon, " thread-id: \"%" PRIu64 "\"\n", c->thread_id);
+ }
+
+ l = l->next;
+ }
+
+ qapi_free_HotpluggableCPUList(saved);
+}
+
+void hmp_info_vm_generation_id(Monitor *mon, const QDict *qdict)
+{
+ Error *err = NULL;
+ GuidInfo *info = qmp_query_vm_generation_id(&err);
+ if (info) {
+ monitor_printf(mon, "%s\n", info->guid);
+ }
+ hmp_handle_error(mon, &err);
+ qapi_free_GuidInfo(info);
+}