X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Ftrace-kernel.c;h=a453fd8b705537ba8908e729517c20b408ef2951;hp=8e074fd91b0dcbe829f8c053d32ac6e92766d32c;hb=7c1f6da21f4d46d9c834820a2b26f0634c7365a9;hpb=645328ae989e5f50a3a49c1ac34b2fee287a3d7b diff --git a/src/bin/lttng-sessiond/trace-kernel.c b/src/bin/lttng-sessiond/trace-kernel.c index 8e074fd91..a453fd8b7 100644 --- a/src/bin/lttng-sessiond/trace-kernel.c +++ b/src/bin/lttng-sessiond/trace-kernel.c @@ -1,37 +1,45 @@ /* - * Copyright (C) 2011 - David Goulet + * Copyright (C) 2011 David Goulet * - * 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 _GNU_SOURCE +#define _LGPL_SOURCE #include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include +#include +#include #include "consumer.h" #include "trace-kernel.h" +#include "lttng-sessiond.h" +#include "notification-thread-commands.h" /* * Find the channel name for the given kernel session. */ struct ltt_kernel_channel *trace_kernel_get_channel_by_name( - char *name, struct ltt_kernel_session *session) + const char *name, struct ltt_kernel_session *session) { struct ltt_kernel_channel *chan; @@ -57,26 +65,79 @@ struct ltt_kernel_channel *trace_kernel_get_channel_by_name( return NULL; } +/* + * Find the event for the given channel. + */ +struct ltt_kernel_event *trace_kernel_find_event( + char *name, struct ltt_kernel_channel *channel, + enum lttng_event_type type, + struct lttng_bytecode *filter) +{ + struct ltt_kernel_event *ev; + int found = 0; + + assert(name); + assert(channel); + + cds_list_for_each_entry(ev, &channel->events_list.head, list) { + if (type != LTTNG_EVENT_ALL && ev->type != type) { + continue; + } + if (strcmp(name, ev->event->name)) { + continue; + } + if ((ev->filter && !filter) || (!ev->filter && filter)) { + continue; + } + if (ev->filter && filter) { + if (ev->filter->len != filter->len || + memcmp(ev->filter->data, filter->data, + filter->len) != 0) { + continue; + } + } + found = 1; + break; + } + if (found) { + DBG("Found event %s for channel %s", name, + channel->channel->name); + return ev; + } else { + return NULL; + } +} + /* * Find the event name for the given channel. */ struct ltt_kernel_event *trace_kernel_get_event_by_name( - char *name, struct ltt_kernel_channel *channel) + char *name, struct ltt_kernel_channel *channel, + enum lttng_event_type type) { struct ltt_kernel_event *ev; + int found = 0; assert(name); assert(channel); cds_list_for_each_entry(ev, &channel->events_list.head, list) { - if (strcmp(name, ev->event->name) == 0) { - DBG("Found event by name %s for channel %s", name, - channel->channel->name); - return ev; + if (type != LTTNG_EVENT_ALL && ev->type != type) { + continue; + } + if (strcmp(name, ev->event->name)) { + continue; } + found = 1; + break; + } + if (found) { + DBG("Found event %s for channel %s", name, + channel->channel->name); + return ev; + } else { + return NULL; } - - return NULL; } /* @@ -103,22 +164,44 @@ struct ltt_kernel_session *trace_kernel_create_session(void) lks->metadata = NULL; CDS_INIT_LIST_HEAD(&lks->channel_list.head); + lks->tracker_pid = process_attr_tracker_create(); + if (!lks->tracker_pid) { + goto error; + } + lks->tracker_vpid = process_attr_tracker_create(); + if (!lks->tracker_vpid) { + goto error; + } + lks->tracker_uid = process_attr_tracker_create(); + if (!lks->tracker_uid) { + goto error; + } + lks->tracker_vuid = process_attr_tracker_create(); + if (!lks->tracker_vuid) { + goto error; + } + lks->tracker_gid = process_attr_tracker_create(); + if (!lks->tracker_gid) { + goto error; + } + lks->tracker_vgid = process_attr_tracker_create(); + if (!lks->tracker_vgid) { + goto error; + } lks->consumer = consumer_create_output(CONSUMER_DST_LOCAL); if (lks->consumer == NULL) { goto error; } - /* - * The tmp_consumer stays NULL until a set_consumer_uri command is - * executed. At this point, the consumer should be nullify until an - * enable_consumer command. This assignment is symbolic since we've zmalloc - * the struct. - */ - lks->tmp_consumer = NULL; - return lks; error: + process_attr_tracker_destroy(lks->tracker_pid); + process_attr_tracker_destroy(lks->tracker_vpid); + process_attr_tracker_destroy(lks->tracker_uid); + process_attr_tracker_destroy(lks->tracker_vuid); + process_attr_tracker_destroy(lks->tracker_gid); + process_attr_tracker_destroy(lks->tracker_vgid); free(lks); alloc_error: @@ -134,6 +217,7 @@ struct ltt_kernel_channel *trace_kernel_create_channel( struct lttng_channel *chan) { struct ltt_kernel_channel *lkc; + struct lttng_channel_extended *extended = NULL; assert(chan); @@ -146,10 +230,18 @@ struct ltt_kernel_channel *trace_kernel_create_channel( lkc->channel = zmalloc(sizeof(struct lttng_channel)); if (lkc->channel == NULL) { PERROR("lttng_channel zmalloc"); - free(lkc); + goto error; + } + + extended = zmalloc(sizeof(struct lttng_channel_extended)); + if (!extended) { + PERROR("lttng_channel_channel zmalloc"); goto error; } memcpy(lkc->channel, chan, sizeof(struct lttng_channel)); + memcpy(extended, chan->attr.extended.ptr, sizeof(struct lttng_channel_extended)); + lkc->channel->attr.extended.ptr = extended; + extended = NULL; /* * If we receive an empty string for channel name, it means the @@ -165,6 +257,7 @@ struct ltt_kernel_channel *trace_kernel_create_channel( lkc->stream_count = 0; lkc->event_count = 0; lkc->enabled = 1; + lkc->published_to_notification_thread = false; /* Init linked list */ CDS_INIT_LIST_HEAD(&lkc->events_list.head); CDS_INIT_LIST_HEAD(&lkc->stream_list.head); @@ -173,6 +266,11 @@ struct ltt_kernel_channel *trace_kernel_create_channel( return lkc; error: + if (lkc) { + free(lkc->channel); + } + free(extended); + free(lkc); return NULL; } @@ -195,27 +293,58 @@ struct ltt_kernel_context *trace_kernel_create_context( if (ctx) { memcpy(&kctx->ctx, ctx, sizeof(kctx->ctx)); } - error: return kctx; } +/* + * Allocate and init a kernel context object from an existing kernel context + * object. + * + * Return the allocated object or NULL on error. + */ +struct ltt_kernel_context *trace_kernel_copy_context( + struct ltt_kernel_context *kctx) +{ + struct ltt_kernel_context *kctx_copy; + + assert(kctx); + kctx_copy = zmalloc(sizeof(*kctx_copy)); + if (!kctx_copy) { + PERROR("zmalloc ltt_kernel_context"); + goto error; + } + + memcpy(kctx_copy, kctx, sizeof(*kctx_copy)); + memset(&kctx_copy->list, 0, sizeof(kctx_copy->list)); + +error: + return kctx_copy; +} + /* * Allocate and initialize a kernel event. Set name and event type. + * We own filter_expression, and filter. * * Return pointer to structure or NULL. */ -struct ltt_kernel_event *trace_kernel_create_event(struct lttng_event *ev) +enum lttng_error_code trace_kernel_create_event( + struct lttng_event *ev, char *filter_expression, + struct lttng_bytecode *filter, + struct ltt_kernel_event **kernel_event) { - struct ltt_kernel_event *lke; + enum lttng_error_code ret; struct lttng_kernel_event *attr; + struct ltt_kernel_event *local_kernel_event; + struct lttng_userspace_probe_location *userspace_probe_location = NULL; assert(ev); - lke = zmalloc(sizeof(struct ltt_kernel_event)); + local_kernel_event = zmalloc(sizeof(struct ltt_kernel_event)); attr = zmalloc(sizeof(struct lttng_kernel_event)); - if (lke == NULL || attr == NULL) { + if (local_kernel_event == NULL || attr == NULL) { PERROR("kernel event zmalloc"); + ret = LTTNG_ERR_NOMEM; goto error; } @@ -228,6 +357,70 @@ struct ltt_kernel_event *trace_kernel_create_event(struct lttng_event *ev) ev->attr.probe.symbol_name, LTTNG_KERNEL_SYM_NAME_LEN); attr->u.kprobe.symbol_name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; break; + case LTTNG_EVENT_USERSPACE_PROBE: + { + const struct lttng_userspace_probe_location* location = NULL; + const struct lttng_userspace_probe_location_lookup_method *lookup = NULL; + + location = lttng_event_get_userspace_probe_location(ev); + if (!location) { + ret = LTTNG_ERR_PROBE_LOCATION_INVAL; + goto error; + } + + /* + * From this point on, the specific term 'uprobe' is used + * instead of the generic 'userspace probe' because it's the + * technology used at the moment for this instrumentation. + * LTTng currently implements userspace probes using uprobes. + * In the interactions with the kernel tracer, we use the + * uprobe term. + */ + attr->instrumentation = LTTNG_KERNEL_UPROBE; + + lookup = lttng_userspace_probe_location_get_lookup_method( + location); + if (!lookup) { + ret = LTTNG_ERR_PROBE_LOCATION_INVAL; + goto error; + } + + /* + * From the kernel tracer's perspective, all userspace probe + * event types are all the same: a file and an offset. + */ + switch (lttng_userspace_probe_location_lookup_method_get_type(lookup)) { + case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF: + /* Get the file descriptor on the target binary. */ + attr->u.uprobe.fd = + lttng_userspace_probe_location_function_get_binary_fd(location); + + /* + * Save a reference to the probe location used during + * the listing of events. + */ + userspace_probe_location = + lttng_userspace_probe_location_copy(location); + break; + case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT: + /* Get the file descriptor on the target binary. */ + attr->u.uprobe.fd = + lttng_userspace_probe_location_tracepoint_get_binary_fd(location); + + /* + * Save a reference to the probe location used during the listing of + * events. + */ + userspace_probe_location = + lttng_userspace_probe_location_copy(location); + break; + default: + DBG("Unsupported lookup method type"); + ret = LTTNG_ERR_PROBE_LOCATION_INVAL; + goto error; + } + break; + } case LTTNG_EVENT_FUNCTION: attr->instrumentation = LTTNG_KERNEL_KRETPROBE; attr->u.kretprobe.addr = ev->attr.probe.addr; @@ -247,12 +440,16 @@ struct ltt_kernel_event *trace_kernel_create_event(struct lttng_event *ev) break; case LTTNG_EVENT_SYSCALL: attr->instrumentation = LTTNG_KERNEL_SYSCALL; + attr->u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_ALL; + attr->u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRYEXIT; + attr->u.syscall.match = LTTNG_KERNEL_SYSCALL_MATCH_NAME; break; case LTTNG_EVENT_ALL: attr->instrumentation = LTTNG_KERNEL_ALL; break; default: ERR("Unknown kernel instrumentation type (%d)", ev->type); + ret = LTTNG_ERR_INVALID; goto error; } @@ -261,18 +458,252 @@ struct ltt_kernel_event *trace_kernel_create_event(struct lttng_event *ev) attr->name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; /* Setting up a kernel event */ - lke->fd = -1; - lke->event = attr; - lke->enabled = 1; + local_kernel_event->fd = -1; + local_kernel_event->event = attr; + local_kernel_event->enabled = 1; + local_kernel_event->filter_expression = filter_expression; + local_kernel_event->filter = filter; + local_kernel_event->userspace_probe_location = userspace_probe_location; - return lke; + *kernel_event = local_kernel_event; + + return LTTNG_OK; error: - free(lke); + free(filter_expression); + free(filter); + free(local_kernel_event); free(attr); - return NULL; + return ret; } +/* + * Allocate and initialize a kernel token event rule. + * + * Return pointer to structure or NULL. + */ +enum lttng_error_code trace_kernel_create_event_notifier_rule( + struct lttng_trigger *trigger, + uint64_t token, + struct ltt_kernel_event_notifier_rule **event_notifier_rule) +{ + enum lttng_error_code ret = LTTNG_OK; + enum lttng_condition_type condition_type; + enum lttng_event_rule_type event_rule_type; + enum lttng_condition_status condition_status; + struct ltt_kernel_event_notifier_rule *local_kernel_token_event_rule; + const struct lttng_condition *condition = NULL; + const struct lttng_event_rule *event_rule = NULL; + + assert(event_notifier_rule); + + condition = lttng_trigger_get_const_condition(trigger); + assert(condition); + + condition_type = lttng_condition_get_type(condition); + assert(condition_type == LTTNG_CONDITION_TYPE_ON_EVENT); + + condition_status = lttng_condition_on_event_get_rule( + condition, &event_rule); + assert(condition_status == LTTNG_CONDITION_STATUS_OK); + assert(event_rule); + + event_rule_type = lttng_event_rule_get_type(event_rule); + assert(event_rule_type != LTTNG_EVENT_RULE_TYPE_UNKNOWN); + + local_kernel_token_event_rule = + zmalloc(sizeof(struct ltt_kernel_event_notifier_rule)); + if (local_kernel_token_event_rule == NULL) { + PERROR("Failed to allocate ltt_kernel_token_event_rule structure"); + ret = LTTNG_ERR_NOMEM; + goto error; + } + + local_kernel_token_event_rule->fd = -1; + local_kernel_token_event_rule->enabled = 1; + local_kernel_token_event_rule->token = token; + + /* Get the reference of the event rule. */ + lttng_trigger_get(trigger); + + local_kernel_token_event_rule->trigger = trigger; + /* The event rule still owns the filter and bytecode. */ + local_kernel_token_event_rule->filter = + lttng_event_rule_get_filter_bytecode(event_rule); + + DBG3("Created kernel event notifier rule: token = %" PRIu64, + local_kernel_token_event_rule->token); +error: + *event_notifier_rule = local_kernel_token_event_rule; + return ret; +} + +/* + * Initialize a kernel trigger from an event rule. + */ +enum lttng_error_code trace_kernel_init_event_notifier_from_event_rule( + const struct lttng_event_rule *rule, + struct lttng_kernel_event_notifier *kernel_event_notifier) +{ + enum lttng_error_code ret_code; + const char *name; + int strncpy_ret; + + switch (lttng_event_rule_get_type(rule)) { + case LTTNG_EVENT_RULE_TYPE_KERNEL_PROBE: + { + uint64_t address = 0, offset = 0; + const char *symbol_name = NULL; + const struct lttng_kernel_probe_location *location = NULL; + enum lttng_kernel_probe_location_status k_status; + enum lttng_event_rule_status status; + + status = lttng_event_rule_kernel_probe_get_location(rule, &location); + if (status != LTTNG_EVENT_RULE_STATUS_OK) { + ret_code = LTTNG_ERR_PROBE_LOCATION_INVAL; + goto error; + } + + switch (lttng_kernel_probe_location_get_type(location)) { + case LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS: + { + k_status = lttng_kernel_probe_location_address_get_address( + location, &address); + assert(k_status == LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK); + break; + } + case LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET: + { + k_status = lttng_kernel_probe_location_symbol_get_offset( + location, &offset); + assert(k_status == LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK); + symbol_name = lttng_kernel_probe_location_symbol_get_name( + location); + break; + } + default: + abort(); + } + + kernel_event_notifier->event.instrumentation = LTTNG_KERNEL_KPROBE; + kernel_event_notifier->event.u.kprobe.addr = address; + kernel_event_notifier->event.u.kprobe.offset = offset; + if (symbol_name) { + strncpy_ret = lttng_strncpy( + kernel_event_notifier->event.u.kprobe.symbol_name, + symbol_name, LTTNG_KERNEL_SYM_NAME_LEN); + + if (strncpy_ret) { + ret_code = LTTNG_ERR_INVALID; + goto error; + } + } + + kernel_event_notifier->event.u.kprobe.symbol_name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; + + status = lttng_event_rule_kernel_probe_get_event_name(rule, &name); + assert(status == LTTNG_EVENT_RULE_STATUS_OK); + ret_code = LTTNG_OK; + break; + } + case LTTNG_EVENT_RULE_TYPE_USERSPACE_PROBE: + { + const struct lttng_userspace_probe_location* location = NULL; + const struct lttng_userspace_probe_location_lookup_method *lookup = NULL; + enum lttng_event_rule_status status; + + status = lttng_event_rule_userspace_probe_get_location(rule, &location); + if (status != LTTNG_EVENT_RULE_STATUS_OK) { + ret_code = LTTNG_ERR_PROBE_LOCATION_INVAL; + goto error; + } + + kernel_event_notifier->event.instrumentation = LTTNG_KERNEL_UPROBE; + + lookup = lttng_userspace_probe_location_get_lookup_method( + location); + if (!lookup) { + ret_code = LTTNG_ERR_PROBE_LOCATION_INVAL; + goto error; + } + + /* + * From the kernel tracer's perspective, all userspace probe + * event types are all the same: a file and an offset. + */ + switch (lttng_userspace_probe_location_lookup_method_get_type(lookup)) { + case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF: + /* Get the file descriptor on the target binary. */ + kernel_event_notifier->event.u.uprobe.fd = + lttng_userspace_probe_location_function_get_binary_fd(location); + + break; + case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT: + /* Get the file descriptor on the target binary. */ + kernel_event_notifier->event.u.uprobe.fd = + lttng_userspace_probe_location_tracepoint_get_binary_fd(location); + break; + default: + abort(); + } + + status = lttng_event_rule_userspace_probe_get_event_name( + rule, &name); + assert(status == LTTNG_EVENT_RULE_STATUS_OK); + ret_code = LTTNG_OK; + break; + } + case LTTNG_EVENT_RULE_TYPE_TRACEPOINT: + { + const enum lttng_domain_type domain = + lttng_event_rule_get_domain_type(rule); + const enum lttng_event_rule_status status = + lttng_event_rule_tracepoint_get_pattern( + rule, &name); + + assert(domain == LTTNG_DOMAIN_KERNEL); + assert(status == LTTNG_EVENT_RULE_STATUS_OK); + kernel_event_notifier->event.instrumentation = + LTTNG_KERNEL_TRACEPOINT; + + ret_code = LTTNG_OK; + break; + } + case LTTNG_EVENT_RULE_TYPE_SYSCALL: + { + const enum lttng_event_rule_status status = + lttng_event_rule_syscall_get_pattern( + rule, &name); + + assert(status == LTTNG_EVENT_RULE_STATUS_OK); + + kernel_event_notifier->event.instrumentation = + LTTNG_KERNEL_SYSCALL; + kernel_event_notifier->event.u.syscall.abi = + LTTNG_KERNEL_SYSCALL_ABI_ALL; + kernel_event_notifier->event.u.syscall.entryexit = + LTTNG_KERNEL_SYSCALL_ENTRY; + kernel_event_notifier->event.u.syscall.match = + LTTNG_KERNEL_SYSCALL_MATCH_NAME; + ret_code = LTTNG_OK; + break; + } + case LTTNG_EVENT_RULE_TYPE_KERNEL_FUNCTION: + default: + abort(); + break; + } + + strncpy_ret = lttng_strncpy(kernel_event_notifier->event.name, name, + LTTNG_KERNEL_SYM_NAME_LEN); + if (strncpy_ret) { + ret_code = LTTNG_ERR_INVALID; + goto error; + } + +error: + return ret_code; +} /* * Allocate and initialize a kernel metadata. * @@ -280,6 +711,7 @@ error: */ struct ltt_kernel_metadata *trace_kernel_create_metadata(void) { + int ret; struct ltt_kernel_metadata *lkm; struct lttng_channel *chan; @@ -290,13 +722,38 @@ struct ltt_kernel_metadata *trace_kernel_create_metadata(void) goto error; } + ret = lttng_strncpy( + chan->name, DEFAULT_METADATA_NAME, sizeof(chan->name)); + if (ret) { + ERR("Failed to initialize metadata channel name to `%s`", + DEFAULT_METADATA_NAME); + goto error; + } + /* Set default attributes */ - chan->attr.overwrite = DEFAULT_CHANNEL_OVERWRITE; + chan->attr.overwrite = DEFAULT_METADATA_OVERWRITE; chan->attr.subbuf_size = default_get_metadata_subbuf_size(); chan->attr.num_subbuf = DEFAULT_METADATA_SUBBUF_NUM; - chan->attr.switch_timer_interval = DEFAULT_KERNEL_CHANNEL_SWITCH_TIMER; - chan->attr.read_timer_interval = DEFAULT_KERNEL_CHANNEL_READ_TIMER; - chan->attr.output = DEFAULT_KERNEL_CHANNEL_OUTPUT; + chan->attr.switch_timer_interval = DEFAULT_METADATA_SWITCH_TIMER; + chan->attr.read_timer_interval = DEFAULT_METADATA_READ_TIMER;; + + + /* + * The metadata channel of kernel sessions must use the "mmap" + * back-end since the consumer daemon accumulates complete + * metadata units before sending them to the relay daemon in + * live mode. The consumer daemon also needs to extract the contents + * of the metadata cache when computing a rotation position. + * + * In both cases, it is not possible to rely on the splice + * back-end as the consumer daemon may need to accumulate more + * content than can be backed by the ring buffer's underlying + * pages. + */ + chan->attr.output = LTTNG_EVENT_MMAP; + chan->attr.tracefile_size = 0; + chan->attr.tracefile_count = 0; + chan->attr.live_timer_interval = 0; /* Init metadata */ lkm->fd = -1; @@ -389,16 +846,51 @@ void trace_kernel_destroy_event(struct ltt_kernel_event *event) PERROR("close"); } } else { - DBG("[trace] Tearing down event (no associated fd)"); + DBG("[trace] Tearing down event (no associated file descriptor)"); } /* Remove from event list */ cds_list_del(&event->list); + free(event->filter_expression); + free(event->filter); + free(event->event); free(event); } +/* + * Cleanup kernel event structure. + */ +static void free_token_event_rule_rcu(struct rcu_head *rcu_node) +{ + struct ltt_kernel_event_notifier_rule *rule = caa_container_of(rcu_node, + struct ltt_kernel_event_notifier_rule, rcu_node); + + free(rule); +} + +void trace_kernel_destroy_event_notifier_rule( + struct ltt_kernel_event_notifier_rule *event) +{ + assert(event); + + if (event->fd >= 0) { + const int ret = close(event->fd); + + DBG("Closing kernel event notifier rule file descriptor: fd = %d", + event->fd); + if (ret) { + PERROR("Failed to close kernel event notifier file descriptor: fd = %d", + event->fd); + } + } else { + DBG("Destroying kernel event notifier rule (no associated file descriptor)"); + } + + lttng_trigger_put(event->trigger); + call_rcu(&event->rcu_node, free_token_event_rule_rcu); +} /* * Cleanup kernel context structure. */ @@ -406,7 +898,9 @@ void trace_kernel_destroy_context(struct ltt_kernel_context *ctx) { assert(ctx); - cds_list_del(&ctx->list); + if (ctx->in_list) { + cds_list_del(&ctx->list); + } free(ctx); } @@ -419,6 +913,7 @@ void trace_kernel_destroy_channel(struct ltt_kernel_channel *channel) struct ltt_kernel_event *event, *etmp; struct ltt_kernel_context *ctx, *ctmp; int ret; + enum lttng_error_code status; assert(channel); @@ -449,6 +944,14 @@ void trace_kernel_destroy_channel(struct ltt_kernel_channel *channel) /* Remove from channel list */ cds_list_del(&channel->list); + if (notification_thread_handle + && channel->published_to_notification_thread) { + status = notification_thread_command_remove_channel( + notification_thread_handle, + channel->key, LTTNG_DOMAIN_KERNEL); + assert(status == LTTNG_OK); + } + free(channel->channel->attr.extended.ptr); free(channel->channel); free(channel); } @@ -511,10 +1014,20 @@ void trace_kernel_destroy_session(struct ltt_kernel_session *session) cds_list_for_each_entry_safe(channel, ctmp, &session->channel_list.head, list) { trace_kernel_destroy_channel(channel); } +} +/* Free elements needed by destroy notifiers. */ +void trace_kernel_free_session(struct ltt_kernel_session *session) +{ /* Wipe consumer output object */ - consumer_destroy_output(session->consumer); - consumer_destroy_output(session->tmp_consumer); + consumer_output_put(session->consumer); + + process_attr_tracker_destroy(session->tracker_pid); + process_attr_tracker_destroy(session->tracker_vpid); + process_attr_tracker_destroy(session->tracker_uid); + process_attr_tracker_destroy(session->tracker_vuid); + process_attr_tracker_destroy(session->tracker_gid); + process_attr_tracker_destroy(session->tracker_vgid); free(session); }