1 /* 2 * QEMU Management Protocol commands 3 * 4 * Copyright IBM, Corp. 2011 5 * 6 * Authors: 7 * Anthony Liguori <aliguori@us.ibm.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2. See 10 * the COPYING file in the top-level directory. 11 * 12 * Contributions after 2012-01-13 are licensed under the terms of the 13 * GNU GPL, version 2 or (at your option) any later version. 14 */ 15 16 #include "qemu/osdep.h" 17 #include "monitor/monitor.h" 18 #include "monitor/qmp-helpers.h" 19 #include "sysemu/sysemu.h" 20 #include "sysemu/kvm.h" 21 #include "sysemu/runstate.h" 22 #include "sysemu/runstate-action.h" 23 #include "sysemu/block-backend.h" 24 #include "qapi/error.h" 25 #include "qapi/qapi-commands-acpi.h" 26 #include "qapi/qapi-commands-control.h" 27 #include "qapi/qapi-commands-misc.h" 28 #include "qapi/qapi-commands-stats.h" 29 #include "qapi/type-helpers.h" 30 #include "hw/mem/memory-device.h" 31 #include "hw/acpi/acpi_dev_interface.h" 32 #include "hw/intc/intc.h" 33 #include "hw/rdma/rdma.h" 34 #include "monitor/stats.h" 35 36 NameInfo *qmp_query_name(Error **errp) 37 { 38 NameInfo *info = g_malloc0(sizeof(*info)); 39 40 info->name = g_strdup(qemu_name); 41 return info; 42 } 43 44 void qmp_quit(Error **errp) 45 { 46 shutdown_action = SHUTDOWN_ACTION_POWEROFF; 47 qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_QMP_QUIT); 48 } 49 50 void qmp_stop(Error **errp) 51 { 52 /* if there is a dump in background, we should wait until the dump 53 * finished */ 54 if (qemu_system_dump_in_progress()) { 55 error_setg(errp, "There is a dump in process, please wait."); 56 return; 57 } 58 59 if (runstate_check(RUN_STATE_INMIGRATE)) { 60 autostart = 0; 61 } else { 62 vm_stop(RUN_STATE_PAUSED); 63 } 64 } 65 66 void qmp_cont(Error **errp) 67 { 68 BlockBackend *blk; 69 BlockJob *job; 70 Error *local_err = NULL; 71 72 /* if there is a dump in background, we should wait until the dump 73 * finished */ 74 if (qemu_system_dump_in_progress()) { 75 error_setg(errp, "There is a dump in process, please wait."); 76 return; 77 } 78 79 if (runstate_needs_reset()) { 80 error_setg(errp, "Resetting the Virtual Machine is required"); 81 return; 82 } else if (runstate_check(RUN_STATE_SUSPENDED)) { 83 return; 84 } else if (runstate_check(RUN_STATE_FINISH_MIGRATE)) { 85 error_setg(errp, "Migration is not finalized yet"); 86 return; 87 } 88 89 for (blk = blk_next(NULL); blk; blk = blk_next(blk)) { 90 blk_iostatus_reset(blk); 91 } 92 93 WITH_JOB_LOCK_GUARD() { 94 for (job = block_job_next_locked(NULL); job; 95 job = block_job_next_locked(job)) { 96 block_job_iostatus_reset_locked(job); 97 } 98 } 99 100 /* Continuing after completed migration. Images have been inactivated to 101 * allow the destination to take control. Need to get control back now. 102 * 103 * If there are no inactive block nodes (e.g. because the VM was just 104 * paused rather than completing a migration), bdrv_inactivate_all() simply 105 * doesn't do anything. */ 106 bdrv_activate_all(&local_err); 107 if (local_err) { 108 error_propagate(errp, local_err); 109 return; 110 } 111 112 if (runstate_check(RUN_STATE_INMIGRATE)) { 113 autostart = 1; 114 } else { 115 vm_start(); 116 } 117 } 118 119 void qmp_add_client(const char *protocol, const char *fdname, 120 bool has_skipauth, bool skipauth, bool has_tls, bool tls, 121 Error **errp) 122 { 123 static const struct { 124 const char *name; 125 bool (*add_client)(int fd, bool has_skipauth, bool skipauth, 126 bool has_tls, bool tls, Error **errp); 127 } protocol_table[] = { 128 { "spice", qmp_add_client_spice }, 129 #ifdef CONFIG_VNC 130 { "vnc", qmp_add_client_vnc }, 131 #endif 132 #ifdef CONFIG_DBUS_DISPLAY 133 { "@dbus-display", qmp_add_client_dbus_display }, 134 #endif 135 }; 136 int fd, i; 137 138 fd = monitor_get_fd(monitor_cur(), fdname, errp); 139 if (fd < 0) { 140 return; 141 } 142 143 for (i = 0; i < ARRAY_SIZE(protocol_table); i++) { 144 if (!strcmp(protocol, protocol_table[i].name)) { 145 if (!protocol_table[i].add_client(fd, has_skipauth, skipauth, 146 has_tls, tls, errp)) { 147 close(fd); 148 } 149 return; 150 } 151 } 152 153 if (!qmp_add_client_char(fd, has_skipauth, skipauth, has_tls, tls, 154 protocol, errp)) { 155 close(fd); 156 } 157 } 158 159 ACPIOSTInfoList *qmp_query_acpi_ospm_status(Error **errp) 160 { 161 bool ambig; 162 ACPIOSTInfoList *head = NULL; 163 ACPIOSTInfoList **prev = &head; 164 Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, &ambig); 165 166 if (obj) { 167 AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj); 168 AcpiDeviceIf *adev = ACPI_DEVICE_IF(obj); 169 170 adevc->ospm_status(adev, &prev); 171 } else { 172 error_setg(errp, "command is not supported, missing ACPI device"); 173 } 174 175 return head; 176 } 177 178 typedef struct StatsCallbacks { 179 StatsProvider provider; 180 StatRetrieveFunc *stats_cb; 181 SchemaRetrieveFunc *schemas_cb; 182 QTAILQ_ENTRY(StatsCallbacks) next; 183 } StatsCallbacks; 184 185 static QTAILQ_HEAD(, StatsCallbacks) stats_callbacks = 186 QTAILQ_HEAD_INITIALIZER(stats_callbacks); 187 188 void add_stats_callbacks(StatsProvider provider, 189 StatRetrieveFunc *stats_fn, 190 SchemaRetrieveFunc *schemas_fn) 191 { 192 StatsCallbacks *entry = g_new(StatsCallbacks, 1); 193 entry->provider = provider; 194 entry->stats_cb = stats_fn; 195 entry->schemas_cb = schemas_fn; 196 197 QTAILQ_INSERT_TAIL(&stats_callbacks, entry, next); 198 } 199 200 static bool invoke_stats_cb(StatsCallbacks *entry, 201 StatsResultList **stats_results, 202 StatsFilter *filter, StatsRequest *request, 203 Error **errp) 204 { 205 ERRP_GUARD(); 206 strList *targets = NULL; 207 strList *names = NULL; 208 209 if (request) { 210 if (request->provider != entry->provider) { 211 return true; 212 } 213 if (request->has_names && !request->names) { 214 return true; 215 } 216 names = request->has_names ? request->names : NULL; 217 } 218 219 switch (filter->target) { 220 case STATS_TARGET_VM: 221 break; 222 case STATS_TARGET_VCPU: 223 if (filter->u.vcpu.has_vcpus) { 224 if (!filter->u.vcpu.vcpus) { 225 /* No targets allowed? Return no statistics. */ 226 return true; 227 } 228 targets = filter->u.vcpu.vcpus; 229 } 230 break; 231 default: 232 abort(); 233 } 234 235 entry->stats_cb(stats_results, filter->target, names, targets, errp); 236 if (*errp) { 237 qapi_free_StatsResultList(*stats_results); 238 *stats_results = NULL; 239 return false; 240 } 241 return true; 242 } 243 244 StatsResultList *qmp_query_stats(StatsFilter *filter, Error **errp) 245 { 246 StatsResultList *stats_results = NULL; 247 StatsCallbacks *entry; 248 StatsRequestList *request; 249 250 QTAILQ_FOREACH(entry, &stats_callbacks, next) { 251 if (filter->has_providers) { 252 for (request = filter->providers; request; request = request->next) { 253 if (!invoke_stats_cb(entry, &stats_results, filter, 254 request->value, errp)) { 255 break; 256 } 257 } 258 } else { 259 if (!invoke_stats_cb(entry, &stats_results, filter, NULL, errp)) { 260 break; 261 } 262 } 263 } 264 265 return stats_results; 266 } 267 268 StatsSchemaList *qmp_query_stats_schemas(bool has_provider, 269 StatsProvider provider, 270 Error **errp) 271 { 272 ERRP_GUARD(); 273 StatsSchemaList *stats_results = NULL; 274 StatsCallbacks *entry; 275 276 QTAILQ_FOREACH(entry, &stats_callbacks, next) { 277 if (!has_provider || provider == entry->provider) { 278 entry->schemas_cb(&stats_results, errp); 279 if (*errp) { 280 qapi_free_StatsSchemaList(stats_results); 281 return NULL; 282 } 283 } 284 } 285 286 return stats_results; 287 } 288 289 void add_stats_entry(StatsResultList **stats_results, StatsProvider provider, 290 const char *qom_path, StatsList *stats_list) 291 { 292 StatsResult *entry = g_new0(StatsResult, 1); 293 294 entry->provider = provider; 295 entry->qom_path = g_strdup(qom_path); 296 entry->stats = stats_list; 297 298 QAPI_LIST_PREPEND(*stats_results, entry); 299 } 300 301 void add_stats_schema(StatsSchemaList **schema_results, 302 StatsProvider provider, StatsTarget target, 303 StatsSchemaValueList *stats_list) 304 { 305 StatsSchema *entry = g_new0(StatsSchema, 1); 306 307 entry->provider = provider; 308 entry->target = target; 309 entry->stats = stats_list; 310 QAPI_LIST_PREPEND(*schema_results, entry); 311 } 312 313 bool apply_str_list_filter(const char *string, strList *list) 314 { 315 strList *str_list = NULL; 316 317 if (!list) { 318 return true; 319 } 320 for (str_list = list; str_list; str_list = str_list->next) { 321 if (g_str_equal(string, str_list->value)) { 322 return true; 323 } 324 } 325 return false; 326 } 327