|  | /* | 
|  | * QMP commands related to stats | 
|  | * | 
|  | * This work is licensed under the terms of the GNU GPL, version 2 or | 
|  | * (at your option) any later version. | 
|  | */ | 
|  |  | 
|  | #include "qemu/osdep.h" | 
|  | #include "system/stats.h" | 
|  | #include "qapi/qapi-commands-stats.h" | 
|  | #include "qemu/queue.h" | 
|  | #include "qapi/error.h" | 
|  |  | 
|  | typedef struct StatsCallbacks { | 
|  | StatsProvider provider; | 
|  | StatRetrieveFunc *stats_cb; | 
|  | SchemaRetrieveFunc *schemas_cb; | 
|  | QTAILQ_ENTRY(StatsCallbacks) next; | 
|  | } StatsCallbacks; | 
|  |  | 
|  | static QTAILQ_HEAD(, StatsCallbacks) stats_callbacks = | 
|  | QTAILQ_HEAD_INITIALIZER(stats_callbacks); | 
|  |  | 
|  | void add_stats_callbacks(StatsProvider provider, | 
|  | StatRetrieveFunc *stats_fn, | 
|  | SchemaRetrieveFunc *schemas_fn) | 
|  | { | 
|  | StatsCallbacks *entry = g_new(StatsCallbacks, 1); | 
|  | entry->provider = provider; | 
|  | entry->stats_cb = stats_fn; | 
|  | entry->schemas_cb = schemas_fn; | 
|  |  | 
|  | QTAILQ_INSERT_TAIL(&stats_callbacks, entry, next); | 
|  | } | 
|  |  | 
|  | static bool invoke_stats_cb(StatsCallbacks *entry, | 
|  | StatsResultList **stats_results, | 
|  | StatsFilter *filter, StatsRequest *request, | 
|  | Error **errp) | 
|  | { | 
|  | ERRP_GUARD(); | 
|  | strList *targets = NULL; | 
|  | strList *names = NULL; | 
|  |  | 
|  | if (request) { | 
|  | if (request->provider != entry->provider) { | 
|  | return true; | 
|  | } | 
|  | if (request->has_names && !request->names) { | 
|  | return true; | 
|  | } | 
|  | names = request->has_names ? request->names : NULL; | 
|  | } | 
|  |  | 
|  | switch (filter->target) { | 
|  | case STATS_TARGET_VM: | 
|  | break; | 
|  | case STATS_TARGET_VCPU: | 
|  | if (filter->u.vcpu.has_vcpus) { | 
|  | if (!filter->u.vcpu.vcpus) { | 
|  | /* No targets allowed?  Return no statistics.  */ | 
|  | return true; | 
|  | } | 
|  | targets = filter->u.vcpu.vcpus; | 
|  | } | 
|  | break; | 
|  | case STATS_TARGET_CRYPTODEV: | 
|  | break; | 
|  | default: | 
|  | abort(); | 
|  | } | 
|  |  | 
|  | entry->stats_cb(stats_results, filter->target, names, targets, errp); | 
|  | if (*errp) { | 
|  | qapi_free_StatsResultList(*stats_results); | 
|  | *stats_results = NULL; | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | StatsResultList *qmp_query_stats(StatsFilter *filter, Error **errp) | 
|  | { | 
|  | StatsResultList *stats_results = NULL; | 
|  | StatsCallbacks *entry; | 
|  | StatsRequestList *request; | 
|  |  | 
|  | QTAILQ_FOREACH(entry, &stats_callbacks, next) { | 
|  | if (filter->has_providers) { | 
|  | for (request = filter->providers; request; request = request->next) { | 
|  | if (!invoke_stats_cb(entry, &stats_results, filter, | 
|  | request->value, errp)) { | 
|  | break; | 
|  | } | 
|  | } | 
|  | } else { | 
|  | if (!invoke_stats_cb(entry, &stats_results, filter, NULL, errp)) { | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return stats_results; | 
|  | } | 
|  |  | 
|  | StatsSchemaList *qmp_query_stats_schemas(bool has_provider, | 
|  | StatsProvider provider, | 
|  | Error **errp) | 
|  | { | 
|  | ERRP_GUARD(); | 
|  | StatsSchemaList *stats_results = NULL; | 
|  | StatsCallbacks *entry; | 
|  |  | 
|  | QTAILQ_FOREACH(entry, &stats_callbacks, next) { | 
|  | if (!has_provider || provider == entry->provider) { | 
|  | entry->schemas_cb(&stats_results, errp); | 
|  | if (*errp) { | 
|  | qapi_free_StatsSchemaList(stats_results); | 
|  | return NULL; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return stats_results; | 
|  | } | 
|  |  | 
|  | void add_stats_entry(StatsResultList **stats_results, StatsProvider provider, | 
|  | const char *qom_path, StatsList *stats_list) | 
|  | { | 
|  | StatsResult *entry = g_new0(StatsResult, 1); | 
|  |  | 
|  | entry->provider = provider; | 
|  | entry->qom_path = g_strdup(qom_path); | 
|  | entry->stats = stats_list; | 
|  |  | 
|  | QAPI_LIST_PREPEND(*stats_results, entry); | 
|  | } | 
|  |  | 
|  | void add_stats_schema(StatsSchemaList **schema_results, | 
|  | StatsProvider provider, StatsTarget target, | 
|  | StatsSchemaValueList *stats_list) | 
|  | { | 
|  | StatsSchema *entry = g_new0(StatsSchema, 1); | 
|  |  | 
|  | entry->provider = provider; | 
|  | entry->target = target; | 
|  | entry->stats = stats_list; | 
|  | QAPI_LIST_PREPEND(*schema_results, entry); | 
|  | } | 
|  |  | 
|  | bool apply_str_list_filter(const char *string, strList *list) | 
|  | { | 
|  | strList *str_list = NULL; | 
|  |  | 
|  | if (!list) { | 
|  | return true; | 
|  | } | 
|  | for (str_list = list; str_list; str_list = str_list->next) { | 
|  | if (g_str_equal(string, str_list->value)) { | 
|  | return true; | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } |