Mirror of the lttng-dev mailing list
 help / color / mirror / Atom feed
* [ltt-dev] [PATCH] ltt-channel: permanent eID
@ 2008-12-16 13:28 Lai Jiangshan
  2008-12-17 19:40 ` Mathieu Desnoyers
  0 siblings, 1 reply; 6+ messages in thread
From: Lai Jiangshan @ 2008-12-16 13:28 UTC (permalink / raw)



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, &ltt_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, &ltt_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, &ltt_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(&ltt_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, &ltt_channels);
-	strncpy(setting->name, name, PATH_MAX-1);
-	setting->index = free_index++;
-init_kref:
-	kref_init(&setting->kref);
-end:
-	mutex_unlock(&ltt_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(&ltt_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(&ltt_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, &ltt_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(&ltt_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(&ltt_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, &ltt_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, &ltt_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(&ltt_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, &ltt_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(&ltt_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(&ltt_channel_mutex);
-	kfree(channels);
-	kref_put(&index_kref, release_trace_channel);
-	mutex_unlock(&ltt_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(&ltt_channel_mutex);
-	ret = _ltt_channels_get_event_id(channel, name);
-	mutex_unlock(&ltt_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);





^ permalink raw reply	[flat|nested] 6+ messages in thread

* [ltt-dev] [PATCH] ltt-channel: permanent eID
  2008-12-16 13:28 [ltt-dev] [PATCH] ltt-channel: permanent eID Lai Jiangshan
@ 2008-12-17 19:40 ` Mathieu Desnoyers
  2008-12-18  2:22   ` Lai Jiangshan
  0 siblings, 1 reply; 6+ messages in thread
From: Mathieu Desnoyers @ 2008-12-17 19:40 UTC (permalink / raw)


* Lai Jiangshan (laijs at cn.fujitsu.com) wrote:
> 
> introduce permanent eID for text output, and change
> the ltt-channel's management.
> 

Hi Lai,

I'd like to review this work, but unfortunately, some documentation is
missing. Would it be possible to describe :

- The reason why each change is done.
- How each change is done.
- Modification done to locking (mutex changes, order of mutexes...)
- Why the "change to ltt-channel's management" is required.

Both in a complete changelog message and with added comments in the
code.

Thanks,

Mathieu


> 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, &ltt_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, &ltt_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, &ltt_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(&ltt_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, &ltt_channels);
> -	strncpy(setting->name, name, PATH_MAX-1);
> -	setting->index = free_index++;
> -init_kref:
> -	kref_init(&setting->kref);
> -end:
> -	mutex_unlock(&ltt_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(&ltt_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(&ltt_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, &ltt_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(&ltt_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(&ltt_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, &ltt_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, &ltt_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(&ltt_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, &ltt_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(&ltt_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(&ltt_channel_mutex);
> -	kfree(channels);
> -	kref_put(&index_kref, release_trace_channel);
> -	mutex_unlock(&ltt_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(&ltt_channel_mutex);
> -	ret = _ltt_channels_get_event_id(channel, name);
> -	mutex_unlock(&ltt_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);
> 
> 
> 
> _______________________________________________
> ltt-dev mailing list
> ltt-dev at lists.casi.polymtl.ca
> http://lists.casi.polymtl.ca/cgi-bin/mailman/listinfo/ltt-dev
> 

-- 
Mathieu Desnoyers
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68



^ permalink raw reply	[flat|nested] 6+ messages in thread

* [ltt-dev] [PATCH] ltt-channel: permanent eID
  2008-12-17 19:40 ` Mathieu Desnoyers
@ 2008-12-18  2:22   ` Lai Jiangshan
  2008-12-18  4:42     ` Mathieu Desnoyers
  0 siblings, 1 reply; 6+ messages in thread
From: Lai Jiangshan @ 2008-12-18  2:22 UTC (permalink / raw)



changelog:

Marker ID and its data must be permanent for text output, this patch
introduce permanent eID.

