rpms/kernel/devel linux-2.6-tracehook.patch, 1.7, 1.8 linux-2.6-utrace-ftrace.patch, NONE, 1.1 config-generic, 1.258, 1.259 kernel.spec, 1.1445, 1.1446 linux-2.6-utrace.patch, 1.107, 1.108

Roland McGrath roland at fedoraproject.org
Thu Mar 19 08:04:29 UTC 2009


Author: roland

Update of /cvs/pkgs/rpms/kernel/devel
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv13625

Modified Files:
	config-generic kernel.spec linux-2.6-utrace.patch 
Added Files:
	linux-2.6-tracehook.patch linux-2.6-utrace-ftrace.patch 
Log Message:
utrace update, add ftrace process-tracer widget, drop utrace-ptrace

linux-2.6-tracehook.patch:

Index: linux-2.6-tracehook.patch
===================================================================
RCS file: linux-2.6-tracehook.patch
diff -N linux-2.6-tracehook.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux-2.6-tracehook.patch	19 Mar 2009 08:03:53 -0000	1.8
@@ -0,0 +1,194 @@
+signals: tracehook_notify_jctl change
+
+This changes tracehook_notify_jctl() so it's called with the siglock held,
+and changes its argument and return value definition.  These clean-ups make
+it a better fit for what new tracing hooks need to check.
+
+Tracing needs the siglock here, held from the time TASK_STOPPED was set,
+to avoid potential SIGCONT races if it wants to allow any blocking in its
+tracing hooks.
+
+This also folds the finish_stop() function into its caller do_signal_stop().
+The function is short, called only once and only unconditionally.  It aids
+readability to fold it in.
+
+Signed-off-by: Roland McGrath <roland at redhat.com>
+---
+ include/linux/tracehook.h |   25 ++++++++++------
+ kernel/signal.c           |   69 +++++++++++++++++++++++----------------------
+ 2 files changed, 51 insertions(+), 43 deletions(-)
+
+diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h
+index 6186a78..b622498 100644  
+--- a/include/linux/tracehook.h
++++ b/include/linux/tracehook.h
+@@ -1,7 +1,7 @@
+ /*
+  * Tracing hooks
+  *
+- * Copyright (C) 2008 Red Hat, Inc.  All rights reserved.
++ * Copyright (C) 2008-2009 Red Hat, Inc.  All rights reserved.
+  *
+  * This copyrighted material is made available to anyone wishing to use,
+  * modify, copy, or redistribute it subject to the terms and conditions
+@@ -469,22 +469,29 @@ static inline int tracehook_get_signal(s
+ 
+ /**
+  * tracehook_notify_jctl - report about job control stop/continue
+- * @notify:		nonzero if this is the last thread in the group to stop
++ * @notify:		zero, %CLD_STOPPED or %CLD_CONTINUED
+  * @why:		%CLD_STOPPED or %CLD_CONTINUED
+  *
+  * This is called when we might call do_notify_parent_cldstop().
+- * It's called when about to stop for job control; we are already in
+- * %TASK_STOPPED state, about to call schedule().  It's also called when
+- * a delayed %CLD_STOPPED or %CLD_CONTINUED report is ready to be made.
+  *
+- * Return nonzero to generate a %SIGCHLD with @why, which is
+- * normal if @notify is nonzero.
++ * @notify is zero if we would not ordinarily send a %SIGCHLD,
++ * or is the %CLD_STOPPED or %CLD_CONTINUED .si_code for %SIGCHLD.
+  *
+- * Called with no locks held.
++ * @why is %CLD_STOPPED when about to stop for job control;
++ * we are already in %TASK_STOPPED state, about to call schedule().
++ * It might also be that we have just exited (check %PF_EXITING),
++ * but need to report that a group-wide stop is complete.
++ *
++ * @why is %CLD_CONTINUED when waking up after job control stop and
++ * ready to make a delayed @notify report.
++ *
++ * Return the %CLD_* value for %SIGCHLD, or zero to generate no signal.
++ *
++ * Called with the siglock held.
+  */
+ static inline int tracehook_notify_jctl(int notify, int why)
+ {
+-	return notify || (current->ptrace & PT_PTRACED);
++	return notify ?: (current->ptrace & PT_PTRACED) ? why : 0;
+ }
+ 
+ #define DEATH_REAP			-1
+diff --git a/kernel/signal.c b/kernel/signal.c
+index 2a74fe8..9a0d98f 100644  
+--- a/kernel/signal.c
++++ b/kernel/signal.c
+@@ -691,7 +691,7 @@ static int prepare_signal(int sig, struc
+ 
+ 		if (why) {
+ 			/*
+-			 * The first thread which returns from finish_stop()
++			 * The first thread which returns from do_signal_stop()
+ 			 * will take ->siglock, notice SIGNAL_CLD_MASK, and
+ 			 * notify its parent. See get_signal_to_deliver().
+ 			 */
+@@ -1629,29 +1629,6 @@ void ptrace_notify(int exit_code)
+ 	spin_unlock_irq(&current->sighand->siglock);
+ }
+ 
+-static void
+-finish_stop(int stop_count)
+-{
+-	/*
+-	 * If there are no other threads in the group, or if there is
+-	 * a group stop in progress and we are the last to stop,
+-	 * report to the parent.  When ptraced, every thread reports itself.
+-	 */
+-	if (tracehook_notify_jctl(stop_count == 0, CLD_STOPPED)) {
+-		read_lock(&tasklist_lock);
+-		do_notify_parent_cldstop(current, CLD_STOPPED);
+-		read_unlock(&tasklist_lock);
+-	}
+-
+-	do {
+-		schedule();
+-	} while (try_to_freeze());
+-	/*
+-	 * Now we don't run again until continued.
+-	 */
+-	current->exit_code = 0;
+-}
+-
+ /*
+  * This performs the stopping for SIGSTOP and other stop signals.
+  * We have to stop all threads in the thread group.
+@@ -1662,6 +1639,7 @@ static int do_signal_stop(int signr)
+ {
+ 	struct signal_struct *sig = current->signal;
+ 	int stop_count;
++	int notify;
+ 
+ 	if (sig->group_stop_count > 0) {
+ 		/*
+@@ -1701,8 +1679,30 @@ static int do_signal_stop(int signr)
+ 	current->exit_code = sig->group_exit_code;
+ 	__set_current_state(TASK_STOPPED);
+ 
++	/*
++	 * If there are no other threads in the group, or if there is
++	 * a group stop in progress and we are the last to stop,
++	 * report to the parent.  When ptraced, every thread reports itself.
++	 */
++	notify = tracehook_notify_jctl(stop_count == 0 ? CLD_STOPPED : 0,
++				       CLD_STOPPED);
++
+ 	spin_unlock_irq(&current->sighand->siglock);
+-	finish_stop(stop_count);
++
++	if (notify) {
++		read_lock(&tasklist_lock);
++		do_notify_parent_cldstop(current, notify);
++		read_unlock(&tasklist_lock);
++	}
++
++	do {
++		schedule();
++	} while (try_to_freeze());
++	/*
++	 * Now we don't run again until continued.
++	 */
++	current->exit_code = 0;
++
+ 	return 1;
+ }
+ 
+@@ -1771,14 +1771,15 @@ relock:
+ 		int why = (signal->flags & SIGNAL_STOP_CONTINUED)
+ 				? CLD_CONTINUED : CLD_STOPPED;
+ 		signal->flags &= ~SIGNAL_CLD_MASK;
+-		spin_unlock_irq(&sighand->siglock);
+ 
+-		if (unlikely(!tracehook_notify_jctl(1, why)))
+-			goto relock;
++		why = tracehook_notify_jctl(why, CLD_CONTINUED);
++		spin_unlock_irq(&sighand->siglock);
+ 
+-		read_lock(&tasklist_lock);
+-		do_notify_parent_cldstop(current->group_leader, why);
+-		read_unlock(&tasklist_lock);
++		if (why) {
++			read_lock(&tasklist_lock);
++			do_notify_parent_cldstop(current->group_leader, why);
++			read_unlock(&tasklist_lock);
++		}
+ 		goto relock;
+ 	}
+ 
+@@ -1936,14 +1937,14 @@ void exit_signals(struct task_struct *ts
+ 	if (unlikely(tsk->signal->group_stop_count) &&
+ 			!--tsk->signal->group_stop_count) {
+ 		tsk->signal->flags = SIGNAL_STOP_STOPPED;
+-		group_stop = 1;
++		group_stop = tracehook_notify_jctl(CLD_STOPPED, CLD_STOPPED);
+ 	}
+ out:
+ 	spin_unlock_irq(&tsk->sighand->siglock);
+ 
+-	if (unlikely(group_stop) && tracehook_notify_jctl(1, CLD_STOPPED)) {
++	if (unlikely(group_stop)) {
+ 		read_lock(&tasklist_lock);
+-		do_notify_parent_cldstop(tsk, CLD_STOPPED);
++		do_notify_parent_cldstop(tsk, group_stop);
+ 		read_unlock(&tasklist_lock);
+ 	}
+ }

linux-2.6-utrace-ftrace.patch:

--- NEW FILE linux-2.6-utrace-ftrace.patch ---
utrace-based ftrace "process" engine, v2

This is v2 of the prototype utrace-ftrace interface.  This code is
based on Roland McGrath's utrace API, which provides programmatic
hooks to the in-tree tracehook layer.  This new patch interfaces many
of those events to ftrace, as configured by a small number of debugfs
controls.  Here's the /debugfs/tracing/process_trace_README:

process event tracer mini-HOWTO

1. Select process hierarchy to monitor.  Other processes will be
completely unaffected.  Leave at 0 for system-wide tracing.
%  echo NNN > process_follow_pid

2. Determine which process event traces are potentially desired.
syscall and signal tracing slow down monitored processes.
%  echo 0 > process_trace_{syscalls,signals,lifecycle}

3. Add any final uid- or taskcomm-based filtering.  Non-matching
processes will skip trace messages, but will still be slowed.
%  echo NNN > process_trace_uid_filter # -1: unrestricted
%  echo ls > process_trace_taskcomm_filter # empty: unrestricted

4. Start tracing.
%  echo process > current_tracer

5. Examine trace.
%  cat trace

6. Stop tracing.
%  echo nop > current_tracer

Signed-off-by: Frank Ch. Eigler <fche at redhat.com>
---
 include/linux/processtrace.h |   41 +++
 kernel/trace/Kconfig         |    9 +
 kernel/trace/Makefile        |    1 +
 kernel/trace/trace.h         |   30 ++-
 kernel/trace/trace_process.c |  601 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 671 insertions(+), 11 deletions(-)

diff --git a/include/linux/processtrace.h b/include/linux/processtrace.h
new file mode 100644
index ...f2b7d94 100644  
--- /dev/null
+++ b/include/linux/processtrace.h
@@ -0,0 +1,41 @@
+#ifndef PROCESSTRACE_H
+#define PROCESSTRACE_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+struct process_trace_entry {
+	unsigned char opcode;	/* one of _UTRACE_EVENT_* */
+	char comm[TASK_COMM_LEN]; /* XXX: should be in/via trace_entry */
+	union {
+		struct {
+			pid_t child;
+			unsigned long flags;
+		} trace_clone;
+		struct {
+			long code;
+		} trace_exit;
+		struct {
+		} trace_exec;
+		struct {
+			int si_signo;
+			int si_errno;
+			int si_code;
+		} trace_signal;
+		struct {
+			long callno;
+			unsigned long args[6];
+		} trace_syscall_entry;
+		struct {
+			long rc;
+			long error;
+		} trace_syscall_exit;
+	};
+};
+
+/* in kernel/trace/trace_process.c */
+
+extern void enable_process_trace(void);
+extern void disable_process_trace(void);
+
+#endif /* PROCESSTRACE_H */
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index 34e707e..8a92d6f 100644  
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -150,6 +150,15 @@ config CONTEXT_SWITCH_TRACER
 	  This tracer gets called from the context switch and records
 	  all switching of tasks.
 
