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(¤t->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(¤t->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