X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fvirt.c;h=c6280d12932e1ff49d0dd64b2f47cdb87fe3ab5e;hb=c10379655f3ab88a1bfd657eeccc311c3c943f38;hp=7896b2e571f2ca58665a160623c4a1b303a231aa;hpb=7325774e210ab695351723e56a32dd3679af2032;p=collectd.git diff --git a/src/virt.c b/src/virt.c index 7896b2e5..c6280d12 100644 --- a/src/virt.c +++ b/src/virt.c @@ -34,10 +34,19 @@ #include #include #include +#include /* Plugin name */ #define PLUGIN_NAME "virt" +/* Secure strcat macro assuring null termination. Parameter (n) is the size of + buffer (d), allowing this macro to be safe for static and dynamic buffers */ +#define SSTRNCAT(d, s, n) \ + do { \ + size_t _l = strlen(d); \ + sstrncpy((d) + _l, (s), (n)-_l); \ + } while (0) + #ifdef LIBVIR_CHECK_VERSION #if LIBVIR_CHECK_VERSION(0, 9, 2) @@ -65,11 +74,9 @@ in some systems which actually have virConnectListAllDomains() we can't detect this. */ -#ifdef LIBVIR_CHECK_VERSION #if LIBVIR_CHECK_VERSION(0, 10, 2) #define HAVE_LIST_ALL_DOMAINS 1 #endif -#endif #if LIBVIR_CHECK_VERSION(1, 0, 1) #define HAVE_DOM_REASON_PAUSED_SNAPSHOT 1 @@ -102,6 +109,14 @@ #endif /* LIBVIR_CHECK_VERSION */ +/* structure used for aggregating notification-thread data*/ +typedef struct virt_notif_thread_s { + pthread_t event_loop_tid; + int domain_event_cb_id; + pthread_mutex_t active_mutex; /* protects 'is_active' member access*/ + bool is_active; +} virt_notif_thread_t; + static const char *config_keys[] = {"Connection", "RefreshInterval", @@ -124,12 +139,10 @@ static const char *config_keys[] = {"Connection", NULL}; /* PersistentNotification is false by default */ -static _Bool persistent_notification = 0; +static bool persistent_notification = false; -/* libvirt event loop */ -static pthread_t event_loop_tid; - -static int domain_event_cb_id; +/* Thread used for handling libvirt notifications events */ +static virt_notif_thread_t notif_thread; const char *domain_states[] = { [VIR_DOMAIN_NOSTATE] = "no state", @@ -163,18 +176,23 @@ static int map_domain_event_to_state(int event) { case VIR_DOMAIN_EVENT_SHUTDOWN: ret = VIR_DOMAIN_SHUTDOWN; break; +#ifdef HAVE_DOM_STATE_PMSUSPENDED case VIR_DOMAIN_EVENT_PMSUSPENDED: ret = VIR_DOMAIN_PMSUSPENDED; break; +#endif +#ifdef HAVE_DOM_REASON_CRASHED case VIR_DOMAIN_EVENT_CRASHED: ret = VIR_DOMAIN_CRASHED; break; +#endif default: ret = VIR_DOMAIN_NOSTATE; } return ret; } +#ifdef HAVE_DOM_REASON static int map_domain_event_detail_to_reason(int event, int detail) { int ret; switch (event) { @@ -183,7 +201,8 @@ static int map_domain_event_detail_to_reason(int event, int detail) { case VIR_DOMAIN_EVENT_STARTED_BOOTED: /* Normal startup from boot */ ret = VIR_DOMAIN_RUNNING_BOOTED; break; - case VIR_DOMAIN_EVENT_STARTED_MIGRATED: /* Incoming migration from another host */ + case VIR_DOMAIN_EVENT_STARTED_MIGRATED: /* Incoming migration from another + host */ ret = VIR_DOMAIN_RUNNING_MIGRATED; break; case VIR_DOMAIN_EVENT_STARTED_RESTORED: /* Restored from a state file */ @@ -192,60 +211,78 @@ static int map_domain_event_detail_to_reason(int event, int detail) { case VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT: /* Restored from snapshot */ ret = VIR_DOMAIN_RUNNING_FROM_SNAPSHOT; break; +#ifdef HAVE_DOM_REASON_RUNNING_WAKEUP case VIR_DOMAIN_EVENT_STARTED_WAKEUP: /* Started due to wakeup event */ ret = VIR_DOMAIN_RUNNING_WAKEUP; break; +#endif default: ret = VIR_DOMAIN_RUNNING_UNKNOWN; } break; case VIR_DOMAIN_EVENT_SUSPENDED: switch (detail) { - case VIR_DOMAIN_EVENT_SUSPENDED_PAUSED: /* Normal suspend due to admin pause */ + case VIR_DOMAIN_EVENT_SUSPENDED_PAUSED: /* Normal suspend due to admin + pause */ ret = VIR_DOMAIN_PAUSED_USER; break; - case VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED: /* Suspended for offline migration */ + case VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED: /* Suspended for offline + migration */ ret = VIR_DOMAIN_PAUSED_MIGRATION; break; - case VIR_DOMAIN_EVENT_SUSPENDED_IOERROR: /* Suspended due to a disk I/O error */ + case VIR_DOMAIN_EVENT_SUSPENDED_IOERROR: /* Suspended due to a disk I/O + error */ ret = VIR_DOMAIN_PAUSED_IOERROR; break; - case VIR_DOMAIN_EVENT_SUSPENDED_WATCHDOG: /* Suspended due to a watchdog firing */ + case VIR_DOMAIN_EVENT_SUSPENDED_WATCHDOG: /* Suspended due to a watchdog + firing */ ret = VIR_DOMAIN_PAUSED_WATCHDOG; break; - case VIR_DOMAIN_EVENT_SUSPENDED_RESTORED: /* Restored from paused state file */ + case VIR_DOMAIN_EVENT_SUSPENDED_RESTORED: /* Restored from paused state + file */ ret = VIR_DOMAIN_PAUSED_UNKNOWN; break; - case VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT: /* Restored from paused snapshot */ + case VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT: /* Restored from paused + snapshot */ ret = VIR_DOMAIN_PAUSED_FROM_SNAPSHOT; break; - case VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR: /* Suspended after failure during libvirt API call */ + case VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR: /* Suspended after failure during + libvirt API call */ ret = VIR_DOMAIN_PAUSED_UNKNOWN; break; - case VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY: /* Suspended for post-copy migration */ +#ifdef HAVE_DOM_REASON_POSTCOPY + case VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY: /* Suspended for post-copy + migration */ ret = VIR_DOMAIN_PAUSED_POSTCOPY; break; - case VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY_FAILED: /* Suspended after failed post-copy */ + case VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY_FAILED: /* Suspended after failed + post-copy */ ret = VIR_DOMAIN_PAUSED_POSTCOPY_FAILED; break; +#endif default: ret = VIR_DOMAIN_PAUSED_UNKNOWN; } break; case VIR_DOMAIN_EVENT_RESUMED: switch (detail) { - case VIR_DOMAIN_EVENT_RESUMED_UNPAUSED: /* Normal resume due to admin unpause */ + case VIR_DOMAIN_EVENT_RESUMED_UNPAUSED: /* Normal resume due to admin + unpause */ ret = VIR_DOMAIN_RUNNING_UNPAUSED; break; - case VIR_DOMAIN_EVENT_RESUMED_MIGRATED: /* Resumed for completion of migration */ + case VIR_DOMAIN_EVENT_RESUMED_MIGRATED: /* Resumed for completion of + migration */ ret = VIR_DOMAIN_RUNNING_MIGRATED; break; case VIR_DOMAIN_EVENT_RESUMED_FROM_SNAPSHOT: /* Resumed from snapshot */ ret = VIR_DOMAIN_RUNNING_FROM_SNAPSHOT; break; - case VIR_DOMAIN_EVENT_RESUMED_POSTCOPY: /* Resumed, but migration is still running in post-copy mode */ +#ifdef HAVE_DOM_REASON_POSTCOPY + case VIR_DOMAIN_EVENT_RESUMED_POSTCOPY: /* Resumed, but migration is still + running in post-copy mode */ ret = VIR_DOMAIN_RUNNING_POSTCOPY; break; +#endif default: ret = VIR_DOMAIN_RUNNING_UNKNOWN; } @@ -279,16 +316,19 @@ static int map_domain_event_detail_to_reason(int event, int detail) { break; case VIR_DOMAIN_EVENT_SHUTDOWN: switch (detail) { - case VIR_DOMAIN_EVENT_SHUTDOWN_FINISHED: /* Guest finished shutdown sequence */ + case VIR_DOMAIN_EVENT_SHUTDOWN_FINISHED: /* Guest finished shutdown + sequence */ ret = VIR_DOMAIN_SHUTDOWN_USER; break; default: ret = VIR_DOMAIN_SHUTDOWN_UNKNOWN; } break; +#ifdef HAVE_DOM_STATE_PMSUSPENDED case VIR_DOMAIN_EVENT_PMSUSPENDED: switch (detail) { - case VIR_DOMAIN_EVENT_PMSUSPENDED_MEMORY: /* Guest was PM suspended to memory */ + case VIR_DOMAIN_EVENT_PMSUSPENDED_MEMORY: /* Guest was PM suspended to + memory */ ret = VIR_DOMAIN_PMSUSPENDED_UNKNOWN; break; case VIR_DOMAIN_EVENT_PMSUSPENDED_DISK: /* Guest was PM suspended to disk */ @@ -298,6 +338,7 @@ static int map_domain_event_detail_to_reason(int event, int detail) { ret = VIR_DOMAIN_PMSUSPENDED_UNKNOWN; } break; +#endif case VIR_DOMAIN_EVENT_CRASHED: switch (detail) { case VIR_DOMAIN_EVENT_CRASHED_PANICKED: /* Guest was panicked */ @@ -313,7 +354,6 @@ static int map_domain_event_detail_to_reason(int event, int detail) { return ret; } -#ifdef HAVE_DOM_REASON #define DOMAIN_STATE_REASON_MAX_SIZE 20 const char *domain_reasons[][DOMAIN_STATE_REASON_MAX_SIZE] = { [VIR_DOMAIN_NOSTATE][VIR_DOMAIN_NOSTATE_UNKNOWN] = @@ -347,7 +387,6 @@ const char *domain_reasons[][DOMAIN_STATE_REASON_MAX_SIZE] = { [VIR_DOMAIN_RUNNING][VIR_DOMAIN_RUNNING_POSTCOPY] = "running in post-copy migration mode", #endif - [VIR_DOMAIN_BLOCKED][VIR_DOMAIN_BLOCKED_UNKNOWN] = "the reason is unknown", @@ -387,7 +426,6 @@ const char *domain_reasons[][DOMAIN_STATE_REASON_MAX_SIZE] = { [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_POSTCOPY_FAILED] = "paused after failed post-copy", #endif - [VIR_DOMAIN_SHUTDOWN][VIR_DOMAIN_SHUTDOWN_UNKNOWN] = "the reason is unknown", [VIR_DOMAIN_SHUTDOWN][VIR_DOMAIN_SHUTDOWN_USER] = @@ -430,8 +468,8 @@ const char *domain_reasons[][DOMAIN_STATE_REASON_MAX_SIZE] = { } while (0) /* Connection. */ -static virConnectPtr conn = 0; -static char *conn_string = NULL; +static virConnectPtr conn; +static char *conn_string; static c_complain_t conn_complain = C_COMPLAIN_INIT_STATIC; /* Node information required for %CPU */ @@ -441,11 +479,11 @@ static virNodeInfo nodeinfo; static int interval = 60; /* List of domains, if specified. */ -static ignorelist_t *il_domains = NULL; +static ignorelist_t *il_domains; /* List of block devices, if specified. */ -static ignorelist_t *il_block_devices = NULL; +static ignorelist_t *il_block_devices; /* List of network interface devices, if specified. */ -static ignorelist_t *il_interface_devices = NULL; +static ignorelist_t *il_interface_devices; static int ignore_device_match(ignorelist_t *, const char *domname, const char *devpath); @@ -467,7 +505,7 @@ struct interface_device { typedef struct domain_s { virDomainPtr ptr; virDomainInfo info; - _Bool active; + bool active; } domain_t; struct lv_read_state { @@ -484,7 +522,7 @@ struct lv_read_state { static void free_domains(struct lv_read_state *state); static int add_domain(struct lv_read_state *state, virDomainPtr dom, - _Bool active); + bool active); static void free_block_devices(struct lv_read_state *state); static int add_block_device(struct lv_read_state *state, virDomainPtr dom, @@ -592,7 +630,7 @@ static const struct ex_stats_item ex_stats_table[] = { }; /* BlockDeviceFormatBasename */ -_Bool blockdevice_format_basename = 0; +static bool blockdevice_format_basename; static enum bd_field blockdevice_format = target; static enum if_field interface_format = if_name; @@ -724,7 +762,6 @@ static int lv_domain_info(virDomainPtr dom, struct lv_info *info) { } static void init_value_list(value_list_t *vl, virDomainPtr dom) { - int n; const char *name; char uuid[VIR_UUID_STRING_BUFLEN]; @@ -737,44 +774,34 @@ static void init_value_list(value_list_t *vl, virDomainPtr dom) { if (hostname_format[i] == hf_none) continue; - n = DATA_MAX_NAME_LEN - strlen(vl->host) - 2; - - if (i > 0 && n >= 1) { - strncat(vl->host, ":", 1); - n--; - } + if (i > 0) + SSTRNCAT(vl->host, ":", sizeof(vl->host)); switch (hostname_format[i]) { case hf_none: break; case hf_hostname: - strncat(vl->host, hostname_g, n); + SSTRNCAT(vl->host, hostname_g, sizeof(vl->host)); break; case hf_name: name = virDomainGetName(dom); if (name) - strncat(vl->host, name, n); + SSTRNCAT(vl->host, name, sizeof(vl->host)); break; case hf_uuid: if (virDomainGetUUIDString(dom, uuid) == 0) - strncat(vl->host, uuid, n); + SSTRNCAT(vl->host, uuid, sizeof(vl->host)); break; } } - vl->host[sizeof(vl->host) - 1] = '\0'; - /* Construct the plugin instance field according to PluginInstanceFormat. */ for (int i = 0; i < PLGINST_MAX_FIELDS; ++i) { if (plugin_instance_format[i] == plginst_none) continue; - n = sizeof(vl->plugin_instance) - strlen(vl->plugin_instance) - 2; - - if (i > 0 && n >= 1) { - strncat(vl->plugin_instance, ":", 1); - n--; - } + if (i > 0) + SSTRNCAT(vl->plugin_instance, ":", sizeof(vl->plugin_instance)); switch (plugin_instance_format[i]) { case plginst_none: @@ -782,17 +809,15 @@ static void init_value_list(value_list_t *vl, virDomainPtr dom) { case plginst_name: name = virDomainGetName(dom); if (name) - strncat(vl->plugin_instance, name, n); + SSTRNCAT(vl->plugin_instance, name, sizeof(vl->plugin_instance)); break; case plginst_uuid: if (virDomainGetUUIDString(dom, uuid) == 0) - strncat(vl->plugin_instance, uuid, n); + SSTRNCAT(vl->plugin_instance, uuid, sizeof(vl->plugin_instance)); break; } } - vl->plugin_instance[sizeof(vl->plugin_instance) - 1] = '\0'; - } /* void init_value_list */ static int init_notif(notification_t *notif, const virDomainPtr domain, @@ -991,7 +1016,7 @@ static unsigned int parse_ex_stats_flags(char **exstats, int numexstats) { } static void domain_state_submit_notif(virDomainPtr dom, int state, int reason) { - if ((state < 0) || (state >= STATIC_ARRAY_SIZE(domain_states))) { + if ((state < 0) || ((size_t)state >= STATIC_ARRAY_SIZE(domain_states))) { ERROR(PLUGIN_NAME ": Array index out of bounds: state=%d", state); return; } @@ -999,7 +1024,7 @@ static void domain_state_submit_notif(virDomainPtr dom, int state, int reason) { char msg[DATA_MAX_NAME_LEN]; const char *state_str = domain_states[state]; #ifdef HAVE_DOM_REASON - if ((reason < 0) || (reason >= STATIC_ARRAY_SIZE(domain_reasons[0]))) { + if ((reason < 0) || ((size_t)reason >= STATIC_ARRAY_SIZE(domain_reasons[0]))) { ERROR(PLUGIN_NAME ": Array index out of bounds: reason=%d", reason); return; } @@ -1098,7 +1123,7 @@ static int lv_config(const char *key, const char *value) { return 0; } if (strcasecmp(key, "BlockDeviceFormatBasename") == 0) { - blockdevice_format_basename = IS_TRUE(value); + blockdevice_format_basename = IS_TRUE(value) ? true : false; return 0; } if (strcasecmp(key, "InterfaceDevice") == 0) { @@ -1372,7 +1397,7 @@ static void vcpu_pin_submit(virDomainPtr dom, int max_cpus, int vcpu, unsigned char *cpu_maps, int cpu_map_len) { for (int cpu = 0; cpu < max_cpus; ++cpu) { char type_instance[DATA_MAX_NAME_LEN]; - _Bool is_set = VIR_CPU_USABLE(cpu_maps, cpu_map_len, vcpu, cpu) ? 1 : 0; + bool is_set = VIR_CPU_USABLE(cpu_maps, cpu_map_len, vcpu, cpu); snprintf(type_instance, sizeof(type_instance), "vcpu_%d-cpu_%d", vcpu, cpu); submit(dom, "cpu_affinity", type_instance, &(value_t){.gauge = is_set}, 1); @@ -1559,7 +1584,7 @@ static int get_block_stats(struct block_device *block_dev) { #define NM_ADD_STR_ITEMS(_items, _size) \ do { \ - for (int _i = 0; _i < _size; ++_i) { \ + for (size_t _i = 0; _i < _size; ++_i) { \ DEBUG(PLUGIN_NAME \ " plugin: Adding notification metadata name=%s value=%s", \ _items[_i].name, _items[_i].value); \ @@ -1584,7 +1609,7 @@ static int fs_info_notify(virDomainPtr domain, virDomainFSInfoPtr fs_info) { {.name = "name", .value = fs_info->name}, {.name = "fstype", .value = fs_info->fstype}}; - for (int i = 0; i < fs_info->ndevAlias; ++i) { + for (size_t i = 0; i < fs_info->ndevAlias; ++i) { fs_dev_alias[i].name = "devAlias"; fs_dev_alias[i].value = fs_info->devAlias[i]; } @@ -1803,7 +1828,10 @@ static int domain_lifecycle_event_cb(__attribute__((unused)) virConnectPtr conn, virDomainPtr dom, int event, int detail, __attribute__((unused)) void *opaque) { int domain_state = map_domain_event_to_state(event); - int domain_reason = map_domain_event_detail_to_reason(event, detail); + int domain_reason = 0; /* 0 means UNKNOWN reason for any state */ +#ifdef HAVE_DOM_REASON + domain_reason = map_domain_event_detail_to_reason(event, detail); +#endif domain_state_submit_notif(dom, domain_state, domain_reason); return 0; @@ -1821,9 +1849,30 @@ static int register_event_impl(void) { return 0; } +static void virt_notif_thread_set_active(virt_notif_thread_t *thread_data, + const bool active) { + assert(thread_data != NULL); + pthread_mutex_lock(&thread_data->active_mutex); + thread_data->is_active = active; + pthread_mutex_unlock(&thread_data->active_mutex); +} + +static bool virt_notif_thread_is_active(virt_notif_thread_t *thread_data) { + bool active = false; + + assert(thread_data != NULL); + pthread_mutex_lock(&thread_data->active_mutex); + active = thread_data->is_active; + pthread_mutex_unlock(&thread_data->active_mutex); + + return active; +} + /* worker function running default event implementation */ -static void *event_loop_worker(__attribute__((unused)) void *arg) { - while (1) { +static void *event_loop_worker(void *arg) { + virt_notif_thread_t *thread_data = (virt_notif_thread_t *)arg; + + while (virt_notif_thread_is_active(thread_data)) { if (virEventRunDefaultImpl() < 0) { virErrorPtr err = virGetLastError(); ERROR(PLUGIN_NAME " plugin: failed to run event loop: %s\n", @@ -1834,19 +1883,44 @@ static void *event_loop_worker(__attribute__((unused)) void *arg) { return NULL; } +static int virt_notif_thread_init(virt_notif_thread_t *thread_data) { + int ret; + + assert(thread_data != NULL); + ret = pthread_mutex_init(&thread_data->active_mutex, NULL); + if (ret != 0) { + ERROR(PLUGIN_NAME ": Failed to initialize mutex, err %u", ret); + return ret; + } + + /** + * '0' and positive integers are meaningful ID's, therefore setting + * domain_event_cb_id to '-1' + */ + thread_data->domain_event_cb_id = -1; + pthread_mutex_lock(&thread_data->active_mutex); + thread_data->is_active = false; + pthread_mutex_unlock(&thread_data->active_mutex); + + return 0; +} + /* register domain event callback and start event loop thread */ -static int start_event_loop(void) { - domain_event_cb_id = virConnectDomainEventRegisterAny( +static int start_event_loop(virt_notif_thread_t *thread_data) { + assert(thread_data != NULL); + thread_data->domain_event_cb_id = virConnectDomainEventRegisterAny( conn, NULL, VIR_DOMAIN_EVENT_ID_LIFECYCLE, VIR_DOMAIN_EVENT_CALLBACK(domain_lifecycle_event_cb), NULL, NULL); - if (domain_event_cb_id == -1) { + if (thread_data->domain_event_cb_id == -1) { ERROR(PLUGIN_NAME " plugin: error while callback registering"); return -1; } - if (pthread_create(&event_loop_tid, NULL, event_loop_worker, NULL)) { + virt_notif_thread_set_active(thread_data, 1); + if (pthread_create(&thread_data->event_loop_tid, NULL, event_loop_worker, + thread_data)) { ERROR(PLUGIN_NAME " plugin: failed event loop thread creation"); - virConnectDomainEventDeregisterAny(conn, domain_event_cb_id); + virConnectDomainEventDeregisterAny(conn, thread_data->domain_event_cb_id); return -1; } @@ -1854,31 +1928,27 @@ static int start_event_loop(void) { } /* stop event loop thread and deregister callback */ -static void stop_event_loop(void) { - if (pthread_cancel(event_loop_tid) != 0) - ERROR(PLUGIN_NAME " plugin: cancelling thread %lu failed", - event_loop_tid); - - if (pthread_join(event_loop_tid, NULL) != 0) - ERROR(PLUGIN_NAME " plugin: stopping thread %lu failed", - event_loop_tid); - - if (conn != NULL && domain_event_cb_id != -1) - virConnectDomainEventDeregisterAny(conn, domain_event_cb_id); +static void stop_event_loop(virt_notif_thread_t *thread_data) { + /* stopping loop and de-registering event handler*/ + virt_notif_thread_set_active(thread_data, 0); + if (conn != NULL && thread_data->domain_event_cb_id != -1) + virConnectDomainEventDeregisterAny(conn, thread_data->domain_event_cb_id); + + if (pthread_join(notif_thread.event_loop_tid, NULL) != 0) + ERROR(PLUGIN_NAME " plugin: stopping notification thread failed"); } static int persistent_domains_state_notification(void) { int status = 0; int n; #ifdef HAVE_LIST_ALL_DOMAINS - virDomainPtr *domains; + virDomainPtr *domains = NULL; n = virConnectListAllDomains(conn, &domains, - VIR_CONNECT_GET_ALL_DOMAINS_STATS_PERSISTENT); + VIR_CONNECT_LIST_DOMAINS_PERSISTENT); if (n < 0) { VIRT_ERROR(conn, "reading list of persistent domains"); status = -1; - } - else { + } else { DEBUG(PLUGIN_NAME " plugin: getting state of %i persistent domains", n); /* Fetch each persistent domain's state and notify it */ int n_notified = n; @@ -1889,6 +1959,7 @@ static int persistent_domains_state_notification(void) { ERROR(PLUGIN_NAME " plugin: could not notify state of domain %s", virDomainGetName(domains[i])); } + virDomainFree(domains[i]); } sfree(domains); @@ -1900,9 +1971,9 @@ static int persistent_domains_state_notification(void) { if (n > 0) { int *domids; /* Get list of domains. */ - domids = malloc(sizeof(*domids) * n); + domids = calloc(n, sizeof(*domids)); if (domids == NULL) { - ERROR(PLUGIN_NAME " plugin: malloc failed."); + ERROR(PLUGIN_NAME " plugin: calloc failed."); return -1; } n = virConnectListDomains(conn, domids, n); @@ -1922,14 +1993,15 @@ static int persistent_domains_state_notification(void) { continue; } status = virDomainGetInfo(dom, &info); - if (status != 0) { + if (status == 0) + /* virDomainGetState is not available. Submit 0, which corresponds to + * unknown reason. */ + domain_state_submit_notif(dom, info.state, 0); + else ERROR(PLUGIN_NAME " plugin: virDomainGetInfo failed with status %i.", status); - continue; - } - /* virDomainGetState is not available. Submit 0, which corresponds to - * unknown reason. */ - domain_state_submit_notif(dom, info.state, 0); + + virDomainFree(dom); } sfree(domids); } @@ -1951,7 +2023,7 @@ static int lv_read(user_data_t *ud) { inst = ud->data; state = &inst->read_state; - _Bool reconnect = conn == NULL ? 1 : 0; + bool reconnect = conn == NULL ? true : false; /* event implementation must be registered before connection is opened */ if (inst->id == 0) { if (!persistent_notification && reconnect) @@ -1962,7 +2034,7 @@ static int lv_read(user_data_t *ud) { return -1; if (!persistent_notification && reconnect && conn != NULL) - if (start_event_loop() != 0) + if (start_event_loop(¬if_thread) != 0) return -1; } @@ -1971,16 +2043,10 @@ static int lv_read(user_data_t *ud) { /* Need to refresh domain or device lists? */ if ((last_refresh == (time_t)0) || ((interval > 0) && ((last_refresh + interval) <= t))) { - if (inst->id == 0 && persistent_notification) { - int status = persistent_domains_state_notification(); - if (status != 0) - DEBUG(PLUGIN_NAME " plugin: persistent_domains_state_notifications " \ - "returned with status %i", status); - } if (refresh_lists(inst) != 0) { if (inst->id == 0) { if (!persistent_notification) - stop_event_loop(); + stop_event_loop(¬if_thread); lv_disconnect(); } return -1; @@ -1988,28 +2054,39 @@ static int lv_read(user_data_t *ud) { last_refresh = t; } - #if COLLECT_DEBUG - for (int i = 0; i < state->nr_domains; ++i) - DEBUG(PLUGIN_NAME " plugin: domain %s", - virDomainGetName(state->domains[i].ptr)); - for (int i = 0; i < state->nr_block_devices; ++i) - DEBUG(PLUGIN_NAME " plugin: block device %d %s:%s", - i, virDomainGetName(state->block_devices[i].dom), - state->block_devices[i].path); - for (int i = 0; i < state->nr_interface_devices; ++i) - DEBUG(PLUGIN_NAME " plugin: interface device %d %s:%s", - i, virDomainGetName(state->interface_devices[i].dom), - state->interface_devices[i].path); - #endif + /* persistent domains state notifications are handled by instance 0 */ + if (inst->id == 0 && persistent_notification) { + int status = persistent_domains_state_notification(); + if (status != 0) + DEBUG(PLUGIN_NAME " plugin: persistent_domains_state_notifications " + "returned with status %i", + status); + } + +#if COLLECT_DEBUG + for (int i = 0; i < state->nr_domains; ++i) + DEBUG(PLUGIN_NAME " plugin: domain %s", + virDomainGetName(state->domains[i].ptr)); + for (int i = 0; i < state->nr_block_devices; ++i) + DEBUG(PLUGIN_NAME " plugin: block device %d %s:%s", i, + virDomainGetName(state->block_devices[i].dom), + state->block_devices[i].path); + for (int i = 0; i < state->nr_interface_devices; ++i) + DEBUG(PLUGIN_NAME " plugin: interface device %d %s:%s", i, + virDomainGetName(state->interface_devices[i].dom), + state->interface_devices[i].path); +#endif /* Get domains' metrics */ for (int i = 0; i < state->nr_domains; ++i) { domain_t *dom = &state->domains[i]; - int status; + int status = 0; if (dom->active) status = get_domain_metrics(dom); +#ifdef HAVE_DOM_REASON else status = get_domain_state(dom->ptr); +#endif if (status != 0) ERROR(PLUGIN_NAME " failed to get metrics for domain=%s", @@ -2086,9 +2163,11 @@ static int lv_init(void) { DEBUG(PLUGIN_NAME " plugin: starting event loop"); - if (!persistent_notification) - if (start_event_loop() != 0) + if (!persistent_notification) { + virt_notif_thread_init(¬if_thread); + if (start_event_loop(¬if_thread) != 0) return -1; + } DEBUG(PLUGIN_NAME " plugin: starting %i instances", nr_instances); @@ -2216,15 +2295,14 @@ static int refresh_lists(struct lv_read_instance *inst) { virDomainPtr *domains, *domains_inactive; int m = virConnectListAllDomains(conn, &domains_inactive, VIR_CONNECT_LIST_DOMAINS_INACTIVE); - n = virConnectListAllDomains(conn, &domains, - VIR_CONNECT_LIST_DOMAINS_ACTIVE); + n = virConnectListAllDomains(conn, &domains, VIR_CONNECT_LIST_DOMAINS_ACTIVE); #else int *domids; /* Get list of domains. */ - domids = malloc(sizeof(*domids) * n); + domids = calloc(n, sizeof(*domids)); if (domids == NULL) { - ERROR(PLUGIN_NAME " plugin: malloc failed."); + ERROR(PLUGIN_NAME " plugin: calloc failed."); return -1; } @@ -2236,6 +2314,8 @@ static int refresh_lists(struct lv_read_instance *inst) { #ifndef HAVE_LIST_ALL_DOMAINS sfree(domids); #else + for (int i = 0; i < m; ++i) + virDomainFree(domains_inactive[i]); sfree(domains_inactive); #endif return -1; @@ -2245,6 +2325,8 @@ static int refresh_lists(struct lv_read_instance *inst) { for (int i = 0; i < m; ++i) if (add_domain(state, domains_inactive[i], 0) < 0) { ERROR(PLUGIN_NAME " plugin: malloc failed."); + virDomainFree(domains_inactive[i]); + domains_inactive[i] = NULL; continue; } #endif @@ -2272,6 +2354,20 @@ static int refresh_lists(struct lv_read_instance *inst) { } #endif + if (add_domain(state, dom, 1) < 0) { + /* + * When domain is already tracked, then there is + * no problem with memory handling (will be freed + * with the rest of domains cached data) + * But in case of error like this (error occurred + * before adding domain to track) we have to take + * care it ourselves and call virDomainFree + */ + ERROR(PLUGIN_NAME " plugin: malloc failed."); + virDomainFree(dom); + goto cont; + } + name = virDomainGetName(dom); if (name == NULL) { VIRT_ERROR(conn, "virDomainGetName"); @@ -2317,11 +2413,6 @@ static int refresh_lists(struct lv_read_instance *inst) { if (!lv_instance_include_domain(inst, name, tag)) goto cont; - if (add_domain(state, dom, 1) < 0) { - ERROR(PLUGIN_NAME " plugin: malloc failed."); - goto cont; - } - /* Block devices. */ const char *bd_xmlpath = "/domain/devices/disk/target[@dev]"; if (blockdevice_format == source) @@ -2412,6 +2503,9 @@ static int refresh_lists(struct lv_read_instance *inst) { } #ifdef HAVE_LIST_ALL_DOMAINS + /* NOTE: domains_active and domains_inactive data will be cleared during + refresh of all domains (inside lv_clean_read_state function) so we need + to free here only allocated arrays */ sfree(domains); sfree(domains_inactive); #else @@ -2439,7 +2533,7 @@ static void free_domains(struct lv_read_state *state) { } static int add_domain(struct lv_read_state *state, virDomainPtr dom, - _Bool active) { + bool active) { domain_t *new_ptr; int new_size = sizeof(state->domains[0]) * (state->nr_domains + 1); @@ -2515,7 +2609,7 @@ static int add_interface_device(struct lv_read_state *state, virDomainPtr dom, struct interface_device *new_ptr; int new_size = sizeof(state->interface_devices[0]) * (state->nr_interface_devices + 1); - char *path_copy, *address_copy, number_string[15]; + char *path_copy, *address_copy, number_string[21]; if ((path == NULL) || (address == NULL)) return EINVAL; @@ -2579,7 +2673,7 @@ static int lv_shutdown(void) { DEBUG(PLUGIN_NAME " plugin: stopping event loop"); if (!persistent_notification) - stop_event_loop(); + stop_event_loop(¬if_thread); lv_disconnect();