1) per channel permanent eID

Basic struct for store eID's data is struct marker_entry. When a channel
is activated, all the struct marker_entry for this channel are permanent
until this channel is deactivated. In this period, event if the marker
is leaved or other things are happened, the eID is permanent.

This patch introduces 4 API for permanent eID:
int start_trace_channel(const char *channel); - activate a channel
int stop_trace_channel(const char *channel); - deactivate a channel
const char *get_name_from_eid(const char *channel, u16 eID); - get name from eID
const char *get_fmt_from_eid(const char *channel, u16 eID); - get fmt from eID

See ltt/ltt-tracer.c for the using of start/stop_trace_channel().

When a channel is deactivated(its trace_count come to 0), we will defrag eID
for this channel. AND we use "trace_mark(metadata, core_marker_id," to tell
userspace that id is reset.

2) per channel struct marker_entry(permanent eID' data) management

All struct marker_entry of a channel are threaded by struct list_head.

It will help us remove a struct marker_entry quickly and help us manage
entries quickly(defrag_id(), remove_chanel_marker_entries())

We also call marker_update_probes() in defrag_id().

Since struct marker_entry is permanent eID' data. We move the definition
of struct marker_entry from marker.c to ltt-channel.h

3) as previous code, we defrag channel index when all tracer is stopped.

different: As described in 1),  permanent eID will defraged when a
channel is deactivated.

It means this patch has more fine-grained ID management.

4) remove ltt_channel_mutex.

Almost all function need lock_markers(), we should remove channel_mutex.

Signed-off-by: Lai Jiangshan <laijs at cn.fujitsu.com>

