X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Ftracker.c;h=05e2fe6cd12d689269b4ba254e2f5b63f1f1ceb8;hp=cff5af3a0612c750a431fea74e435fd0d5c89591;hb=159b042f34366d0fde5dcd73b4231c558922a664;hpb=ac41e67e39946acd97752ce52b964976890c5e87 diff --git a/src/bin/lttng-sessiond/tracker.c b/src/bin/lttng-sessiond/tracker.c index cff5af3a0..05e2fe6cd 100644 --- a/src/bin/lttng-sessiond/tracker.c +++ b/src/bin/lttng-sessiond/tracker.c @@ -1,525 +1,312 @@ /* * Copyright (C) 2018 Mathieu Desnoyers + * Copyright (C) 2020 Jérémie Galarneau * * SPDX-License-Identifier: GPL-2.0-only * */ +#include "lttng/tracker.h" +#include "common/dynamic-array.h" +#include "common/macros.h" #define _LGPL_SOURCE #include #include #include #include +#include +#include +#include #include "tracker.h" #include #include #include #include +#include #include -#include -#define FALLBACK_USER_BUFLEN 16384 -#define FALLBACK_GROUP_BUFLEN 16384 +struct process_attr_tracker_value_node { + struct process_attr_value *value; + struct cds_lfht_node inclusion_set_ht_node; + struct rcu_head rcu_head; +}; -struct lttng_tracker_list *lttng_tracker_list_create(void) +struct process_attr_tracker { + enum lttng_tracking_policy policy; + struct cds_lfht *inclusion_set_ht; +}; + +static void process_attr_tracker_value_node_rcu_free(struct rcu_head *rcu_head) +{ + struct process_attr_tracker_value_node *node = + container_of(rcu_head, typeof(*node), rcu_head); + + free(node); +} + +struct process_attr_tracker *process_attr_tracker_create(void) { - struct lttng_tracker_list *t; + struct process_attr_tracker *tracker; - t = zmalloc(sizeof(*t)); - if (!t) { + tracker = zmalloc(sizeof(*tracker)); + if (!tracker) { return NULL; } - t->ht = cds_lfht_new(DEFAULT_HT_SIZE, 1, 0, + + (void) process_attr_tracker_set_tracking_policy( + tracker, LTTNG_TRACKING_POLICY_INCLUDE_ALL); + + tracker->inclusion_set_ht = cds_lfht_new(DEFAULT_HT_SIZE, 1, 0, CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING, NULL); - if (!t->ht) { + if (!tracker->inclusion_set_ht) { goto error; } - CDS_INIT_LIST_HEAD(&t->list_head); - t->state = LTTNG_TRACK_ALL; - return t; + return tracker; error: - free(t); + process_attr_tracker_destroy(tracker); return NULL; } -static int match_tracker_key(struct cds_lfht_node *node, const void *key) +static void process_attr_tracker_remove_value_node( + struct process_attr_tracker *tracker, + struct process_attr_tracker_value_node *value_node) { - const struct lttng_tracker_id *tracker_key = key; - struct lttng_tracker_list_node *tracker_node; - - tracker_node = caa_container_of( - node, struct lttng_tracker_list_node, ht_node); - - return lttng_tracker_id_is_equal(tracker_node->id, tracker_key); + cds_lfht_del(tracker->inclusion_set_ht, + &value_node->inclusion_set_ht_node); + process_attr_value_destroy(value_node->value); + call_rcu(&value_node->rcu_head, + process_attr_tracker_value_node_rcu_free); } -static unsigned long hash_tracker_key( - const struct lttng_tracker_id *tracker_key) +static void process_attr_tracker_clear_inclusion_set( + struct process_attr_tracker *tracker) { - unsigned long key_hash = 0; - int value; - const char *string; - enum lttng_tracker_id_type type; - - /* We do not care for invalid state during hash computation */ - type = lttng_tracker_id_get_type(tracker_key); - (void) lttng_tracker_id_get_value(tracker_key, &value); - (void) lttng_tracker_id_get_string(tracker_key, &string); - - switch (type) { - case LTTNG_ID_ALL: - break; - case LTTNG_ID_VALUE: - key_hash ^= hash_key_ulong( - (void *) (unsigned long) value, lttng_ht_seed); - break; - case LTTNG_ID_STRING: - key_hash ^= hash_key_str(string, lttng_ht_seed); - break; - case LTTNG_ID_UNKNOWN: - break; - } - key_hash ^= hash_key_ulong( - (void *) (unsigned long) type, lttng_ht_seed); - return key_hash; -} + int ret; + struct lttng_ht_iter iter; + struct process_attr_tracker_value_node *value_node; -static struct lttng_tracker_id **lttng_tracker_list_lookup( - const struct lttng_tracker_list *tracker_list, - const struct lttng_tracker_id *key) -{ - struct lttng_tracker_list_node *list_node; - struct cds_lfht_iter iter; - struct cds_lfht_node *node; + if (!tracker->inclusion_set_ht) { + return; + } - cds_lfht_lookup(tracker_list->ht, hash_tracker_key(key), - match_tracker_key, key, &iter); - node = cds_lfht_iter_get_node(&iter); - if (!node) { - return NULL; + rcu_read_lock(); + cds_lfht_for_each_entry (tracker->inclusion_set_ht, &iter.iter, + value_node, inclusion_set_ht_node) { + process_attr_tracker_remove_value_node(tracker, value_node); } - list_node = caa_container_of( - node, struct lttng_tracker_list_node, ht_node); - return &list_node->id; + rcu_read_unlock(); + ret = cds_lfht_destroy(tracker->inclusion_set_ht, NULL); + assert(ret == 0); + tracker->inclusion_set_ht = NULL; } -static void destroy_list_node_rcu(struct rcu_head *head) +static int process_attr_tracker_create_inclusion_set( + struct process_attr_tracker *tracker) { - struct lttng_tracker_list_node *n = caa_container_of( - head, struct lttng_tracker_list_node, rcu_head); - - lttng_tracker_id_destroy(n->id); - free(n); + assert(!tracker->inclusion_set_ht); + tracker->inclusion_set_ht = cds_lfht_new(DEFAULT_HT_SIZE, 1, 0, + CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING, NULL); + return tracker->inclusion_set_ht ? 0 : -1; } -static void _lttng_tracker_list_remove(struct lttng_tracker_list *tracker_list, - struct lttng_tracker_list_node *n) +void process_attr_tracker_destroy(struct process_attr_tracker *tracker) { - cds_list_del(&n->list_node); - - rcu_read_lock(); - cds_lfht_del(tracker_list->ht, &n->ht_node); - rcu_read_unlock(); + if (!tracker) { + return; + } - call_rcu(&n->rcu_head, destroy_list_node_rcu); + process_attr_tracker_clear_inclusion_set(tracker); + free(tracker); } -static void lttng_tracker_list_reset(struct lttng_tracker_list *tracker_list) +enum lttng_tracking_policy process_attr_tracker_get_tracking_policy( + const struct process_attr_tracker *tracker) { - struct lttng_tracker_list_node *n, *t; - - cds_list_for_each_entry_safe ( - n, t, &tracker_list->list_head, list_node) { - _lttng_tracker_list_remove(tracker_list, n); - } - tracker_list->state = LTTNG_TRACK_ALL; + return tracker->policy; } -/* Protected by session mutex held by caller. */ -int lttng_tracker_list_add(struct lttng_tracker_list *tracker_list, - const struct lttng_tracker_id *_id) +int process_attr_tracker_set_tracking_policy( + struct process_attr_tracker *tracker, + enum lttng_tracking_policy tracking_policy) { - struct lttng_tracker_id **id; - struct lttng_tracker_list_node *n = NULL; - int ret; + int ret = 0; - if (lttng_tracker_id_get_type(_id) == LTTNG_ID_ALL) { - /* Track all, so remove each individual item. */ - lttng_tracker_list_reset(tracker_list); - ret = LTTNG_OK; - goto error; - } - rcu_read_lock(); - id = lttng_tracker_list_lookup(tracker_list, _id); - /* - * It is okay to release the RCU read lock here since id is only checked - * for != NULL and not dereferenced. - */ - rcu_read_unlock(); - if (id) { - ret = LTTNG_ERR_ID_TRACKED; - goto error; - } - n = zmalloc(sizeof(*n)); - if (!n) { - ret = LTTNG_ERR_NOMEM; - goto error; + if (tracker->policy == tracking_policy) { + goto end; } - n->id = lttng_tracker_id_duplicate(_id); - if (!n->id) { - ret = LTTNG_ERR_NOMEM; - goto error; + process_attr_tracker_clear_inclusion_set(tracker); + ret = process_attr_tracker_create_inclusion_set(tracker); + if (ret) { + goto end; } - - cds_list_add_tail(&n->list_node, &tracker_list->list_head); - tracker_list->state = LTTNG_TRACK_LIST; - - rcu_read_lock(); - cds_lfht_add(tracker_list->ht, hash_tracker_key(n->id), &n->ht_node); - rcu_read_unlock(); - - return LTTNG_OK; - -error: - free(n); + tracker->policy = tracking_policy; +end: return ret; } -/* - * Lookup and remove. - * Protected by session mutex held by caller. - */ -int lttng_tracker_list_remove(struct lttng_tracker_list *tracker_list, - const struct lttng_tracker_id *_id) +static int match_inclusion_set_value( + struct cds_lfht_node *node, const void *key) { - enum lttng_error_code ret = LTTNG_OK; - struct lttng_tracker_id **id; - struct lttng_tracker_list_node *n; - - if (lttng_tracker_id_get_type(_id) == LTTNG_ID_ALL) { - /* Untrack all. */ - lttng_tracker_list_reset(tracker_list); - /* Set state to "track none". */ - tracker_list->state = LTTNG_TRACK_NONE; - goto end; - } + const struct process_attr_value *value_key = key; + const struct process_attr_tracker_value_node *value_node = + caa_container_of(node, + struct process_attr_tracker_value_node, + inclusion_set_ht_node); - rcu_read_lock(); - id = lttng_tracker_list_lookup(tracker_list, _id); - if (!id) { - ret = LTTNG_ERR_ID_NOT_TRACKED; - goto rcu_unlock; - } + return process_attr_tracker_value_equal(value_node->value, value_key); +} - n = caa_container_of(id, struct lttng_tracker_list_node, id); - _lttng_tracker_list_remove(tracker_list, n); +static struct process_attr_tracker_value_node *process_attr_tracker_lookup( + const struct process_attr_tracker *tracker, + const struct process_attr_value *value) +{ + struct cds_lfht_iter iter; + struct cds_lfht_node *node; -rcu_unlock: + assert(tracker->policy == LTTNG_TRACKING_POLICY_INCLUDE_SET); + + rcu_read_lock(); + cds_lfht_lookup(tracker->inclusion_set_ht, + process_attr_value_hash(value), + match_inclusion_set_value, value, &iter); + node = cds_lfht_iter_get_node(&iter); rcu_read_unlock(); -end: - return ret; + + return node ? container_of(node, struct process_attr_tracker_value_node, + inclusion_set_ht_node) : + NULL; } -void lttng_tracker_list_destroy(struct lttng_tracker_list *tracker_list) +/* Protected by session mutex held by caller. */ +enum process_attr_tracker_status process_attr_tracker_inclusion_set_add_value( + struct process_attr_tracker *tracker, + const struct process_attr_value *value) { - int ret; + enum process_attr_tracker_status status = + PROCESS_ATTR_TRACKER_STATUS_OK; + struct process_attr_value *value_copy = NULL; + struct process_attr_tracker_value_node *value_node = NULL; - if (!tracker_list) { - return; + rcu_read_lock(); + if (tracker->policy != LTTNG_TRACKING_POLICY_INCLUDE_SET) { + status = PROCESS_ATTR_TRACKER_STATUS_INVALID_TRACKING_POLICY; + goto end; } - lttng_tracker_list_reset(tracker_list); - ret = cds_lfht_destroy(tracker_list->ht, NULL); - assert(!ret); - free(tracker_list); -} -static int lttng_lookup_user(const char *username, int *result) -{ - struct passwd p, *pres; - int ret, retval = LTTNG_OK; - char *buf = NULL; - ssize_t buflen; - - buflen = sysconf(_SC_GETPW_R_SIZE_MAX); - if (buflen < 0) { - buflen = FALLBACK_USER_BUFLEN; - } - buf = zmalloc(buflen); - if (!buf) { - retval = LTTNG_ERR_NOMEM; + if (process_attr_tracker_lookup(tracker, value)) { + status = PROCESS_ATTR_TRACKER_STATUS_EXISTS; goto end; } - for (;;) { - ret = getpwnam_r(username, &p, buf, buflen, &pres); - switch (ret) { - case EINTR: - continue; - case ERANGE: - buflen *= 2; - free(buf); - buf = zmalloc(buflen); - if (!buf) { - retval = LTTNG_ERR_NOMEM; - goto end; - } - continue; - default: - goto end_loop; - } - } -end_loop: - - switch (ret) { - case 0: - if (pres == NULL) { - retval = LTTNG_ERR_USER_NOT_FOUND; - } else { - *result = (int) p.pw_uid; - DBG("Lookup of tracker UID/VUID: name '%s' maps to id %d.", - username, *result); - retval = LTTNG_OK; - } - break; - case ENOENT: - case ESRCH: - case EBADF: - case EPERM: - retval = LTTNG_ERR_USER_NOT_FOUND; - break; - default: - retval = LTTNG_ERR_NOMEM; - } -end: - free(buf); - return retval; -} -static int lttng_lookup_group(const char *groupname, int *result) -{ - struct group g, *gres; - int ret, retval = LTTNG_OK; - char *buf = NULL; - ssize_t buflen; - - buflen = sysconf(_SC_GETGR_R_SIZE_MAX); - if (buflen < 0) { - buflen = FALLBACK_GROUP_BUFLEN; + value_node = zmalloc(sizeof(*value_node)); + if (!value_node) { + status = PROCESS_ATTR_TRACKER_STATUS_ERROR; + goto end; } - buf = zmalloc(buflen); - if (!buf) { - retval = LTTNG_ERR_NOMEM; + + value_copy = process_attr_value_copy(value); + if (!value_copy) { + status = PROCESS_ATTR_TRACKER_STATUS_ERROR; goto end; } - for (;;) { - ret = getgrnam_r(groupname, &g, buf, buflen, &gres); - switch (ret) { - case EINTR: - continue; - case ERANGE: - buflen *= 2; - free(buf); - buf = zmalloc(buflen); - if (!buf) { - retval = LTTNG_ERR_NOMEM; - goto end; - } - continue; - default: - goto end_loop; - } + + value_node->value = value_copy; + cds_lfht_add(tracker->inclusion_set_ht, + process_attr_value_hash(value_copy), + &value_node->inclusion_set_ht_node); + value_copy = NULL; + value_node = NULL; +end: + if (value_copy) { + process_attr_value_destroy(value_copy); } -end_loop: - - switch (ret) { - case 0: - if (gres == NULL) { - retval = LTTNG_ERR_GROUP_NOT_FOUND; - } else { - *result = (int) g.gr_gid; - DBG("Lookup of tracker GID/GUID: name '%s' maps to id %d.", - groupname, *result); - retval = LTTNG_OK; - } - break; - case ENOENT: - case ESRCH: - case EBADF: - case EPERM: - retval = LTTNG_ERR_GROUP_NOT_FOUND; - break; - default: - retval = LTTNG_ERR_NOMEM; + if (value_node) { + free(value_node); } -end: - free(buf); - return retval; + rcu_read_unlock(); + return status; } -int lttng_tracker_id_lookup_string(enum lttng_tracker_type tracker_type, - const struct lttng_tracker_id *id, - int *result) +/* Protected by session mutex held by caller. */ +enum process_attr_tracker_status +process_attr_tracker_inclusion_set_remove_value( + struct process_attr_tracker *tracker, + const struct process_attr_value *value) { - enum lttng_tracker_id_status status; - int value; - const char *string; - - switch (lttng_tracker_id_get_type(id)) { - case LTTNG_ID_ALL: - *result = -1; - return LTTNG_OK; - case LTTNG_ID_VALUE: - status = lttng_tracker_id_get_value(id, &value); - if (status != LTTNG_TRACKER_ID_STATUS_OK) { - return LTTNG_ERR_INVALID; - } - *result = id->value; - return LTTNG_OK; - case LTTNG_ID_STRING: - status = lttng_tracker_id_get_string(id, &string); - if (status != LTTNG_TRACKER_ID_STATUS_OK) { - return LTTNG_ERR_INVALID; - } - switch (tracker_type) { - case LTTNG_TRACKER_PID: - case LTTNG_TRACKER_VPID: - ERR("Lookup of tracker PID/VPID by name unsupported."); - return LTTNG_ERR_INVALID; - case LTTNG_TRACKER_UID: - case LTTNG_TRACKER_VUID: - DBG("Lookup of tracker UID/VUID by name."); - return lttng_lookup_user(string, result); - case LTTNG_TRACKER_GID: - case LTTNG_TRACKER_VGID: - DBG("Lookup of tracker GID/VGID by name."); - return lttng_lookup_group(string, result); - default: - return LTTNG_ERR_INVALID; - } - default: - return LTTNG_ERR_INVALID; - } -} + struct process_attr_tracker_value_node *value_node; + enum process_attr_tracker_status status = + PROCESS_ATTR_TRACKER_STATUS_OK; -/* - * Protected by session mutex held by caller. - * On success, _ids and the ids it contains must be freed by the caller. - */ -int lttng_tracker_id_get_list(const struct lttng_tracker_list *tracker_list, - struct lttng_tracker_ids **_ids) -{ - int retval = LTTNG_OK, ret; - struct lttng_tracker_list_node *n; - ssize_t count = 0, i = 0; - struct lttng_tracker_ids *ids = NULL; - struct lttng_tracker_id *id; - enum lttng_tracker_id_status status; - - switch (tracker_list->state) { - case LTTNG_TRACK_LIST: - cds_list_for_each_entry ( - n, &tracker_list->list_head, list_node) { - count++; - } - ids = lttng_tracker_ids_create(count); - if (ids == NULL) { - PERROR("Failed to allocate tracked ID list"); - retval = -LTTNG_ERR_NOMEM; - goto end; - } - cds_list_for_each_entry ( - n, &tracker_list->list_head, list_node) { - id = lttng_tracker_ids_get_pointer_of_index(ids, i); - if (!id) { - retval = -LTTNG_ERR_INVALID; - goto error; - } - - ret = lttng_tracker_id_copy(id, n->id); - if (ret) { - retval = -LTTNG_ERR_NOMEM; - goto error; - } - i++; - } - break; - case LTTNG_TRACK_ALL: - - ids = lttng_tracker_ids_create(1); - if (ids == NULL) { - PERROR("Failed to allocate tracked ID list"); - retval = -LTTNG_ERR_NOMEM; - goto end; - } + rcu_read_lock(); + if (tracker->policy != LTTNG_TRACKING_POLICY_INCLUDE_SET) { + status = PROCESS_ATTR_TRACKER_STATUS_INVALID_TRACKING_POLICY; + goto end; + } - id = lttng_tracker_ids_get_pointer_of_index(ids, 0); - status = lttng_tracker_id_set_all(id); - if (status != LTTNG_TRACKER_ID_STATUS_OK) { - ERR("Invalid tracker id for track all"); - retval = -LTTNG_ERR_INVALID; - goto error; - } - break; - case LTTNG_TRACK_NONE: - /* No ids track, so we return 0 element collection. */ - ids = lttng_tracker_ids_create(0); - if (ids == NULL) { - PERROR("alloc list ids"); - retval = -LTTNG_ERR_NOMEM; - goto end; - } - break; + value_node = process_attr_tracker_lookup(tracker, value); + if (!value_node) { + status = PROCESS_ATTR_TRACKER_STATUS_MISSING; + goto end; } - *_ids = ids; + process_attr_tracker_remove_value_node(tracker, value_node); end: - return retval; - -error: - lttng_tracker_ids_destroy(ids); - return retval; + rcu_read_unlock(); + return status; } -int lttng_tracker_id_set_list(struct lttng_tracker_list *tracker_list, - const struct lttng_tracker_ids *ids) +enum process_attr_tracker_status process_attr_tracker_get_inclusion_set( + const struct process_attr_tracker *tracker, + struct lttng_process_attr_values **_values) { - unsigned int i, count; - const struct lttng_tracker_id *id; - enum lttng_tracker_id_status status; - - assert(tracker_list); - assert(ids); - - lttng_tracker_list_reset(tracker_list); - - status = lttng_tracker_ids_get_count(ids, &count); - if (status != LTTNG_TRACKER_ID_STATUS_OK) { - return LTTNG_ERR_INVALID; + struct lttng_ht_iter iter; + struct process_attr_tracker_value_node *value_node; + enum process_attr_tracker_status status = + PROCESS_ATTR_TRACKER_STATUS_OK; + struct lttng_process_attr_values *values; + struct process_attr_value *new_value = NULL; + + values = lttng_process_attr_values_create(); + if (!values) { + status = PROCESS_ATTR_TRACKER_STATUS_ERROR; + goto error; } - if (count == 0) { - /* Set state to "track none". */ - tracker_list->state = LTTNG_TRACK_NONE; - return LTTNG_OK; + if (tracker->policy != LTTNG_TRACKING_POLICY_INCLUDE_SET) { + status = PROCESS_ATTR_TRACKER_STATUS_INVALID_TRACKING_POLICY; + goto error; } - if (count == 1) { - id = lttng_tracker_ids_get_at_index(ids, 0); - if (lttng_tracker_id_get_type(id) == LTTNG_ID_ALL) { - /* Track all. */ - return LTTNG_OK; + rcu_read_lock(); + cds_lfht_for_each_entry (tracker->inclusion_set_ht, &iter.iter, + value_node, inclusion_set_ht_node) { + int ret; + + new_value = process_attr_value_copy(value_node->value); + if (!new_value) { + status = PROCESS_ATTR_TRACKER_STATUS_ERROR; + goto error_unlock; } - } - for (i = 0; i < count; i++) { - int ret; - id = lttng_tracker_ids_get_at_index(ids, i); - ret = lttng_tracker_list_add(tracker_list, id); - if (ret != LTTNG_OK) { - return ret; + ret = lttng_dynamic_pointer_array_add_pointer( + &values->array, new_value); + if (ret) { + status = PROCESS_ATTR_TRACKER_STATUS_ERROR; + goto error_unlock; } + + new_value = NULL; } - return LTTNG_OK; + rcu_read_unlock(); + *_values = values; + return status; +error_unlock: + rcu_read_unlock(); +error: + lttng_process_attr_values_destroy(values); + process_attr_value_destroy(new_value); + return status; }