Patches contributed by Eötvös Lorand University


commit b53dde9d34f2df396540988ebc65c33400f57b04
Author: Ingo Molnar <mingo@elte.hu>
Date:   Mon May 12 21:20:51 2008 +0200

    ftrace: disable -pg for the tracer itself
    
    Signed-off-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index 3fec653d6533..c25a6cd6a529 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -1,3 +1,11 @@
+
+# Do not instrument the tracer itself:
+
+ifdef CONFIG_FTRACE
+ORIG_CFLAGS := $(KBUILD_CFLAGS)
+KBUILD_CFLAGS = $(subst -pg,,$(ORIG_CFLAGS))
+endif
+
 obj-$(CONFIG_FTRACE) += libftrace.o
 
 obj-$(CONFIG_TRACING) += trace.o

commit 9ff9cdb2d3b0971f89e899b3420aadd91bddc215
Author: Ingo Molnar <mingo@elte.hu>
Date:   Mon May 12 21:20:50 2008 +0200

    ftrace: cleanups
    
    clean up recent code.
    
    Signed-off-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index ff42345dd78e..425b1fec3d83 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -197,8 +197,8 @@ static int ftrace_record_suspend;
 
 static struct dyn_ftrace *ftrace_free_records;
 
-static inline int
-notrace ftrace_ip_in_hash(unsigned long ip, unsigned long key)
+static inline int notrace
+ftrace_ip_in_hash(unsigned long ip, unsigned long key)
 {
 	struct dyn_ftrace *p;
 	struct hlist_node *t;
@@ -1249,6 +1249,7 @@ static int __init notrace ftrace_dynamic_init(void)
 	int ret;
 
 	addr = (unsigned long)ftrace_record_ip;
+
 	stop_machine_run(ftrace_dyn_arch_init, &addr, NR_CPUS);
 
 	/* ftrace_dyn_arch_init places the return code in addr */
diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c
index 3269f4ff5172..2ac0d09db6fb 100644
--- a/kernel/trace/trace_irqsoff.c
+++ b/kernel/trace/trace_irqsoff.c
@@ -309,7 +309,7 @@ void trace_softirqs_off(unsigned long ip)
 {
 }
 
-inline void print_irqtrace_events(struct task_struct *curr)
+inline notrace void print_irqtrace_events(struct task_struct *curr)
 {
 }
 
diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c
index 85715b86a342..546307de6e3d 100644
--- a/kernel/trace/trace_selftest.c
+++ b/kernel/trace/trace_selftest.c
@@ -3,7 +3,7 @@
 #include <linux/kthread.h>
 #include <linux/delay.h>
 
-static inline int trace_valid_entry(struct trace_entry *entry)
+static notrace inline int trace_valid_entry(struct trace_entry *entry)
 {
 	switch (entry->type) {
 	case TRACE_FN:

commit aeaee8a2c9cb4489f166ca0e39c568e8254faaa6
Author: Ingo Molnar <mingo@elte.hu>
Date:   Mon May 12 21:20:49 2008 +0200

    ftrace: build fix
    
    Signed-off-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 4650a3160b7f..08fbef1744cc 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -58,9 +58,6 @@ struct dyn_ftrace {
 int ftrace_force_update(void);
 void ftrace_set_filter(unsigned char *buf, int len, int reset);
 
-/* totally disable ftrace - can not re-enable after this */
-void ftrace_kill(void);
-
 /* defined in arch */
 extern int ftrace_ip_converted(unsigned long ip);
 extern unsigned char *ftrace_nop_replace(void);
@@ -74,10 +71,13 @@ extern void ftrace_caller(void);
 extern void ftrace_call(void);
 extern void mcount_call(void);
 #else
-# define ftrace_force_update() ({ 0; })
-# define ftrace_set_filter(buf, len, reset) do { } while (0)
+# define ftrace_force_update()			({ 0; })
+# define ftrace_set_filter(buf, len, reset)	do { } while (0)
 #endif
 
+/* totally disable ftrace - can not re-enable after this */
+void ftrace_kill(void);
+
 static inline void tracer_disable(void)
 {
 #ifdef CONFIG_FTRACE

commit 2577046740fe6d77864128c6187c11125c2449ea
Author: Ingo Molnar <mingo@elte.hu>
Date:   Mon May 12 21:20:49 2008 +0200

    ftrace: build fix
    
    no need to backmerge, only affects ftrace-enabled kernels. (which is
    not the default)
    
    Signed-off-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 6974b212e938..958c4d77a67b 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -1965,7 +1965,9 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,
 	static cpumask_t mask;
 	static int start;
 	unsigned long flags;
+#ifdef CONFIG_FTRACE
 	int ftrace_save;
+#endif
 	int read = 0;
 	int cpu;
 	int len;
@@ -2044,8 +2046,10 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,
 
 	cpus_clear(mask);
 	local_irq_save(flags);
+#ifdef CONFIG_FTRACE
 	ftrace_save = ftrace_enabled;
 	ftrace_enabled = 0;
+#endif
 	smp_wmb();
 	for_each_possible_cpu(cpu) {
 		data = iter->tr->data[cpu];
@@ -2087,7 +2091,9 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,
 		data = iter->tr->data[cpu];
 		atomic_dec(&data->disabled);
 	}
+#ifdef CONFIG_FTRACE
 	ftrace_enabled = ftrace_save;
+#endif
 	local_irq_restore(flags);
 
 	/* Now copy what we have to the user */

commit 5e3ca0ec76fce92daa4eed0d02de9c79b1fe3920
Author: Ingo Molnar <mingo@elte.hu>
Date:   Mon May 12 21:20:49 2008 +0200

    ftrace: introduce the "hex" output method
    
    Signed-off-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 71b25b79b3de..6974b212e938 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -103,7 +103,8 @@ enum trace_iterator_flags {
 	TRACE_ITER_SYM_ADDR		= 0x04,
 	TRACE_ITER_VERBOSE		= 0x08,
 	TRACE_ITER_RAW			= 0x10,
-	TRACE_ITER_BIN			= 0x20,
+	TRACE_ITER_HEX			= 0x20,
+	TRACE_ITER_BIN			= 0x40,
 };
 
 #define TRACE_ITER_SYM_MASK \
@@ -116,6 +117,7 @@ static const char *trace_options[] = {
 	"sym-addr",
 	"verbose",
 	"raw",
+	"hex",
 	"bin",
 	NULL
 };
@@ -238,6 +240,47 @@ trace_seq_putmem(struct trace_seq *s, void *mem, size_t len)
 	return len;
 }
 
+#define HEX_CHARS 17
+
+static notrace int
+trace_seq_putmem_hex(struct trace_seq *s, void *mem, size_t len)
+{
+	unsigned char hex[HEX_CHARS];
+	unsigned char *data;
+	unsigned char byte;
+	int i, j;
+
+	BUG_ON(len >= HEX_CHARS);
+
+	data = mem;
+
+#ifdef __BIG_ENDIAN
+	for (i = 0, j = 0; i < len; i++) {
+#else
+	for (i = len-1, j = 0; i >= 0; i--) {
+#endif
+		byte = data[i];
+
+		hex[j]   = byte & 0x0f;
+		if (hex[j] >= 10)
+			hex[j] += 'a' - 10;
+		else
+			hex[j] += '0';
+		j++;
+
+		hex[j] = byte >> 4;
+		if (hex[j] >= 10)
+			hex[j] += 'a' - 10;
+		else
+			hex[j] += '0';
+		j++;
+	}
+	hex[j] = ' ';
+	j++;
+
+	return trace_seq_putmem(s, hex, j);
+}
+
 static notrace void
 trace_seq_reset(struct trace_seq *s)
 {
@@ -1274,6 +1317,51 @@ do {							\
 		return 0;				\
 } while (0)
 
+#define SEQ_PUT_HEX_FIELD_RET(s, x)			\
+do {							\
+	if (!trace_seq_putmem_hex(s, &(x), sizeof(x)))	\
+		return 0;				\
+} while (0)
+
+static notrace int print_hex_fmt(struct trace_iterator *iter)
+{
+	struct trace_seq *s = &iter->seq;
+	unsigned char newline = '\n';
+	struct trace_entry *entry;
+	int S;
+
+	entry = iter->ent;
+
+	SEQ_PUT_HEX_FIELD_RET(s, entry->pid);
+	SEQ_PUT_HEX_FIELD_RET(s, iter->cpu);
+	SEQ_PUT_HEX_FIELD_RET(s, entry->t);
+
+	switch (entry->type) {
+	case TRACE_FN:
+		SEQ_PUT_HEX_FIELD_RET(s, entry->fn.ip);
+		SEQ_PUT_HEX_FIELD_RET(s, entry->fn.parent_ip);
+		break;
+	case TRACE_CTX:
+		S = entry->ctx.prev_state < sizeof(state_to_char) ?
+			state_to_char[entry->ctx.prev_state] : 'X';
+		SEQ_PUT_HEX_FIELD_RET(s, entry->ctx.prev_pid);
+		SEQ_PUT_HEX_FIELD_RET(s, entry->ctx.prev_prio);
+		SEQ_PUT_HEX_FIELD_RET(s, S);
+		SEQ_PUT_HEX_FIELD_RET(s, entry->ctx.next_pid);
+		SEQ_PUT_HEX_FIELD_RET(s, entry->ctx.next_prio);
+		SEQ_PUT_HEX_FIELD_RET(s, entry->fn.parent_ip);
+		break;
+	case TRACE_SPECIAL:
+		SEQ_PUT_HEX_FIELD_RET(s, entry->special.arg1);
+		SEQ_PUT_HEX_FIELD_RET(s, entry->special.arg2);
+		SEQ_PUT_HEX_FIELD_RET(s, entry->special.arg3);
+		break;
+	}
+	SEQ_PUT_FIELD_RET(s, newline);
+
+	return 1;
+}
+
 static notrace int print_bin_fmt(struct trace_iterator *iter)
 {
 	struct trace_seq *s = &iter->seq;
@@ -1327,6 +1415,9 @@ static int print_trace_line(struct trace_iterator *iter)
 	if (trace_flags & TRACE_ITER_BIN)
 		return print_bin_fmt(iter);
 
+	if (trace_flags & TRACE_ITER_HEX)
+		return print_hex_fmt(iter);
+
 	if (trace_flags & TRACE_ITER_RAW)
 		return print_raw_fmt(iter);
 

commit 2e0f57618529a2739a5e1570e6c445c9c966b595
Author: Ingo Molnar <mingo@elte.hu>
Date:   Mon May 12 21:20:49 2008 +0200

    ftrace: build fix
    
    Signed-off-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index d74c039305ad..71b25b79b3de 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -432,47 +432,6 @@ notrace void tracing_reset(struct trace_array_cpu *data)
 	data->trace_tail_idx = 0;
 }
 
-#ifdef CONFIG_FTRACE
-static notrace void
-function_trace_call(unsigned long ip, unsigned long parent_ip)
-{
-	struct trace_array *tr = &global_trace;
-	struct trace_array_cpu *data;
-	unsigned long flags;
-	long disabled;
-	int cpu;
-
-	if (unlikely(!tracer_enabled))
-		return;
-
-	local_irq_save(flags);
-	cpu = raw_smp_processor_id();
-	data = tr->data[cpu];
-	disabled = atomic_inc_return(&data->disabled);
-
-	if (likely(disabled == 1))
-		ftrace(tr, data, ip, parent_ip, flags);
-
-	atomic_dec(&data->disabled);
-	local_irq_restore(flags);
-}
-
-static struct ftrace_ops trace_ops __read_mostly =
-{
-	.func = function_trace_call,
-};
-#endif
-
-notrace void tracing_start_function_trace(void)
-{
-	register_ftrace_function(&trace_ops);
-}
-
-notrace void tracing_stop_function_trace(void)
-{
-	unregister_ftrace_function(&trace_ops);
-}
-
 #define SAVED_CMDLINES 128
 static unsigned map_pid_to_cmdline[PID_MAX_DEFAULT+1];
 static unsigned map_cmdline_to_pid[SAVED_CMDLINES];
@@ -635,8 +594,8 @@ tracing_generic_entry_update(struct trace_entry *entry, unsigned long flags)
 }
 
 notrace void
-ftrace(struct trace_array *tr, struct trace_array_cpu *data,
-       unsigned long ip, unsigned long parent_ip, unsigned long flags)
+__ftrace(struct trace_array *tr, struct trace_array_cpu *data,
+	 unsigned long ip, unsigned long parent_ip, unsigned long flags)
 {
 	struct trace_entry *entry;
 	unsigned long irq_flags;
@@ -650,6 +609,14 @@ ftrace(struct trace_array *tr, struct trace_array_cpu *data,
 	spin_unlock_irqrestore(&data->lock, irq_flags);
 }
 
+notrace void
+ftrace(struct trace_array *tr, struct trace_array_cpu *data,
+       unsigned long ip, unsigned long parent_ip, unsigned long flags)
+{
+	if (likely(!atomic_read(&data->disabled)))
+		__ftrace(tr, data, ip, parent_ip, flags);
+}
+
 notrace void
 trace_special(struct trace_array *tr, struct trace_array_cpu *data,
 	      unsigned long arg1, unsigned long arg2, unsigned long arg3)
@@ -688,6 +655,47 @@ tracing_sched_switch_trace(struct trace_array *tr,
 	spin_unlock_irqrestore(&data->lock, irq_flags);
 }
 
+#ifdef CONFIG_FTRACE
+static notrace void
+function_trace_call(unsigned long ip, unsigned long parent_ip)
+{
+	struct trace_array *tr = &global_trace;
+	struct trace_array_cpu *data;
+	unsigned long flags;
+	long disabled;
+	int cpu;
+
+	if (unlikely(!tracer_enabled))
+		return;
+
+	local_irq_save(flags);
+	cpu = raw_smp_processor_id();
+	data = tr->data[cpu];
+	disabled = atomic_inc_return(&data->disabled);
+
+	if (likely(disabled == 1))
+		__ftrace(tr, data, ip, parent_ip, flags);
+
+	atomic_dec(&data->disabled);
+	local_irq_restore(flags);
+}
+
+static struct ftrace_ops trace_ops __read_mostly =
+{
+	.func = function_trace_call,
+};
+
+notrace void tracing_start_function_trace(void)
+{
+	register_ftrace_function(&trace_ops);
+}
+
+notrace void tracing_stop_function_trace(void)
+{
+	unregister_ftrace_function(&trace_ops);
+}
+#endif
+
 enum trace_file_type {
 	TRACE_FILE_LAT_FMT	= 1,
 };
@@ -722,7 +730,7 @@ trace_entry_idx(struct trace_array *tr, struct trace_array_cpu *data,
 	return &array[iter->next_page_idx[cpu]];
 }
 
-static struct notrace trace_entry *
+static struct trace_entry * notrace
 find_next_entry(struct trace_iterator *iter, int *ent_cpu)
 {
 	struct trace_array *tr = iter->tr;
@@ -1866,6 +1874,7 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,
 	static cpumask_t mask;
 	static int start;
 	unsigned long flags;
+	int ftrace_save;
 	int read = 0;
 	int cpu;
 	int len;
@@ -1944,6 +1953,9 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,
 
 	cpus_clear(mask);
 	local_irq_save(flags);
+	ftrace_save = ftrace_enabled;
+	ftrace_enabled = 0;
+	smp_wmb();
 	for_each_possible_cpu(cpu) {
 		data = iter->tr->data[cpu];
 
@@ -1951,10 +1963,14 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,
 			continue;
 
 		atomic_inc(&data->disabled);
-		spin_lock(&data->lock);
 		cpu_set(cpu, mask);
 	}
 
+	for_each_cpu_mask(cpu, mask) {
+		data = iter->tr->data[cpu];
+		spin_lock(&data->lock);
+	}
+
 	while (find_next_entry_inc(iter) != NULL) {
 		int len = iter->seq.len;
 
@@ -1974,8 +1990,13 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,
 	for_each_cpu_mask(cpu, mask) {
 		data = iter->tr->data[cpu];
 		spin_unlock(&data->lock);
+	}
+
+	for_each_cpu_mask(cpu, mask) {
+		data = iter->tr->data[cpu];
 		atomic_dec(&data->disabled);
 	}
+	ftrace_enabled = ftrace_save;
 	local_irq_restore(flags);
 
 	/* Now copy what we have to the user */
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
index e5d34b78fc99..69a0eb00a0a5 100644
--- a/kernel/trace/trace_functions.c
+++ b/kernel/trace/trace_functions.c
@@ -9,10 +9,10 @@
  *  Copyright (C) 2004-2006 Ingo Molnar
  *  Copyright (C) 2004 William Lee Irwin III
  */
-#include <linux/fs.h>
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
 #include <linux/ftrace.h>
+#include <linux/fs.h>
 
 #include "trace.h"
 

commit 0fd9e0dac9026df09986a4b201518ae015814aef
Author: Ingo Molnar <mingo@elte.hu>
Date:   Mon May 12 21:20:48 2008 +0200

    ftrace: use cpu clock again
    
    Signed-off-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 3dc6eac85b11..d74c039305ad 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -42,61 +42,9 @@ ns2usecs(cycle_t nsec)
 	return nsec;
 }
 
-static const int time_sync_freq_max = 128;
-static const cycle_t time_sync_thresh = 100000;
-
-static DEFINE_PER_CPU(cycle_t, time_offset);
-static DEFINE_PER_CPU(cycle_t, prev_cpu_time);
-static DEFINE_PER_CPU(int, time_sync_count);
-static DEFINE_PER_CPU(int, time_sync_freq);
-
-/*
- * Global lock which we take every now and then to synchronize
- * the CPUs time. This method is not warp-safe, but it's good
- * enough to synchronize slowly diverging time sources and thus
- * it's good enough for tracing:
- */
-static DEFINE_SPINLOCK(time_sync_lock);
-static cycle_t prev_global_time;
-
-static notrace cycle_t __ftrace_now_sync(cycles_t time, int cpu)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&time_sync_lock, flags);
-
-	/*
-	 * Update the synchronization frequency:
-	 */
-	if (per_cpu(time_sync_freq, cpu) < time_sync_freq_max)
-		per_cpu(time_sync_freq, cpu) *= 2;
-	per_cpu(time_sync_count, cpu) = per_cpu(time_sync_freq, cpu);
-
-	if (time < prev_global_time) {
-		per_cpu(time_offset, cpu) += prev_global_time - time;
-		time = prev_global_time;
-	} else {
-		prev_global_time = time;
-	}
-
-	spin_unlock_irqrestore(&time_sync_lock, flags);
-
-	return time;
-}
-
 notrace cycle_t ftrace_now(int cpu)
 {
-	cycle_t prev_cpu_time, time, delta_time;
-
-	prev_cpu_time = per_cpu(prev_cpu_time, cpu);
-	time = sched_clock() + per_cpu(time_offset, cpu);
-	delta_time = time-prev_cpu_time;
-
-	if (unlikely(delta_time > time_sync_thresh ||
-				--per_cpu(time_sync_count, cpu) <= 0))
-		time = __ftrace_now_sync(time, cpu);
-
-	return time;
+	return cpu_clock(cpu);
 }
 
 static struct trace_array	global_trace;

commit dcb6308f2b56720599f6b9d5a01c33e67e69bde4
Author: Ingo Molnar <mingo@elte.hu>
Date:   Mon May 12 21:20:48 2008 +0200

    ftrace, locking fix
    
    should be an irq-safe lock ...
    
    Signed-off-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index fa13059eb462..70f94fa92c10 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -691,14 +691,15 @@ ftrace(struct trace_array *tr, struct trace_array_cpu *data,
        unsigned long ip, unsigned long parent_ip, unsigned long flags)
 {
 	struct trace_entry *entry;
+	unsigned long irq_flags;
 
-	spin_lock(&data->lock);
+	spin_lock_irqsave(&data->lock, irq_flags);
 	entry			= tracing_get_trace_entry(tr, data);
 	tracing_generic_entry_update(entry, flags);
 	entry->type		= TRACE_FN;
 	entry->fn.ip		= ip;
 	entry->fn.parent_ip	= parent_ip;
-	spin_unlock(&data->lock);
+	spin_unlock_irqrestore(&data->lock, irq_flags);
 }
 
 notrace void
@@ -706,15 +707,16 @@ trace_special(struct trace_array *tr, struct trace_array_cpu *data,
 	      unsigned long arg1, unsigned long arg2, unsigned long arg3)
 {
 	struct trace_entry *entry;
+	unsigned long irq_flags;
 
-	spin_lock(&data->lock);
+	spin_lock_irqsave(&data->lock, irq_flags);
 	entry			= tracing_get_trace_entry(tr, data);
 	tracing_generic_entry_update(entry, 0);
 	entry->type		= TRACE_SPECIAL;
 	entry->special.arg1	= arg1;
 	entry->special.arg2	= arg2;
 	entry->special.arg3	= arg3;
-	spin_unlock(&data->lock);
+	spin_unlock_irqrestore(&data->lock, irq_flags);
 }
 
 notrace void
@@ -724,8 +726,9 @@ tracing_sched_switch_trace(struct trace_array *tr,
 			   unsigned long flags)
 {
 	struct trace_entry *entry;
+	unsigned long irq_flags;
 
-	spin_lock(&data->lock);
+	spin_lock_irqsave(&data->lock, irq_flags);
 	entry			= tracing_get_trace_entry(tr, data);
 	tracing_generic_entry_update(entry, flags);
 	entry->type		= TRACE_CTX;
@@ -734,7 +737,7 @@ tracing_sched_switch_trace(struct trace_array *tr,
 	entry->ctx.prev_state	= prev->state;
 	entry->ctx.next_pid	= next->pid;
 	entry->ctx.next_prio	= next->prio;
-	spin_unlock(&data->lock);
+	spin_unlock_irqrestore(&data->lock, irq_flags);
 }
 
 enum trace_file_type {

commit f0a920d5752e1788c0cba2add103076bcc0f7a49
Author: Ingo Molnar <mingo@elte.hu>
Date:   Mon May 12 21:20:47 2008 +0200

    ftrace: add trace_special()
    
    for ad-hoc tracing.
    
    Signed-off-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index d78cbc4fc519..fa13059eb462 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -137,6 +137,7 @@ enum trace_type {
 
 	TRACE_FN,
 	TRACE_CTX,
+	TRACE_SPECIAL,
 
 	__TRACE_LAST_TYPE
 };
@@ -700,6 +701,22 @@ ftrace(struct trace_array *tr, struct trace_array_cpu *data,
 	spin_unlock(&data->lock);
 }
 
+notrace void
+trace_special(struct trace_array *tr, struct trace_array_cpu *data,
+	      unsigned long arg1, unsigned long arg2, unsigned long arg3)
+{
+	struct trace_entry *entry;
+
+	spin_lock(&data->lock);
+	entry			= tracing_get_trace_entry(tr, data);
+	tracing_generic_entry_update(entry, 0);
+	entry->type		= TRACE_SPECIAL;
+	entry->special.arg1	= arg1;
+	entry->special.arg2	= arg2;
+	entry->special.arg3	= arg3;
+	spin_unlock(&data->lock);
+}
+
 notrace void
 tracing_sched_switch_trace(struct trace_array *tr,
 			   struct trace_array_cpu *data,
@@ -1167,6 +1184,12 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
 				 entry->ctx.next_prio,
 				 comm);
 		break;
+	case TRACE_SPECIAL:
+		trace_seq_printf(s, " %lx %lx %lx\n",
+				 entry->special.arg1,
+				 entry->special.arg2,
+				 entry->special.arg3);
+		break;
 	default:
 		trace_seq_printf(s, "Unknown type %d\n", entry->type);
 	}
@@ -1234,6 +1257,14 @@ static notrace int print_trace_fmt(struct trace_iterator *iter)
 		if (!ret)
 			return 0;
 		break;
+	case TRACE_SPECIAL:
+		ret = trace_seq_printf(s, " %lx %lx %lx\n",
+				 entry->special.arg1,
+				 entry->special.arg2,
+				 entry->special.arg3);
+		if (!ret)
+			return 0;
+		break;
 	}
 	return 1;
 }
@@ -1271,6 +1302,14 @@ static notrace int print_raw_fmt(struct trace_iterator *iter)
 		if (!ret)
 			return 0;
 		break;
+	case TRACE_SPECIAL:
+		ret = trace_seq_printf(s, " %lx %lx %lx\n",
+				 entry->special.arg1,
+				 entry->special.arg2,
+				 entry->special.arg3);
+		if (!ret)
+			return 0;
+		break;
 	}
 	return 1;
 }
@@ -1304,6 +1343,11 @@ static notrace int print_bin_fmt(struct trace_iterator *iter)
 		SEQ_PUT_FIELD_RET(s, entry->ctx.next_pid);
 		SEQ_PUT_FIELD_RET(s, entry->ctx.next_prio);
 		break;
+	case TRACE_SPECIAL:
+		SEQ_PUT_FIELD_RET(s, entry->special.arg1);
+		SEQ_PUT_FIELD_RET(s, entry->special.arg2);
+		SEQ_PUT_FIELD_RET(s, entry->special.arg3);
+		break;
 	}
 	return 1;
 }
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 27fa2d06f499..7bdfef35c05a 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -25,6 +25,15 @@ struct ctx_switch_entry {
 	unsigned char		next_prio;
 };
 
