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 case STATS_TARGET_CRYPTODEV: 68 break; 69 default: 70 abort(); 71 } 72 73 entry->stats_cb(stats_results, filter->target, names, targets, errp); 74 if (*errp) { 75 qapi_free_StatsResultList(*stats_results); 76 *stats_results = NULL; 77 return false; 78 } 79 return true; 80 } 81 82 StatsResultList *qmp_query_stats(StatsFilter *filter, Error **errp) 83 { 84 StatsResultList *stats_results = NULL; 85 StatsCallbacks *entry; 86 StatsRequestList *request; 87 88 QTAILQ_FOREACH(entry, &stats_callbacks, next) { 89 if (filter->has_providers) { 90 for (request = filter->providers; request; request = request->next) { 91 if (!invoke_stats_cb(entry, &stats_results, filter, 92 request->value, errp)) { 93 break; 94 } 95 } 96 } else { 97 if (!invoke_stats_cb(entry, &stats_results, filter, NULL, errp)) { 98 break; 99 } 100 } 101 } 102 103 return stats_results; 104 } 105 106 StatsSchemaList *qmp_query_stats_schemas(bool has_provider, 107 StatsProvider provider, 108 Error **errp) 109 { 110 ERRP_GUARD(); 111 StatsSchemaList *stats_results = NULL; 112 StatsCallbacks *entry; 113 114 QTAILQ_FOREACH(entry, &stats_callbacks, next) { 115 if (!has_provider || provider == entry->provider) { 116 entry->schemas_cb(&stats_results, errp); 117 if (*errp) { 118 qapi_free_StatsSchemaList(stats_results); 119 return NULL; 120 } 121 } 122 } 123 124 return stats_results; 125 } 126 127 void add_stats_entry(StatsResultList **stats_results, StatsProvider provider, 128 const char *qom_path, StatsList *stats_list) 129 { 130 StatsResult *entry = g_new0(StatsResult, 1); 131 132 entry->provider = provider; 133 entry->qom_path = g_strdup(qom_path); 134 entry->stats = stats_list; 135 136 QAPI_LIST_PREPEND(*stats_results, entry); 137 } 138 139 void add_stats_schema(StatsSchemaList **schema_results, 140 StatsProvider provider, StatsTarget target, 141 StatsSchemaValueList *stats_list) 142 { 143 StatsSchema *entry = g_new0(StatsSchema, 1); 144 145 entry->provider = provider; 146 entry->target = target; 147 entry->stats = stats_list; 148 QAPI_LIST_PREPEND(*schema_results, entry); 149 } 150 151 bool apply_str_list_filter(const char *string, strList *list) 152 { 153 strList *str_list = NULL; 154 155 if (!list) { 156 return true; 157 } 158 for (str_list = list; str_list; str_list = str_list->next) { 159 if (g_str_equal(string, str_list->value)) { 160 return true; 161 } 162 } 163 return false; 164 } 165