X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fagent.c;h=66c55fc46e870275a659af9f543d2089b12b20aa;hp=b2608a186f83095b9faf20fd58a222eb4f2b0283;hb=2463b7879c00298daa79744cdaae82ac061a4ed8;hpb=bdf640139afb02572eb23f014e4a61ad68fdfeb1 diff --git a/src/bin/lttng-sessiond/agent.c b/src/bin/lttng-sessiond/agent.c index b2608a186..66c55fc46 100644 --- a/src/bin/lttng-sessiond/agent.c +++ b/src/bin/lttng-sessiond/agent.c @@ -1,19 +1,9 @@ /* - * Copyright (C) 2013 - David Goulet - * Copyright (C) 2016 - Jérémie Galarneau + * Copyright (C) 2013 David Goulet + * Copyright (C) 2016 Jérémie Galarneau * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License, version 2 only, as - * published by the Free Software Foundation. + * SPDX-License-Identifier: GPL-2.0-only * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 51 - * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define _LGPL_SOURCE @@ -21,6 +11,12 @@ #include #include +#include +#include +#include +#include +#include + #include #include @@ -29,7 +25,7 @@ #include "agent.h" #include "ust-app.h" #include "utils.h" -#include "error.h" +#include "common/error.h" #define AGENT_RET_CODE_INDEX(code) (code - AGENT_RET_CODE_SUCCESS) @@ -111,7 +107,8 @@ no_match: } /* - * Match function for the events hash table lookup by name and loglevel. + * Match function for the events hash table lookup by name, loglevel and + * filter_expression. */ static int ht_match_event(struct cds_lfht_node *node, const void *_key) @@ -143,11 +140,18 @@ static int ht_match_event(struct cds_lfht_node *node, } /* Filter expression */ - if (strncmp(event->filter_expression, key->filter_expression, - strlen(event->filter_expression)) != 0) { + if (!!event->filter_expression != !!key->filter_expression) { + /* One has a filter expression, the other does not */ goto no_match; } + if (event->filter_expression) { + if (strncmp(event->filter_expression, key->filter_expression, + strlen(event->filter_expression)) != 0) { + goto no_match; + } + } + return 1; no_match: @@ -353,8 +357,11 @@ static ssize_t list_events(struct agent_app *app, struct lttng_event **events) for (i = 0; i < nb_event; i++) { offset += len; - strncpy(tmp_events[i].name, reply->payload + offset, - sizeof(tmp_events[i].name)); + if (lttng_strncpy(tmp_events[i].name, reply->payload + offset, + sizeof(tmp_events[i].name))) { + ret = LTTNG_ERR_INVALID; + goto error; + } tmp_events[i].pid = app->pid; tmp_events[i].enabled = -1; len = strlen(reply->payload + offset) + 1; @@ -380,7 +387,7 @@ error: * * Return LTTNG_OK on success or else a LTTNG_ERR* code. */ -static int enable_event(struct agent_app *app, struct agent_event *event) +static int enable_event(const struct agent_app *app, struct agent_event *event) { int ret; char *bytes_to_send; @@ -408,17 +415,20 @@ static int enable_event(struct agent_app *app, struct agent_event *event) } data_size = sizeof(msg) + filter_expression_length; - ret = send_header(app->sock, data_size, AGENT_CMD_ENABLE, 0); - if (ret < 0) { - goto error_io; - } - memset(&msg, 0, sizeof(msg)); msg.loglevel_value = htobe32(event->loglevel_value); msg.loglevel_type = htobe32(event->loglevel_type); - strncpy(msg.name, event->name, sizeof(msg.name)); + if (lttng_strncpy(msg.name, event->name, sizeof(msg.name))) { + ret = LTTNG_ERR_INVALID; + goto error; + } msg.filter_expression_length = htobe32(filter_expression_length); + ret = send_header(app->sock, data_size, AGENT_CMD_ENABLE, 0); + if (ret < 0) { + goto error_io; + } + bytes_to_send = zmalloc(data_size); if (!bytes_to_send) { ret = LTTNG_ERR_NOMEM; @@ -492,8 +502,8 @@ end: * * Return LTTNG_OK on success or else a LTTNG_ERR* code. */ -static int app_context_op(struct agent_app *app, - struct agent_app_ctx *ctx, enum lttcomm_agent_command cmd) +static int app_context_op(const struct agent_app *app, + const struct agent_app_ctx *ctx, enum lttcomm_agent_command cmd) { int ret; uint32_t reply_ret_code; @@ -591,14 +601,17 @@ static int disable_event(struct agent_app *app, struct agent_event *event) app->pid, app->sock->fd); data_size = sizeof(msg); + memset(&msg, 0, sizeof(msg)); + if (lttng_strncpy(msg.name, event->name, sizeof(msg.name))) { + ret = LTTNG_ERR_INVALID; + goto error; + } ret = send_header(app->sock, data_size, AGENT_CMD_DISABLE, 0); if (ret < 0) { goto error_io; } - memset(&msg, 0, sizeof(msg)); - strncpy(msg.name, event->name, sizeof(msg.name)); ret = send_payload(app->sock, &msg, sizeof(msg)); if (ret < 0) { goto error_io; @@ -676,6 +689,7 @@ int agent_enable_event(struct agent_event *event, } event->enabled = 1; + event->user_refcount++; ret = LTTNG_OK; error: @@ -692,7 +706,7 @@ void destroy_app_ctx(struct agent_app_ctx *ctx) } static -struct agent_app_ctx *create_app_ctx(struct lttng_event_context *ctx) +struct agent_app_ctx *create_app_ctx(const struct lttng_event_context *ctx) { struct agent_app_ctx *agent_ctx = NULL; @@ -722,7 +736,7 @@ end: * * Return LTTNG_OK on success or else a LTTNG_ERR* code. */ -int agent_enable_context(struct lttng_event_context *ctx, +int agent_enable_context(const struct lttng_event_context *ctx, enum lttng_domain_type domain) { int ret; @@ -747,13 +761,14 @@ int agent_enable_context(struct lttng_event_context *ctx, agent_ctx = create_app_ctx(ctx); if (!agent_ctx) { + ret = LTTNG_ERR_NOMEM; goto error_unlock; } /* Enable event on agent application through TCP socket. */ ret = app_context_op(app, agent_ctx, AGENT_CMD_APP_CTX_ENABLE); + destroy_app_ctx(agent_ctx); if (ret != LTTNG_OK) { - destroy_app_ctx(agent_ctx); goto error_unlock; } } @@ -784,6 +799,17 @@ int agent_disable_event(struct agent_event *event, goto end; } + if (event->user_refcount - 1 != 0) { + /* + * Disable the agent event only when all users (trigger etc.) + * have disabled it. + */ + + event->user_refcount--; + ret = LTTNG_OK; + goto end; + } + rcu_read_lock(); cds_lfht_for_each_entry(agent_apps_ht_by_sock->ht, &iter.iter, app, @@ -799,6 +825,7 @@ int agent_disable_event(struct agent_event *event, } } + event->user_refcount = 0; event->enabled = 0; error: @@ -813,7 +840,8 @@ end: * * Return LTTNG_OK on success or else a LTTNG_ERR* code. */ -int disable_context(struct agent_app_ctx *ctx, enum lttng_domain_type domain) +static int disable_context(struct agent_app_ctx *ctx, + enum lttng_domain_type domain) { int ret = LTTNG_OK; struct agent_app *app; @@ -938,7 +966,7 @@ struct agent_app *agent_create_app(pid_t pid, enum lttng_domain_type domain, app = zmalloc(sizeof(*app)); if (!app) { - PERROR("zmalloc agent create"); + PERROR("Failed to allocate agent application instance"); goto error; } @@ -1101,7 +1129,7 @@ error: */ struct agent_event *agent_create_event(const char *name, enum lttng_loglevel_type loglevel_type, int loglevel_value, - struct lttng_filter_bytecode *filter, char *filter_expression) + struct lttng_bytecode *filter, char *filter_expression) { struct agent_event *event = NULL; @@ -1149,7 +1177,7 @@ void agent_add_event(struct agent_event *event, struct agent *agt) /* * Unique add of a agent context to an agent object. */ -int agent_add_context(struct lttng_event_context *ctx, struct agent *agt) +int agent_add_context(const struct lttng_event_context *ctx, struct agent *agt) { int ret = LTTNG_OK; struct agent_app_ctx *agent_ctx = NULL; @@ -1198,6 +1226,66 @@ void agent_find_events_by_name(const char *name, struct agent *agt, ht_match_event_by_name, &key, &iter->iter); } +/* + * Find the agent event matching the trigger. + * + * RCU read side lock MUST be acquired. It must be kept for as long as + * the returned agent_event is used. + * + * Return object if found else NULL. + */ +struct agent_event *agent_find_event_by_trigger( + const struct lttng_trigger *trigger, struct agent *agt) +{ + enum lttng_condition_status c_status; + enum lttng_event_rule_status er_status; + enum lttng_domain_type d_type; + const struct lttng_condition *condition; + const struct lttng_event_rule *rule; + const char *name; + const char *filter_expression; + /* TODO validate if this is the unset value or no */ + int loglevel_value = 0; + enum lttng_loglevel_type loglevel_type; + + assert(agt); + assert(agt->events); + + condition = lttng_trigger_get_const_condition(trigger); + + assert(lttng_condition_get_type(condition) == + LTTNG_CONDITION_TYPE_EVENT_RULE_HIT); + + c_status = lttng_condition_event_rule_get_rule(condition, &rule); + assert(c_status == LTTNG_CONDITION_STATUS_OK); + + assert(lttng_event_rule_get_type(rule) == + LTTNG_EVENT_RULE_TYPE_TRACEPOINT); + + d_type = lttng_event_rule_get_domain_type(rule); + assert(d_type == LTTNG_DOMAIN_JUL || d_type == LTTNG_DOMAIN_LOG4J || + d_type == LTTNG_DOMAIN_PYTHON); + + /* Get the name (aka pattern) */ + er_status = lttng_event_rule_tracepoint_get_pattern(rule, &name); + assert(er_status == LTTNG_EVENT_RULE_STATUS_OK); + + /* Get the internal filter_expression */ + filter_expression = lttng_event_rule_get_filter(rule); + + er_status = lttng_event_rule_tracepoint_get_log_level_type( + rule, &loglevel_type); + assert(er_status == LTTNG_EVENT_RULE_STATUS_OK); + if (loglevel_type != LTTNG_EVENT_LOGLEVEL_ALL) { + er_status = lttng_event_rule_tracepoint_get_log_level( + rule, &loglevel_value); + assert(er_status == LTTNG_EVENT_RULE_STATUS_OK); + } + + return agent_find_event(name, loglevel_type, loglevel_value, + filter_expression, agt); +} + /* * Get the next agent event duplicate by name. This should be called * after a call to agent_find_events_by_name() to iterate on events. @@ -1225,8 +1313,10 @@ void agent_event_next_duplicate(const char *name, * Return object if found else NULL. */ struct agent_event *agent_find_event(const char *name, - enum lttng_loglevel_type loglevel_type, int loglevel_value, - char *filter_expression, struct agent *agt) + enum lttng_loglevel_type loglevel_type, + int loglevel_value, + const char *filter_expression, + struct agent *agt) { struct lttng_ht_node_str *node; struct lttng_ht_iter iter; @@ -1339,6 +1429,21 @@ int agent_app_ht_alloc(void) return ret; } +/* + * Allocate agent_apps_ht_by_sock. + */ +int trigger_agent_ht_alloc(void) +{ + int ret = 0; + + trigger_agents_ht_by_domain = lttng_ht_new(0, LTTNG_HT_TYPE_U64); + if (!trigger_agents_ht_by_domain) { + ret = -1; + } + + return ret; +} + /* * Destroy a agent application by socket. */ @@ -1388,32 +1493,56 @@ void agent_app_ht_clean(void) lttng_ht_destroy(agent_apps_ht_by_sock); } +/* + * Clean-up the trigger agent hash table and destroy it. + */ +void trigger_agent_ht_clean(void) +{ + struct lttng_ht_node_u64 *node; + struct lttng_ht_iter iter; + + if (!trigger_agents_ht_by_domain) { + return; + } + rcu_read_lock(); + cds_lfht_for_each_entry (trigger_agents_ht_by_domain->ht, &iter.iter, + node, node) { + struct agent *agent; + + (void) lttng_ht_del(trigger_agents_ht_by_domain, &iter); + + agent = caa_container_of(node, struct agent, node); + agent_destroy(agent); + } + rcu_read_unlock(); + + lttng_ht_destroy(trigger_agents_ht_by_domain); +} + /* * Update a agent application (given socket) using the given agent. * * Note that this function is most likely to be used with a tracing session * thus the caller should make sure to hold the appropriate lock(s). */ -void agent_update(struct agent *agt, int sock) +void agent_update(const struct agent *agt, const struct agent_app *app) { int ret; - struct agent_app *app; struct agent_event *event; struct lttng_ht_iter iter; struct agent_app_ctx *ctx; assert(agt); - assert(sock >= 0); + assert(app); - DBG("Agent updating app socket %d", sock); + DBG("Agent updating app: pid = %ld", (long) app->pid); rcu_read_lock(); - app = agent_find_app_by_sock(sock); /* * We are in the registration path thus if the application is gone, * there is a serious code flow error. */ - assert(app); + cds_lfht_for_each_entry(agt->events->ht, &iter.iter, event, node.node) { /* Skip event if disabled. */ if (!event->enabled) { @@ -1441,3 +1570,27 @@ void agent_update(struct agent *agt, int sock) rcu_read_unlock(); } + +struct agent *trigger_find_agent(enum lttng_domain_type domain_type) +{ + struct agent *agt = NULL; + struct lttng_ht_node_u64 *node; + struct lttng_ht_iter iter; + uint64_t key; + + assert(trigger_agents_ht_by_domain); + + DBG3("Trigger agent lookup for domain %d", domain_type); + + key = domain_type; + + lttng_ht_lookup(trigger_agents_ht_by_domain, &key, &iter); + node = lttng_ht_iter_get_node_u64(&iter); + if (!node) { + goto end; + } + agt = caa_container_of(node, struct agent, node); + +end: + return agt; +}