+config PROCESS_TRACER
+	bool "Trace process events via utrace"
+	depends on DEBUG_KERNEL
+	select TRACING
+	select UTRACE
+	help
+	  This tracer provides trace records from process events
+	  accessible to utrace: lifecycle, system calls, and signals.
+
 config BOOT_TRACER
 	bool "Trace boot initcalls"
 	depends on DEBUG_KERNEL
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index 349d5a9..a774db2 100644  
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -33,5 +33,6 @@ obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += t
 obj-$(CONFIG_TRACE_BRANCH_PROFILING) += trace_branch.o
 obj-$(CONFIG_HW_BRANCH_TRACER) += trace_hw_branches.o
 obj-$(CONFIG_POWER_TRACER) += trace_power.o
+obj-$(CONFIG_PROCESS_TRACER) += trace_process.o
 
 libftrace-y := ftrace.o
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 4d3d381..b4ebccb 100644  
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -7,6 +7,7 @@
 #include <linux/clocksource.h>
 #include <linux/ring_buffer.h>
 #include <linux/mmiotrace.h>
+#include <linux/processtrace.h>
 #include <linux/ftrace.h>
 #include <trace/boot.h>
 
@@ -30,6 +31,7 @@ enum trace_type {
 	TRACE_USER_STACK,
 	TRACE_HW_BRANCHES,
 	TRACE_POWER,
+	TRACE_PROCESS,
 
 	__TRACE_LAST_TYPE
 };
