xref: /openbmc/qemu/monitor/qmp-cmds.c (revision 3125af295e92825834031e8cbb8ca55c718a6fcb)
1f1b3ccfaSKevin Wolf /*
2f1b3ccfaSKevin Wolf  * QEMU Management Protocol commands
3f1b3ccfaSKevin Wolf  *
4f1b3ccfaSKevin Wolf  * Copyright IBM, Corp. 2011
5f1b3ccfaSKevin Wolf  *
6f1b3ccfaSKevin Wolf  * Authors:
7f1b3ccfaSKevin Wolf  *  Anthony Liguori   <aliguori@us.ibm.com>
8f1b3ccfaSKevin Wolf  *
9f1b3ccfaSKevin Wolf  * This work is licensed under the terms of the GNU GPL, version 2.  See
10f1b3ccfaSKevin Wolf  * the COPYING file in the top-level directory.
11f1b3ccfaSKevin Wolf  *
12f1b3ccfaSKevin Wolf  * Contributions after 2012-01-13 are licensed under the terms of the
13f1b3ccfaSKevin Wolf  * GNU GPL, version 2 or (at your option) any later version.
14f1b3ccfaSKevin Wolf  */
15f1b3ccfaSKevin Wolf 
16f1b3ccfaSKevin Wolf #include "qemu/osdep.h"
17f1b3ccfaSKevin Wolf #include "qemu/cutils.h"
18f1b3ccfaSKevin Wolf #include "qemu/option.h"
19f1b3ccfaSKevin Wolf #include "monitor/monitor.h"
20*3125af29SMarkus Armbruster #include "monitor/qmp-helpers.h"
21f1b3ccfaSKevin Wolf #include "sysemu/sysemu.h"
22f1b3ccfaSKevin Wolf #include "qemu/config-file.h"
23f1b3ccfaSKevin Wolf #include "qemu/uuid.h"
24f1b3ccfaSKevin Wolf #include "chardev/char.h"
25f1b3ccfaSKevin Wolf #include "sysemu/kvm.h"
2654d31236SMarkus Armbruster #include "sysemu/runstate.h"
27e6dba048SAlejandro Jimenez #include "sysemu/runstate-action.h"
28f1b3ccfaSKevin Wolf #include "sysemu/blockdev.h"
29f1b3ccfaSKevin Wolf #include "sysemu/block-backend.h"
30f1b3ccfaSKevin Wolf #include "qapi/error.h"
3127c9188fSPhilippe Mathieu-Daudé #include "qapi/qapi-commands-acpi.h"
325a16818bSKevin Wolf #include "qapi/qapi-commands-block.h"
33fa4dcf57SKevin Wolf #include "qapi/qapi-commands-control.h"
348ac25c84SMarkus Armbruster #include "qapi/qapi-commands-machine.h"
35f1b3ccfaSKevin Wolf #include "qapi/qapi-commands-misc.h"
36b9f88dc0SMark Kanda #include "qapi/qapi-commands-stats.h"
3737087fdeSDaniel P. Berrangé #include "qapi/type-helpers.h"
38ca411b7cSDaniel P. Berrangé #include "exec/ramlist.h"
39f1b3ccfaSKevin Wolf #include "hw/mem/memory-device.h"
40f1b3ccfaSKevin Wolf #include "hw/acpi/acpi_dev_interface.h"
4191f2fa70SDaniel P. Berrangé #include "hw/intc/intc.h"
428dbbca5cSDaniel P. Berrangé #include "hw/rdma/rdma.h"
43b9f88dc0SMark Kanda #include "monitor/stats.h"
44f1b3ccfaSKevin Wolf 
45f1b3ccfaSKevin Wolf NameInfo *qmp_query_name(Error **errp)
46f1b3ccfaSKevin Wolf {
47f1b3ccfaSKevin Wolf     NameInfo *info = g_malloc0(sizeof(*info));
48f1b3ccfaSKevin Wolf 
49f1b3ccfaSKevin Wolf     info->name = g_strdup(qemu_name);
50f1b3ccfaSKevin Wolf     return info;
51f1b3ccfaSKevin Wolf }
52f1b3ccfaSKevin Wolf 
53f1b3ccfaSKevin Wolf KvmInfo *qmp_query_kvm(Error **errp)
54f1b3ccfaSKevin Wolf {
55f1b3ccfaSKevin Wolf     KvmInfo *info = g_malloc0(sizeof(*info));
56f1b3ccfaSKevin Wolf 
57f1b3ccfaSKevin Wolf     info->enabled = kvm_enabled();
584f9205beSPeter Maydell     info->present = accel_find("kvm");
59f1b3ccfaSKevin Wolf 
60f1b3ccfaSKevin Wolf     return info;
61f1b3ccfaSKevin Wolf }
62f1b3ccfaSKevin Wolf 
63f1b3ccfaSKevin Wolf UuidInfo *qmp_query_uuid(Error **errp)
64f1b3ccfaSKevin Wolf {
65f1b3ccfaSKevin Wolf     UuidInfo *info = g_malloc0(sizeof(*info));
66f1b3ccfaSKevin Wolf 
67f1b3ccfaSKevin Wolf     info->UUID = qemu_uuid_unparse_strdup(&qemu_uuid);
68f1b3ccfaSKevin Wolf     return info;
69f1b3ccfaSKevin Wolf }
70f1b3ccfaSKevin Wolf 
71f1b3ccfaSKevin Wolf void qmp_quit(Error **errp)
72f1b3ccfaSKevin Wolf {
73e6dba048SAlejandro Jimenez     shutdown_action = SHUTDOWN_ACTION_POWEROFF;
74f1b3ccfaSKevin Wolf     qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_QMP_QUIT);
75f1b3ccfaSKevin Wolf }
76f1b3ccfaSKevin Wolf 
77f1b3ccfaSKevin Wolf void qmp_stop(Error **errp)
78f1b3ccfaSKevin Wolf {
79f1b3ccfaSKevin Wolf     /* if there is a dump in background, we should wait until the dump
80f1b3ccfaSKevin Wolf      * finished */
81544803c7SMarc-André Lureau     if (qemu_system_dump_in_progress()) {
82f1b3ccfaSKevin Wolf         error_setg(errp, "There is a dump in process, please wait.");
83f1b3ccfaSKevin Wolf         return;
84f1b3ccfaSKevin Wolf     }
85f1b3ccfaSKevin Wolf 
86f1b3ccfaSKevin Wolf     if (runstate_check(RUN_STATE_INMIGRATE)) {
87f1b3ccfaSKevin Wolf         autostart = 0;
88f1b3ccfaSKevin Wolf     } else {
89f1b3ccfaSKevin Wolf         vm_stop(RUN_STATE_PAUSED);
90f1b3ccfaSKevin Wolf     }
91f1b3ccfaSKevin Wolf }
92f1b3ccfaSKevin Wolf 
93f1b3ccfaSKevin Wolf void qmp_system_reset(Error **errp)
94f1b3ccfaSKevin Wolf {
95f1b3ccfaSKevin Wolf     qemu_system_reset_request(SHUTDOWN_CAUSE_HOST_QMP_SYSTEM_RESET);
96f1b3ccfaSKevin Wolf }
97f1b3ccfaSKevin Wolf 
98ec48595eSVladimir Sementsov-Ogievskiy void qmp_system_powerdown(Error **errp)
99f1b3ccfaSKevin Wolf {
100f1b3ccfaSKevin Wolf     qemu_system_powerdown_request();
101f1b3ccfaSKevin Wolf }
102f1b3ccfaSKevin Wolf 
103f1b3ccfaSKevin Wolf void qmp_cont(Error **errp)
104f1b3ccfaSKevin Wolf {
105f1b3ccfaSKevin Wolf     BlockBackend *blk;
10668d00e42SVladimir Sementsov-Ogievskiy     BlockJob *job;
107f1b3ccfaSKevin Wolf     Error *local_err = NULL;
108f1b3ccfaSKevin Wolf 
109f1b3ccfaSKevin Wolf     /* if there is a dump in background, we should wait until the dump
110f1b3ccfaSKevin Wolf      * finished */
111544803c7SMarc-André Lureau     if (qemu_system_dump_in_progress()) {
112f1b3ccfaSKevin Wolf         error_setg(errp, "There is a dump in process, please wait.");
113f1b3ccfaSKevin Wolf         return;
114f1b3ccfaSKevin Wolf     }
115f1b3ccfaSKevin Wolf 
116f1b3ccfaSKevin Wolf     if (runstate_needs_reset()) {
117f1b3ccfaSKevin Wolf         error_setg(errp, "Resetting the Virtual Machine is required");
118f1b3ccfaSKevin Wolf         return;
119f1b3ccfaSKevin Wolf     } else if (runstate_check(RUN_STATE_SUSPENDED)) {
120f1b3ccfaSKevin Wolf         return;
121f1b3ccfaSKevin Wolf     } else if (runstate_check(RUN_STATE_FINISH_MIGRATE)) {
122f1b3ccfaSKevin Wolf         error_setg(errp, "Migration is not finalized yet");
123f1b3ccfaSKevin Wolf         return;
124f1b3ccfaSKevin Wolf     }
125f1b3ccfaSKevin Wolf 
126f1b3ccfaSKevin Wolf     for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
127f1b3ccfaSKevin Wolf         blk_iostatus_reset(blk);
128f1b3ccfaSKevin Wolf     }
129f1b3ccfaSKevin Wolf 
130880eeec6SEmanuele Giuseppe Esposito     WITH_JOB_LOCK_GUARD() {
131880eeec6SEmanuele Giuseppe Esposito         for (job = block_job_next_locked(NULL); job;
132880eeec6SEmanuele Giuseppe Esposito              job = block_job_next_locked(job)) {
133880eeec6SEmanuele Giuseppe Esposito             block_job_iostatus_reset_locked(job);
134880eeec6SEmanuele Giuseppe Esposito         }
13568d00e42SVladimir Sementsov-Ogievskiy     }
13668d00e42SVladimir Sementsov-Ogievskiy 
137f1b3ccfaSKevin Wolf     /* Continuing after completed migration. Images have been inactivated to
138f1b3ccfaSKevin Wolf      * allow the destination to take control. Need to get control back now.
139f1b3ccfaSKevin Wolf      *
140f1b3ccfaSKevin Wolf      * If there are no inactive block nodes (e.g. because the VM was just
141f1b3ccfaSKevin Wolf      * paused rather than completing a migration), bdrv_inactivate_all() simply
142f1b3ccfaSKevin Wolf      * doesn't do anything. */
1433b717194SEmanuele Giuseppe Esposito     bdrv_activate_all(&local_err);
144f1b3ccfaSKevin Wolf     if (local_err) {
145f1b3ccfaSKevin Wolf         error_propagate(errp, local_err);
146f1b3ccfaSKevin Wolf         return;
147f1b3ccfaSKevin Wolf     }
148f1b3ccfaSKevin Wolf 
149f1b3ccfaSKevin Wolf     if (runstate_check(RUN_STATE_INMIGRATE)) {
150f1b3ccfaSKevin Wolf         autostart = 1;
151f1b3ccfaSKevin Wolf     } else {
152f1b3ccfaSKevin Wolf         vm_start();
153f1b3ccfaSKevin Wolf     }
154f1b3ccfaSKevin Wolf }
155f1b3ccfaSKevin Wolf 
156f1b3ccfaSKevin Wolf void qmp_system_wakeup(Error **errp)
157f1b3ccfaSKevin Wolf {
158f1b3ccfaSKevin Wolf     if (!qemu_wakeup_suspend_enabled()) {
159f1b3ccfaSKevin Wolf         error_setg(errp,
160f1b3ccfaSKevin Wolf                    "wake-up from suspend is not supported by this guest");
161f1b3ccfaSKevin Wolf         return;
162f1b3ccfaSKevin Wolf     }
163f1b3ccfaSKevin Wolf 
164f1b3ccfaSKevin Wolf     qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, errp);
165f1b3ccfaSKevin Wolf }
166f1b3ccfaSKevin Wolf 
167f1b3ccfaSKevin Wolf void qmp_add_client(const char *protocol, const char *fdname,
168f1b3ccfaSKevin Wolf                     bool has_skipauth, bool skipauth, bool has_tls, bool tls,
169f1b3ccfaSKevin Wolf                     Error **errp)
170f1b3ccfaSKevin Wolf {
171*3125af29SMarkus Armbruster     static struct {
172*3125af29SMarkus Armbruster         const char *name;
173*3125af29SMarkus Armbruster         bool (*add_client)(int fd, bool has_skipauth, bool skipauth,
174*3125af29SMarkus Armbruster                            bool has_tls, bool tls, Error **errp);
175*3125af29SMarkus Armbruster     } protocol_table[] = {
176*3125af29SMarkus Armbruster         { "spice", qmp_add_client_spice },
177*3125af29SMarkus Armbruster #ifdef CONFIG_VNC
178*3125af29SMarkus Armbruster         { "vnc", qmp_add_client_vnc },
179*3125af29SMarkus Armbruster #endif
180*3125af29SMarkus Armbruster #ifdef CONFIG_DBUS_DISPLAY
181*3125af29SMarkus Armbruster         { "@dbus-display", qmp_add_client_dbus_display },
182*3125af29SMarkus Armbruster #endif
183*3125af29SMarkus Armbruster     };
184f1b3ccfaSKevin Wolf     Chardev *s;
185*3125af29SMarkus Armbruster     int fd, i;
186f1b3ccfaSKevin Wolf 
187947e4744SKevin Wolf     fd = monitor_get_fd(monitor_cur(), fdname, errp);
188f1b3ccfaSKevin Wolf     if (fd < 0) {
189f1b3ccfaSKevin Wolf         return;
190f1b3ccfaSKevin Wolf     }
191f1b3ccfaSKevin Wolf 
192*3125af29SMarkus Armbruster     for (i = 0; i < ARRAY_SIZE(protocol_table); i++) {
193*3125af29SMarkus Armbruster         if (!strcmp(protocol, protocol_table[i].name)) {
194*3125af29SMarkus Armbruster             if (!protocol_table[i].add_client(fd, has_skipauth, skipauth,
195*3125af29SMarkus Armbruster                                               has_tls, tls, errp)) {
196f1b3ccfaSKevin Wolf                 close(fd);
197*3125af29SMarkus Armbruster             }
198f1b3ccfaSKevin Wolf             return;
199f1b3ccfaSKevin Wolf         }
200f1b3ccfaSKevin Wolf     }
201*3125af29SMarkus Armbruster 
20261d7f2a9SMarkus Armbruster     s = qemu_chr_find(protocol);
20361d7f2a9SMarkus Armbruster     if (!s) {
20461d7f2a9SMarkus Armbruster         error_setg(errp, "protocol '%s' is invalid", protocol);
20561d7f2a9SMarkus Armbruster         close(fd);
20661d7f2a9SMarkus Armbruster         return;
20761d7f2a9SMarkus Armbruster     }
208f1b3ccfaSKevin Wolf     if (qemu_chr_add_client(s, fd) < 0) {
209f1b3ccfaSKevin Wolf         error_setg(errp, "failed to add client");
210f1b3ccfaSKevin Wolf         close(fd);
211f1b3ccfaSKevin Wolf         return;
212f1b3ccfaSKevin Wolf     }
213f1b3ccfaSKevin Wolf }
214f1b3ccfaSKevin Wolf 
215f1b3ccfaSKevin Wolf MemoryDeviceInfoList *qmp_query_memory_devices(Error **errp)
216f1b3ccfaSKevin Wolf {
217f1b3ccfaSKevin Wolf     return qmp_memory_device_list();
218f1b3ccfaSKevin Wolf }
219f1b3ccfaSKevin Wolf 
220f1b3ccfaSKevin Wolf ACPIOSTInfoList *qmp_query_acpi_ospm_status(Error **errp)
221f1b3ccfaSKevin Wolf {
222f1b3ccfaSKevin Wolf     bool ambig;
223f1b3ccfaSKevin Wolf     ACPIOSTInfoList *head = NULL;
224f1b3ccfaSKevin Wolf     ACPIOSTInfoList **prev = &head;
225f1b3ccfaSKevin Wolf     Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, &ambig);
226f1b3ccfaSKevin Wolf 
227f1b3ccfaSKevin Wolf     if (obj) {
228f1b3ccfaSKevin Wolf         AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj);
229f1b3ccfaSKevin Wolf         AcpiDeviceIf *adev = ACPI_DEVICE_IF(obj);
230f1b3ccfaSKevin Wolf 
231f1b3ccfaSKevin Wolf         adevc->ospm_status(adev, &prev);
232f1b3ccfaSKevin Wolf     } else {
233f1b3ccfaSKevin Wolf         error_setg(errp, "command is not supported, missing ACPI device");
234f1b3ccfaSKevin Wolf     }
235f1b3ccfaSKevin Wolf 
236f1b3ccfaSKevin Wolf     return head;
237f1b3ccfaSKevin Wolf }
238f1b3ccfaSKevin Wolf 
239f1b3ccfaSKevin Wolf MemoryInfo *qmp_query_memory_size_summary(Error **errp)
240f1b3ccfaSKevin Wolf {
241b21e2380SMarkus Armbruster     MemoryInfo *mem_info = g_new0(MemoryInfo, 1);
242b326b6eaSPaolo Bonzini     MachineState *ms = MACHINE(qdev_get_machine());
243f1b3ccfaSKevin Wolf 
244b326b6eaSPaolo Bonzini     mem_info->base_memory = ms->ram_size;
245f1b3ccfaSKevin Wolf 
246f1b3ccfaSKevin Wolf     mem_info->plugged_memory = get_plugged_memory_size();
247f1b3ccfaSKevin Wolf     mem_info->has_plugged_memory =
248f1b3ccfaSKevin Wolf         mem_info->plugged_memory != (uint64_t)-1;
249f1b3ccfaSKevin Wolf 
250f1b3ccfaSKevin Wolf     return mem_info;
251f1b3ccfaSKevin Wolf }
2529cc07651SZihao Chang 
2538dbbca5cSDaniel P. Berrangé static int qmp_x_query_rdma_foreach(Object *obj, void *opaque)
2548dbbca5cSDaniel P. Berrangé {
2558dbbca5cSDaniel P. Berrangé     RdmaProvider *rdma;
2568dbbca5cSDaniel P. Berrangé     RdmaProviderClass *k;
2578dbbca5cSDaniel P. Berrangé     GString *buf = opaque;
2588dbbca5cSDaniel P. Berrangé 
2598dbbca5cSDaniel P. Berrangé     if (object_dynamic_cast(obj, INTERFACE_RDMA_PROVIDER)) {
2608dbbca5cSDaniel P. Berrangé         rdma = RDMA_PROVIDER(obj);
2618dbbca5cSDaniel P. Berrangé         k = RDMA_PROVIDER_GET_CLASS(obj);
2628dbbca5cSDaniel P. Berrangé         if (k->format_statistics) {
2638dbbca5cSDaniel P. Berrangé             k->format_statistics(rdma, buf);
2648dbbca5cSDaniel P. Berrangé         } else {
2658dbbca5cSDaniel P. Berrangé             g_string_append_printf(buf,
2668dbbca5cSDaniel P. Berrangé                                    "RDMA statistics not available for %s.\n",
2678dbbca5cSDaniel P. Berrangé                                    object_get_typename(obj));
2688dbbca5cSDaniel P. Berrangé         }
2698dbbca5cSDaniel P. Berrangé     }
2708dbbca5cSDaniel P. Berrangé 
2718dbbca5cSDaniel P. Berrangé     return 0;
2728dbbca5cSDaniel P. Berrangé }
2738dbbca5cSDaniel P. Berrangé 
2748dbbca5cSDaniel P. Berrangé HumanReadableText *qmp_x_query_rdma(Error **errp)
2758dbbca5cSDaniel P. Berrangé {
2768dbbca5cSDaniel P. Berrangé     g_autoptr(GString) buf = g_string_new("");
2778dbbca5cSDaniel P. Berrangé 
2788dbbca5cSDaniel P. Berrangé     object_child_foreach_recursive(object_get_root(),
2798dbbca5cSDaniel P. Berrangé                                    qmp_x_query_rdma_foreach, buf);
2808dbbca5cSDaniel P. Berrangé 
2818dbbca5cSDaniel P. Berrangé     return human_readable_text_from_str(buf);
2828dbbca5cSDaniel P. Berrangé }
283ca411b7cSDaniel P. Berrangé 
284ca411b7cSDaniel P. Berrangé HumanReadableText *qmp_x_query_ramblock(Error **errp)
285ca411b7cSDaniel P. Berrangé {
286ca411b7cSDaniel P. Berrangé     g_autoptr(GString) buf = ram_block_format();
287ca411b7cSDaniel P. Berrangé 
288ca411b7cSDaniel P. Berrangé     return human_readable_text_from_str(buf);
289ca411b7cSDaniel P. Berrangé }
29091f2fa70SDaniel P. Berrangé 
29191f2fa70SDaniel P. Berrangé static int qmp_x_query_irq_foreach(Object *obj, void *opaque)
29291f2fa70SDaniel P. Berrangé {
29391f2fa70SDaniel P. Berrangé     InterruptStatsProvider *intc;
29491f2fa70SDaniel P. Berrangé     InterruptStatsProviderClass *k;
29591f2fa70SDaniel P. Berrangé     GString *buf = opaque;
29691f2fa70SDaniel P. Berrangé 
29791f2fa70SDaniel P. Berrangé     if (object_dynamic_cast(obj, TYPE_INTERRUPT_STATS_PROVIDER)) {
29891f2fa70SDaniel P. Berrangé         intc = INTERRUPT_STATS_PROVIDER(obj);
29991f2fa70SDaniel P. Berrangé         k = INTERRUPT_STATS_PROVIDER_GET_CLASS(obj);
30091f2fa70SDaniel P. Berrangé         uint64_t *irq_counts;
30191f2fa70SDaniel P. Berrangé         unsigned int nb_irqs, i;
30291f2fa70SDaniel P. Berrangé         if (k->get_statistics &&
30391f2fa70SDaniel P. Berrangé             k->get_statistics(intc, &irq_counts, &nb_irqs)) {
30491f2fa70SDaniel P. Berrangé             if (nb_irqs > 0) {
30591f2fa70SDaniel P. Berrangé                 g_string_append_printf(buf, "IRQ statistics for %s:\n",
30691f2fa70SDaniel P. Berrangé                                        object_get_typename(obj));
30791f2fa70SDaniel P. Berrangé                 for (i = 0; i < nb_irqs; i++) {
30891f2fa70SDaniel P. Berrangé                     if (irq_counts[i] > 0) {
30991f2fa70SDaniel P. Berrangé                         g_string_append_printf(buf, "%2d: %" PRId64 "\n", i,
31091f2fa70SDaniel P. Berrangé                                                irq_counts[i]);
31191f2fa70SDaniel P. Berrangé                     }
31291f2fa70SDaniel P. Berrangé                 }
31391f2fa70SDaniel P. Berrangé             }
31491f2fa70SDaniel P. Berrangé         } else {
31591f2fa70SDaniel P. Berrangé             g_string_append_printf(buf,
31691f2fa70SDaniel P. Berrangé                                    "IRQ statistics not available for %s.\n",
31791f2fa70SDaniel P. Berrangé                                    object_get_typename(obj));
31891f2fa70SDaniel P. Berrangé         }
31991f2fa70SDaniel P. Berrangé     }
32091f2fa70SDaniel P. Berrangé 
32191f2fa70SDaniel P. Berrangé     return 0;
32291f2fa70SDaniel P. Berrangé }
32391f2fa70SDaniel P. Berrangé 
32491f2fa70SDaniel P. Berrangé HumanReadableText *qmp_x_query_irq(Error **errp)
32591f2fa70SDaniel P. Berrangé {
32691f2fa70SDaniel P. Berrangé     g_autoptr(GString) buf = g_string_new("");
32791f2fa70SDaniel P. Berrangé 
32891f2fa70SDaniel P. Berrangé     object_child_foreach_recursive(object_get_root(),
32991f2fa70SDaniel P. Berrangé                                    qmp_x_query_irq_foreach, buf);
33091f2fa70SDaniel P. Berrangé 
33191f2fa70SDaniel P. Berrangé     return human_readable_text_from_str(buf);
33291f2fa70SDaniel P. Berrangé }
333b9f88dc0SMark Kanda 
334b9f88dc0SMark Kanda typedef struct StatsCallbacks {
335068cc51dSPaolo Bonzini     StatsProvider provider;
336b9f88dc0SMark Kanda     StatRetrieveFunc *stats_cb;
337b9f88dc0SMark Kanda     SchemaRetrieveFunc *schemas_cb;
338b9f88dc0SMark Kanda     QTAILQ_ENTRY(StatsCallbacks) next;
339b9f88dc0SMark Kanda } StatsCallbacks;
340b9f88dc0SMark Kanda 
341b9f88dc0SMark Kanda static QTAILQ_HEAD(, StatsCallbacks) stats_callbacks =
342b9f88dc0SMark Kanda     QTAILQ_HEAD_INITIALIZER(stats_callbacks);
343b9f88dc0SMark Kanda 
344068cc51dSPaolo Bonzini void add_stats_callbacks(StatsProvider provider,
345068cc51dSPaolo Bonzini                          StatRetrieveFunc *stats_fn,
346b9f88dc0SMark Kanda                          SchemaRetrieveFunc *schemas_fn)
347b9f88dc0SMark Kanda {
348b9f88dc0SMark Kanda     StatsCallbacks *entry = g_new(StatsCallbacks, 1);
349068cc51dSPaolo Bonzini     entry->provider = provider;
350b9f88dc0SMark Kanda     entry->stats_cb = stats_fn;
351b9f88dc0SMark Kanda     entry->schemas_cb = schemas_fn;
352b9f88dc0SMark Kanda 
353b9f88dc0SMark Kanda     QTAILQ_INSERT_TAIL(&stats_callbacks, entry, next);
354b9f88dc0SMark Kanda }
355b9f88dc0SMark Kanda 
356b9f88dc0SMark Kanda static bool invoke_stats_cb(StatsCallbacks *entry,
357b9f88dc0SMark Kanda                             StatsResultList **stats_results,
358068cc51dSPaolo Bonzini                             StatsFilter *filter, StatsRequest *request,
359b9f88dc0SMark Kanda                             Error **errp)
360b9f88dc0SMark Kanda {
36105e385d2SMarkus Armbruster     ERRP_GUARD();
362467ef823SPaolo Bonzini     strList *targets = NULL;
363cf7405bcSPaolo Bonzini     strList *names = NULL;
364b9f88dc0SMark Kanda 
365068cc51dSPaolo Bonzini     if (request) {
366068cc51dSPaolo Bonzini         if (request->provider != entry->provider) {
367068cc51dSPaolo Bonzini             return true;
368068cc51dSPaolo Bonzini         }
369cf7405bcSPaolo Bonzini         if (request->has_names && !request->names) {
370cf7405bcSPaolo Bonzini             return true;
371cf7405bcSPaolo Bonzini         }
372cf7405bcSPaolo Bonzini         names = request->has_names ? request->names : NULL;
373068cc51dSPaolo Bonzini     }
374068cc51dSPaolo Bonzini 
375467ef823SPaolo Bonzini     switch (filter->target) {
376467ef823SPaolo Bonzini     case STATS_TARGET_VM:
377467ef823SPaolo Bonzini         break;
378467ef823SPaolo Bonzini     case STATS_TARGET_VCPU:
379467ef823SPaolo Bonzini         if (filter->u.vcpu.has_vcpus) {
380467ef823SPaolo Bonzini             if (!filter->u.vcpu.vcpus) {
381467ef823SPaolo Bonzini                 /* No targets allowed?  Return no statistics.  */
382467ef823SPaolo Bonzini                 return true;
383467ef823SPaolo Bonzini             }
384467ef823SPaolo Bonzini             targets = filter->u.vcpu.vcpus;
385467ef823SPaolo Bonzini         }
386467ef823SPaolo Bonzini         break;
387467ef823SPaolo Bonzini     default:
388467ef823SPaolo Bonzini         abort();
389467ef823SPaolo Bonzini     }
390467ef823SPaolo Bonzini 
391cf7405bcSPaolo Bonzini     entry->stats_cb(stats_results, filter->target, names, targets, errp);
392b9f88dc0SMark Kanda     if (*errp) {
393b9f88dc0SMark Kanda         qapi_free_StatsResultList(*stats_results);
394b9f88dc0SMark Kanda         *stats_results = NULL;
395b9f88dc0SMark Kanda         return false;
396b9f88dc0SMark Kanda     }
397b9f88dc0SMark Kanda     return true;
398b9f88dc0SMark Kanda }
399b9f88dc0SMark Kanda 
400b9f88dc0SMark Kanda StatsResultList *qmp_query_stats(StatsFilter *filter, Error **errp)
401b9f88dc0SMark Kanda {
402b9f88dc0SMark Kanda     StatsResultList *stats_results = NULL;
403b9f88dc0SMark Kanda     StatsCallbacks *entry;
404068cc51dSPaolo Bonzini     StatsRequestList *request;
405b9f88dc0SMark Kanda 
406b9f88dc0SMark Kanda     QTAILQ_FOREACH(entry, &stats_callbacks, next) {
407068cc51dSPaolo Bonzini         if (filter->has_providers) {
408068cc51dSPaolo Bonzini             for (request = filter->providers; request; request = request->next) {
409068cc51dSPaolo Bonzini                 if (!invoke_stats_cb(entry, &stats_results, filter,
410068cc51dSPaolo Bonzini                                      request->value, errp)) {
411b9f88dc0SMark Kanda                     break;
412b9f88dc0SMark Kanda                 }
413b9f88dc0SMark Kanda             }
414068cc51dSPaolo Bonzini         } else {
415068cc51dSPaolo Bonzini             if (!invoke_stats_cb(entry, &stats_results, filter, NULL, errp)) {
416068cc51dSPaolo Bonzini                 break;
417068cc51dSPaolo Bonzini             }
418068cc51dSPaolo Bonzini         }
419068cc51dSPaolo Bonzini     }
420b9f88dc0SMark Kanda 
421b9f88dc0SMark Kanda     return stats_results;
422b9f88dc0SMark Kanda }
423b9f88dc0SMark Kanda 
424068cc51dSPaolo Bonzini StatsSchemaList *qmp_query_stats_schemas(bool has_provider,
425068cc51dSPaolo Bonzini                                          StatsProvider provider,
426068cc51dSPaolo Bonzini                                          Error **errp)
427b9f88dc0SMark Kanda {
42805e385d2SMarkus Armbruster     ERRP_GUARD();
429b9f88dc0SMark Kanda     StatsSchemaList *stats_results = NULL;
430b9f88dc0SMark Kanda     StatsCallbacks *entry;
431b9f88dc0SMark Kanda 
432b9f88dc0SMark Kanda     QTAILQ_FOREACH(entry, &stats_callbacks, next) {
433068cc51dSPaolo Bonzini         if (!has_provider || provider == entry->provider) {
434b9f88dc0SMark Kanda             entry->schemas_cb(&stats_results, errp);
435b9f88dc0SMark Kanda             if (*errp) {
436b9f88dc0SMark Kanda                 qapi_free_StatsSchemaList(stats_results);
437b9f88dc0SMark Kanda                 return NULL;
438b9f88dc0SMark Kanda             }
439b9f88dc0SMark Kanda         }
440068cc51dSPaolo Bonzini     }
441b9f88dc0SMark Kanda 
442b9f88dc0SMark Kanda     return stats_results;
443b9f88dc0SMark Kanda }
444b9f88dc0SMark Kanda 
445b9f88dc0SMark Kanda void add_stats_entry(StatsResultList **stats_results, StatsProvider provider,
446b9f88dc0SMark Kanda                      const char *qom_path, StatsList *stats_list)
447b9f88dc0SMark Kanda {
448b9f88dc0SMark Kanda     StatsResult *entry = g_new0(StatsResult, 1);
449b9f88dc0SMark Kanda 
450b9f88dc0SMark Kanda     entry->provider = provider;
451b9f88dc0SMark Kanda     entry->qom_path = g_strdup(qom_path);
452b9f88dc0SMark Kanda     entry->stats = stats_list;
453b9f88dc0SMark Kanda 
454b9f88dc0SMark Kanda     QAPI_LIST_PREPEND(*stats_results, entry);
455b9f88dc0SMark Kanda }
456b9f88dc0SMark Kanda 
457b9f88dc0SMark Kanda void add_stats_schema(StatsSchemaList **schema_results,
458b9f88dc0SMark Kanda                       StatsProvider provider, StatsTarget target,
459b9f88dc0SMark Kanda                       StatsSchemaValueList *stats_list)
460b9f88dc0SMark Kanda {
461b9f88dc0SMark Kanda     StatsSchema *entry = g_new0(StatsSchema, 1);
462b9f88dc0SMark Kanda 
463b9f88dc0SMark Kanda     entry->provider = provider;
464b9f88dc0SMark Kanda     entry->target = target;
465b9f88dc0SMark Kanda     entry->stats = stats_list;
466b9f88dc0SMark Kanda     QAPI_LIST_PREPEND(*schema_results, entry);
467b9f88dc0SMark Kanda }
468467ef823SPaolo Bonzini 
469467ef823SPaolo Bonzini bool apply_str_list_filter(const char *string, strList *list)
470467ef823SPaolo Bonzini {
471467ef823SPaolo Bonzini     strList *str_list = NULL;
472467ef823SPaolo Bonzini 
473467ef823SPaolo Bonzini     if (!list) {
474467ef823SPaolo Bonzini         return true;
475467ef823SPaolo Bonzini     }
476467ef823SPaolo Bonzini     for (str_list = list; str_list; str_list = str_list->next) {
477467ef823SPaolo Bonzini         if (g_str_equal(string, str_list->value)) {
478467ef823SPaolo Bonzini             return true;
479467ef823SPaolo Bonzini         }
480467ef823SPaolo Bonzini     }
481467ef823SPaolo Bonzini     return false;
482467ef823SPaolo Bonzini }
483