]> git.proxmox.com Git - mirror_qemu.git/blob - monitor/qmp-cmds.c
4a8d1e9a151eff4879d7ce145c05e453d88de077
[mirror_qemu.git] / monitor / qmp-cmds.c
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 }