1 /* 2 * QMP commands related to stats 3 * 4 * This work is licensed under the terms of the GNU GPL, version 2 or 5 * (at your option) any later version. 6 */ 7 8 #include "qemu/osdep.h" 9 #include "sysemu/stats.h" 10 #include "qapi/qapi-commands-stats.h" 11 #include "qemu/queue.h" 12 #include "qapi/error.h" 13 14 typedef struct StatsCallbacks { 15 StatsProvider provider; 16 StatRetrieveFunc *stats_cb; 17 SchemaRetrieveFunc *schemas_cb; 18 QTAILQ_ENTRY(StatsCallbacks) next; 19 } StatsCallbacks; 20 21 static QTAILQ_HEAD(, StatsCallbacks) stats_callbacks = 22 QTAILQ_HEAD_INITIALIZER(stats_callbacks); 23 24 void add_stats_callbacks(StatsProvider provider, 25 StatRetrieveFunc *stats_fn, 26 SchemaRetrieveFunc *schemas_fn) 27 { 28 StatsCallbacks *entry = g_new(StatsCallbacks, 1); 29 entry->provider = provider; 30 entry->stats_cb = stats_fn; 31 entry->schemas_cb = schemas_fn; 32 33 QTAILQ_INSERT_TAIL(&stats_callbacks, entry, next); 34 } 35 36 static bool invoke_stats_cb(StatsCallbacks *entry, 37 StatsResultList **stats_results, 38 StatsFilter *filter, StatsRequest *request, 39 Error **errp) 40 { 41 ERRP_GUARD(); 42 strList *targets = NULL; 43 strList *names = NULL; 44 45 if (request) { 46 if (request->provider != entry->provider) { 47 return true; 48 } 49 if (request->has_names && !request->names) { 50 return true; 51 } 52 names = request->has_names ? request->names : NULL; 53 } 54 55 switch (filter->target) { 56 case STATS_TARGET_VM: 57 break; 58 case STATS_TARGET_VCPU: 59 if (filter->u.vcpu.has_vcpus) { 60 if (!filter->u.vcpu.vcpus) { 61 /* No targets allowed? Return no statistics. */ 62 return true; 63 } 64 targets = filter->u.vcpu.vcpus; 65 } 66 break; 67 default: 68 abort(); 69 } 70 71 entry->stats_cb(stats_results, filter->target, names, targets, errp); 72 if (*errp) { 73 qapi_free_StatsResultList(*stats_results); 74 *stats_results = NULL; 75 return false; 76 } 77 return true; 78 } 79 80 StatsResultList *qmp_query_stats(StatsFilter *filter, Error **errp) 81 { 82 StatsResultList *stats_results = NULL; 83 StatsCallbacks *entry; 84 StatsRequestList *request; 85 86 QTAILQ_FOREACH(entry, &stats_callbacks, next) { 87 if (filter->has_providers) { 88 for (request = filter->providers; request; request = request->next) { 89 if (!invoke_stats_cb(entry, &stats_results, filter, 90 request->value, errp)) { 91 break; 92 } 93 } 94 } else { 95 if (!invoke_stats_cb(entry, &stats_results, filter, NULL, errp)) { 96 break; 97 } 98 } 99 } 100 101 return stats_results; 102 } 103 104 StatsSchemaList *qmp_query_stats_schemas(bool has_provider, 105 StatsProvider provider, 106 Error **errp) 107 { 108 ERRP_GUARD(); 109 StatsSchemaList *stats_results = NULL; 110 StatsCallbacks *entry; 111 112 QTAILQ_FOREACH(entry, &stats_callbacks, next) { 113 if (!has_provider || provider == entry->provider) { 114 entry->schemas_cb(&stats_results, errp); 115 if (*errp) { 116 qapi_free_StatsSchemaList(stats_results); 117 return NULL; 118 } 119 } 120 } 121 122 return stats_results; 123 } 124 125 void add_stats_entry(StatsResultList **stats_results, StatsProvider provider, 126 const char *qom_path, StatsList *stats_list) 127 { 128 StatsResult *entry = g_new0(StatsResult, 1); 129 130 entry->provider = provider; 131 entry->qom_path = g_strdup(qom_path); 132 entry->stats = stats_list; 133 134 QAPI_LIST_PREPEND(*stats_results, entry); 135 } 136 137 void add_stats_schema(StatsSchemaList **schema_results, 138 StatsProvider provider, StatsTarget target, 139 StatsSchemaValueList *stats_list) 140 { 141 StatsSchema *entry = g_new0(StatsSchema, 1); 142 143 entry->provider = provider; 144 entry->target = target; 145 entry->stats = stats_list; 146 QAPI_LIST_PREPEND(*schema_results, entry); 147 } 148 149 bool apply_str_list_filter(const char *string, strList *list) 150 { 151 strList *str_list = NULL; 152 153 if (!list) { 154 return true; 155 } 156 for (str_list = list; str_list; str_list = str_list->next) { 157 if (g_str_equal(string, str_list->value)) { 158 return true; 159 } 160 } 161 return false; 162 } 163