X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=monitor.c;h=5c003731e288ba654dd39c44a4d0199a81e36eb6;hb=353801cde4e1e98cc1e2790f92cf934adac9f7dd;hp=e4cf34e3cb18d199ed01e7ce15365fd43992f99e;hpb=0a9516c2d6711cb6760a726952bdbbe931fd045c;p=mirror_qemu.git diff --git a/monitor.c b/monitor.c index e4cf34e3cb..5c003731e2 100644 --- a/monitor.c +++ b/monitor.c @@ -21,7 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#include "qemu/osdep.h" #include +#include "qemu-common.h" +#include "cpu.h" #include "hw/hw.h" #include "monitor/qdev.h" #include "hw/usb.h" @@ -41,6 +44,7 @@ #include "ui/console.h" #include "ui/input.h" #include "sysemu/blockdev.h" +#include "sysemu/block-backend.h" #include "audio/audio.h" #include "disas/disas.h" #include "sysemu/balloon.h" @@ -50,16 +54,11 @@ #include "qemu/acl.h" #include "sysemu/tpm.h" #include "qapi/qmp/qerror.h" -#include "qapi/qmp/qint.h" -#include "qapi/qmp/qfloat.h" -#include "qapi/qmp/qlist.h" -#include "qapi/qmp/qbool.h" -#include "qapi/qmp/qstring.h" +#include "qapi/qmp/types.h" #include "qapi/qmp/qjson.h" #include "qapi/qmp/json-streamer.h" #include "qapi/qmp/json-parser.h" -#include -#include "qemu/osdep.h" +#include "qom/object_interfaces.h" #include "cpu.h" #include "trace.h" #include "trace/control.h" @@ -68,6 +67,8 @@ #include "trace/simple.h" #endif #include "exec/memory.h" +#include "exec/exec-all.h" +#include "qemu/log.h" #include "qmp-commands.h" #include "hmp.h" #include "qemu/thread.h" @@ -76,6 +77,8 @@ #include "qapi-event.h" #include "qmp-introspect.h" #include "sysemu/block-backend.h" +#include "sysemu/qtest.h" +#include "qemu/cutils.h" /* for hmp_info_irq/pic */ #if defined(TARGET_SPARC) @@ -232,6 +235,8 @@ static const mon_cmd_t qmp_cmds[]; Monitor *cur_mon; +static QEMUClockType event_clock_type = QEMU_CLOCK_REALTIME; + static void monitor_command_cb(void *opaque, const char *cmdline, void *readline_opaque); @@ -311,7 +316,7 @@ static void monitor_flush_locked(Monitor *mon) return; } if (rc > 0) { - /* partinal write */ + /* partial write */ QString *tmp = qstring_from_str(buf + rc); QDECREF(mon->outbuf); mon->outbuf = tmp; @@ -403,7 +408,7 @@ static QDict *build_qmp_error_dict(Error *err) QObject *obj; obj = qobject_from_jsonf("{ 'error': { 'class': %s, 'desc': %s } }", - ErrorClass_lookup[error_get_class(err)], + QapiErrorClass_lookup[error_get_class(err)], error_get_pretty(err)); return qobject_to_qdict(obj); @@ -441,7 +446,7 @@ static void monitor_protocol_emitter(Monitor *mon, QObject *data, } -static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT_MAX] = { +static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] = { /* Limit guest-triggerable events to 1 per second */ [QAPI_EVENT_RTC_CHANGE] = { 1000 * SCALE_MS }, [QAPI_EVENT_WATCHDOG] = { 1000 * SCALE_MS }, @@ -481,7 +486,7 @@ monitor_qapi_event_queue(QAPIEvent event, QDict *qdict, Error **errp) MonitorQAPIEventConf *evconf; MonitorQAPIEventState *evstate; - assert(event < QAPI_EVENT_MAX); + assert(event < QAPI_EVENT__MAX); evconf = &monitor_qapi_event_conf[event]; trace_monitor_protocol_event_queue(event, qdict, evconf->rate); @@ -513,7 +518,7 @@ monitor_qapi_event_queue(QAPIEvent event, QDict *qdict, Error **errp) * monitor_qapi_event_handler() in evconf->rate ns. Any * events arriving before then will be delayed until then. */ - int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); + int64_t now = qemu_clock_get_ns(event_clock_type); monitor_qapi_event_emit(event, qdict); @@ -522,7 +527,7 @@ monitor_qapi_event_queue(QAPIEvent event, QDict *qdict, Error **errp) evstate->data = data; QINCREF(evstate->data); evstate->qdict = NULL; - evstate->timer = timer_new_ns(QEMU_CLOCK_REALTIME, + evstate->timer = timer_new_ns(event_clock_type, monitor_qapi_event_handler, evstate); g_hash_table_add(monitor_qapi_event_state, evstate); @@ -547,7 +552,7 @@ static void monitor_qapi_event_handler(void *opaque) qemu_mutex_lock(&monitor_lock); if (evstate->qdict) { - int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); + int64_t now = qemu_clock_get_ns(event_clock_type); monitor_qapi_event_emit(evstate->event, evstate->qdict); QDECREF(evstate->qdict); @@ -572,6 +577,10 @@ static unsigned int qapi_event_throttle_hash(const void *key) hash += g_str_hash(qdict_get_str(evstate->data, "id")); } + if (evstate->event == QAPI_EVENT_QUORUM_REPORT_BAD) { + hash += g_str_hash(qdict_get_str(evstate->data, "node-name")); + } + return hash; } @@ -589,11 +598,20 @@ static gboolean qapi_event_throttle_equal(const void *a, const void *b) qdict_get_str(evb->data, "id")); } + if (eva->event == QAPI_EVENT_QUORUM_REPORT_BAD) { + return !strcmp(qdict_get_str(eva->data, "node-name"), + qdict_get_str(evb->data, "node-name")); + } + return TRUE; } static void monitor_qapi_event_init(void) { + if (qtest_enabled()) { + event_clock_type = QEMU_CLOCK_VIRTUAL; + } + monitor_qapi_event_state = g_hash_table_new(qapi_event_throttle_hash, qapi_event_throttle_equal); qmp_event_set_func_emit(monitor_qapi_event_queue); @@ -617,6 +635,13 @@ static void monitor_data_init(Monitor *mon) static void monitor_data_destroy(Monitor *mon) { + if (mon->chr) { + qemu_chr_add_handlers(mon->chr, NULL, NULL, NULL, NULL); + } + if (monitor_is_qmp(mon)) { + json_message_parser_destroy(&mon->qmp.parser); + } + g_free(mon->rs); QDECREF(mon->outbuf); qemu_mutex_destroy(&mon->out_lock); } @@ -886,9 +911,16 @@ static void hmp_trace_event(Monitor *mon, const QDict *qdict) { const char *tp_name = qdict_get_str(qdict, "name"); bool new_state = qdict_get_bool(qdict, "option"); + bool has_vcpu = qdict_haskey(qdict, "vcpu"); + int vcpu = qdict_get_try_int(qdict, "vcpu", 0); Error *local_err = NULL; - qmp_trace_event_set_state(tp_name, new_state, true, true, &local_err); + if (vcpu < 0) { + monitor_printf(mon, "argument vcpu must be positive"); + return; + } + + qmp_trace_event_set_state(tp_name, new_state, true, true, has_vcpu, vcpu, &local_err); if (local_err) { error_report_err(local_err); } @@ -946,7 +978,7 @@ EventInfoList *qmp_query_events(Error **errp) EventInfoList *info, *ev_list = NULL; QAPIEvent e; - for (e = 0 ; e < QAPI_EVENT_MAX ; e++) { + for (e = 0 ; e < QAPI_EVENT__MAX ; e++) { const char *event_name = QAPIEvent_lookup[e]; assert(event_name != NULL); info = g_malloc0(sizeof(*info)); @@ -1047,8 +1079,26 @@ static void hmp_info_cpustats(Monitor *mon, const QDict *qdict) static void hmp_info_trace_events(Monitor *mon, const QDict *qdict) { - TraceEventInfoList *events = qmp_trace_event_get_state("*", NULL); + const char *name = qdict_get_try_str(qdict, "name"); + bool has_vcpu = qdict_haskey(qdict, "vcpu"); + int vcpu = qdict_get_try_int(qdict, "vcpu", 0); + TraceEventInfoList *events; TraceEventInfoList *elem; + Error *local_err = NULL; + + if (name == NULL) { + name = "*"; + } + if (vcpu < 0) { + monitor_printf(mon, "argument vcpu must be positive"); + return; + } + + events = qmp_trace_event_get_state(name, has_vcpu, vcpu, &local_err); + if (local_err) { + error_report_err(local_err); + return; + } for (elem = events; elem != NULL; elem = elem->next) { monitor_printf(mon, "%s : state %u\n", @@ -1089,7 +1139,12 @@ void qmp_client_migrate_info(const char *protocol, const char *hostname, static void hmp_logfile(Monitor *mon, const QDict *qdict) { - qemu_set_log_filename(qdict_get_str(qdict, "filename")); + Error *err = NULL; + + qemu_set_log_filename(qdict_get_str(qdict, "filename"), &err); + if (err) { + error_report_err(err); + } } static void hmp_log(Monitor *mon, const QDict *qdict) @@ -1386,7 +1441,7 @@ static void hmp_mouse_move(Monitor *mon, const QDict *qdict) static void hmp_mouse_button(Monitor *mon, const QDict *qdict) { - static uint32_t bmap[INPUT_BUTTON_MAX] = { + static uint32_t bmap[INPUT_BUTTON__MAX] = { [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON, [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON, [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON, @@ -1464,8 +1519,7 @@ static void hmp_boot_set(Monitor *mon, const QDict *qdict) qemu_boot_set(bootdevice, &local_err); if (local_err) { - monitor_printf(mon, "%s\n", error_get_pretty(local_err)); - error_free(local_err); + error_report_err(local_err); } else { monitor_printf(mon, "boot device list now set to %s\n", bootdevice); } @@ -1507,9 +1561,9 @@ int64_t dev_time; static void hmp_info_profile(Monitor *mon, const QDict *qdict) { monitor_printf(mon, "async time %" PRId64 " (%0.3f)\n", - dev_time, dev_time / (double)get_ticks_per_sec()); + dev_time, dev_time / (double)NANOSECONDS_PER_SECOND); monitor_printf(mon, "qemu time %" PRId64 " (%0.3f)\n", - tcg_time, tcg_time / (double)get_ticks_per_sec()); + tcg_time, tcg_time / (double)NANOSECONDS_PER_SECOND); tcg_time = 0; dev_time = 0; } @@ -3033,8 +3087,8 @@ void netdev_add_completion(ReadLineState *rs, int nb_args, const char *str) } len = strlen(str); readline_set_completion_index(rs, len); - for (i = 0; NetClientOptionsKind_lookup[i]; i++) { - add_completion_option(rs, str, NetClientOptionsKind_lookup[i]); + for (i = 0; NetClientDriver_lookup[i]; i++) { + add_completion_option(rs, str, NetClientDriver_lookup[i]); } } @@ -3217,7 +3271,7 @@ void sendkey_completion(ReadLineState *rs, int nb_args, const char *str) } len = strlen(str); readline_set_completion_index(rs, len); - for (i = 0; i < Q_KEY_CODE_MAX; i++) { + for (i = 0; i < Q_KEY_CODE__MAX; i++) { if (!strncmp(str, QKeyCode_lookup[i], len)) { readline_add_completion(rs, QKeyCode_lookup[i]); } @@ -3234,7 +3288,7 @@ void set_link_completion(ReadLineState *rs, int nb_args, const char *str) NetClientState *ncs[MAX_QUEUE_NUM]; int count, i; count = qemu_find_net_clients_except(NULL, ncs, - NET_CLIENT_OPTIONS_KIND_NONE, + NET_CLIENT_DRIVER_NONE, MAX_QUEUE_NUM); for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) { const char *name = ncs[i]->name; @@ -3259,7 +3313,7 @@ void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str) len = strlen(str); readline_set_completion_index(rs, len); - count = qemu_find_net_clients_except(NULL, ncs, NET_CLIENT_OPTIONS_KIND_NIC, + count = qemu_find_net_clients_except(NULL, ncs, NET_CLIENT_DRIVER_NIC, MAX_QUEUE_NUM); for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) { QemuOpts *opts; @@ -3274,6 +3328,23 @@ void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str) } } +void info_trace_events_completion(ReadLineState *rs, int nb_args, const char *str) +{ + size_t len; + + len = strlen(str); + readline_set_completion_index(rs, len); + if (nb_args == 2) { + TraceEventID id; + for (id = 0; id < trace_event_count(); id++) { + const char *event_name = trace_event_get_name(trace_event_id(id)); + if (!strncmp(str, event_name, len)) { + readline_add_completion(rs, event_name); + } + } + } +} + void trace_event_completion(ReadLineState *rs, int nb_args, const char *str) { size_t len; @@ -3316,7 +3387,7 @@ void migrate_set_capability_completion(ReadLineState *rs, int nb_args, readline_set_completion_index(rs, len); if (nb_args == 2) { int i; - for (i = 0; i < MIGRATION_CAPABILITY_MAX; i++) { + for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) { const char *name = MigrationCapability_lookup[i]; if (!strncmp(str, name, len)) { readline_add_completion(rs, name); @@ -3337,7 +3408,7 @@ void migrate_set_parameter_completion(ReadLineState *rs, int nb_args, readline_set_completion_index(rs, len); if (nb_args == 2) { int i; - for (i = 0; i < MIGRATION_PARAMETER_MAX; i++) { + for (i = 0; i < MIGRATION_PARAMETER__MAX; i++) { const char *name = MigrationParameter_lookup[i]; if (!strncmp(str, name, len)) { readline_add_completion(rs, name); @@ -3371,7 +3442,7 @@ void host_net_remove_completion(ReadLineState *rs, int nb_args, const char *str) readline_set_completion_index(rs, len); if (nb_args == 2) { count = qemu_find_net_clients_except(NULL, ncs, - NET_CLIENT_OPTIONS_KIND_NONE, + NET_CLIENT_DRIVER_NONE, MAX_QUEUE_NUM); for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) { int id; @@ -3388,13 +3459,13 @@ void host_net_remove_completion(ReadLineState *rs, int nb_args, const char *str) return; } else if (nb_args == 3) { count = qemu_find_net_clients_except(NULL, ncs, - NET_CLIENT_OPTIONS_KIND_NIC, + NET_CLIENT_DRIVER_NIC, MAX_QUEUE_NUM); for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) { int id; const char *name; - if (ncs[i]->info->type == NET_CLIENT_OPTIONS_KIND_HUBPORT || + if (ncs[i]->info->type == NET_CLIENT_DRIVER_HUBPORT || net_hub_id_for_client(ncs[i], &id)) { continue; } @@ -3410,11 +3481,13 @@ void host_net_remove_completion(ReadLineState *rs, int nb_args, const char *str) static void vm_completion(ReadLineState *rs, const char *str) { size_t len; - BlockDriverState *bs = NULL; + BlockDriverState *bs; + BdrvNextIterator it; len = strlen(str); readline_set_completion_index(rs, len); - while ((bs = bdrv_next(bs))) { + + for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { SnapshotInfoList *snapshots, *snapshot; AioContext *ctx = bdrv_get_aio_context(bs); bool ok = false; @@ -3468,7 +3541,7 @@ static void monitor_find_completion_by_table(Monitor *mon, int i; const char *ptype, *str, *name; const mon_cmd_t *cmd; - BlockDriverState *bs; + BlockBackend *blk = NULL; if (nb_args <= 1) { /* command completion */ @@ -3523,8 +3596,8 @@ static void monitor_find_completion_by_table(Monitor *mon, case 'B': /* block device name completion */ readline_set_completion_index(mon->rs, strlen(str)); - for (bs = bdrv_next(NULL); bs; bs = bdrv_next(bs)) { - name = bdrv_get_device_name(bs); + while ((blk = blk_next(blk)) != NULL) { + name = blk_name(blk); if (str[0] == '\0' || !strncmp(name, str, strlen(str))) { readline_add_completion(mon->rs, name); @@ -3849,7 +3922,7 @@ static QDict *qmp_check_input_obj(QObject *input_obj, Error **errp) return input_dict; } -static void handle_qmp_command(JSONMessageParser *parser, QList *tokens) +static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens) { Error *local_err = NULL; QObject *obj, *data; @@ -3907,6 +3980,7 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens) err_out: monitor_protocol_emitter(mon, data, local_err); qobject_decref(data); + error_free(local_err); QDECREF(input); QDECREF(args); } @@ -4068,15 +4142,6 @@ static void sortcmdlist(void) qsort((void *)info_cmds, array_num, elem_size, compare_mon_cmd); } - -/* - * Local variables: - * c-indent-level: 4 - * c-basic-offset: 4 - * tab-width: 8 - * End: - */ - /* These functions just adapt the readline interface in a typesafe way. We * could cast function pointers but that discards compiler checks. */ @@ -4138,6 +4203,19 @@ void monitor_init(CharDriverState *chr, int flags) qemu_mutex_unlock(&monitor_lock); } +void monitor_cleanup(void) +{ + Monitor *mon, *next; + + qemu_mutex_lock(&monitor_lock); + QLIST_FOREACH_SAFE(mon, &mon_list, entry, next) { + QLIST_REMOVE(mon, entry); + monitor_data_destroy(mon); + g_free(mon); + } + qemu_mutex_unlock(&monitor_lock); +} + static void bdrv_password_cb(void *opaque, const char *password, void *readline_opaque) { @@ -4148,8 +4226,7 @@ static void bdrv_password_cb(void *opaque, const char *password, bdrv_add_key(bs, password, &local_err); if (local_err) { - monitor_printf(mon, "%s\n", error_get_pretty(local_err)); - error_free(local_err); + error_report_err(local_err); ret = -EPERM; } if (mon->password_completion_cb) @@ -4242,3 +4319,24 @@ void qmp_dump_skeys(const char *filename, Error **errp) error_setg(errp, QERR_FEATURE_DISABLED, "dump-skeys"); } #endif + +#ifndef TARGET_ARM +GICCapabilityList *qmp_query_gic_capabilities(Error **errp) +{ + error_setg(errp, QERR_FEATURE_DISABLED, "query-gic-capabilities"); + return NULL; +} +#endif + +HotpluggableCPUList *qmp_query_hotpluggable_cpus(Error **errp) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + MachineClass *mc = MACHINE_GET_CLASS(ms); + + if (!mc->query_hotpluggable_cpus) { + error_setg(errp, QERR_FEATURE_DISABLED, "query-hotpluggable-cpus"); + return NULL; + } + + return mc->query_hotpluggable_cpus(ms); +}