@@ -38,7 +40,7 @@ enum trace_type {
  * 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:
  *
- *     bash-15816 [01]   235.197585: idle_cpu <- irq_enter
+ *     bash-15816 [01]	 235.197585: idle_cpu <- irq_enter
  */
 struct trace_entry {
 	unsigned char		type;
@@ -153,7 +155,7 @@ struct trace_boot_ret {
 #define TRACE_FILE_SIZE 20
 struct trace_branch {
 	struct trace_entry	ent;
-	unsigned	        line;
+	unsigned		line;
 	char			func[TRACE_FUNC_SIZE+1];
 	char			file[TRACE_FILE_SIZE+1];
 	char			correct;
@@ -170,11 +172,16 @@ struct trace_power {
 	struct power_trace	state_data;
 };
 
+struct trace_process {
+	struct trace_entry		ent;
+	struct process_trace_entry	event;
+};
+
 /*
  * trace_flag_type is an enumeration that holds different
  * states when a trace occurs. These are:
  *  IRQS_OFF		- interrupts were disabled
- *  IRQS_NOSUPPORT 	- arch does not support irqs_disabled_flags
+ *  IRQS_NOSUPPORT	- arch does not support irqs_disabled_flags
  *  NEED_RESCED		- reschedule is requested
  *  HARDIRQ		- inside an interrupt handler
  *  SOFTIRQ		- inside a softirq handler
@@ -279,7 +286,8 @@ extern void __ftrace_bad_type(void);
 		IF_ASSIGN(var, ent, struct ftrace_graph_ret_entry,	\
 			  TRACE_GRAPH_RET);		\
 		IF_ASSIGN(var, ent, struct hw_branch_entry, TRACE_HW_BRANCHES);\
- 		IF_ASSIGN(var, ent, struct trace_power, TRACE_POWER); \
+		IF_ASSIGN(var, ent, struct trace_power, TRACE_POWER); \
+		IF_ASSIGN(var, ent, struct trace_process, TRACE_PROCESS); \
 		__ftrace_bad_type();					\
 	} while (0)
 
@@ -297,8 +305,8 @@ enum print_line_t {
  * flags value in struct tracer_flags.
  */
 struct tracer_opt {
-	const char 	*name; /* Will appear on the trace_options file */
-	u32 		bit; /* Mask assigned in val field in tracer_flags */
+	const char	*name; /* Will appear on the trace_options file */
+	u32		bit; /* Mask assigned in val field in tracer_flags */
 };
 
 /*
@@ -307,7 +315,7 @@ struct tracer_opt {
  */
 struct tracer_flags {
 	u32			val;
-	struct tracer_opt 	*opts;
+	struct tracer_opt	*opts;
 };
 
 /* Makes more easy to define a tracer opt */
@@ -339,7 +347,7 @@ struct tracer {
 	int			(*set_flag)(u32 old_flags, u32 bit, int set);
 	struct tracer		*next;
 	int			print_max;
-	struct tracer_flags 	*flags;
+	struct tracer_flags	*flags;
 };
 
 struct trace_seq {
@@ -561,7 +569,7 @@ static inline int ftrace_trace_task(stru
  * positions into trace_flags that controls the output.
  *
  * NOTE: These bits must match the trace_options array in
- *       trace.c.
+ *	 trace.c.
  */
 enum trace_iterator_flags {
 	TRACE_ITER_PRINT_PARENT		= 0x01,
@@ -578,8 +586,8 @@ enum trace_iterator_flags {
 	TRACE_ITER_PREEMPTONLY		= 0x800,
 	TRACE_ITER_BRANCH		= 0x1000,
 	TRACE_ITER_ANNOTATE		= 0x2000,
-	TRACE_ITER_USERSTACKTRACE       = 0x4000,
-	TRACE_ITER_SYM_USEROBJ          = 0x8000,
+	TRACE_ITER_USERSTACKTRACE	= 0x4000,
+	TRACE_ITER_SYM_USEROBJ		= 0x8000,
 	TRACE_ITER_PRINTK_MSGONLY	= 0x10000
 };
 
diff --git a/kernel/trace/trace_process.c b/kernel/trace/trace_process.c
new file mode 100644
index ...0820e56 100644  
--- /dev/null
+++ b/kernel/trace/trace_process.c
@@ -0,0 +1,601 @@
+/*
+ * utrace-based process event tracing
+ * Copyright (C) 2009 Red Hat Inc.
+ * By Frank Ch. Eigler <fche at redhat.com>
+ *
+ * Based on mmio ftrace engine by Pekka Paalanen
+ * and utrace-syscall-tracing prototype by Ananth Mavinakayanahalli
+ */
+
+/* #define DEBUG 1 */
+
+#include <linux/kernel.h>
+#include <linux/utrace.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+#include <asm/syscall.h>
+
+#include "trace.h"
+
+/* A process must match these filters in order to be traced. */
+static char trace_taskcomm_filter[TASK_COMM_LEN]; /* \0: unrestricted */
+static u32 trace_taskuid_filter = -1; /* -1: unrestricted */
+static u32 trace_lifecycle_p = 1;
+static u32 trace_syscalls_p = 1;
+static u32 trace_signals_p = 1;
+
+/* A process must be a direct child of given pid in order to be
+   followed. */
+static u32 process_follow_pid; /* 0: unrestricted/systemwide */
+
+/* XXX: lock the above? */
+
+
+/* trace data collection */
+
+static struct trace_array *process_trace_array;
+
+static void process_reset_data(struct trace_array *tr)
+{
+	pr_debug("in %s\n", __func__);
+	tracing_reset_online_cpus(tr);
+}
+
+static int process_trace_init(struct trace_array *tr)
+{
+	pr_debug("in %s\n", __func__);
+	process_trace_array = tr;
+	process_reset_data(tr);
+	enable_process_trace();
+	return 0;
+}
+
+static void process_trace_reset(struct trace_array *tr)
+{
+	pr_debug("in %s\n", __func__);
+	disable_process_trace();
+	process_reset_data(tr);
+	process_trace_array = NULL;
+}
+
+static void process_trace_start(struct trace_array *tr)
+{
+	pr_debug("in %s\n", __func__);
+	process_reset_data(tr);
+}
+
+static void __trace_processtrace(struct trace_array *tr,
+				struct trace_array_cpu *data,
+				struct process_trace_entry *ent)
+{
+	struct ring_buffer_event *event;
+	struct trace_process *entry;
+	unsigned long irq_flags;
+
+	event	= ring_buffer_lock_reserve(tr->buffer, sizeof(*entry),
+					   &irq_flags);
+	if (!event)
+		return;
+	entry	= ring_buffer_event_data(event);
+	tracing_generic_entry_update(&entry->ent, 0, preempt_count());
+	entry->ent.cpu			= raw_smp_processor_id();
+	entry->ent.type			= TRACE_PROCESS;
+	strlcpy(ent->comm, current->comm, TASK_COMM_LEN);
+	entry->event			= *ent;
+	ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
+
+	trace_wake_up();
+}
+
+void process_trace(struct process_trace_entry *ent)
+{
+	struct trace_array *tr = process_trace_array;
+	struct trace_array_cpu *data;
+
+	preempt_disable();
+	data = tr->data[smp_processor_id()];
+	__trace_processtrace(tr, data, ent);
+	preempt_enable();
+}
+
+
+/* trace data rendering */
+
+static void process_pipe_open(struct trace_iterator *iter)
+{
+	struct trace_seq *s = &iter->seq;
+	pr_debug("in %s\n", __func__);
+	trace_seq_printf(s, "VERSION 200901\n");
+}
+
+static void process_close(struct trace_iterator *iter)
+{
+	iter->private = NULL;
+}
+
+static ssize_t process_read(struct trace_iterator *iter, struct file *filp,
+				char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	ssize_t ret;
+	struct trace_seq *s = &iter->seq;
+	ret = trace_seq_to_user(s, ubuf, cnt);
+	return (ret == -EBUSY) ? 0 : ret;
+}
+
+static enum print_line_t process_print(struct trace_iterator *iter)
+{
+	struct trace_entry *entry = iter->ent;
+	struct trace_process *field;
+	struct trace_seq *s	= &iter->seq;
+	unsigned long long t	= ns2usecs(iter->ts);
+	unsigned long usec_rem	= do_div(t, 1000000ULL);
+	unsigned secs		= (unsigned long)t;
+	int ret = 1;
+
+	trace_assign_type(field, entry);
+
+	/* XXX: If print_lat_fmt() were not static, we wouldn't have
+	   to duplicate this. */
+	trace_seq_printf(s, "%16s %5d %3d %9lu.%06ld ",
+			 field->event.comm,
+			 entry->pid, entry->cpu,
+			 secs,
+			 usec_rem);
+
+	switch (field->event.opcode) {
+	case _UTRACE_EVENT_CLONE:
+		ret = trace_seq_printf(s, "fork %d flags 0x%lx\n",
+				       field->event.trace_clone.child,
+				       field->event.trace_clone.flags);
+		break;
+	case _UTRACE_EVENT_EXEC:
+		ret = trace_seq_printf(s, "exec\n");
+		break;
+	case _UTRACE_EVENT_EXIT:
+		ret = trace_seq_printf(s, "exit %ld\n",
+				       field->event.trace_exit.code);
+		break;
+	case _UTRACE_EVENT_SIGNAL:
+		ret = trace_seq_printf(s, "signal %d errno %d code 0x%x\n",
+				       field->event.trace_signal.si_signo,
+				       field->event.trace_signal.si_errno,
+				       field->event.trace_signal.si_code);
+		break;
+	case _UTRACE_EVENT_SYSCALL_ENTRY:
+		ret = trace_seq_printf(s, "syscall %ld [0x%lx 0x%lx 0x%lx"
+					  " 0x%lx 0x%lx 0x%lx]\n",
+				      field->event.trace_syscall_entry.callno,
+				      field->event.trace_syscall_entry.args[0],
+				      field->event.trace_syscall_entry.args[1],
+				      field->event.trace_syscall_entry.args[2],
+				      field->event.trace_syscall_entry.args[3],
+				      field->event.trace_syscall_entry.args[4],
+				      field->event.trace_syscall_entry.args[5]);
+		break;
+	case _UTRACE_EVENT_SYSCALL_EXIT:
+		ret = trace_seq_printf(s, "syscall rc %ld error %ld\n",
+				       field->event.trace_syscall_exit.rc,
+				       field->event.trace_syscall_exit.error);
+		break;
+	default:
+		ret = trace_seq_printf(s, "process code %d?\n",
+				       field->event.opcode);
+		break;
+	}
+	if (ret)
+		return TRACE_TYPE_HANDLED;
+	return TRACE_TYPE_HANDLED;
+}
+
+
+static enum print_line_t process_print_line(struct trace_iterator *iter)
+{
+	switch (iter->ent->type) {
+	case TRACE_PROCESS:
+		return process_print(iter);
+	default:
+		return TRACE_TYPE_HANDLED; /* ignore unknown entries */
+	}
+}
+
+static struct tracer process_tracer = {
+	.name		= "process",
+	.init		= process_trace_init,
+	.reset		= process_trace_reset,
+	.start		= process_trace_start,
+	.pipe_open	= process_pipe_open,
+	.close		= process_close,
+	.read		= process_read,
+	.print_line	= process_print_line,
+};
+
+
+
+/* utrace backend */
+
+/* Should tracing apply to given task?	Compare against filter
+   values. */
+static int trace_test(struct task_struct *tsk)
+{
+	if (trace_taskcomm_filter[0]
+	    && strncmp(trace_taskcomm_filter, tsk->comm, TASK_COMM_LEN))
+		return 0;
+
+	if (trace_taskuid_filter != (u32)-1
+	    && trace_taskuid_filter != task_uid(tsk))
+		return 0;
+
+	return 1;
+}
+
+
+static const struct utrace_engine_ops process_trace_ops;
+
+static void process_trace_tryattach(struct task_struct *tsk)
+{
+	struct utrace_engine *engine;
+
+	pr_debug("in %s\n", __func__);
+	engine = utrace_attach_task(tsk,
+				    UTRACE_ATTACH_CREATE |
+				    UTRACE_ATTACH_EXCLUSIVE,
+				    &process_trace_ops, NULL);
+	if (IS_ERR(engine) || (engine == NULL)) {
+		pr_warning("utrace_attach_task %d (rc %p)\n",
+			   tsk->pid, engine);
+	} else {
+		int rc;
+
+		/* We always hook cost-free events. */
+		unsigned long events =
+			UTRACE_EVENT(CLONE) |
+			UTRACE_EVENT(EXEC) |
+			UTRACE_EVENT(EXIT);
+
+		/* Penalizing events are individually controlled, so that
+		   utrace doesn't even take the monitored threads off their
+		   fast paths, nor bother call our callbacks. */
+		if (trace_syscalls_p)
+			events |= UTRACE_EVENT_SYSCALL;
+		if (trace_signals_p)
+			events |= UTRACE_EVENT_SIGNAL_ALL;
+
+		rc = utrace_set_events(tsk, engine, events);
+		if (rc == -EINPROGRESS)
+			rc = utrace_barrier(tsk, engine);
+		if (rc)
+			pr_warning("utrace_set_events/barrier rc %d\n", rc);
+
+		utrace_engine_put(engine);
+		pr_debug("attached in %s to %s(%d)\n", __func__,
+			 tsk->comm, tsk->pid);
+	}
+}
+
+
+u32 process_trace_report_clone(enum utrace_resume_action action,
+			       struct utrace_engine *engine,
+			       struct task_struct *parent,
+			       unsigned long clone_flags,
+			       struct task_struct *child)
+{
+	if (trace_lifecycle_p && trace_test(parent)) {
+		struct process_trace_entry ent;
+		ent.opcode = _UTRACE_EVENT_CLONE;
+		ent.trace_clone.child = child->pid;
+		ent.trace_clone.flags = clone_flags;
+		process_trace(&ent);
+	}
+
+	process_trace_tryattach(child);
+
+	return UTRACE_RESUME;
+}
+
+
+u32 process_trace_report_syscall_entry(u32 action,
+				       struct utrace_engine *engine,
+				       struct task_struct *task,
+				       struct pt_regs *regs)
+{
+	if (trace_syscalls_p && trace_test(task)) {
+		struct process_trace_entry ent;
+		ent.opcode = _UTRACE_EVENT_SYSCALL_ENTRY;
+		ent.trace_syscall_entry.callno = syscall_get_nr(task, regs);
+		syscall_get_arguments(task, regs, 0, 6,
+				      ent.trace_syscall_entry.args);
+		process_trace(&ent);
+	}
+
+	return UTRACE_RESUME;
+}
+
+
+u32 process_trace_report_syscall_exit(enum utrace_resume_action action,
+				   struct utrace_engine *engine,
+				   struct task_struct *task,
+				   struct pt_regs *regs)
+{
+	if (trace_syscalls_p && trace_test(task)) {
+		struct process_trace_entry ent;
+		ent.opcode = _UTRACE_EVENT_SYSCALL_EXIT;
+		ent.trace_syscall_exit.rc =
+			syscall_get_return_value(task, regs);
+		ent.trace_syscall_exit.error = syscall_get_error(task, regs);
+		process_trace(&ent);
+	}
+
+	return UTRACE_RESUME;
+}
+
+
+u32 process_trace_report_exec(enum utrace_resume_action action,
+			      struct utrace_engine *engine,
+			      struct task_struct *task,
+			      const struct linux_binfmt *fmt,
+			      const struct linux_binprm *bprm,
+			      struct pt_regs *regs)
+{
+	if (trace_lifecycle_p && trace_test(task)) {
+		struct process_trace_entry ent;
+		ent.opcode = _UTRACE_EVENT_EXEC;
+		process_trace(&ent);
+	}
+
+	/* We're already attached; no need for a new tryattach. */
+
+	return UTRACE_RESUME;
+}
+
+
+u32 process_trace_report_signal(u32 action,
+				struct utrace_engine *engine,
+				struct task_struct *task,
+				struct pt_regs *regs,
+				siginfo_t *info,
+				const struct k_sigaction *orig_ka,
+				struct k_sigaction *return_ka)
+{
+	if (trace_signals_p && trace_test(task)) {
+		struct process_trace_entry ent;
+		ent.opcode = _UTRACE_EVENT_SIGNAL;
+		ent.trace_signal.si_signo = info->si_signo;
+		ent.trace_signal.si_errno = info->si_errno;
+		ent.trace_signal.si_code = info->si_code;
+		process_trace(&ent);
+	}
+
+	/* We're already attached, so no need for a new tryattach. */
+
+	return UTRACE_RESUME | utrace_signal_action(action);
+}
+
+
+u32 process_trace_report_exit(enum utrace_resume_action action,
+			      struct utrace_engine *engine,
+			      struct task_struct *task,
+			      long orig_code, long *code)
+{
+	if (trace_lifecycle_p && trace_test(task)) {
+		struct process_trace_entry ent;
+		ent.opcode = _UTRACE_EVENT_EXIT;
+		ent.trace_exit.code = orig_code;
+		process_trace(&ent);
+	}
+
+	/* There is no need to explicitly attach or detach here. */
+
+	return UTRACE_RESUME;
+}
+
+
+void enable_process_trace()
+{
+	struct task_struct *grp, *tsk;
+
+	pr_debug("in %s\n", __func__);
+	rcu_read_lock();
+	do_each_thread(grp, tsk) {
+		/* Skip over kernel threads. */
+		if (tsk->flags & PF_KTHREAD)
+			continue;
+
+		if (process_follow_pid) {
+			if (tsk->tgid == process_follow_pid ||
+			    tsk->parent->tgid == process_follow_pid)
+				process_trace_tryattach(tsk);
+		} else {
+			process_trace_tryattach(tsk);
+		}
+	} while_each_thread(grp, tsk);
+	rcu_read_unlock();
+}
+
+void disable_process_trace()
+{
+	struct utrace_engine *engine;
+	struct task_struct *grp, *tsk;
+	int rc;
+
+	pr_debug("in %s\n", __func__);
+	rcu_read_lock();
+	do_each_thread(grp, tsk) {
+		/* Find matching engine, if any.  Returns -ENOENT for
+		   unattached threads. */
+		engine = utrace_attach_task(tsk, UTRACE_ATTACH_MATCH_OPS,
+					    &process_trace_ops, 0);
+		if (IS_ERR(engine)) {
+			if (PTR_ERR(engine) != -ENOENT)
+				pr_warning("utrace_attach_task %d (rc %ld)\n",
+					   tsk->pid, -PTR_ERR(engine));
+		} else if (engine == NULL) {
+			pr_warning("utrace_attach_task %d (null engine)\n",
+				   tsk->pid);
+		} else {
+			/* Found one of our own engines.  Detach.  */
+			rc = utrace_control(tsk, engine, UTRACE_DETACH);
+			switch (rc) {
+			case 0:		    /* success */
+				break;
+			case -ESRCH:	    /* REAP callback already begun */
+			case -EALREADY:	    /* DEATH callback already begun */
+				break;
+			default:
+				rc = -rc;
+				pr_warning("utrace_detach %d (rc %d)\n",
+					   tsk->pid, rc);
+				break;
+			}
+			utrace_engine_put(engine);
+			pr_debug("detached in %s from %s(%d)\n", __func__,
+				 tsk->comm, tsk->pid);
+		}
+	} while_each_thread(grp, tsk);
+	rcu_read_unlock();
+}
+
+
+static const struct utrace_engine_ops process_trace_ops = {
+	.report_clone = process_trace_report_clone,
+	.report_exec = process_trace_report_exec,
+	.report_exit = process_trace_report_exit,
+	.report_signal = process_trace_report_signal,
+	.report_syscall_entry = process_trace_report_syscall_entry,
+	.report_syscall_exit = process_trace_report_syscall_exit,
+};
+
+
+
+/* control interfaces */
+
+
+static ssize_t
+trace_taskcomm_filter_read(struct file *filp, char __user *ubuf,
+			   size_t cnt, loff_t *ppos)
+{
+	return simple_read_from_buffer(ubuf, cnt, ppos,
+				       trace_taskcomm_filter, TASK_COMM_LEN);
+}
+
+
+static ssize_t
+trace_taskcomm_filter_write(struct file *filp, const char __user *ubuf,
+			    size_t cnt, loff_t *fpos)
+{
+	char *end;
+
+	if (cnt > TASK_COMM_LEN)
+		cnt = TASK_COMM_LEN;
+
+	if (copy_from_user(trace_taskcomm_filter, ubuf, cnt))
+		return -EFAULT;
+
+	/* Cut from the first nil or newline. */
+	trace_taskcomm_filter[cnt] = '\0';
+	end = strchr(trace_taskcomm_filter, '\n');
+	if (end)
+		*end = '\0';
+
+	*fpos += cnt;
+	return cnt;
+}
+
+
+static const struct file_operations trace_taskcomm_filter_fops = {
+	.open		= tracing_open_generic,
+	.read		= trace_taskcomm_filter_read,
+	.write		= trace_taskcomm_filter_write,
+};
+
+
+
+static char README_text[] =
+	"process event tracer mini-HOWTO\n"
+	"\n"
+	"1. Select process hierarchy to monitor.  Other processes will be\n"
+	"   completely unaffected.  Leave at 0 for system-wide tracing.\n"
+	"#  echo NNN > process_follow_pid\n"
+	"\n"
+	"2. Determine which process event traces are potentially desired.\n"
+	"   syscall and signal tracing slow down monitored processes.\n"
+	"#  echo 0 > process_trace_{syscalls,signals,lifecycle}\n"
+	"\n"
+	"3. Add any final uid- or taskcomm-based filtering.  Non-matching\n"
+	"   processes will skip trace messages, but will still be slowed.\n"
+	"#  echo NNN > process_trace_uid_filter # -1: unrestricted \n"
+	"#  echo ls > process_trace_taskcomm_filter # empty: unrestricted\n"
+	"\n"
+	"4. Start tracing.\n"
+	"#  echo process > current_tracer\n"
+	"\n"
+	"5. Examine trace.\n"
+	"#  cat trace\n"
+	"\n"
+	"6. Stop tracing.\n"
+	"#  echo nop > current_tracer\n"
+	;
+
+static struct debugfs_blob_wrapper README_blob = {
+	.data = README_text,
+	.size = sizeof(README_text),
+};
+
+
+static __init int init_process_trace(void)
+{
+	struct dentry *d_tracer;
+	struct dentry *entry;
+
+	d_tracer = tracing_init_dentry();
+
+	entry = debugfs_create_blob("process_trace_README", 0444, d_tracer,
+				    &README_blob);
+	if (!entry)
+		pr_warning("Could not create debugfs "
+			   "'process_trace_README' entry\n");
+
+	/* Control for scoping process following. */
+	entry = debugfs_create_u32("process_follow_pid", 0644, d_tracer,
+				   &process_follow_pid);
+	if (!entry)
+		pr_warning("Could not create debugfs "
+			   "'process_follow_pid' entry\n");
+
+	/* Process-level filters */
+	entry = debugfs_create_file("process_trace_taskcomm_filter", 0644,
+				    d_tracer, NULL,
+				    &trace_taskcomm_filter_fops);
+	/* XXX: it'd be nice to have a read/write debugfs_create_blob. */
+	if (!entry)
+		pr_warning("Could not create debugfs "
+			   "'process_trace_taskcomm_filter' entry\n");
+
+	entry = debugfs_create_u32("process_trace_uid_filter", 0644, d_tracer,
+				   &trace_taskuid_filter);
+	if (!entry)
+		pr_warning("Could not create debugfs "
+			   "'process_trace_uid_filter' entry\n");
+
+	/* Event-level filters. */
+	entry = debugfs_create_u32("process_trace_lifecycle", 0644, d_tracer,
+				   &trace_lifecycle_p);
+	if (!entry)
+		pr_warning("Could not create debugfs "
+			   "'process_trace_lifecycle' entry\n");
+
+	entry = debugfs_create_u32("process_trace_syscalls", 0644, d_tracer,
+				   &trace_syscalls_p);
+	if (!entry)
+		pr_warning("Could not create debugfs "
+			   "'process_trace_syscalls' entry\n");
+
+	entry = debugfs_create_u32("process_trace_signals", 0644, d_tracer,
+				   &trace_signals_p);
+	if (!entry)
+		pr_warning("Could not create debugfs "
+			   "'process_trace_signals' entry\n");
+
+	return register_tracer(&process_tracer);
+}
+
+device_initcall(init_process_trace);


Index: config-generic
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/devel/config-generic,v
retrieving revision 1.258
retrieving revision 1.259
diff -u -r1.258 -r1.259
--- config-generic	19 Mar 2009 05:20:03 -0000	1.258
+++ config-generic	19 Mar 2009 08:03:52 -0000	1.259
@@ -3628,11 +3628,11 @@
 CONFIG_UNUSED_SYMBOLS=y
 
 CONFIG_UTRACE=y
-CONFIG_UTRACE_PTRACE=y
 
 CONFIG_FTRACE=y
 CONFIG_IRQSOFF_TRACER=y
 CONFIG_SCHED_TRACER=y
+CONFIG_PROCESS_TRACER=y
 CONFIG_CONTEXT_SWITCH_TRACER=y
 CONFIG_DYNAMIC_FTRACE=y
 CONFIG_FTRACE_MCOUNT_RECORD=y


Index: kernel.spec
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/devel/kernel.spec,v
retrieving revision 1.1445
retrieving revision 1.1446
diff -u -r1.1445 -r1.1446
--- kernel.spec	19 Mar 2009 06:06:10 -0000	1.1445
+++ kernel.spec	19 Mar 2009 08:03:53 -0000	1.1446
@@ -593,8 +593,9 @@
 # Standalone patches
 Patch20: linux-2.6-hotfixes.patch
 
-
-Patch21: linux-2.6-utrace.patch
+Patch21: linux-2.6-tracehook.patch
+Patch22: linux-2.6-utrace.patch
+Patch23: linux-2.6-utrace-ftrace.patch
 
 Patch30: linux-2.6-debug-dma-api.patch
 Patch41: linux-2.6-sysrq-c.patch
@@ -1057,7 +1058,9 @@
 ApplyPatch linux-2.6-hotfixes.patch
 
 # Roland's utrace ptrace replacement.
+ApplyPatch linux-2.6-tracehook.patch
 ApplyPatch linux-2.6-utrace.patch
+ApplyPatch linux-2.6-utrace-ftrace.patch
 
 # DMA API debugging
 ApplyPatch linux-2.6-debug-dma-api.patch
@@ -1810,6 +1813,9 @@
 # and build.
 
 %changelog
+* Thu Mar 19 2009 Roland McGrath <roland at redhat.com> 2.6.29-0.266.rc8.git4
+- utrace update, add ftrace process-tracer widget, drop utrace-ptrace
+
 * Thu Mar 19 2009 Ben Skeggs <bskeggs at redhat.com>
 - drm-nouveau.patch: kms fixes and cleanups
 
@@ -1905,9 +1911,9 @@
   around insufficient flushing on i855 and i865 chipsets.
 
 * Wed Mar 11 2009 Steve Dickson <steved at redhat.com> 2.6.29-0.236.rc7.git4
-- Removed both the lockd-svc-register.patch and 
+- Removed both the lockd-svc-register.patch and
   sunrpc-ipv6-rpcbind.patch patches in favor of simply turning
-  off CONFIG_SUNRPC_REGISTER_V4 config variable. 
+  off CONFIG_SUNRPC_REGISTER_V4 config variable.
 
 * Wed Mar 11 2009 Eric Sandeen <sandeen at redhat.com> 2.6.29-0.235.rc7.git4
 - Fix incorrect header check values in ext4_ext_search_right()
@@ -2224,7 +2230,7 @@
 * Thu Feb 19 2009 Dave Jones <davej at redhat.com> 2.6.29-0.131.rc5.git3
 - 2.6.29-rc5-git3
 
-* Thu Feb 19 2009 Dave Airlie <airlied at redhat.com> 
+* Thu Feb 19 2009 Dave Airlie <airlied at redhat.com>
 - radeon: add module device table
 
 * Wed Feb 18 2009 Kyle McMartin <kyle at redhat.com>
@@ -2709,7 +2715,7 @@
 
 * Mon Dec 08 2008 Kyle McMartin <kyle at redhat.com>
 - properly fix headers in kernel-devel if headers are in arch/$arch/include,
-  sadly was not able to kill off %hdrarch since $Arch is undefined at the
+  sadly was not able to kill off %%hdrarch since $Arch is undefined at the
   time we need it for headers install.
 
 * Mon Dec 08 2008 Kyle McMartin <kyle at redhat.com>
@@ -4357,3 +4363,10 @@
 
 * Wed May 07 2008 Chuck Ebbert <cebbert at redhat.com> 2.6.25.2-5
 - Add the patches queued for 2.6.25.3
+
+###
+# The following Emacs magic makes C-c C-e use UTC dates.
+# Local Variables:
+# rpm-change-log-uses-utc: t
+# End:
+###

linux-2.6-utrace.patch:

View full diff with command:
/usr/bin/cvs -f diff  -kk -u -N -r 1.107 -r 1.108 linux-2.6-utrace.patch
Index: linux-2.6-utrace.patch
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/devel/linux-2.6-utrace.patch,v
retrieving revision 1.107
retrieving revision 1.108
diff -u -r1.107 -r1.108
--- linux-2.6-utrace.patch	8 Jan 2009 04:42:24 -0000	1.107
+++ linux-2.6-utrace.patch	19 Mar 2009 08:03:54 -0000	1.108
@@ -1,33 +1,60 @@
+utrace core
+
+This adds the utrace facility, a new modular interface in the kernel for
+implementing user thread tracing and debugging.  This fits on top of the
+tracehook_* layer, so the new code is well-isolated.
+
+The new interface is in <linux/utrace.h> and the DocBook utrace book
+describes it.  It allows for multiple separate tracing engines to work in
+parallel without interfering with each other.  Higher-level tracing
+facilities can be implemented as loadable kernel modules using this layer.
+
+The new facility is made optional under CONFIG_UTRACE.
+When this is not enabled, no new code is added.
+It can only be enabled on machines that have all the
+prerequisites and select CONFIG_HAVE_ARCH_TRACEHOOK.
+
+In this initial version, utrace and ptrace do not play together at all.
+If ptrace is attached to a thread, the attach calls in the utrace kernel
+API return -EBUSY.  If utrace is attached to a thread, the PTRACE_ATTACH
+or PTRACE_TRACEME request will return EBUSY to userland.  The old ptrace
+code is otherwise unchanged and nothing using ptrace should be affected
+by this patch as long as utrace is not used at the same time.  In the
+future we can clean up the ptrace implementation and rework it to use
+the utrace API.
+
+Signed-off-by: Roland McGrath <roland at redhat.com>
+---
  Documentation/DocBook/Makefile    |    2 +-
- Documentation/DocBook/utrace.tmpl |  571 ++++++++
+ Documentation/DocBook/utrace.tmpl |  571 +++++++++
  fs/proc/array.c                   |    3 +
- include/linux/ptrace.h            |   21 +
+ include/linux/init_task.h         |    1 +
  include/linux/sched.h             |    6 +
- include/linux/tracehook.h         |   68 +-
- include/linux/utrace.h            |  707 ++++++++++
- init/Kconfig                      |   26 +
+ include/linux/tracehook.h         |   50 +-
+ include/linux/utrace.h            |  692 +++++++++++
+ include/linux/utrace_struct.h     |   58 +
+ init/Kconfig                      |    9 +
  kernel/Makefile                   |    1 +
- kernel/ptrace.c                   |  791 +++++++++++-
- kernel/signal.c                   |   14 +-
- kernel/utrace.c                   | 2590 +++++++++++++++++++++++++++++++++++++
- 12 files changed, 4789 insertions(+), 11 deletions(-)
+ kernel/ptrace.c                   |   18 +-
+ kernel/utrace.c                   | 2346 +++++++++++++++++++++++++++++++++++++
+ 12 files changed, 3754 insertions(+), 3 deletions(-)
 
 diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
-index 0a08126..7570189 100644  
+index 1462ed8..f5da1b4 100644  
 --- a/Documentation/DocBook/Makefile
 +++ b/Documentation/DocBook/Makefile
 @@ -9,7 +9,7 @@
- DOCBOOKS := z8530book.xml mcabook.xml \
+ DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \
  	    kernel-hacking.xml kernel-locking.xml deviceiobook.xml \
  	    procfs-guide.xml writing_usb_driver.xml networking.xml \
 -	    kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \
 +	    kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml utrace.xml \
  	    gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
  	    genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
- 	    mac80211.xml debugobjects.xml sh.xml
+ 	    mac80211.xml debugobjects.xml sh.xml regulator.xml
 diff --git a/Documentation/DocBook/utrace.tmpl b/Documentation/DocBook/utrace.tmpl
 new file mode 100644
-index ...f253402 100644  
+index ...b802c55 100644  
 --- /dev/null
 +++ b/Documentation/DocBook/utrace.tmpl
 @@ -0,0 +1,571 @@
@@ -251,7 +278,7 @@
 +  <sect2 id="refcount"><title>Engine and task pointers</title>
 +  <para>
 +    The first sort of guarantee concerns the core data structures
-+    themselves.  <structname>struct utrace_attached_engine</structname> is
++    themselves.  <structname>struct utrace_engine</structname> is
 +    a reference-counted data structure.  While you hold a reference, an
 +    engine pointer will always stay valid so that you can safely pass it to
 +    any <application>utrace</application> call.  Each call to
@@ -294,7 +321,7 @@
 +    <function>rcu_read_lock</function> nor any other lock is held while
 +    making a callback, it's always guaranteed that the <structname>struct
 +    task_struct</structname> and the <structname>struct
-+    utrace_attached_engine</structname> passed as arguments remain valid
++    utrace_engine</structname> passed as arguments remain valid
 +    until the callback function returns.
 +  </para>
 +
@@ -359,7 +386,7 @@
 +    <function>report_death</function> or <function>report_reap</function>
 +    callback will try to do the same.  <constant>utrace_detach</constant>
 +    returns <constant>-ESRCH</constant> when the <structname>struct
-+    utrace_attached_engine</structname> has already been detached, but is
++    utrace_engine</structname> has already been detached, but is
 +    still a valid pointer because of its reference count.  A tracing engine
 +    can use this to safely synchronize its own independent multiple threads
 +    of control with each other and with its event callbacks that detach.
@@ -623,71 +650,44 @@
  	task_lock(p);
  	if (p->files)
  		fdt = files_fdtable(p->files);
-diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
-index 98b93ca..9b0d5be 100644  
---- a/include/linux/ptrace.h
-+++ b/include/linux/ptrace.h
-@@ -121,6 +121,7 @@ static inline void ptrace_unlink(struct 
- int generic_ptrace_peekdata(struct task_struct *tsk, long addr, long data);
- int generic_ptrace_pokedata(struct task_struct *tsk, long addr, long data);
- 
-+#ifndef CONFIG_UTRACE_PTRACE
- /**
-  * task_ptrace - return %PT_* flags that apply to a task
-  * @task:	pointer to &task_struct in question
-@@ -154,6 +155,26 @@ static inline int ptrace_event(int mask,
- 	return 1;
+diff --git a/include/linux/init_task.h b/include/linux/init_task.h
+index e752d97..ebce118 100644  
+--- a/include/linux/init_task.h
++++ b/include/linux/init_task.h
+@@ -184,6 +184,7 @@ extern struct cred init_cred;
+ 	INIT_IDS							\
+ 	INIT_TRACE_IRQFLAGS						\
+ 	INIT_LOCKDEP							\
++	INIT_UTRACE(tsk)						\
  }
  
-+static inline void ptrace_utrace_exit(struct task_struct *task)
-+{
-+}
-+
-+#else  /* CONFIG_UTRACE_PTRACE */
-+
-+static inline int task_ptrace(struct task_struct *task)
-+{
-+	return 0;
-+}
-+
-+static inline int ptrace_event(int mask, int event, unsigned long message)
-+{
-+	return 0;
-+}
-+
-+extern void ptrace_utrace_exit(struct task_struct *);
-+
-+#endif	/* !CONFIG_UTRACE_PTRACE */
-+
- /**
-  * ptrace_init_task - initialize ptrace state for a new child
-  * @child:		new child task
+ 
 diff --git a/include/linux/sched.h b/include/linux/sched.h
-index 4cae9b8..ca0861e 100644  
+index 011db2f..786ef2d 100644  
 --- a/include/linux/sched.h
 +++ b/include/linux/sched.h
-@@ -1266,6 +1266,11 @@ struct task_struct {
+@@ -59,6 +59,7 @@ struct sched_param {
+ #include <linux/errno.h>
+ #include <linux/nodemask.h>
+ #include <linux/mm_types.h>
++#include <linux/utrace_struct.h>
+ 
+ #include <asm/system.h>
+ #include <asm/page.h>
+@@ -1287,6 +1288,11 @@ struct task_struct {
  #endif
  	seccomp_t seccomp;
  
 +#ifdef CONFIG_UTRACE
-+	struct utrace *utrace;
++	struct utrace utrace;
 +	unsigned long utrace_flags;
 +#endif
 +
  /* Thread group tracking */
     	u32 parent_exec_id;
     	u32 self_exec_id;
-@@ -1865,6 +1870,7 @@ extern int kill_pgrp(struct pid *pid, in
- extern int kill_pid(struct pid *pid, int sig, int priv);
- extern int kill_proc_info(int, struct siginfo *, pid_t);
- extern int do_notify_parent(struct task_struct *, int);
-+extern void do_notify_parent_cldstop(struct task_struct *, int);
- extern void force_sig(int, struct task_struct *);
- extern void force_sig_specific(int, struct task_struct *);
- extern int send_sig(int, struct task_struct *, int);
 diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h
-index 6186a78..03a4555 100644  
+index b622498..6ff7277 100644  
[...3306 lines suppressed...]
-+		if (unlikely(task->utrace != utrace)) {
-+			spin_unlock(&utrace->lock);
-+			cond_resched();
-+			return -1;
-+		}
 +
 +		splice_attaching(utrace);
 +
@@ -4718,6 +3650,7 @@
 +		 * interrupt path, so clear the flags asking for those.
 +		 */
 +		utrace->interrupt = utrace->report = utrace->signal_handler = 0;
++		utrace->stopped = 0;
 +
 +		/*
 +		 * Make sure signal_pending() only returns true
@@ -4746,41 +3679,20 @@
 +		event = 0;
 +		ka = NULL;
 +		memset(return_ka, 0, sizeof *return_ka);
-+	} else if ((task->utrace_flags & UTRACE_EVENT_SIGNAL_ALL) == 0) {
++	} else if ((task->utrace_flags & UTRACE_EVENT_SIGNAL_ALL) == 0 &&
++		   !utrace->stopped) {
 +		/*
-+		 * If noone is interested in intercepting signals,
++		 * If no engine is interested in intercepting signals,
 +		 * let the caller just dequeue them normally.
 +		 */
-+		rcu_read_unlock();
 +		return 0;
 +	} else {
 +		if (unlikely(utrace->stopped)) {
-+			/*
-+			 * We were just in TASK_STOPPED, so we have to
-+			 * check for the race mentioned above.
-+			 *
-+			 * RCU makes it safe to get the utrace->lock even
-+			 * if it's being freed.  Once we have that lock,
-+			 * either an external detach has finished and this
-+			 * struct has been freed, or else we know we are
-+			 * excluding any other detach attempt.  Since we
-+			 * are no longer in TASK_STOPPED now, all we needed
-+			 * the lock for was to order any utrace_do_stop()
-+			 * call after us.
-+			 */
 +			spin_unlock_irq(&task->sighand->siglock);
 +			spin_lock(&utrace->lock);
-+			rcu_read_unlock();
-+			if (unlikely(task->utrace != utrace)) {
-+				spin_unlock(&utrace->lock);
-+				cond_resched();
-+				return -1;
-+			}
 +			utrace->stopped = 0;
 +			spin_unlock(&utrace->lock);
 +			spin_lock_irq(&task->sighand->siglock);
-+		} else {
-+			rcu_read_unlock();
 +		}
 +
 +		/*
@@ -4829,8 +3741,8 @@
 +		}
 +
 +		/*
-+		 * Now that we know what event type this signal is,
-+		 * we can short-circuit if noone cares about those.
++		 * Now that we know what event type this signal is, we
++		 * can short-circuit if no engines care about those.
 +		 */
 +		if ((task->utrace_flags & (event | UTRACE_EVENT(QUIESCE))) == 0)
 +			return signr;
@@ -4845,7 +3757,10 @@
 +	/*
 +	 * This reporting pass chooses what signal disposition we'll act on.
 +	 */
-+	list_for_each_entry_safe(engine, next, &utrace->attached, entry) {
++	list_for_each_entry(engine, &utrace->attached, entry) {
++		/*
++		 * See start_callback() comment about this barrier.
++		 */
 +		utrace->reporting = engine;
 +		smp_mb();
 +
@@ -5021,7 +3936,7 @@
 + */
 +void utrace_signal_handler(struct task_struct *task, int stepping)
 +{
-+	struct utrace *utrace = task->utrace;
++	struct utrace *utrace = task_utrace_struct(task);
 +
 +	spin_lock(&utrace->lock);
 +
@@ -5030,7 +3945,7 @@
 +		utrace->interrupt = 1;
 +		set_tsk_thread_flag(task, TIF_SIGPENDING);
 +	} else {
-+		set_notify_resume(task);
++		set_tsk_thread_flag(task, TIF_NOTIFY_RESUME);
 +	}
 +
 +	spin_unlock(&utrace->lock);
@@ -5065,7 +3980,7 @@
 + * completed safely.
 + */
 +int utrace_prepare_examine(struct task_struct *target,
-+			   struct utrace_attached_engine *engine,
++			   struct utrace_engine *engine,
 +			   struct utrace_examiner *exam)
 +{
 +	int ret = 0;
@@ -5118,7 +4033,7 @@
 + * keeping @target stopped, or -%EAGAIN if @target woke up unexpectedly.
 + */
 +int utrace_finish_examine(struct task_struct *target,
-+			  struct utrace_attached_engine *engine,
++			  struct utrace_engine *engine,
 +			  struct utrace_examiner *exam)
 +{
 +	int ret = 0;
@@ -5153,73 +4068,14 @@
 +EXPORT_SYMBOL_GPL(task_user_regset_view);
 +
 +/*
-+ * Return the &struct task_struct for the task using ptrace on this one,
-+ * or %NULL.  Must be called with rcu_read_lock() held to keep the returned
-+ * struct alive.
-+ *
-+ * At exec time, this may be called with task_lock() still held from when
-+ * tracehook_unsafe_exec() was just called.  In that case it must give
-+ * results consistent with those unsafe_exec() results, i.e. non-%NULL if
-+ * any %LSM_UNSAFE_PTRACE_* bits were set.
-+ *
-+ * The value is also used to display after "TracerPid:" in /proc/PID/status,
-+ * where it is called with only rcu_read_lock() held.
-+ */
-+struct task_struct *utrace_tracer_task(struct task_struct *target)
-+{
-+	struct utrace *utrace;
-+	struct task_struct *tracer = NULL;
-+
-+	utrace = rcu_dereference(target->utrace);
-+	if (utrace != NULL) {
-+		struct list_head *pos, *next;
-+		struct utrace_attached_engine *engine;
-+		const struct utrace_engine_ops *ops;
-+		list_for_each_safe(pos, next, &utrace->attached) {
-+			engine = list_entry(pos, struct utrace_attached_engine,
-+					    entry);
-+			ops = rcu_dereference(engine->ops);
-+			if (ops->tracer_task) {
-+				tracer = (*ops->tracer_task)(engine, target);
-+				if (tracer != NULL)
-+					break;
-+			}
-+		}
-+	}
-+
-+	return tracer;
-+}
-+
-+/*
-+ * Called on the current task to return LSM_UNSAFE_* bits implied by tracing.
-+ * Called with task_lock() held.
-+ */
-+int utrace_unsafe_exec(struct task_struct *task)
-+{
-+	struct utrace *utrace = task->utrace;
-+	struct utrace_attached_engine *engine, *next;
-+	const struct utrace_engine_ops *ops;
-+	int unsafe = 0;
-+
-+	list_for_each_entry_safe(engine, next, &utrace->attached, entry) {
-+		ops = rcu_dereference(engine->ops);
-+		if (ops->unsafe_exec)
-+			unsafe |= (*ops->unsafe_exec)(engine, task);
-+	}
-+
-+	return unsafe;
-+}
-+
-+/*
 + * Called with rcu_read_lock() held.
 + */
 +void task_utrace_proc_status(struct seq_file *m, struct task_struct *p)
 +{
-+	struct utrace *utrace = rcu_dereference(p->utrace);
-+	if (unlikely(utrace))
-+		seq_printf(m, "Utrace: %lx%s%s%s\n",
-+			   p->utrace_flags,
-+			   utrace->stopped ? " (stopped)" : "",
-+			   utrace->report ? " (report)" : "",
-+			   utrace->interrupt ? " (interrupt)" : "");
++	struct utrace *utrace = &p->utrace;
++	seq_printf(m, "Utrace: %lx%s%s%s\n",
++		   p->utrace_flags,
++		   utrace->stopped ? " (stopped)" : "",
++		   utrace->report ? " (report)" : "",
++		   utrace->interrupt ? " (interrupt)" : "");
 +}




More information about the fedora-extras-commits mailing list