X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=hmp.c;h=a4b1d3d220840536a07b0edc70149395ffc14464;hb=f6f949e9295889fb272698aea763dcea77d616ce;hp=16006aa7bcb5fdb73d44fb6952cb0eb6b136e967;hpb=39ff43d9e1f42b1d829a955e546cddab87ac0626;p=mirror_qemu.git diff --git a/hmp.c b/hmp.c index 16006aa7bc..a4b1d3d220 100644 --- a/hmp.c +++ b/hmp.c @@ -13,6 +13,7 @@ * GNU GPL, version 2 or (at your option) any later version. */ +#include "qemu/osdep.h" #include "hmp.h" #include "net/net.h" #include "net/eth.h" @@ -27,10 +28,14 @@ #include "qapi/opts-visitor.h" #include "qapi/qmp/qerror.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/qapi.h" #include "qemu-io.h" +#include "qemu/cutils.h" +#include "qemu/error-report.h" #ifdef CONFIG_SPICE #include @@ -40,8 +45,7 @@ static void hmp_handle_error(Monitor *mon, Error **errp) { assert(errp); if (*errp) { - monitor_printf(mon, "%s\n", error_get_pretty(*errp)); - error_free(*errp); + error_report_err(*errp); } } @@ -165,8 +169,15 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) } 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) { @@ -232,9 +243,9 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) 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); @@ -278,11 +289,17 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict) 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); + MigrationParameter_lookup[MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL], + params->cpu_throttle_initial); monitor_printf(mon, " %s: %" PRId64, - MigrationParameter_lookup[MIGRATION_PARAMETER_X_CPU_THROTTLE_INCREMENT], - params->x_cpu_throttle_increment); + MigrationParameter_lookup[MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT], + params->cpu_throttle_increment); + monitor_printf(mon, " %s: '%s'", + MigrationParameter_lookup[MIGRATION_PARAMETER_TLS_CREDS], + params->tls_creds ? : ""); + monitor_printf(mon, " %s: '%s'", + MigrationParameter_lookup[MIGRATION_PARAMETER_TLS_HOSTNAME], + params->tls_hostname ? : ""); monitor_printf(mon, "\n"); } @@ -310,17 +327,27 @@ void hmp_info_cpus(Monitor *mon, const QDict *qdict) monitor_printf(mon, "%c CPU #%" PRId64 ":", active, cpu->value->CPU); - if (cpu->value->has_pc) { - monitor_printf(mon, " pc=0x%016" PRIx64, cpu->value->pc); - } - if (cpu->value->has_nip) { - monitor_printf(mon, " nip=0x%016" PRIx64, cpu->value->nip); - } - if (cpu->value->has_npc) { - monitor_printf(mon, " npc=0x%016" PRIx64, cpu->value->npc); - } - if (cpu->value->has_PC) { - monitor_printf(mon, " PC=0x%016" PRIx64, cpu->value->PC); + switch (cpu->value->arch) { + case CPU_INFO_ARCH_X86: + monitor_printf(mon, " pc=0x%016" PRIx64, cpu->value->u.x86.pc); + break; + case CPU_INFO_ARCH_PPC: + monitor_printf(mon, " nip=0x%016" PRIx64, cpu->value->u.ppc.nip); + break; + case CPU_INFO_ARCH_SPARC: + monitor_printf(mon, " pc=0x%016" PRIx64, + cpu->value->u.q_sparc.pc); + monitor_printf(mon, " npc=0x%016" PRIx64, + cpu->value->u.q_sparc.npc); + break; + case CPU_INFO_ARCH_MIPS: + monitor_printf(mon, " PC=0x%016" PRIx64, cpu->value->u.q_mips.PC); + break; + case CPU_INFO_ARCH_TRICORE: + monitor_printf(mon, " PC=0x%016" PRIx64, cpu->value->u.tricore.PC); + break; + default: + break; } if (cpu->value->halted) { @@ -521,6 +548,7 @@ void hmp_info_blockstats(Monitor *mon, const QDict *qdict) " flush_total_time_ns=%" PRId64 " rd_merged=%" PRId64 " wr_merged=%" PRId64 + " idle_time_ns=%" PRId64 "\n", stats->value->stats->rd_bytes, stats->value->stats->wr_bytes, @@ -531,7 +559,8 @@ void hmp_info_blockstats(Monitor *mon, const QDict *qdict) stats->value->stats->rd_total_time_ns, stats->value->stats->flush_total_time_ns, stats->value->stats->rd_merged, - stats->value->stats->wr_merged); + stats->value->stats->wr_merged, + stats->value->stats->idle_time_ns); } qapi_free_BlockStatsList(stats_list); @@ -545,8 +574,7 @@ void hmp_info_vnc(Monitor *mon, const QDict *qdict) info = qmp_query_vnc(&err); if (err) { - monitor_printf(mon, "%s\n", error_get_pretty(err)); - error_free(err); + error_report_err(err); return; } @@ -668,8 +696,7 @@ void hmp_info_balloon(Monitor *mon, const QDict *qdict) info = qmp_query_balloon(&err); if (err) { - monitor_printf(mon, "%s\n", error_get_pretty(err)); - error_free(err); + error_report_err(err); return; } @@ -845,14 +872,14 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict) switch (ti->options->type) { case TPM_TYPE_OPTIONS_KIND_PASSTHROUGH: - tpo = ti->options->u.passthrough; + tpo = ti->options->u.passthrough.data; 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; - case TPM_TYPE_OPTIONS_KIND_MAX: + case TPM_TYPE_OPTIONS_KIND__MAX: break; } monitor_printf(mon, "\n"); @@ -937,8 +964,7 @@ void hmp_ringbuf_read(Monitor *mon, const QDict *qdict) data = qmp_ringbuf_read(chardev, size, false, 0, &err); if (err) { - monitor_printf(mon, "%s\n", error_get_pretty(err)); - error_free(err); + error_report_err(err); return; } @@ -1031,8 +1057,7 @@ void hmp_balloon(Monitor *mon, const QDict *qdict) qmp_balloon(value, &err); if (err) { - monitor_printf(mon, "balloon: %s\n", error_get_pretty(err)); - error_free(err); + error_report_err(err); } } @@ -1180,8 +1205,7 @@ void hmp_migrate_set_cache_size(Monitor *mon, const QDict *qdict) qmp_migrate_set_cache_size(value, &err); if (err) { - monitor_printf(mon, "%s\n", error_get_pretty(err)); - error_free(err); + error_report_err(err); return; } } @@ -1200,7 +1224,7 @@ void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict) MigrationCapabilityStatusList *caps = g_malloc0(sizeof(*caps)); int i; - for (i = 0; i < MIGRATION_CAPABILITY_MAX; i++) { + for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) { if (strcmp(cap, MigrationCapability_lookup[i]) == 0) { caps->value = g_malloc0(sizeof(*caps->value)); caps->value->capability = i; @@ -1211,68 +1235,90 @@ void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict) } } - if (i == MIGRATION_CAPABILITY_MAX) { + if (i == MIGRATION_CAPABILITY__MAX) { error_setg(&err, QERR_INVALID_PARAMETER, cap); } qapi_free_MigrationCapabilityStatusList(caps); if (err) { - monitor_printf(mon, "migrate_set_capability: %s\n", - error_get_pretty(err)); - error_free(err); + error_report_err(err); } } 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"); + long valueint = 0; 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; + bool has_cpu_throttle_initial = false; + bool has_cpu_throttle_increment = false; + bool has_tls_creds = false; + bool has_tls_hostname = false; + bool use_int_value = false; int i; - for (i = 0; i < MIGRATION_PARAMETER_MAX; i++) { + for (i = 0; i < MIGRATION_PARAMETER__MAX; i++) { if (strcmp(param, MigrationParameter_lookup[i]) == 0) { switch (i) { case MIGRATION_PARAMETER_COMPRESS_LEVEL: has_compress_level = true; + use_int_value = true; break; case MIGRATION_PARAMETER_COMPRESS_THREADS: has_compress_threads = true; + use_int_value = true; break; case MIGRATION_PARAMETER_DECOMPRESS_THREADS: has_decompress_threads = true; + use_int_value = true; + break; + case MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL: + has_cpu_throttle_initial = true; + use_int_value = true; + break; + case MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT: + has_cpu_throttle_increment = true; break; - case MIGRATION_PARAMETER_X_CPU_THROTTLE_INITIAL: - has_x_cpu_throttle_initial = true; + case MIGRATION_PARAMETER_TLS_CREDS: + has_tls_creds = true; break; - case MIGRATION_PARAMETER_X_CPU_THROTTLE_INCREMENT: - has_x_cpu_throttle_increment = true; + case MIGRATION_PARAMETER_TLS_HOSTNAME: + has_tls_hostname = true; 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, + + if (use_int_value) { + if (qemu_strtol(valuestr, NULL, 10, &valueint) < 0) { + error_setg(&err, "Unable to parse '%s' as an int", + valuestr); + goto cleanup; + } + } + + qmp_migrate_set_parameters(has_compress_level, valueint, + has_compress_threads, valueint, + has_decompress_threads, valueint, + has_cpu_throttle_initial, valueint, + has_cpu_throttle_increment, valueint, + has_tls_creds, valuestr, + has_tls_hostname, valuestr, &err); break; } } - if (i == MIGRATION_PARAMETER_MAX) { + if (i == MIGRATION_PARAMETER__MAX) { error_setg(&err, QERR_INVALID_PARAMETER, param); } + cleanup: if (err) { - monitor_printf(mon, "migrate_set_parameter: %s\n", - error_get_pretty(err)); - error_free(err); + error_report_err(err); } } @@ -1343,9 +1389,16 @@ 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"); + const char *read_only = qdict_get_try_str(qdict, "read-only-mode"); + BlockdevChangeReadOnlyMode read_only_mode = 0; Error *err = NULL; if (strcmp(device, "vnc") == 0) { + if (read_only) { + monitor_printf(mon, + "Parameter 'read-only-mode' is invalid for VNC\n"); + return; + } if (strcmp(target, "passwd") == 0 || strcmp(target, "password") == 0) { if (!arg) { @@ -1355,7 +1408,19 @@ void hmp_change(Monitor *mon, const QDict *qdict) } qmp_change("vnc", target, !!arg, arg, &err); } else { - qmp_blockdev_change_medium(device, target, !!arg, arg, false, 0, &err); + if (read_only) { + read_only_mode = + qapi_enum_parse(BlockdevChangeReadOnlyMode_lookup, + read_only, BLOCKDEV_CHANGE_READ_ONLY_MODE__MAX, + BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN, &err); + if (err) { + hmp_handle_error(mon, &err); + return; + } + } + + qmp_blockdev_change_medium(device, target, !!arg, arg, + !!read_only, read_only_mode, &err); if (err && error_get_class(err) == ERROR_CLASS_DEVICE_ENCRYPTED) { error_free(err); @@ -1390,6 +1455,18 @@ void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict) 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, @@ -1496,6 +1573,9 @@ static void hmp_migrate_status_cb(void *opaque) 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); @@ -1514,8 +1594,7 @@ void hmp_migrate(Monitor *mon, const QDict *qdict) qmp_migrate(uri, !!blk, blk, !!inc, inc, false, false, &err); if (err) { - monitor_printf(mon, "migrate: %s\n", error_get_pretty(err)); - error_free(err); + error_report_err(err); return; } @@ -1564,8 +1643,10 @@ void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict) const char *file = qdict_get_str(qdict, "filename"); bool has_begin = qdict_haskey(qdict, "begin"); bool has_length = qdict_haskey(qdict, "length"); + bool has_detach = qdict_haskey(qdict, "detach"); int64_t begin = 0; int64_t length = 0; + bool detach = false; enum DumpGuestMemoryFormat dump_format = DUMP_GUEST_MEMORY_FORMAT_ELF; char *prot; @@ -1593,11 +1674,14 @@ void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict) if (has_length) { length = qdict_get_int(qdict, "length"); } + if (has_detach) { + detach = qdict_get_bool(qdict, "detach"); + } prot = g_strconcat("file:", file, NULL); - qmp_dump_guest_memory(paging, prot, has_begin, begin, has_length, length, - true, dump_format, &err); + qmp_dump_guest_memory(paging, prot, true, detach, has_begin, begin, + has_length, length, true, dump_format, &err); hmp_handle_error(mon, &err); g_free(prot); } @@ -1633,58 +1717,27 @@ void hmp_netdev_del(Monitor *mon, const QDict *qdict) void hmp_object_add(Monitor *mon, const QDict *qdict) { Error *err = NULL; - Error *err_end = NULL; QemuOpts *opts; - char *type = NULL; - char *id = NULL; - void *dummy = NULL; OptsVisitor *ov; - QDict *pdict; + Object *obj = NULL; opts = qemu_opts_from_qdict(qemu_find_opts("object"), qdict, &err); if (err) { - goto out; + hmp_handle_error(mon, &err); + return; } ov = opts_visitor_new(opts); - pdict = qdict_clone_shallow(qdict); - - visit_start_struct(opts_get_visitor(ov), &dummy, NULL, NULL, 0, &err); - if (err) { - goto out_clean; - } - - qdict_del(pdict, "qom-type"); - visit_type_str(opts_get_visitor(ov), &type, "qom-type", &err); - if (err) { - goto out_end; - } + obj = user_creatable_add(qdict, opts_get_visitor(ov), &err); + opts_visitor_cleanup(ov); + qemu_opts_del(opts); - qdict_del(pdict, "id"); - visit_type_str(opts_get_visitor(ov), &id, "id", &err); if (err) { - goto out_end; + hmp_handle_error(mon, &err); } - - object_add(type, id, pdict, opts_get_visitor(ov), &err); - -out_end: - visit_end_struct(opts_get_visitor(ov), &err_end); - if (!err && err_end) { - qmp_object_del(id, NULL); + if (obj) { + object_unref(obj); } - error_propagate(&err, err_end); -out_clean: - opts_visitor_cleanup(ov); - - QDECREF(pdict); - qemu_opts_del(opts); - g_free(id); - g_free(type); - g_free(dummy); - -out: - hmp_handle_error(mon, &err); } void hmp_getfd(Monitor *mon, const QDict *qdict) @@ -1712,21 +1765,18 @@ void hmp_sendkey(Monitor *mon, const QDict *qdict) int has_hold_time = qdict_haskey(qdict, "hold-time"); int hold_time = qdict_get_try_int(qdict, "hold-time", -1); Error *err = NULL; - char keyname_buf[16]; char *separator; int keyname_len; while (1) { separator = strchr(keys, '-'); keyname_len = separator ? separator - keys : strlen(keys); - pstrcpy(keyname_buf, sizeof(keyname_buf), keys); /* Be compatible with old interface, convert user inputted "<" */ - if (!strncmp(keyname_buf, "<", 1) && keyname_len == 1) { - pstrcpy(keyname_buf, sizeof(keyname_buf), "less"); + if (keys[0] == '<' && keyname_len == 1) { + keys = "less"; keyname_len = 4; } - keyname_buf[keyname_len] = 0; keylist = g_malloc0(sizeof(*keylist)); keylist->value = g_malloc0(sizeof(*keylist->value)); @@ -1739,21 +1789,22 @@ void hmp_sendkey(Monitor *mon, const QDict *qdict) } tmp = keylist; - if (strstart(keyname_buf, "0x", NULL)) { + if (strstart(keys, "0x", NULL)) { char *endp; - int value = strtoul(keyname_buf, &endp, 0); - if (*endp != '\0') { + int value = strtoul(keys, &endp, 0); + assert(endp <= keys + keyname_len); + if (endp != keys + keyname_len) { goto err_out; } keylist->value->type = KEY_VALUE_KIND_NUMBER; - keylist->value->u.number = value; + keylist->value->u.number.data = value; } else { - int idx = index_from_key(keyname_buf); - if (idx == Q_KEY_CODE_MAX) { + int idx = index_from_key(keys, keyname_len); + if (idx == Q_KEY_CODE__MAX) { goto err_out; } keylist->value->type = KEY_VALUE_KIND_QCODE; - keylist->value->u.qcode = idx; + keylist->value->u.qcode.data = idx; } if (!separator) { @@ -1770,7 +1821,7 @@ out: return; err_out: - monitor_printf(mon, "invalid parameter: %s\n", keyname_buf); + monitor_printf(mon, "invalid parameter: %.*s\n", keyname_len, keys); goto out; } @@ -1803,7 +1854,7 @@ void hmp_nbd_server_start(Monitor *mon, const QDict *qdict) goto exit; } - qmp_nbd_server_start(addr, &local_err); + qmp_nbd_server_start(addr, false, NULL, &local_err); qapi_free_SocketAddress(addr); if (local_err != NULL) { goto exit; @@ -1914,7 +1965,7 @@ void hmp_object_del(Monitor *mon, const QDict *qdict) const char *id = qdict_get_str(qdict, "id"); Error *err = NULL; - qmp_object_del(id, &err); + user_creatable_del(id, &err); hmp_handle_error(mon, &err); } @@ -1930,8 +1981,8 @@ void hmp_info_memdev(Monitor *mon, const QDict *qdict) while (m) { ov = string_output_visitor_new(false); - visit_type_uint16List(string_output_get_visitor(ov), - &m->value->host_nodes, NULL, NULL); + visit_type_uint16List(string_output_get_visitor(ov), NULL, + &m->value->host_nodes, NULL); monitor_printf(mon, "memory backend: %d\n", i); monitor_printf(mon, " size: %" PRId64 "\n", m->value->size); monitor_printf(mon, " merge: %s\n", @@ -1970,7 +2021,7 @@ void hmp_info_memory_devices(Monitor *mon, const QDict *qdict) if (value) { switch (value->type) { case MEMORY_DEVICE_INFO_KIND_DIMM: - di = value->u.dimm; + di = value->u.dimm.data; monitor_printf(mon, "Memory device [%s]: \"%s\"\n", MemoryDeviceInfoKind_lookup[value->type], @@ -2059,11 +2110,11 @@ void hmp_rocker(Monitor *mon, const QDict *qdict) { const char *name = qdict_get_str(qdict, "name"); RockerSwitch *rocker; - Error *errp = NULL; + Error *err = NULL; - rocker = qmp_query_rocker(name, &errp); - if (errp != NULL) { - hmp_handle_error(mon, &errp); + rocker = qmp_query_rocker(name, &err); + if (err != NULL) { + hmp_handle_error(mon, &err); return; } @@ -2078,11 +2129,11 @@ void hmp_rocker_ports(Monitor *mon, const QDict *qdict) { RockerPortList *list, *port; const char *name = qdict_get_str(qdict, "name"); - Error *errp = NULL; + Error *err = NULL; - list = qmp_query_rocker_ports(name, &errp); - if (errp != NULL) { - hmp_handle_error(mon, &errp); + list = qmp_query_rocker_ports(name, &err); + if (err != NULL) { + hmp_handle_error(mon, &err); return; } @@ -2107,11 +2158,11 @@ 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); - Error *errp = NULL; + Error *err = NULL; - list = qmp_query_rocker_of_dpa_flows(name, tbl_id != -1, tbl_id, &errp); - if (errp != NULL) { - hmp_handle_error(mon, &errp); + list = qmp_query_rocker_of_dpa_flows(name, tbl_id != -1, tbl_id, &err); + if (err != NULL) { + hmp_handle_error(mon, &err); return; } @@ -2257,12 +2308,12 @@ 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); - Error *errp = NULL; + Error *err = NULL; bool set = false; - list = qmp_query_rocker_of_dpa_groups(name, type != 9, type, &errp); - if (errp != NULL) { - hmp_handle_error(mon, &errp); + list = qmp_query_rocker_of_dpa_groups(name, type != 9, type, &err); + if (err != NULL) { + hmp_handle_error(mon, &err); return; } @@ -2356,3 +2407,20 @@ void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict) qapi_free_RockerOfDpaGroupList(list); } + +void hmp_info_dump(Monitor *mon, const QDict *qdict) +{ + DumpQueryResult *result = qmp_query_dump(NULL); + + assert(result && result->status < DUMP_STATUS__MAX); + monitor_printf(mon, "Status: %s\n", DumpStatus_lookup[result->status]); + + 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); +}