+/*
+ * Special (free-form) trace entry:
+ */
+struct special_entry {
+	unsigned long		arg1;
+	unsigned long		arg2;
+	unsigned long		arg3;
+};
+
 /*
  * The trace entry - the most basic unit of tracing. This is what
  * is printed in the end as a single line in the trace output, such as:
@@ -41,6 +50,7 @@ struct trace_entry {
 	union {
 		struct ftrace_entry		fn;
 		struct ctx_switch_entry		ctx;
+		struct special_entry		special;
 	};
 };
 
@@ -154,6 +164,11 @@ void tracing_sched_switch_trace(struct trace_array *tr,
 				struct task_struct *next,
 				unsigned long flags);
 void tracing_record_cmdline(struct task_struct *tsk);
+void trace_special(struct trace_array *tr,
+		   struct trace_array_cpu *data,
+		   unsigned long arg1,
+		   unsigned long arg2,
+		   unsigned long arg3);
 
 void tracing_start_function_trace(void);
 void tracing_stop_function_trace(void);

commit cb0f12aae8d085140d37ada351aa5a8e76c3f9b0
Author: Ingo Molnar <mingo@elte.hu>
Date:   Mon May 12 21:20:47 2008 +0200

    ftrace: bin-output
    
    Signed-off-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index bebd263f582f..d78cbc4fc519 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -154,6 +154,7 @@ enum trace_iterator_flags {
 	TRACE_ITER_SYM_ADDR		= 0x04,
 	TRACE_ITER_VERBOSE		= 0x08,
 	TRACE_ITER_RAW			= 0x10,
+	TRACE_ITER_BIN			= 0x20,
 };
 
 #define TRACE_ITER_SYM_MASK \
@@ -166,6 +167,7 @@ static const char *trace_options[] = {
 	"sym-addr",
 	"verbose",
 	"raw",
+	"bin",
 	NULL
 };
 
@@ -275,6 +277,18 @@ trace_seq_putc(struct trace_seq *s, unsigned char c)
 	return 1;
 }
 
+static notrace int
+trace_seq_putmem(struct trace_seq *s, void *mem, size_t len)
+{
+	if (len > ((PAGE_SIZE - 1) - s->len))
+		return 0;
+
+	memcpy(s->buffer + s->len, mem, len);
+	s->len += len;
+
+	return len;
+}
+
 static notrace void
 trace_seq_reset(struct trace_seq *s)
 {
@@ -1261,6 +1275,39 @@ static notrace int print_raw_fmt(struct trace_iterator *iter)
 	return 1;
 }
 
+#define SEQ_PUT_FIELD_RET(s, x)				\
+do {							\
+	if (!trace_seq_putmem(s, &(x), sizeof(x)))	\
+		return 0;				\
+} while (0)
+
+static notrace int print_bin_fmt(struct trace_iterator *iter)
+{
+	struct trace_seq *s = &iter->seq;
+	struct trace_entry *entry;
+
+	entry = iter->ent;
+
+	SEQ_PUT_FIELD_RET(s, entry->pid);
+	SEQ_PUT_FIELD_RET(s, entry->cpu);
+	SEQ_PUT_FIELD_RET(s, entry->t);
+
+	switch (entry->type) {
+	case TRACE_FN:
+		SEQ_PUT_FIELD_RET(s, entry->fn.ip);
+		SEQ_PUT_FIELD_RET(s, entry->fn.parent_ip);
+		break;
+	case TRACE_CTX:
+		SEQ_PUT_FIELD_RET(s, entry->ctx.prev_pid);
+		SEQ_PUT_FIELD_RET(s, entry->ctx.prev_prio);
+		SEQ_PUT_FIELD_RET(s, entry->ctx.prev_state);
+		SEQ_PUT_FIELD_RET(s, entry->ctx.next_pid);
+		SEQ_PUT_FIELD_RET(s, entry->ctx.next_prio);
+		break;
+	}
+	return 1;
+}
+
 static int trace_empty(struct trace_iterator *iter)
 {
 	struct trace_array_cpu *data;
@@ -1279,6 +1326,9 @@ static int trace_empty(struct trace_iterator *iter)
 
 static int print_trace_line(struct trace_iterator *iter)
 {
+	if (trace_flags & TRACE_ITER_BIN)
+		return print_bin_fmt(iter);
+
 	if (trace_flags & TRACE_ITER_RAW)
 		return print_raw_fmt(iter);