Mathieu Desnoyers wrote:
> * Lai Jiangshan (laijs at cn.fujitsu.com) wrote:
>> introduce permanent eID for text output, and change
>> the ltt-channel's management.
>>
> 
> Hi Lai,
> 
> I'd like to review this work, but unfortunately, some documentation is
> missing. Would it be possible to describe :
> 
> - The reason why each change is done.
> - How each change is done.
> - Modification done to locking (mutex changes, order of mutexes...)
> - Why the "change to ltt-channel's management" is required.
> 
> Both in a complete changelog message and with added comments in the
> code.
> 
> Thanks,
> 
> Mathieu
> 
> 
>> 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, &ltt_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, &ltt_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, &ltt_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(&ltt_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, &ltt_channels);
>> -	strncpy(setting->name, name, PATH_MAX-1);
>> -	setting->index = free_index++;
>> -init_kref:
>> -	kref_init(&setting->kref);
>> -end:
>> -	mutex_unlock(&ltt_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(&ltt_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(&ltt_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, &ltt_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(&ltt_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(&ltt_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, &ltt_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, &ltt_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(&ltt_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, &ltt_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(&ltt_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(&ltt_channel_mutex);
>> -	kfree(channels);
>> -	kref_put(&index_kref, release_trace_channel);
>> -	mutex_unlock(&ltt_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(&ltt_channel_mutex);
>> -	ret = _ltt_channels_get_event_id(channel, name);
>> -	mutex_unlock(&ltt_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);
>>
>>
>>
>> _______________________________________________
>> ltt-dev mailing list
>> ltt-dev at lists.casi.polymtl.ca
>> http://lists.casi.polymtl.ca/cgi-bin/mailman/listinfo/ltt-dev
>>
> 






^ permalink raw reply	[flat|nested] 6+ messages in thread

* [ltt-dev] [PATCH] ltt-channel: permanent eID
  2008-12-18  2:22   ` Lai Jiangshan
@ 2008-12-18  4:42     ` Mathieu Desnoyers
  2008-12-18  6:07       ` Lai Jiangshan
  0 siblings, 1 reply; 6+ messages in thread
From: Mathieu Desnoyers @ 2008-12-18  4:42 UTC (permalink / raw)


* Lai Jiangshan (laijs at cn.fujitsu.com) wrote:
> 

Thanks for this description, comments below,

> changelog:
> 
> Marker ID and its data must be permanent for text output, this patch
> introduce permanent eID.
> 
> 1) per channel permanent eID
> 
> Basic struct for store eID's data is struct marker_entry. When a channel
> is activated, all the struct marker_entry for this channel are permanent
> until this channel is deactivated. In this period, event if the marker
> is leaved or other things are happened, the eID is permanent.
> 

Ok, so you keep the struct marker_entry around until the channel is
unused (all traces are destroyed, including that all in-kernel ascii
converters have released the trace) ?

> This patch introduces 4 API for permanent eID:
> int start_trace_channel(const char *channel); - activate a channel
> int stop_trace_channel(const char *channel); - deactivate a channel

Hrm, can we change the names for
get_trace_channel()
put_trace_channel() ?

start and stop sounds a bit misleading with the tracing start/stop
semantics.

Also, why do we have "waste" ids ? This is bad, because whenever
possible, we should fit IDs in ~28 IDs allowed for "compact" event ids.
If the IDs are larger than this, the tracer will have to generate an
extended header and waste trace space. Do we really _need_ such id waste?

> const char *get_name_from_eid(const char *channel, u16 eID); - get name from eID
> const char *get_fmt_from_eid(const char *channel, u16 eID); - get fmt from eID
> 
> See ltt/ltt-tracer.c for the using of start/stop_trace_channel().
> 
hrm, stop_trace_channel (or put_trace_channel) is in __destroy, but
should probably be in the kref desctructor, so we are sure that it's
only called with all references to the trace data, including the
in-kernel ascii converters, have released their reference.



> When a channel is deactivated(its trace_count come to 0), we will defrag eID
> for this channel. AND we use "trace_mark(metadata, core_marker_id," to tell
> userspace that id is reset.

Sounds good.

> 
> 2) per channel struct marker_entry(permanent eID' data) management
> 
> All struct marker_entry of a channel are threaded by struct list_head.
> 
> It will help us remove a struct marker_entry quickly and help us manage
> entries quickly(defrag_id(), remove_chanel_marker_entries())
> 
> We also call marker_update_probes() in defrag_id().
> 

Hrm, aren't we taking the marker mutex twice here ? I am probably
missing something.

> Since struct marker_entry is permanent eID' data. We move the definition
> of struct marker_entry from marker.c to ltt-channel.h
> 

BTW, I would not use the term "permanent" for this. Because permanent,
to me, really means "we allocate something that we will only free when
the machine reboots". We are simply extending the life of the the eIDs
for the duration of all references to those IDs.

Let's say that we extend the event ID lifetime to the overall event ID
references, which now includes trace references, which includes ascii
converters.

> 3) as previous code, we defrag channel index when all tracer is stopped.
> 
> different: As described in 1),  permanent eID will defraged when a
> channel is deactivated.
> 
> It means this patch has more fine-grained ID management.
> 

There are two cases here :

Tracing starts
  add/remove markers many times
Tracing stops -> defrag

And

No tracing
add/remove markers many times -> defrag each time

You don't say much about what is done at marker add/remove when tracing
is inactive. Is there some compaction done ?


> 4) remove ltt_channel_mutex.
> 
> Almost all function need lock_markers(), we should remove channel_mutex.
> 

Yep, sounds simpler and those two are pretty much coupled anyway.

Mathieu

> Signed-off-by: Lai Jiangshan <laijs at cn.fujitsu.com>
> 
> Mathieu Desnoyers wrote:
> > * Lai Jiangshan (laijs at cn.fujitsu.com) wrote:
> >> introduce permanent eID for text output, and change
> >> the ltt-channel's management.
> >>
> > 
> > Hi Lai,
> > 
> > I'd like to review this work, but unfortunately, some documentation is
> > missing. Would it be possible to describe :
> > 
> > - The reason why each change is done.
> > - How each change is done.
> > - Modification done to locking (mutex changes, order of mutexes...)
> > - Why the "change to ltt-channel's management" is required.
> > 
> > Both in a complete changelog message and with added comments in the
> > code.
> > 
> > Thanks,
> > 
> > Mathieu
> > 
> > 
> >> 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, &ltt_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, &ltt_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, &ltt_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(&ltt_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, &ltt_channels);
> >> -	strncpy(setting->name, name, PATH_MAX-1);
> >> -	setting->index = free_index++;
> >> -init_kref:
> >> -	kref_init(&setting->kref);
> >> -end:
> >> -	mutex_unlock(&ltt_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(&ltt_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(&ltt_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, &ltt_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(&ltt_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(&ltt_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, &ltt_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, &ltt_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(&ltt_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, &ltt_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(&ltt_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(&ltt_channel_mutex);
> >> -	kfree(channels);
> >> -	kref_put(&index_kref, release_trace_channel);
> >> -	mutex_unlock(&ltt_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(&ltt_channel_mutex);
> >> -	ret = _ltt_channels_get_event_id(channel, name);
> >> -	mutex_unlock(&ltt_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);
> >>
> >>
> >>
> >> _______________________________________________
> >> ltt-dev mailing list
> >> ltt-dev at lists.casi.polymtl.ca
> >> http://lists.casi.polymtl.ca/cgi-bin/mailman/listinfo/ltt-dev
> >>
> > 
> 
> 

-- 
Mathieu Desnoyers
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68



^ permalink raw reply	[flat|nested] 6+ messages in thread

* [ltt-dev] [PATCH] ltt-channel: permanent eID
  2008-12-18  4:42     ` Mathieu Desnoyers
@ 2008-12-18  6:07       ` Lai Jiangshan
  2008-12-18 15:05         ` Mathieu Desnoyers
  0 siblings, 1 reply; 6+ messages in thread
From: Lai Jiangshan @ 2008-12-18  6:07 UTC (permalink / raw)


Mathieu Desnoyers wrote:
> * Lai Jiangshan (laijs at cn.fujitsu.com) wrote:
> 
> Thanks for this description, comments below,
> 
>> changelog:
>>
>> Marker ID and its data must be permanent for text output, this patch
>> introduce permanent eID.
>>
>> 1) per channel permanent eID
>>
>> Basic struct for store eID's data is struct marker_entry. When a channel
>> is activated, all the struct marker_entry for this channel are permanent
>> until this channel is deactivated. In this period, event if the marker
>> is leaved or other things are happened, the eID is permanent.
>>
> 
> Ok, so you keep the struct marker_entry around until the channel is
> unused (all traces are destroyed, including that all in-kernel ascii
> converters have released the trace) ?

When "this channel is deactivated", the unused struct marker_entry for
this channel will be removed, event if this channel is still live.
all traces are destroyed means all channel are deactivated.

when we trace a channel, we say this channel is activated.

> 
>> This patch introduces 4 API for permanent eID:
>> int start_trace_channel(const char *channel); - activate a channel
>> int stop_trace_channel(const char *channel); - deactivate a channel
> 
> Hrm, can we change the names for
> get_trace_channel()
> put_trace_channel() ?
> 
> start and stop sounds a bit misleading with the tracing start/stop
> semantics.
> 
> Also, why do we have "waste" ids ? This is bad, because whenever
> possible, we should fit IDs in ~28 IDs allowed for "compact" event ids.
> If the IDs are larger than this, the tracer will have to generate an
> extended header and waste trace space. Do we really _need_ such id waste?

The previous code has a degression: when eID for a marker is changed,
userspace tool do not know the ID changed. this patch make eIDs are
not changed too frequent.

> 
>> const char *get_name_from_eid(const char *channel, u16 eID); - get name from eID
>> const char *get_fmt_from_eid(const char *channel, u16 eID); - get fmt from eID
>>
>> See ltt/ltt-tracer.c for the using of start/stop_trace_channel().
>>
> hrm, stop_trace_channel (or put_trace_channel) is in __destroy, but
> should probably be in the kref desctructor, so we are sure that it's
> only called with all references to the trace data, including the
> in-kernel ascii converters, have released their reference.
> 

start_trace_channel()
create ltt relay channel

ID's life time

destory ltt relay channel
stop_trace_channel()

Is it incorrect?

> 
> 
>> When a channel is deactivated(its trace_count come to 0), we will defrag eID
>> for this channel. AND we use "trace_mark(metadata, core_marker_id," to tell
>> userspace that id is reset.
> 
> Sounds good.
> 
>> 2) per channel struct marker_entry(permanent eID' data) management
>>
>> All struct marker_entry of a channel are threaded by struct list_head.
>>
>> It will help us remove a struct marker_entry quickly and help us manage
>> entries quickly(defrag_id(), remove_chanel_marker_entries())
>>
>> We also call marker_update_probes() in defrag_id().
>>
> 
> Hrm, aren't we taking the marker mutex twice here ? I am probably
> missing something.

Oh, I forgot marker_update_probes() needs marker.
This patch have been tested, but without marker_update_probes() in defrag_id().
It was added when I saw my review note about markers_compact_event_ids()
when I was going to send patch.
marker_update_probes() is affirmatively need after defrag_id() or
markers_compact_event_ids()(removed function).

> 
>> Since struct marker_entry is permanent eID' data. We move the definition
>> of struct marker_entry from marker.c to ltt-channel.h
>>
> 
> BTW, I would not use the term "permanent" for this. Because permanent,
> to me, really means "we allocate something that we will only free when
> the machine reboots". We are simply extending the life of the the eIDs
> for the duration of all references to those IDs.
> 
> Let's say that we extend the event ID lifetime to the overall event ID
> references, which now includes trace references, which includes ascii
> converters.
> 
>> 3) as previous code, we defrag channel index when all tracer is stopped.
>>
>> different: As described in 1),  permanent eID will defraged when a
>> channel is deactivated.
>>
>> It means this patch has more fine-grained ID management.
>>
> 
> There are two cases here :
> 
> Tracing starts
>   add/remove markers many times
> Tracing stops -> defrag
> 
> And
> 
> No tracing
> add/remove markers many times -> defrag each time
> 
> You don't say much about what is done at marker add/remove when tracing
> is inactive. Is there some compaction done ?

start/stop_trace_channel() is very short. Reviewing the code is better than
ugly English comment:

stop_trace_channel()
   remove_chanel_marker_entries() ------- remove unused marker_entry

start_trace_channel()
   defrag_id()     ----Usually, defrag_id() should in stop_trace_channel()
                 but delay defrag_id() until start_trace_channel() is better.

if no tracing
	removing marker_entry is done quickly. not defrag id

if tracing
	removing marker_entry will be delayed.






^ permalink raw reply	[flat|nested] 6+ messages in thread

* [ltt-dev] [PATCH] ltt-channel: permanent eID
  2008-12-18  6:07       ` Lai Jiangshan
@ 2008-12-18 15:05         ` Mathieu Desnoyers
  0 siblings, 0 replies; 6+ messages in thread
From: Mathieu Desnoyers @ 2008-12-18 15:05 UTC (permalink / raw)


* Lai Jiangshan (laijs at cn.fujitsu.com) wrote:
> Mathieu Desnoyers wrote:
> > * Lai Jiangshan (laijs at cn.fujitsu.com) wrote:
> > 
> > Thanks for this description, comments below,
> > 
> >> changelog:
> >>
> >> Marker ID and its data must be permanent for text output, this patch
> >> introduce permanent eID.
> >>
> >> 1) per channel permanent eID
> >>
> >> Basic struct for store eID's data is struct marker_entry. When a channel
> >> is activated, all the struct marker_entry for this channel are permanent
> >> until this channel is deactivated. In this period, event if the marker
> >> is leaved or other things are happened, the eID is permanent.
> >>
> > 
> > Ok, so you keep the struct marker_entry around until the channel is
> > unused (all traces are destroyed, including that all in-kernel ascii
> > converters have released the trace) ?
> 
> When "this channel is deactivated", the unused struct marker_entry for
> this channel will be removed, event if this channel is still live.
> all traces are destroyed means all channel are deactivated.
> 
> when we trace a channel, we say this channel is activated.
>

OK

> > 
> >> This patch introduces 4 API for permanent eID:
> >> int start_trace_channel(const char *channel); - activate a channel
> >> int stop_trace_channel(const char *channel); - deactivate a channel
> > 
> > Hrm, can we change the names for
> > get_trace_channel()
> > put_trace_channel() ?
> > 
> > start and stop sounds a bit misleading with the tracing start/stop
> > semantics.
> > 
> > Also, why do we have "waste" ids ? This is bad, because whenever
> > possible, we should fit IDs in ~28 IDs allowed for "compact" event ids.
> > If the IDs are larger than this, the tracer will have to generate an
> > extended header and waste trace space. Do we really _need_ such id waste?
> 
> The previous code has a degression: when eID for a marker is changed,
> userspace tool do not know the ID changed. this patch make eIDs are
> not changed too frequent.
> 

An event ID should _never_ be re-used for a different marker when a trace
is active. But when tracing is activated, we defragment the ID space (as
you do). Actually, we could postpone the ID allocation to tracing
activation rather than doing it at marker registration.

> > 
> >> const char *get_name_from_eid(const char *channel, u16 eID); - get name from eID
> >> const char *get_fmt_from_eid(const char *channel, u16 eID); - get fmt from eID
> >>
> >> See ltt/ltt-tracer.c for the using of start/stop_trace_channel().
> >>
> > hrm, stop_trace_channel (or put_trace_channel) is in __destroy, but
> > should probably be in the kref desctructor, so we are sure that it's
> > only called with all references to the trace data, including the
> > in-kernel ascii converters, have released their reference.
> > 
> 
> start_trace_channel()
> create ltt relay channel
> 
> ID's life time
> 
> destory ltt relay channel
> stop_trace_channel()
> 
> Is it incorrect?
> 

This is correct, but the "destroy ltt relay channel" does not happen
exactly in

        for (i = 0; i < trace->nr_channels; i++) {
                chan = &trace->channels[i];
                if (chan->active)
                        trace->ops->remove_channel(chan);
        }

Because all it calls is :

static void ltt_relay_remove_channel(struct ltt_channel_struct *channel)
{
        struct rchan *rchan = channel->trans_channel_data;

        ltt_relay_close(rchan);
          -> does a kref_put(&buf->kref, relay_remove_buf);
        kref_put(&channel->kref, ltt_relay_release_channel);
}


But relay_file_open (in ltt-relay-alloc.c) does :
  kref_get(&buf->kref);
And relay_file_release in ltt-relay-alloc.c does :
  kref_put(&buf->kref, relay_remove_buf);

__ltt_trace_destroy
  trace->ops->remove_channel -> ltt-relay.c:ltt_relay_remove_channel
    ltt-relay-alloc.c:ltt_relay_close
      ltt-relay-alloc.c:relay_close_buf
        kref_put(&buf->kref, relay_remove_buf);
 
So we basically have to :
- Have __ltt_trace_destroy releasing the kref
- Have any file opener releasing the kref

Before the following gets called :

ltt-relay-alloc.c:relay_remove_buf
  buf->chan->cb->remove_buf_file -> ltt-relay.c:ltt_remove_buf_file_callback
    ltt_relay_destroy_buffer
      kref_put(&ltt_chan->trace->ltt_transport_kref,
        ltt_release_transport);
      kref_put(&ltt_chan->kref, ltt_relay_release_channel);
      kref_put(&trace->kref, ltt_release_trace);
  relay_destroy_buf
    kref_put(&chan->kref, relay_destroy_channel);



If we look below in __ltt_trace_destroy, we see :

       /*
         * Wait for lttd readers to release the files, therefore making sure
         * the last subbuffers have been read.
         */
        if (atomic_read(&trace->kref.refcount) > 1) {
                int ret = 0;
                __wait_event_interruptible(trace->kref_wq,
                        (atomic_read(&trace->kref.refcount) == 1), ret);
        }
        kref_put(&trace->kref, ltt_release_trace);

This lets us wait for any file opener to exit before we continue.

So, the correct moment to do the stop_trace_channel(chan->channel_name);
is when all references to the traces are done. The easiest spot to put
it is in ltt_release_trace() just before the ltt_channels_trace_free
call.



> > 
> > 
> >> When a channel is deactivated(its trace_count come to 0), we will defrag eID
> >> for this channel. AND we use "trace_mark(metadata, core_marker_id," to tell
> >> userspace that id is reset.
> > 
> > Sounds good.
> > 
> >> 2) per channel struct marker_entry(permanent eID' data) management
> >>
> >> All struct marker_entry of a channel are threaded by struct list_head.
> >>
> >> It will help us remove a struct marker_entry quickly and help us manage
> >> entries quickly(defrag_id(), remove_chanel_marker_entries())
> >>
> >> We also call marker_update_probes() in defrag_id().
> >>
> > 
> > Hrm, aren't we taking the marker mutex twice here ? I am probably
> > missing something.
> 
> Oh, I forgot marker_update_probes() needs marker.
> This patch have been tested, but without marker_update_probes() in defrag_id().
> It was added when I saw my review note about markers_compact_event_ids()
> when I was going to send patch.
> marker_update_probes() is affirmatively need after defrag_id() or
> markers_compact_event_ids()(removed function).
> 

Yep.

> > 
> >> Since struct marker_entry is permanent eID' data. We move the definition
> >> of struct marker_entry from marker.c to ltt-channel.h
> >>
> > 
> > BTW, I would not use the term "permanent" for this. Because permanent,
> > to me, really means "we allocate something that we will only free when
> > the machine reboots". We are simply extending the life of the the eIDs
> > for the duration of all references to those IDs.
> > 
> > Let's say that we extend the event ID lifetime to the overall event ID
> > references, which now includes trace references, which includes ascii
> > converters.
> > 
> >> 3) as previous code, we defrag channel index when all tracer is stopped.
> >>
> >> different: As described in 1),  permanent eID will defraged when a
> >> channel is deactivated.
> >>
> >> It means this patch has more fine-grained ID management.
> >>
> > 
> > There are two cases here :
> > 
> > Tracing starts
> >   add/remove markers many times
> > Tracing stops -> defrag
> > 
> > And
> > 
> > No tracing
> > add/remove markers many times -> defrag each time
> > 
> > You don't say much about what is done at marker add/remove when tracing
> > is inactive. Is there some compaction done ?
> 
> start/stop_trace_channel() is very short. Reviewing the code is better than
> ugly English comment:
> 
> stop_trace_channel()
>    remove_chanel_marker_entries() ------- remove unused marker_entry
> 
> start_trace_channel()
>    defrag_id()     ----Usually, defrag_id() should in stop_trace_channel()
>                  but delay defrag_id() until start_trace_channel() is better.
> 
> if no tracing
> 	removing marker_entry is done quickly. not defrag id
> 
> if tracing
> 	removing marker_entry will be delayed.
> 

That makes sense.

Mathieu

-- 
Mathieu Desnoyers
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68




^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2008-12-18 15:05 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-12-16 13:28 [ltt-dev] [PATCH] ltt-channel: permanent eID Lai Jiangshan
2008-12-17 19:40 ` Mathieu Desnoyers
2008-12-18  2:22   ` Lai Jiangshan
2008-12-18  4:42     ` Mathieu Desnoyers
2008-12-18  6:07       ` Lai Jiangshan
2008-12-18 15:05         ` Mathieu Desnoyers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox