[ltt-dev] [PATCH] ltt-channel: permanent eID
Lai Jiangshan
laijs at cn.fujitsu.com
Tue Dec 16 08:28:53 EST 2008
introduce permanent eID for text output, and change
the ltt-channel's management.
Signed-off-by: Lai Jiangshan <laijs at cn.fujitsu.com>
---
include/linux/ltt-channels.h | 45 ++++++-
include/linux/marker.h | 4
kernel/marker.c | 95 +++------------
ltt/ltt-channels.c | 271 +++++++++++++++++++++++++------------------
ltt/ltt-tracer.c | 9 +
5 files changed, 230 insertions(+), 194 deletions(-)
diff --git a/include/linux/ltt-channels.h b/include/linux/ltt-channels.h
index ce19eda..edf959b 100644
--- a/include/linux/ltt-channels.h
+++ b/include/linux/ltt-channels.h
@@ -8,8 +8,10 @@
*/
#include <linux/limits.h>
+#include <linux/marker.h>
#define EVENTS_PER_CHANNEL 65536
+#define EVENTS_MOST_WASTE_IDS 128
struct ltt_trace_struct;
struct rchan_buf;
@@ -51,15 +53,51 @@ struct ltt_channel_struct {
struct ltt_channel_setting {
unsigned int subbuf_size;
unsigned int subbuf_cnt;
- struct kref kref; /* Number of references to structure content */
+ int trace_count;
+ int live_count;
struct list_head list;
+ struct list_head marker_entry;
unsigned int index; /* index of channel in trace channel array */
u16 free_event_id; /* Next event ID to allocate */
char name[PATH_MAX];
};
-int ltt_channels_register(const char *name);
-int ltt_channels_unregister(const char *name);
+/*
+ * Note about RCU :
+ * It is used to make sure every handler has finished using its private data
+ * between two consecutive operation (add or remove) on a given marker. It is
+ * also used to delay the free of multiple probes array until a quiescent state
+ * is reached.
+ * marker entries modifications are protected by the markers_mutex.
+ */
+struct marker_entry {
+ struct hlist_node hlist;
+ char *format;
+ char *name;
+ /* Probe wrapper */
+ void (*call)(const struct marker *mdata, void *call_private, ...);
+ struct marker_probe_closure single;
+ struct marker_probe_closure *multi;
+ int refcount; /* Number of times armed. 0 if disarmed. */
+ struct rcu_head rcu;
+ void *oldptr;
+ int rcu_pending;
+ u16 channel_id;
+ u16 event_id;
+ unsigned char ptype:1;
+ unsigned char format_allocated:1;
+ unsigned char used:1;
+ struct list_head sibling; /* sibling of channel's maker_entry */
+ struct ltt_channel_setting *lcs;
+ char channel[0]; /* Contains channel'\0'name'\0'format'\0' */
+};
+int __makrer_set_channel(struct marker_entry *entry, const char *channel);
+
+int start_trace_channel(const char *channel);
+int stop_trace_channel(const char *channel);
+const char *get_name_from_eid(const char *channel, u16 eID);
+const char *get_fmt_from_eid(const char *channel, u16 eID);
+
int ltt_channels_set_default(const char *name,
unsigned int subbuf_size,
unsigned int subbuf_cnt);
@@ -69,7 +107,6 @@ struct ltt_channel_struct *ltt_channels_trace_alloc(unsigned int *nr_channels,
int overwrite,
int active);
void ltt_channels_trace_free(struct ltt_channel_struct *channels);
-int _ltt_channels_get_event_id(const char *channel, const char *name);
int ltt_channels_get_event_id(const char *channel, const char *name);
#endif /* _LTT_CHANNELS_H */
diff --git a/include/linux/marker.h b/include/linux/marker.h
index 32387e8..82e4f7c 100644
--- a/include/linux/marker.h
+++ b/include/linux/marker.h
@@ -15,7 +15,6 @@
#include <stdarg.h>
#include <linux/types.h>
#include <linux/immediate.h>
-#include <linux/ltt-channels.h>
struct module;
struct task_struct;
@@ -126,6 +125,7 @@ struct marker {
extern void marker_update_probe_range(struct marker *begin,
struct marker *end);
+extern void marker_update_probes(void);
#define GET_MARKER(channel, name) (__mark_##channel##_##name)
@@ -199,8 +199,6 @@ static inline void marker_update_probe_range(struct marker *begin,
extern void lock_markers(void);
extern void unlock_markers(void);
-extern void markers_compact_event_ids(void);
-
/* To be used for string format validity checking with gcc */
static inline void __printf(1, 2) ___mark_check_format(const char *fmt, ...)
{
diff --git a/kernel/marker.c b/kernel/marker.c
index b11a82a..cd38ba0 100644
--- a/kernel/marker.c
+++ b/kernel/marker.c
@@ -22,6 +22,7 @@
#include <linux/list.h>
#include <linux/rcupdate.h>
#include <linux/marker.h>
+#include <linux/ltt-channels.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/immediate.h>
@@ -60,33 +61,6 @@ void unlock_markers(void)
#define MARKER_TABLE_SIZE (1 << MARKER_HASH_BITS)
static struct hlist_head marker_table[MARKER_TABLE_SIZE];
-/*
- * Note about RCU :
- * It is used to make sure every handler has finished using its private data
- * between two consecutive operation (add or remove) on a given marker. It is
- * also used to delay the free of multiple probes array until a quiescent state
- * is reached.
- * marker entries modifications are protected by the markers_mutex.
- */
-struct marker_entry {
- struct hlist_node hlist;
- char *format;
- char *name;
- /* Probe wrapper */
- void (*call)(const struct marker *mdata, void *call_private, ...);
- struct marker_probe_closure single;
- struct marker_probe_closure *multi;
- int refcount; /* Number of times armed. 0 if disarmed. */
- struct rcu_head rcu;
- void *oldptr;
- int rcu_pending;
- u16 channel_id;
- u16 event_id;
- unsigned char ptype:1;
- unsigned char format_allocated:1;
- char channel[0]; /* Contains channel'\0'name'\0'format'\0' */
-};
-
#ifdef CONFIG_MARKERS_USERSPACE
static void marker_update_processes(void);
#else
@@ -474,7 +448,6 @@ static int remove_marker(const char *channel, const char *name)
size_t channel_len = strlen(channel) + 1;
size_t name_len = strlen(name) + 1;
u32 hash;
- int ret;
hash = jhash(channel, channel_len-1, 0) ^ jhash(name, name_len-1, 0);
head = &marker_table[hash & ((1 << MARKER_HASH_BITS)-1)];
@@ -488,11 +461,26 @@ static int remove_marker(const char *channel, const char *name)
return -ENOENT;
if (e->single.func != __mark_empty_function)
return -EBUSY;
+
+ if (e->lcs) {
+ e->lcs->live_count--;
+ if (!e->lcs->live_count && !e->lcs->trace_count) {
+ BUG_ON(!list_empty(&e->lcs->marker_entry));
+ list_del(&e->lcs->list);
+ kfree(e->lcs);
+ e->lcs = NULL;
+ }
+ }
+
+ /* It will be released in remove_chanel_marker_entries() */
+ if (e->used && e->lcs && e->lcs->trace_count)
+ return 0;
+
hlist_del(&e->hlist);
if (e->format_allocated)
kfree(e->format);
- ret = ltt_channels_unregister(e->channel);
- WARN_ON(ret);
+ if (e->lcs)
+ list_del(&e->sibling);
/* Make sure the call_rcu has been executed */
if (e->rcu_pending)
rcu_barrier_sched();
@@ -540,6 +528,7 @@ static int set_marker(struct marker_entry *entry, struct marker *elem,
if (ret)
return ret;
}
+ entry->used = 1;
/*
* probe_cb setup (statically known) is done here. It is
@@ -695,7 +684,7 @@ void marker_update_probe_range(struct marker *begin,
* Site effect : marker_set_format may delete the marker entry (creating a
* replacement).
*/
-static void marker_update_probes(void)
+void marker_update_probes(void)
{
/* Core kernel markers */
marker_update_probe_range(__start___markers, __stop___markers);
@@ -738,18 +727,9 @@ int marker_probe_register(const char *channel, const char *name,
ret = PTR_ERR(entry);
if (ret)
goto end;
- ret = ltt_channels_register(channel);
+ ret = __makrer_set_channel(entry, channel);
if (ret)
goto error_remove_marker;
- ret = ltt_channels_get_index_from_name(channel);
- if (ret < 0)
- goto error_unregister_channel;
- entry->channel_id = ret;
- ret = ltt_channels_get_event_id(channel, name);
- if (ret < 0)
- goto error_unregister_channel;
- entry->event_id = ret;
- ret = 0;
trace_mark(metadata, core_marker_id,
"channel %s name %s event_id %hu "
"int #1u%zu long #1u%zu pointer #1u%zu "
@@ -776,7 +756,7 @@ int marker_probe_register(const char *channel, const char *name,
if (IS_ERR(old)) {
ret = PTR_ERR(old);
if (first_probe)
- goto error_unregister_channel;
+ goto error_remove_marker;
else
goto end;
}
@@ -797,9 +777,6 @@ int marker_probe_register(const char *channel, const char *name,
call_rcu_sched(&entry->rcu, free_old_closure);
goto end;
-error_unregister_channel:
- ret_err = ltt_channels_unregister(channel);
- WARN_ON(ret_err);
error_remove_marker:
ret_err = remove_marker(channel, name);
WARN_ON(ret_err);
@@ -997,34 +974,6 @@ void *marker_get_private_data(const char *channel, const char *name,
}
EXPORT_SYMBOL_GPL(marker_get_private_data);
-/**
- * markers_compact_event_ids: Compact markers event IDs and reassign channels
- *
- * Called when no channel users are active by the channel infrastructure.
- * Called with lock_markers() and channel mutex held.
- */
-void markers_compact_event_ids(void)
-{
- struct marker_entry *entry;
- unsigned int i;
- struct hlist_head *head;
- struct hlist_node *node;
- int ret;
-
- for (i = 0; i < MARKER_TABLE_SIZE; i++) {
- head = &marker_table[i];
- hlist_for_each_entry(entry, node, head, hlist) {
- ret = ltt_channels_get_index_from_name(entry->channel);
- WARN_ON(ret < 0);
- entry->channel_id = ret;
- ret = _ltt_channels_get_event_id(entry->channel,
- entry->name);
- WARN_ON(ret < 0);
- entry->event_id = ret;
- }
- }
-}
-
#ifdef CONFIG_MODULES
/**
diff --git a/ltt/ltt-channels.c b/ltt/ltt-channels.c
index c57e737..e876f04 100644
--- a/ltt/ltt-channels.c
+++ b/ltt/ltt-channels.c
@@ -13,13 +13,12 @@
#include <linux/ltt-channels.h>
#include <linux/mutex.h>
#include <linux/vmalloc.h>
+#include <linux/marker.h>
+#include <linux/err.h>
+#include <linux/ltt-tracer.h>
+
+LIST_HEAD(ltt_channels);
-/*
- * ltt_channel_mutex may be nested inside the LTT trace mutex.
- * ltt_channel_mutex mutex may be nested inside markers mutex.
- */
-static DEFINE_MUTEX(ltt_channel_mutex);
-static LIST_HEAD(ltt_channels);
/*
* Index of next channel in array. Makes sure that as long as a trace channel is
* allocated, no array index will be re-used when a channel is freed and then
@@ -40,104 +39,165 @@ static struct ltt_channel_setting *lookup_channel(const char *name)
return NULL;
}
-/*
- * Must be called when channel refcount falls to 0 _and_ also when the last
- * trace is freed. This function is responsible for compacting the channel and
- * event IDs when no users are active.
- *
- * Called with lock_markers() and channels mutex held.
- */
-static void release_channel_setting(struct kref *kref)
-{
- struct ltt_channel_setting *setting = container_of(kref,
- struct ltt_channel_setting, kref);
- struct ltt_channel_setting *iter;
+static int _ltt_channels_get_event_id(struct ltt_channel_setting *setting,
+ const char *name);
- if (atomic_read(&index_kref.refcount) == 0
- && atomic_read(&setting->kref.refcount) == 0) {
- list_del(&setting->list);
- kfree(setting);
+int __makrer_set_channel(struct marker_entry *entry, const char *channel)
+{
+ struct ltt_channel_setting *setting = lookup_channel(channel);
+ if (!setting) {
+ setting = kzalloc(sizeof(*setting), GFP_KERNEL);
+ if (!setting)
+ return -ENOMEM;
+ list_add_tail(&setting->list, <t_channels);
+ strncpy(setting->name, channel, PATH_MAX-1);
+ setting->index = free_index++;
+ INIT_LIST_HEAD(&setting->marker_entry);
+ }else if (setting->free_event_id == EVENTS_PER_CHANNEL - 1)
+ return -ENOSPC;
+ setting->live_count++;
+ list_add(&entry->sibling, &setting->marker_entry);
+ entry->channel_id = setting->index;
+ entry->event_id = _ltt_channels_get_event_id(setting, entry->name);
+ return 0;
+}
- free_index = 0;
- list_for_each_entry(iter, <t_channels, list) {
- iter->index = free_index++;
- iter->free_event_id = 0;
+static void defrag_id(struct ltt_channel_setting *setting)
+{
+ struct marker_entry *e;
+ int free_count = setting->free_event_id;
+ if (setting->live_count + EVENTS_MOST_WASTE_IDS > free_count)
+ return;
+ free_count = 0;
+ list_for_each_entry(e, &setting->marker_entry, sibling) {
+ if (e->event_id != free_count) {
+ trace_mark(metadata, core_marker_id,
+ "channel %s name %s event_id %hu "
+ "int #1u%zu long #1u%zu pointer #1u%zu "
+ "size_t #1u%zu alignment #1u%u",
+ e->channel, e->name, (u16)free_count,
+ sizeof(int), sizeof(long), sizeof(void *),
+ sizeof(size_t), ltt_get_alignment());
}
- markers_compact_event_ids();
+ e->event_id = free_count++;
}
+ setting->free_event_id = (u16)free_count;
+ marker_update_probes();
}
-/*
- * Perform channel index compaction when the last trace channel is freed.
- *
- * Called with lock_markers() and channels mutex held.
- */
-static void release_trace_channel(struct kref *kref)
+static void remove_chanel_marker_entries(struct ltt_channel_setting *setting)
{
- struct ltt_channel_setting *iter, *n;
+ struct marker_entry *e, *n;
+
+ list_for_each_entry_safe(e, n, &setting->marker_entry, sibling) {
+ if (e->single.func != __mark_empty_function)
+ continue;
- list_for_each_entry_safe(iter, n, <t_channels, list)
- release_channel_setting(&iter->kref);
+ hlist_del(&e->hlist);
+ if (e->format_allocated)
+ kfree(e->format);
+ list_del(&e->sibling);
+ /* Make sure the call_rcu has been executed */
+ if (e->rcu_pending)
+ rcu_barrier_sched();
+ kfree(e);
+ }
}
-/**
- * ltt_channels_register: Register a trace channel.
- *
- * Uses refcounting.
- */
-int ltt_channels_register(const char *name)
+int start_trace_channel(const char *channel)
{
+ int ret = -ENOENT;
struct ltt_channel_setting *setting;
- int ret = 0;
- mutex_lock(<t_channel_mutex);
- setting = lookup_channel(name);
+ lock_markers();
+ setting = lookup_channel(channel);
+ if (setting) {
+ if (!setting->trace_count)
+ defrag_id(setting);
+ setting->trace_count++;
+ ret = 0;
+ }
+ unlock_markers();
+ return ret;
+}
+EXPORT_SYMBOL_GPL(start_trace_channel);
+
+int stop_trace_channel(const char *channel)
+{
+ int ret = -ENOENT;
+ struct ltt_channel_setting *setting;
+
+ lock_markers();
+ setting = lookup_channel(channel);
if (setting) {
- if (atomic_read(&setting->kref.refcount) == 0)
- goto init_kref;
- else {
- kref_get(&setting->kref);
- goto end;
+ setting->trace_count--;
+ if (!setting->trace_count)
+ remove_chanel_marker_entries(setting);
+ ret = 0;
+ if (!setting->live_count && !setting->trace_count) {
+ BUG_ON(!list_empty(&setting->marker_entry));
+ list_del(&setting->list);
+ kfree(setting);
}
}
- setting = kzalloc(sizeof(*setting), GFP_KERNEL);
- if (!setting) {
- ret = -ENOMEM;
- goto end;
+ unlock_markers();
+ return ret;
+}
+EXPORT_SYMBOL_GPL(stop_trace_channel);
+
+/* permanent! the return value is valid before stop_strace_channel() */
+
+const char *get_name_from_eid(const char *channel, u16 eID)
+{
+ char *ret = ERR_PTR(-ENOENT);
+ struct ltt_channel_setting *setting;
+ struct marker_entry *e;
+
+ lock_markers();
+ setting = lookup_channel(channel);
+ list_for_each_entry(e, &setting->marker_entry, sibling) {
+ if (e->event_id == eID) {
+ ret = e->name;
+ break;
+ }
}
- list_add(&setting->list, <t_channels);
- strncpy(setting->name, name, PATH_MAX-1);
- setting->index = free_index++;
-init_kref:
- kref_init(&setting->kref);
-end:
- mutex_unlock(<t_channel_mutex);
+ unlock_markers();
return ret;
}
-EXPORT_SYMBOL_GPL(ltt_channels_register);
+EXPORT_SYMBOL_GPL(get_name_from_eid);
-/**
- * ltt_channels_unregister(): Unregister a trace channel.
- *
- * Must be called with markers mutex held.
- */
-int ltt_channels_unregister(const char *name)
+const char *get_fmt_from_eid(const char *channel, u16 eID)
{
+ char *ret = ERR_PTR(-ENOENT);
struct ltt_channel_setting *setting;
- int ret = 0;
+ struct marker_entry *e;
- mutex_lock(<t_channel_mutex);
- setting = lookup_channel(name);
- if (!setting || atomic_read(&setting->kref.refcount) == 0) {
- ret = -ENOENT;
- goto end;
+ lock_markers();
+ setting = lookup_channel(channel);
+ list_for_each_entry(e, &setting->marker_entry, sibling) {
+ if (e->event_id == eID) {
+ if (e->used)
+ ret = e->format;
+ break;
+ }
}
- kref_put(&setting->kref, release_channel_setting);
-end:
- mutex_unlock(<t_channel_mutex);
+ unlock_markers();
return ret;
}
-EXPORT_SYMBOL_GPL(ltt_channels_unregister);
+EXPORT_SYMBOL_GPL(get_fmt_from_eid);
+
+/*
+ * Must be called when channel refcount falls to 0 _and_ also when the last
+ * trace is freed. This function is responsible for compacting the channel
+ * index when no users are active.
+ */
+static void release_channel_index(struct kref *kref)
+{
+ struct ltt_channel_setting *setting;
+ free_index = 0;
+ list_for_each_entry(setting, <t_channels, list)
+ setting->index = free_index++;
+}
/**
* ltt_channels_set_default: Set channel default behavior.
@@ -149,16 +209,16 @@ int ltt_channels_set_default(const char *name,
struct ltt_channel_setting *setting;
int ret = 0;
- mutex_lock(<t_channel_mutex);
+ lock_markers();
setting = lookup_channel(name);
- if (!setting || atomic_read(&setting->kref.refcount) == 0) {
+ if (!setting) {
ret = -ENOENT;
goto end;
}
setting->subbuf_size = subbuf_size;
setting->subbuf_cnt = subbuf_cnt;
end:
- mutex_unlock(<t_channel_mutex);
+ unlock_markers();
return ret;
}
EXPORT_SYMBOL_GPL(ltt_channels_set_default);
@@ -174,7 +234,7 @@ const char *ltt_channels_get_name_from_index(unsigned int index)
struct ltt_channel_setting *iter;
list_for_each_entry(iter, <t_channels, list)
- if (iter->index == index && atomic_read(&iter->kref.refcount))
+ if (iter->index == index)
return iter->name;
return NULL;
}
@@ -186,8 +246,7 @@ ltt_channels_get_setting_from_name(const char *name)
struct ltt_channel_setting *iter;
list_for_each_entry(iter, <t_channels, list)
- if (!strcmp(iter->name, name)
- && atomic_read(&iter->kref.refcount))
+ if (!strcmp(iter->name, name))
return iter;
return NULL;
}
@@ -228,7 +287,7 @@ struct ltt_channel_struct *ltt_channels_trace_alloc(unsigned int *nr_channels,
struct ltt_channel_struct *channel = NULL;
struct ltt_channel_setting *iter;
- mutex_lock(<t_channel_mutex);
+ lock_markers();
if (!free_index)
goto end;
if (!atomic_read(&index_kref.refcount))
@@ -241,7 +300,7 @@ struct ltt_channel_struct *ltt_channels_trace_alloc(unsigned int *nr_channels,
if (!channel)
goto end;
list_for_each_entry(iter, <t_channels, list) {
- if (!atomic_read(&iter->kref.refcount))
+ if (!iter->live_count)
continue;
channel[iter->index].subbuf_size = iter->subbuf_size;
channel[iter->index].subbuf_cnt = iter->subbuf_cnt;
@@ -250,7 +309,7 @@ struct ltt_channel_struct *ltt_channels_trace_alloc(unsigned int *nr_channels,
channel[iter->index].channel_name = iter->name;
}
end:
- mutex_unlock(<t_channel_mutex);
+ unlock_markers();
return channel;
}
EXPORT_SYMBOL_GPL(ltt_channels_trace_alloc);
@@ -264,33 +323,18 @@ EXPORT_SYMBOL_GPL(ltt_channels_trace_alloc);
void ltt_channels_trace_free(struct ltt_channel_struct *channels)
{
lock_markers();
- mutex_lock(<t_channel_mutex);
- kfree(channels);
- kref_put(&index_kref, release_trace_channel);
- mutex_unlock(<t_channel_mutex);
+ kref_put(&index_kref, release_channel_index);
unlock_markers();
+ kfree(channels);
}
EXPORT_SYMBOL_GPL(ltt_channels_trace_free);
-/**
- * _ltt_channels_get_event_id: get next event ID for a marker
- * @channel: channel name
- * @name: event name
- *
- * Returns a unique event ID (for this channel) or < 0 on error.
- * Must be called with channels mutex held.
- */
-int _ltt_channels_get_event_id(const char *channel, const char *name)
+static int _ltt_channels_get_event_id(struct ltt_channel_setting *setting,
+ const char *name)
{
- struct ltt_channel_setting *setting;
int ret;
- setting = ltt_channels_get_setting_from_name(channel);
- if (!setting) {
- ret = -ENOENT;
- goto end;
- }
- if (strcmp(channel, "metadata") == 0) {
+ if (strcmp(setting->name, "metadata") == 0) {
if (strcmp(name, "core_marker_id") == 0)
ret = 0;
else if (strcmp(name, "core_marker_format") == 0)
@@ -299,7 +343,7 @@ int _ltt_channels_get_event_id(const char *channel, const char *name)
ret = -ENOENT;
goto end;
}
- if (setting->free_event_id == EVENTS_PER_CHANNEL) {
+ if (setting->free_event_id == EVENTS_PER_CHANNEL - 1) {
ret = -ENOSPC;
goto end;
}
@@ -316,11 +360,14 @@ end:
*/
int ltt_channels_get_event_id(const char *channel, const char *name)
{
- int ret;
+ int ret = -ENOENT;
+ struct ltt_channel_setting *setting;
- mutex_lock(<t_channel_mutex);
- ret = _ltt_channels_get_event_id(channel, name);
- mutex_unlock(<t_channel_mutex);
+ lock_markers();
+ setting = ltt_channels_get_setting_from_name(channel);
+ if (setting)
+ ret = _ltt_channels_get_event_id(setting, name);
+ unlock_markers();
return ret;
}
diff --git a/ltt/ltt-tracer.c b/ltt/ltt-tracer.c
index af14135..71289f9 100644
--- a/ltt/ltt-tracer.c
+++ b/ltt/ltt-tracer.c
@@ -772,6 +772,7 @@ int ltt_trace_alloc(const char *trace_name)
subbuf_size = trace->channels[chan].subbuf_size;
subbuf_cnt = trace->channels[chan].subbuf_cnt;
prepare_chan_size_num(&subbuf_size, &subbuf_cnt);
+ start_trace_channel(channel_name);
err = trace->ops->create_channel(trace_name, trace,
trace->dentry.trace_root,
channel_name,
@@ -801,8 +802,10 @@ int ltt_trace_alloc(const char *trace_name)
create_channel_error:
for (chan--; chan >= 0; chan--)
- if (trace->channels[chan].active)
+ if (trace->channels[chan].active) {
trace->ops->remove_channel(&trace->channels[chan]);
+ stop_trace_channel(trace->channels[chan].channel_name);
+ }
dirs_error:
module_put(trace->transport->owner);
@@ -901,8 +904,10 @@ static void __ltt_trace_destroy(struct ltt_trace_struct *trace)
for (i = 0; i < trace->nr_channels; i++) {
chan = &trace->channels[i];
- if (chan->active)
+ if (chan->active) {
trace->ops->remove_channel(chan);
+ stop_trace_channel(chan->channel_name);
+ }
}
kref_put(&trace->ltt_transport_kref, ltt_release_transport);
More information about the lttng-dev
mailing list