rpms/kernel/devel kernel.spec, 1.860, 1.861 linux-2.6-utrace.patch, 1.87, 1.88
Roland McGrath (roland)
fedora-extras-commits at redhat.com
Thu Aug 7 11:38:40 UTC 2008
- Previous message (by thread): rpms/openoffice.org/devel openoffice.org.spec,1.1607,1.1608
- Next message (by thread): rpms/ruby-RRDtool/devel RubyRRDtool-0.6.0.patch, NONE, 1.1 import.log, NONE, 1.1 ruby-RRDtool.spec, NONE, 1.1 .cvsignore, 1.1, 1.2 sources, 1.1, 1.2
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
Author: roland
Update of /cvs/pkgs/rpms/kernel/devel
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv6274
Modified Files:
kernel.spec linux-2.6-utrace.patch
Log Message:
* Thu Aug 7 2008 Roland McGrath <roland at redhat.com>
- utrace update
- Clean up %prep old vanilla-* source purging.
Index: kernel.spec
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/devel/kernel.spec,v
retrieving revision 1.860
retrieving revision 1.861
diff -u -r1.860 -r1.861
--- kernel.spec 7 Aug 2008 02:11:58 -0000 1.860
+++ kernel.spec 7 Aug 2008 11:38:10 -0000 1.861
@@ -881,14 +881,10 @@
if [ -d kernel-%{kversion}/vanilla-%{kversion} ]; then
cd kernel-%{kversion}
- # any vanilla-* directories other than the base one are stale
- oldvanilla=$(ls -d vanilla-* | grep -v "^vanilla-%{kversion}$")
- # Just in case we ctrl-c'd a prep already
- rm -rf deleteme.vanilla-*
- for staledir in $oldvanilla ; do
- # Move away the stale away, and delete in background.
- mv $staledir deleteme.$staledir
- rm -rf deleteme.$staledir &
+
+ # Any vanilla-* directories other than the base one are stale.
+ for dir in vanilla-*; do
+ [ "$dir" = vanilla-%{kversion} ] || rm -rf $dir &
done
else
@@ -1049,7 +1045,7 @@
# ACPI
-ApplyPatch linux-2.6-defaults-acpi-video.patch
+ApplyPatch linux-2.6-defaults-acpi-video.patch
ApplyPatch linux-2.6-acpi-video-dos.patch
ApplyPatch linux-2.6-acpi-clear-wake-status.patch
@@ -1731,6 +1727,10 @@
%kernel_variant_files -k vmlinux %{with_kdump} kdump
%changelog
+* Thu Aug 7 2008 Roland McGrath <roland at redhat.com>
+- utrace update
+- Clean up %%prep old vanilla-* source purging.
+
* Wed Aug 06 2008 Dave Jones <davej at redhat.com>
- Enable USB_PERSIST
@@ -1761,7 +1761,7 @@
* Tue Aug 05 2008 Dave Jones <davej at redhat.com>
- 2.6.27-rc1-git6
-* Tue Aug 05 2008 Dave Airlie <airlied at redhat.com>
+* Tue Aug 05 2008 Dave Airlie <airlied at redhat.com>
- more drm regressions squashed
* Mon Aug 04 2008 Dave Jones <davej at redhat.com>
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.87
retrieving revision 1.88
diff -u -r1.87 -r1.88
--- linux-2.6-utrace.patch 1 Aug 2008 23:03:42 -0000 1.87
+++ linux-2.6-utrace.patch 7 Aug 2008 11:38:10 -0000 1.88
@@ -1,19 +1,19 @@
Documentation/DocBook/Makefile | 2 +-
- Documentation/DocBook/utrace.tmpl | 475 ++++++++
+ Documentation/DocBook/utrace.tmpl | 566 +++++++++
fs/proc/array.c | 3 +
include/linux/ptrace.h | 21 +
include/linux/sched.h | 6 +
include/linux/tracehook.h | 62 +
- include/linux/utrace.h | 616 ++++++++++
+ include/linux/utrace.h | 711 +++++++++++
init/Kconfig | 27 +
kernel/Makefile | 1 +
- kernel/ptrace.c | 578 +++++++++-
+ kernel/ptrace.c | 604 +++++++++-
kernel/signal.c | 14 +-
- kernel/utrace.c | 2324 +++++++++++++++++++++++++++++++++++++
- 12 files changed, 4122 insertions(+), 7 deletions(-)
+ kernel/utrace.c | 2531 +++++++++++++++++++++++++++++++++++++
+ 12 files changed, 4541 insertions(+), 7 deletions(-)
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
-index 0eb0d02..49a78b7 100644
+index 1d1b345..1ca1628 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -7,7 +7,7 @@
@@ -27,10 +27,10 @@
gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
diff --git a/Documentation/DocBook/utrace.tmpl b/Documentation/DocBook/utrace.tmpl
new file mode 100644
-index ...df6b6ba 100644
+index ...396a00d 100644
--- /dev/null
+++ b/Documentation/DocBook/utrace.tmpl
-@@ -0,0 +1,475 @@
+@@ -0,0 +1,566 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
@@ -67,7 +67,8 @@
+
+ <para>
+ Tracing begins by attaching an engine to a thread, using
-+ <function>utrace_attach</function>. If successful, it returns a
++ <function>utrace_attach_task</function> or
++ <function>utrace_attach_pid</function>. If successful, it returns a
+ pointer that is the handle used in all other calls.
+ </para>
+
@@ -115,45 +116,50 @@
+
+ </sect1>
+
-+ <sect1 id="stopping"><title>Stopping Safely</title>
++ <sect1 id="safely"><title>Stopping Safely</title>
++
++ <sect2 id="well-behaved"><title>Writing well-behaved callbacks</title>
+
+ <para>
+ Well-behaved callbacks are important to maintain two essential
+ properties of the interface. The first of these is that unrelated
-+ tracing engines not interfere with each other. If your engine's
-+ event callback does not return quickly, then another engine won't
-+ get the event notification in a timely manner. The second important
-+ property is that tracing be as noninvasive as possible to the normal
-+ operation of the system overall and of the traced thread in
++ tracing engines should not interfere with each other. If your engine's
++ event callback does not return quickly, then another engine won't get
++ the event notification in a timely manner. The second important
++ property is that tracing should be as noninvasive as possible to the
++ normal operation of the system overall and of the traced thread in
+ particular. That is, attached tracing engines should not perturb a
-+ thread's behavior, except to the extent that changing its
-+ user-visible state is explicitly what you want to do. (Obviously
-+ some perturbation is unavoidable, primarily timing changes, ranging
-+ from small delays due to the overhead of tracing, to arbitrary
-+ pauses in user code execution when a user stops a thread with a
-+ debugger for examination.) Even when you explicitly want the
-+ perturbation of making the traced thread block, just blocking
-+ directly in your callback has more unwanted effects. For example,
-+ the <constant>CLONE</constant> event callbacks are called when the
-+ new child thread has been created but not yet started running; the
++ thread's behavior, except to the extent that changing its user-visible
++ state is explicitly what you want to do. (Obviously some perturbation
++ is unavoidable, primarily timing changes, ranging from small delays due
++ to the overhead of tracing, to arbitrary pauses in user code execution
++ when a user stops a thread with a debugger for examination.) Even when
++ you explicitly want the perturbation of making the traced thread block,
++ just blocking directly in your callback has more unwanted effects. For
++ example, the <constant>CLONE</constant> event callbacks are called when
++ the new child thread has been created but not yet started running; the
+ child can never be scheduled until the <constant>CLONE</constant>
-+ tracing callbacks return. (This allows engines tracing the parent
-+ to attach to the child.) If a <constant>CLONE</constant> event
-+ callback blocks the parent thread, it also prevents the child thread
-+ from running (even to process a <constant>SIGKILL</constant>). If
-+ what you want is to make both the parent and child block, then use
-+ <function>utrace_attach</function> on the child and then use
++ tracing callbacks return. (This allows engines tracing the parent to
++ attach to the child.) If a <constant>CLONE</constant> event callback
++ blocks the parent thread, it also prevents the child thread from
++ running (even to process a <constant>SIGKILL</constant>). If what you
++ want is to make both the parent and child block, then use
++ <function>utrace_attach_task</function> on the child and then use
+ <constant>UTRACE_STOP</constant> on both threads. A more crucial
+ problem with blocking in callbacks is that it can prevent
-+ <constant>SIGKILL</constant> from working. A thread that is
-+ blocking due to <constant>UTRACE_STOP</constant> will still wake up
-+ and die immediately when sent a <constant>SIGKILL</constant>, as all
-+ threads should. Relying on the <application>utrace</application>
++ <constant>SIGKILL</constant> from working. A thread that is blocking
++ due to <constant>UTRACE_STOP</constant> will still wake up and die
++ immediately when sent a <constant>SIGKILL</constant>, as all threads
++ should. Relying on the <application>utrace</application>
+ infrastructure rather than on private synchronization calls in event
+ callbacks is an important way to help keep tracing robustly
+ noninvasive.
+ </para>
+
++ </sect2>
++
++ <sect2 id="UTRACE_STOP"><title>Using <constant>UTRACE_STOP</constant></title>
++
+ <para>
+ To control another thread and access its state, it must be stopped
+ with <constant>UTRACE_STOP</constant>. This means that it is
@@ -177,10 +183,13 @@
+ (See also <xref linkend="teardown"/>.)
+ </para>
+
++ </sect2>
++
+ </sect1>
+
+ <sect1 id="teardown"><title>Tear-down Races</title>
+
++ <sect2 id="SIGKILL"><title>Primacy of <constant>SIGKILL</constant></title>
+ <para>
+ Ordinarily synchronization issues for tracing engines are kept fairly
+ straightforward by using <constant>UTRACE_STOP</constant>. You ask a
@@ -208,19 +217,21 @@
+ engine can prevent or delay all other threads in the same thread group
+ dying.
+ </para>
++ </sect2>
+
++ <sect2 id="reap"><title>Final callbacks</title>
+ <para>
-+ As described above, the <function>report_reap</function> callback is
-+ always the final event in the life cycle of a traced thread. Tracing
-+ engines can use this as the trigger to clean up their own data
-+ structures. The <function>report_death</function> callback is always
-+ the penultimate event a tracing engine might see; it's seen unless the
-+ thread was already in the midst of dying when the engine attached.
-+ Many tracing engines will have no interest in when a parent reaps a
-+ dead process, and nothing they want to do with a zombie thread once it
-+ dies; for them, the <function>report_death</function> callback is the
-+ natural place to clean up data structures and detach. To facilitate
-+ writing such engines robustly, given the asynchrony of
++ The <function>report_reap</function> callback is always the final event
++ in the life cycle of a traced thread. Tracing engines can use this as
++ the trigger to clean up their own data structures. The
++ <function>report_death</function> callback is always the penultimate
++ event a tracing engine might see; it's seen unless the thread was
++ already in the midst of dying when the engine attached. Many tracing
++ engines will have no interest in when a parent reaps a dead process,
++ and nothing they want to do with a zombie thread once it dies; for
++ them, the <function>report_death</function> callback is the natural
++ place to clean up data structures and detach. To facilitate writing
++ such engines robustly, given the asynchrony of
+ <constant>SIGKILL</constant>, and without error-prone manual
+ implementation of synchronization schemes, the
+ <application>utrace</application> infrastructure provides some special
@@ -230,28 +241,51 @@
+ rules make it reasonably straightforward and concise to handle a lot of
+ corner cases correctly.
+ </para>
++ </sect2>
+
++ <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
-+ allocated using RCU, as is <structname>struct task_struct</structname>.
-+ If you call <function>utrace_attach</function> under
-+ <function>rcu_read_lock</function>, then the pointer it returns will
-+ always be valid while in the RCU critical section. (Note that
-+ <function>utrace_attach</function> can block doing memory allocation,
-+ so you must consider the real critical section to start when
-+ <function>utrace_attach</function> returns.
-+ <function>utrace_attach</function> can never block when not given the
-+ <constant>UTRACE_ATTACH_CREATE</constant> flag bit). Conversely, you
-+ can call <function>utrace_attach</function> outside of
-+ <function>rcu_read_lock</function> and though the pointer can become
-+ stale asynchronously if the thread dies and is reaped, you can safely
-+ pass it to a subsequent <function>utrace_set_events</function> or
-+ <function>utrace_control</function> call and will just get an
-+ <constant>-ESRCH</constant> error return. However, you must be sure the
-+ <structname>struct task_struct</structname> remains valid, either via
-+ <function>get_task_struct</function> or via RCU. The infrastructure
-+ never holds task references of its own. Though neither
++ 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
++ <function>utrace_attach_task</function> or
++ <function>utrace_attach_pid</function> returns an engine pointer with a
++ reference belonging to the caller. You own that reference until you
++ drop it using <function>utrace_engine_put</function>. There is an
++ implicit reference on the engine while it is attached. So if you drop
++ your only reference, and then use
++ <function>utrace_attach_task</function> without
++ <constant>UTRACE_ATTACH_CREATE</constant> to look up that same engine,
++ you will get the same pointer with a new reference to replace the one
++ you dropped, just like calling <function>utrace_engine_get</function>.
++ When an engine has been detached, either explicitly with
++ <constant>UTRACE_DETACH</constant> or implicitly after
++ <function>report_reap</function>, then any references you hold are all
++ that keep the old engine pointer alive.
++ </para>
++
++ <para>
++ There is nothing a kernel module can do to keep a <structname>struct
++ task_struct</structname> alive outside of
++ <function>rcu_read_lock</function>. When the task dies and is reaped
++ by its parent (or itself), that structure can be freed so that any
++ dangling pointers you have stored become invalid.
++ <application>utrace</application> will not prevent this, but it can
++ help you detect it safely. By definition, a task that has been reaped
++ has had all its engines detached. All
++ <application>utrace</application> calls can be safely called on a
++ detached engine if the caller holds a reference on that engine pointer,
++ even if the task pointer passed in the call is invalid. All calls
++ return <constant>-ESRCH</constant> for a detached engine, which tells
++ you that the task pointer you passed could be invalid now. Since
++ <function>utrace_control</function> and
++ <function>utrace_set_events</function> do not block, you can call those
++ inside a <function>rcu_read_lock</function> section and be sure after
++ they don't return <constant>-ESRCH</constant> that the task pointer is
++ still valid until <function>rcu_read_unlock</function>. The
++ infrastructure never holds task references of its own. Though neither
+ <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
@@ -260,22 +294,40 @@
+ </para>
+
+ <para>
-+ The second guarantee is the serialization of <constant>DEATH</constant>
-+ and <constant>reap</constant> event callbacks for a given thread. The
-+ actual reaping by the parent (<function>release_task</function> call)
-+ can occur simultaneously while the thread is still doing the final
-+ steps of dying, including the <function>report_death</function>
-+ callback. If a tracing engine has requested both
-+ <constant>DEATH</constant> and <constant>REAP</constant> event reports,
-+ it's guaranteed that the <function>report_reap</function> callback will
-+ not be made until after the <function>report_death</function> callback
-+ has returned. If the <function>report_death</function> callback itself
-+ detaches from the thread, then the <function>report_reap</function>
-+ callback will never be made. Thus it is safe for a
-+ <function>report_death</function> callback to clean up data structures
-+ and detach.
++ The common means for safely holding task pointers that is available to
++ kernel modules is to use <structname>struct pid</structname>, which
++ permits <function>put_pid</function> from kernel modules. When using
++ that, the calls <function>utrace_attach_pid</function>,
++ <function>utrace_control_pid</function>,
++ <function>utrace_set_events_pid</function>, and
++ <function>utrace_barrier_pid</function> are available.
+ </para>
++ </sect2>
++
++ <sect2 id="reap-after-death">
++ <title>
++ Serialization of <constant>DEATH</constant> and <constant>REAP</constant>
++ </title>
++ <para>
++ The second guarantee is the serialization of
++ <constant>DEATH</constant> and <constant>REAP</constant> event
++ callbacks for a given thread. The actual reaping by the parent
++ (<function>release_task</function> call) can occur simultaneously
++ while the thread is still doing the final steps of dying, including
++ the <function>report_death</function> callback. If a tracing engine
++ has requested both <constant>DEATH</constant> and
++ <constant>REAP</constant> event reports, it's guaranteed that the
++ <function>report_reap</function> callback will not be made until
++ after the <function>report_death</function> callback has returned.
++ If the <function>report_death</function> callback itself detaches
++ from the thread, then the <function>report_reap</function> callback
++ will never be made. Thus it is safe for a
++ <function>report_death</function> callback to clean up data
++ structures and detach.
++ </para>
++ </sect2>
+
++ <sect2 id="interlock"><title>Interlock with final callbacks</title>
+ <para>
+ The final sort of guarantee is that a tracing engine will know for sure
+ whether or not the <function>report_death</function> and/or
@@ -303,10 +355,9 @@
+ 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
-+ still a valid pointer because of <function>rcu_read_lock</function>.
-+ If RCU is used properly, 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.
++ 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.
+ </para>
+
+ <para>
@@ -328,6 +379,46 @@
+ errors, it can know whether to clean up its data structures immediately
+ or to let its callbacks do the work.
+ </para>
++ </sect2>
++
++ <sect2 id="barrier"><title>Using <function>utrace_barrier</function></title>
++ <para>
++ When a thread is safely stopped, calling
++ <function>utrace_control</function> with <constant>UTRACE_DETACH</constant>
++ or calling <function>utrace_set_events</function> to disable some events
++ ensures synchronously that your engine won't get any more of the callbacks
++ that have been disabled (none at all when detaching). But these can also
++ be used while the thread is not stopped, when it might be simultaneously
++ making a callback to your engine. For this situation, these calls return
++ <constant>-EINPROGRESS</constant> when it's possible a callback is in
++ progress. If you are not prepared to have your old callbacks still run,
++ then you can synchronize to be sure all the old callbacks are finished,
++ using <function>utrace_barrier</function>. This is necessary if the
++ kernel module containing your callback code is going to be unloaded.
++ </para>
++ <para>
++ After using <constant>UTRACE_DETACH</constant> once, further calls to
++ <function>utrace_control</function> with the same engine pointer will
++ return <constant>-ESRCH</constant>. In contrast, after getting
++ <constant>-EINPROGRESS</constant> from
++ <function>utrace_set_events</function>, you can call
++ <function>utrace_set_events</function> again later and if it returns zero
++ then know the old callbacks have finished.
++ </para>
++ <para>
++ Unlike all other calls, <function>utrace_barrier</function> (and
++ <function>utrace_barrier_pid</function>) will accept any engine pointer you
++ hold a reference on, even if <constant>UTRACE_DETACH</constant> has already
++ been used. After any <function>utrace_control</function> or
++ <function>utrace_set_events</function> call (these do not block), you can
++ call <function>utrace_barrier</function> to block until callbacks have
++ finished. This returns <constant>-ESRCH</constant> only if the engine is
++ completely detached (finished all callbacks). Otherwise returns it waits
++ until the thread is definitely not in the midst of a callback to this
++ engine and then returns zero, but can return
++ <constant>-ERESTARTSYS</constant> if its wait is interrupted.
++ </para>
++ </sect2>
+
+</sect1>
+
@@ -349,7 +440,7 @@
+<para>
+ The <function>task_current_syscall</function> function can be used on any
+ valid <structname>struct task_struct</structname> at any time, and does
-+ not even require that <function>utrace_attach</function> was used at all.
++ not even require that <function>utrace_attach_task</function> was used at all.
+</para>
+
+<para>
@@ -591,7 +682,7 @@
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 1253283..3ded045 100644
+index ab3ef7a..a45f692 100644
--- a/include/linux/tracehook.h
+++ b/include/linux/tracehook.h
@@ -49,6 +49,7 @@
@@ -777,7 +868,7 @@
return notify || (current->ptrace & PT_PTRACED);
}
-@@ -506,6 +559,8 @@ static inline int tracehook_notify_jctl(
+@@ -507,6 +560,8 @@ static inline int tracehook_notify_jctl(
static inline int tracehook_notify_death(struct task_struct *task,
void **death_cookie, int group_dead)
{
@@ -786,7 +877,7 @@
if (task->exit_signal == -1)
return task->ptrace ? SIGCHLD : DEATH_REAP;
-@@ -542,6 +597,10 @@ static inline void tracehook_report_deat
+@@ -543,6 +598,10 @@ static inline void tracehook_report_deat
int signal, void *death_cookie,
int group_dead)
{
@@ -797,7 +888,7 @@
}
#ifdef TIF_NOTIFY_RESUME
-@@ -575,6 +634,9 @@ static inline void set_notify_resume(str
+@@ -576,6 +635,9 @@ static inline void set_notify_resume(str
*/
static inline void tracehook_notify_resume(struct pt_regs *regs)
{
@@ -809,10 +900,10 @@
diff --git a/include/linux/utrace.h b/include/linux/utrace.h
new file mode 100644
-index ...35cc5be 100644
+index ...17ac621 100644
--- /dev/null
+++ b/include/linux/utrace.h
-@@ -0,0 +1,616 @@
+@@ -0,0 +1,711 @@
+/*
+ * utrace infrastructure interface for debugging user processes
+ *
@@ -829,12 +920,12 @@
+ * Multiple unrelated users can be associated with a single thread.
+ * We call each of these a tracing engine.
+ *
-+ * A tracing engine starts by calling utrace_attach() on the chosen
-+ * thread, passing in a set of hooks (&struct utrace_engine_ops), and
-+ * some associated data. This produces a &struct
-+ * utrace_attached_engine, which is the handle used for all other
-+ * operations. An attached engine has its ops vector, its data, and
-+ * an event mask controlled by utrace_set_events().
++ * A tracing engine starts by calling utrace_attach_task() or
++ * utrace_attach_pid() on the chosen thread, passing in a set of hooks
++ * (&struct utrace_engine_ops), and some associated data. This produces a
++ * &struct utrace_attached_engine, which is the handle used for all other
++ * operations. An attached engine has its ops vector, its data, and an
++ * event mask controlled by utrace_set_events().
+ *
+ * For each event bit that is set, that engine will get the
+ * appropriate ops->report_*() callback when the event occurs. The
@@ -846,7 +937,7 @@
+#define _LINUX_UTRACE_H 1
+
+#include <linux/list.h>
-+#include <linux/rcupdate.h>
++#include <linux/kref.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+
@@ -983,21 +1074,25 @@
+ * These are the exported entry points for tracing engines to use.
+ * See kernel/utrace.c for their kerneldoc comments with interface details.
+ */
-+struct utrace_attached_engine *utrace_attach(struct task_struct *, int flags,
-+ const struct utrace_engine_ops *,
-+ void *data);
++struct utrace_attached_engine *utrace_attach_task(
++ struct task_struct *, int, const struct utrace_engine_ops *, void *);
++struct utrace_attached_engine *utrace_attach_pid(
++ struct pid *, int, const struct utrace_engine_ops *, void *);
+int __must_check utrace_control(struct task_struct *,
+ struct utrace_attached_engine *,
+ enum utrace_resume_action);
+int __must_check utrace_set_events(struct task_struct *,
+ struct utrace_attached_engine *,
+ unsigned long eventmask);
++int __must_check utrace_barrier(struct task_struct *,
++ struct utrace_attached_engine *);
+int __must_check utrace_prepare_examine(struct task_struct *,
+ struct utrace_attached_engine *,
+ struct utrace_examiner *);
+int __must_check utrace_finish_examine(struct task_struct *,
+ struct utrace_attached_engine *,
+ struct utrace_examiner *);
++void __utrace_engine_release(struct kref *);
+
+/**
+ * enum utrace_resume_action - engine's choice of action for a traced task
@@ -1116,7 +1211,7 @@
+}
+
+/*
-+ * Flags for utrace_attach().
++ * Flags for utrace_attach_task() and utrace_attach_pid().
+ */
+#define UTRACE_ATTACH_CREATE 0x0010 /* Attach a new engine. */
+#define UTRACE_ATTACH_EXCLUSIVE 0x0020 /* Refuse if existing match. */
@@ -1126,20 +1221,22 @@
+
+/**
+ * struct utrace_attached_engine - per-engine structure
-+ * @ops: &struct utrace_engine_ops pointer passed to utrace_attach()
-+ * @data: engine-private &void * passed to utrace_attach()
++ * @ops: &struct utrace_engine_ops pointer passed to utrace_attach_task()
++ * @data: engine-private &void * passed to utrace_attach_task()
+ * @flags: event mask set by utrace_set_events() plus internal flag bits
+ *
+ * The task itself never has to worry about engines detaching while
-+ * it's doing event callbacks. These structures are freed only when
-+ * the task is quiescent. For other parties, the list is protected
-+ * by RCU and utrace->lock.
++ * it's doing event callbacks. These structures are removed from the
++ * task's active list only when it's stopped, or by the task itself.
++ *
++ * utrace_engine_get() and utrace_engine_put() maintain a reference count.
++ * When it drops to zero, the structure is freed. One reference is held
++ * implicitly while the engine is attached to its task.
+ */
+struct utrace_attached_engine {
+/* private: */
++ struct kref kref;
+ struct list_head entry;
-+ struct rcu_head rhead;
-+ atomic_t check_dead;
+
+/* public: */
+ const struct utrace_engine_ops *ops;
@@ -1149,6 +1246,29 @@
+};
+
+/**
++ * utrace_engine_get - acquire a reference on a &struct utrace_attached_engine
++ * @engine: &struct utrace_attached_engine pointer
++ *
++ * You must hold a reference on @engine, and you get another.
++ */
++static inline void utrace_engine_get(struct utrace_attached_engine *engine)
++{
++ kref_get(&engine->kref);
++}
++
++/**
++ * utrace_engine_put - release a reference on a &struct utrace_attached_engine
++ * @engine: &struct utrace_attached_engine pointer
++ *
++ * You must hold a reference on @engine, and you lose that reference.
++ * If it was the last one, @engine becomes an invalid pointer.
++ */
++static inline void utrace_engine_put(struct utrace_attached_engine *engine)
++{
++ kref_put(&engine->kref, __utrace_engine_release);
++}
++
++/**
+ * struct utrace_engine_ops - tracing engine callbacks
+ *
+ * Each @report_*() callback corresponds to an %UTRACE_EVENT(*) bit.
@@ -1256,8 +1376,8 @@
+ * Event reported for parent, before the new task @child might run.
+ * @clone_flags gives the flags used in the clone system call,
+ * or equivalent flags for a fork() or vfork() system call.
-+ * This function can use utrace_attach() on @child. It's guaranteed
-+ * that asynchronous utrace_attach() calls will be ordered after
++ * This function can use utrace_attach_task() on @child. It's guaranteed
++ * that asynchronous utrace_attach_task() calls will be ordered after
+ * any calls in @report_clone callbacks for the parent. Thus
+ * when using %UTRACE_ATTACH_EXCLUSIVE in the asynchronous calls,
+ * you can be sure that the parent's @report_clone callback has
@@ -1426,6 +1546,72 @@
+ struct {} dummy;
+};
+
++/**
++ * utrace_control_pid - control a thread being traced by a tracing engine
++ * @pid: thread to affect
++ * @engine: attached engine to affect
++ * @action: &enum utrace_resume_action for thread to do
++ *
++ * This is the same as utrace_control(), but takes a &struct pid
++ * pointer rather than a &struct task_struct pointer. The caller must
++ * hold a ref on @pid, but does not need to worry about the task
++ * staying valid. If it's been reaped so that @pid points nowhere,
++ * then this call returns -%ESRCH.
++ */
++static inline __must_check int utrace_control_pid(
++ struct pid *pid, struct utrace_attached_engine *engine,
++ enum utrace_resume_action action)
++{
++ /*
++ * We don't bother with rcu_read_lock() here to protect the
++ * task_struct pointer, because utrace_control will return
++ * -ESRCH without looking at that pointer if the engine is
++ * already detached. A task_struct pointer can't die before
++ * all the engines are detached in release_task() first.
++ */
++ struct task_struct *task = pid_task(pid, PIDTYPE_PID);
++ return unlikely(!task) ? -ESRCH : utrace_control(task, engine, action);
++}
++
++/**
++ * utrace_set_events_pid - choose which event reports a tracing engine gets
++ * @pid: thread to affect
++ * @engine: attached engine to affect
++ * @eventmask: new event mask
++ *
++ * This is the same as utrace_set_events(), but takes a &struct pid
++ * pointer rather than a &struct task_struct pointer. The caller must
++ * hold a ref on @pid, but does not need to worry about the task
++ * staying valid. If it's been reaped so that @pid points nowhere,
++ * then this call returns -%ESRCH.
++ */
++static inline __must_check int utrace_set_events_pid(
++ struct pid *pid, struct utrace_attached_engine *engine,
++ unsigned long eventmask)
++{
++ struct task_struct *task = pid_task(pid, PIDTYPE_PID);
++ return unlikely(!task) ? -ESRCH :
++ utrace_set_events(task, engine, eventmask);
++}
++
++/**
++ * utrace_barrier_pid - synchronize with simultaneous tracing callbacks
++ * @pid: thread to affect
++ * @engine: engine to affect (can be detached)
++ *
++ * This is the same as utrace_barrier(), but takes a &struct pid
++ * pointer rather than a &struct task_struct pointer. The caller must
++ * hold a ref on @pid, but does not need to worry about the task
++ * staying valid. If it's been reaped so that @pid points nowhere,
++ * then this call returns -%ESRCH.
++ */
++static inline __must_check int utrace_barrier_pid(
++ struct pid *pid, struct utrace_attached_engine *engine)
++{
++ struct task_struct *task = pid_task(pid, PIDTYPE_PID);
++ return unlikely(!task) ? -ESRCH : utrace_barrier(task, engine);
++}
++
+#endif /* CONFIG_UTRACE */
+
+#endif /* linux/utrace.h */
@@ -1480,7 +1666,7 @@
obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
obj-$(CONFIG_AUDIT_TREE) += audit_tree.o
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
-index 082b3fc..f6dacfd 100644
+index 082b3fc..90d4a90 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -16,6 +16,7 @@
@@ -1499,7 +1685,7 @@
/*
* Turn a tracing stop into a normal stop now, since with no tracer there
* would be no way to wake it up with SIGCONT or SIGKILL. If there was a
-@@ -58,6 +60,51 @@ void ptrace_untrace(struct task_struct *
+@@ -58,6 +60,54 @@ void ptrace_untrace(struct task_struct *
spin_unlock(&child->sighand->siglock);
}
@@ -1516,6 +1702,10 @@
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+}
+
++static void utrace_engine_put(struct utrace_attached_engine *engine)
++{
++}
++
+#else /* CONFIG_UTRACE_PTRACE */
+
+static const struct utrace_engine_ops ptrace_utrace_ops; /* forward decl */
@@ -1523,14 +1713,13 @@
+static void ptrace_detach_task(struct task_struct *child)
+{
+ struct utrace_attached_engine *engine;
-+ rcu_read_lock();
-+ engine = utrace_attach(child, UTRACE_ATTACH_MATCH_OPS,
-+ &ptrace_utrace_ops, NULL);
++ engine = utrace_attach_task(child, UTRACE_ATTACH_MATCH_OPS,
++ &ptrace_utrace_ops, NULL);
+ if (likely(!IS_ERR(engine))) {
+ int ret = utrace_control(child, engine, UTRACE_DETACH);
+ WARN_ON(ret && ret != -ESRCH);
++ utrace_engine_put(engine);
+ }
-+ rcu_read_unlock();
+}
+
+void ptrace_utrace_exit(struct task_struct *task)
@@ -1551,7 +1740,7 @@
/*
* unptrace a task: move it back to its original parent and
* remove it from the ptrace list.
-@@ -72,10 +119,11 @@ void __ptrace_unlink(struct task_struct
+@@ -72,10 +122,11 @@ void __ptrace_unlink(struct task_struct
child->parent = child->real_parent;
list_del_init(&child->ptrace_entry);
@@ -1565,7 +1754,7 @@
/*
* Check that we have indeed attached to the thing..
*/
-@@ -113,6 +161,446 @@ int ptrace_check_attach(struct task_stru
+@@ -113,6 +164,457 @@ int ptrace_check_attach(struct task_stru
return ret;
}
@@ -1593,13 +1782,6 @@
+{
+ unsigned long events;
+
-+ if (!engine) {
-+ engine = utrace_attach(task, UTRACE_ATTACH_MATCH_OPS,
-+ &ptrace_utrace_ops, NULL);
-+ if (IS_ERR(engine))
-+ return -ESRCH;
-+ }
-+
+ /*
+ * We need this for resume handling.
+ */
@@ -1621,6 +1803,17 @@
+ if (task->ptrace & PT_TRACE_EXIT)
+ events |= UTRACE_EVENT(EXIT);
+
++ if (!engine) {
++ int ret;
++ engine = utrace_attach_task(task, UTRACE_ATTACH_MATCH_OPS,
++ &ptrace_utrace_ops, NULL);
++ if (IS_ERR(engine))
++ return -ESRCH;
++ ret = utrace_set_events(task, engine, events);
++ utrace_engine_put(engine);
++ return ret;
++ }
++
+ return utrace_set_events(task, engine, events);
+}
+
@@ -1753,10 +1946,10 @@
+ /*
+ * Any of these reports implies auto-attaching the new child.
+ */
-+ child_engine = utrace_attach(child, UTRACE_ATTACH_CREATE |
-+ UTRACE_ATTACH_EXCLUSIVE |
-+ UTRACE_ATTACH_MATCH_OPS,
-+ &ptrace_utrace_ops, NULL);
++ child_engine = utrace_attach_task(child, UTRACE_ATTACH_CREATE |
++ UTRACE_ATTACH_EXCLUSIVE |
++ UTRACE_ATTACH_MATCH_OPS,
++ &ptrace_utrace_ops, NULL);
+ if (unlikely(IS_ERR(child_engine))) {
+ WARN_ON(1); /* XXX */
+ } else {
@@ -1767,6 +1960,7 @@
+ task_unlock(child);
+ */
+ ptrace_update_utrace(child, child_engine);
++ utrace_engine_put(child_engine);
+ }
+
+ return utrace_ptrace_event(parent, event, child->pid);
@@ -1975,36 +2169,42 @@
+ struct task_struct *child)
+{
+ struct utrace_attached_engine *engine;
-+ engine = utrace_attach(child, UTRACE_ATTACH_CREATE |
-+ UTRACE_ATTACH_EXCLUSIVE |
-+ UTRACE_ATTACH_MATCH_OPS,
-+ &ptrace_utrace_ops, NULL);
++ engine = utrace_attach_task(child, UTRACE_ATTACH_CREATE |
++ UTRACE_ATTACH_EXCLUSIVE |
++ UTRACE_ATTACH_MATCH_OPS,
++ &ptrace_utrace_ops, NULL);
+ if (IS_ERR(engine))
+ return engine;
+ if (likely(!ptrace_update_utrace(child, engine)))
+ return engine;
+ ptrace_detach_utrace(child, engine);
++ utrace_engine_put(engine);
+ return ERR_PTR(-ESRCH);
+}
+
+int ptrace_check_attach(struct task_struct *child, int kill)
+{
+ struct utrace_attached_engine *engine;
-+ long state;
++ struct utrace_examiner exam;
++ int ret;
+
-+ engine = utrace_attach(child, UTRACE_ATTACH_MATCH_OPS,
-+ &ptrace_utrace_ops, NULL);
++ engine = utrace_attach_task(child, UTRACE_ATTACH_MATCH_OPS,
++ &ptrace_utrace_ops, NULL);
+ if (IS_ERR(engine))
+ return -ESRCH;
+
+ /*
+ * Make sure our engine has already stopped the child.
++ * Then wait for it to be off the CPU.
+ */
-+ if (utrace_control(child, engine, UTRACE_STOP) != 0)
-+ return -ESRCH;
++ ret = 0;
++ if (utrace_control(child, engine, UTRACE_STOP) ||
++ utrace_prepare_examine(child, engine, &exam))
++ ret = -ESRCH;
+
-+ state = child->state;
-+ return (state && wait_task_inactive(child, state)) ? 0 : -ESRCH;
++ utrace_engine_put(engine);
++
++ return ret;
+}
+
+#endif /* !CONFIG_UTRACE_PTRACE */
@@ -2012,7 +2212,7 @@
int __ptrace_may_access(struct task_struct *task, unsigned int mode)
{
/* May we inspect the given task?
-@@ -156,6 +644,7 @@ int ptrace_attach(struct task_struct *ta
+@@ -156,6 +658,7 @@ int ptrace_attach(struct task_struct *ta
{
int retval;
unsigned long flags;
@@ -2020,7 +2220,7 @@
audit_ptrace(task);
-@@ -163,6 +652,13 @@ int ptrace_attach(struct task_struct *ta
+@@ -163,6 +666,13 @@ int ptrace_attach(struct task_struct *ta
if (same_thread_group(task, current))
goto out;
@@ -2034,16 +2234,19 @@
repeat:
/*
* Nasty, nasty.
-@@ -202,6 +698,8 @@ repeat:
+@@ -202,6 +712,11 @@ repeat:
bad:
write_unlock_irqrestore(&tasklist_lock, flags);
task_unlock(task);
-+ if (retval && !IS_ERR(engine))
-+ ptrace_detach_utrace(task, engine);
++ if (!IS_ERR(engine)) {
++ if (retval)
++ ptrace_detach_utrace(task, engine);
++ utrace_engine_put(engine);
++ }
out:
return retval;
}
-@@ -221,9 +719,7 @@ int ptrace_detach(struct task_struct *ch
+@@ -221,9 +736,7 @@ int ptrace_detach(struct task_struct *ch
if (!valid_signal(data))
return -EIO;
@@ -2054,7 +2257,7 @@
write_lock_irq(&tasklist_lock);
/* protect against de_thread()->release_task() */
-@@ -309,6 +805,8 @@ static int ptrace_setoptions(struct task
+@@ -309,6 +822,8 @@ static int ptrace_setoptions(struct task
if (data & PTRACE_O_TRACEEXIT)
child->ptrace |= PT_TRACE_EXIT;
@@ -2063,7 +2266,7 @@
return (data & ~PTRACE_O_MASK) ? -EINVAL : 0;
}
-@@ -367,6 +865,7 @@ static int ptrace_setsiginfo(struct task
+@@ -367,6 +882,7 @@ static int ptrace_setsiginfo(struct task
#define is_sysemu_singlestep(request) 0
#endif
@@ -2071,7 +2274,7 @@
static int ptrace_resume(struct task_struct *child, long request, long data)
{
if (!valid_signal(data))
-@@ -401,6 +900,68 @@ static int ptrace_resume(struct task_str
+@@ -401,6 +917,76 @@ static int ptrace_resume(struct task_str
return 0;
}
@@ -2081,12 +2284,13 @@
+ struct utrace_attached_engine *engine;
+ enum utrace_resume_action action;
+ enum utrace_syscall_action syscall;
++ int ret = 0;
+
+ if (!valid_signal(data))
+ return -EIO;
+
-+ engine = utrace_attach(child, UTRACE_ATTACH_MATCH_OPS,
-+ &ptrace_utrace_ops, NULL);
++ engine = utrace_attach_task(child, UTRACE_ATTACH_MATCH_OPS,
++ &ptrace_utrace_ops, NULL);
+ if (IS_ERR(engine))
+ return -ESRCH;
+
@@ -2100,47 +2304,54 @@
+ if (!(engine->flags & UTRACE_EVENT_SYSCALL) &&
+ utrace_set_events(child, engine,
+ engine->flags | UTRACE_EVENT_SYSCALL))
-+ return -ESRCH;
++ ret = -ESRCH;
+ } else if (engine->flags & UTRACE_EVENT(SYSCALL_ENTRY)) {
+ if (utrace_set_events(child, engine,
+ engine->flags & ~UTRACE_EVENT_SYSCALL))
-+ return -ESRCH;
++ ret = -ESRCH;
+ }
+
+ action = UTRACE_RESUME;
+ if (is_singleblock(request)) {
+ if (unlikely(!arch_has_block_step()))
-+ return -EIO;
++ ret = -EIO;
+ action = UTRACE_BLOCKSTEP;
+ } else if (is_singlestep(request) || is_sysemu_singlestep(request)) {
+ if (unlikely(!arch_has_single_step()))
-+ return -EIO;
++ ret = -EIO;
+ action = UTRACE_SINGLESTEP;
+ }
+
-+ child->exit_code = data;
++ if (!ret) {
++ child->exit_code = data;
++
++ ptrace_set_action(child, action, syscall);
+
-+ ptrace_set_action(child, action, syscall);
++ if (task_is_stopped(child)) {
++ spin_lock_irq(&child->sighand->siglock);
++ child->signal->flags &= ~SIGNAL_STOP_STOPPED;
++ spin_unlock_irq(&child->sighand->siglock);
++ }
+
-+ if (task_is_stopped(child)) {
-+ spin_lock_irq(&child->sighand->siglock);
-+ child->signal->flags &= ~SIGNAL_STOP_STOPPED;
-+ spin_unlock_irq(&child->sighand->siglock);
++ /*
++ * To resume with a signal we must hit ptrace_report_signal.
++ */
++ if (data)
++ action = UTRACE_INTERRUPT;
++
++ if (utrace_control(child, engine, action))
++ ret = -ESRCH;
+ }
+
-+ /*
-+ * To resume with a signal we must hit ptrace_report_signal.
-+ */
-+ if (data)
-+ action = UTRACE_INTERRUPT;
++ utrace_engine_put(engine);
+
-+ return utrace_control(child, engine, action) ? -ESRCH : 0;
++ return ret;
+}
+#endif /* !CONFIG_UTRACE_PTRACE */
int ptrace_request(struct task_struct *child, long request,
long addr, long data)
-@@ -480,6 +1041,11 @@ int ptrace_request(struct task_struct *c
+@@ -480,6 +1066,11 @@ int ptrace_request(struct task_struct *c
int ptrace_traceme(void)
{
int ret = -EPERM;
@@ -2152,12 +2363,13 @@
/*
* Are we already being traced?
-@@ -514,6 +1080,8 @@ repeat:
+@@ -514,6 +1105,9 @@ repeat:
write_unlock_irqrestore(&tasklist_lock, flags);
}
task_unlock(current);
+ if (ret)
+ ptrace_detach_utrace(current, engine);
++ utrace_engine_put(engine);
return ret;
}
@@ -2216,10 +2428,10 @@
struct pt_regs *regs, void *cookie)
diff --git a/kernel/utrace.c b/kernel/utrace.c
new file mode 100644
-index ...688a18e 100644
+index ...f4851b2 100644
--- /dev/null
+++ b/kernel/utrace.c
-@@ -0,0 +1,2324 @@
+@@ -0,0 +1,2531 @@
+/*
+ * utrace infrastructure interface for debugging user processes
+ *
@@ -2302,6 +2514,8 @@
+ atomic_t check_dead;
+#endif
+
++ struct utrace_attached_engine *reporting;
++
+ unsigned int stopped:1;
+ unsigned int report:1;
+ unsigned int interrupt:1;
@@ -2312,6 +2526,7 @@
+
+static struct kmem_cache *utrace_cachep;
+static struct kmem_cache *utrace_engine_cachep;
++static const struct utrace_engine_ops utrace_detached_ops; /* forward decl */
+
+static int __init utrace_init(void)
+{
@@ -2418,28 +2633,26 @@
+ call_rcu(&utrace->u.dead, utrace_free);
+}
+
-+static void utrace_engine_free(struct rcu_head *rhead)
++/*
++ * This is the exported function used by the utrace_engine_put() inline.
++ */
++void __utrace_engine_release(struct kref *kref)
+{
+ struct utrace_attached_engine *engine =
-+ container_of(rhead, struct utrace_attached_engine, rhead);
++ container_of(kref, struct utrace_attached_engine, kref);
++ BUG_ON(!list_empty(&engine->entry));
+ kmem_cache_free(utrace_engine_cachep, engine);
+}
++EXPORT_SYMBOL_GPL(__utrace_engine_release);
+
-+static inline void rcu_engine_free(struct utrace_attached_engine *engine)
-+{
-+ CHECK_DEAD(engine);
-+ call_rcu(&engine->rhead, utrace_engine_free);
-+}
-+
-+static bool engine_matches(struct utrace_attached_engine *engine,
-+ int flags,
++static bool engine_matches(struct utrace_attached_engine *engine, int flags,
+ const struct utrace_engine_ops *ops, void *data)
+{
+ if ((flags & UTRACE_ATTACH_MATCH_OPS) && engine->ops != ops)
+ return false;
+ if ((flags & UTRACE_ATTACH_MATCH_DATA) && engine->data != data)
+ return false;
-+ return true;
++ return engine->ops && engine->ops != &utrace_detached_ops;
+}
+
+static struct utrace_attached_engine *matching_engine(
@@ -2453,18 +2666,35 @@
+ list_for_each_entry(engine, &utrace->attaching, entry)
+ if (engine_matches(engine, flags, ops, data))
+ return engine;
-+ return ERR_PTR(-ENOENT);
++ return NULL;
++}
++
++/*
++ * Allocate a new engine structure. It starts out with two refs:
++ * one ref for utrace_attach_task() to return, and ref for being attached.
++ */
++static struct utrace_attached_engine *alloc_engine(void)
++{
++ struct utrace_attached_engine *engine;
++ engine = kmem_cache_alloc(utrace_engine_cachep, GFP_KERNEL);
++ if (likely(engine)) {
++ engine->flags = 0;
++ kref_set(&engine->kref, 2);
++ }
++ return engine;
+}
+
+/**
-+ * utrace_attach - attach new engine to a thread, or look up an attached engine
++ * utrace_attach_task - attach new engine, or look up an attached engine
+ * @target: thread to attach to
+ * @flags: flag bits combined with OR, see below
+ * @ops: callback table for new engine
+ * @data: engine private data pointer
+ *
+ * The caller must ensure that the @target thread does not get freed,
-+ * i.e. hold a ref or be its parent.
++ * i.e. hold a ref or be its parent. It is always safe to call this
++ * on @current, or on the @child pointer in a @report_clone callback.
++ * For most other cases, it's easier to use utrace_attach_pid() instead.
+ *
+ * UTRACE_ATTACH_CREATE:
+ * Create a new engine. If %UTRACE_ATTACH_CREATE is not specified, you
@@ -2476,7 +2706,7 @@
+ * UTRACE_ATTACH_MATCH_OPS: Only consider engines matching @ops.
+ * UTRACE_ATTACH_MATCH_DATA: Only consider engines matching @data.
+ */
-+struct utrace_attached_engine *utrace_attach(
++struct utrace_attached_engine *utrace_attach_task(
+ struct task_struct *target, int flags,
+ const struct utrace_engine_ops *ops, void *data)
+{
@@ -2510,27 +2740,30 @@
+ */
+ return ERR_PTR(-EPERM);
+
-+ engine = kmem_cache_alloc(utrace_engine_cachep, GFP_KERNEL);
-+ if (unlikely(engine == NULL))
++ engine = alloc_engine();
++ if (unlikely(!engine))
+ return ERR_PTR(-ENOMEM);
-+ engine->flags = 0;
-+ CHECK_INIT(engine);
+
+ goto first;
+ }
+
+ if (!(flags & UTRACE_ATTACH_CREATE)) {
++ spin_lock(&utrace->lock);
+ engine = matching_engine(utrace, flags, ops, data);
++ if (engine)
++ utrace_engine_get(engine);
++ spin_unlock(&utrace->lock);
+ rcu_read_unlock();
-+ return engine;
++ return engine ?: ERR_PTR(-ENOENT);
+ }
+ rcu_read_unlock();
+
-+ engine = kmem_cache_alloc(utrace_engine_cachep, GFP_KERNEL);
-+ if (unlikely(engine == NULL))
++ if (unlikely(!ops) || unlikely(ops == &utrace_detached_ops))
++ return ERR_PTR(-EINVAL);
++
++ engine = alloc_engine();
++ if (unlikely(!engine))
+ return ERR_PTR(-ENOMEM);
-+ engine->flags = 0;
-+ CHECK_INIT(engine);
+
+ rcu_read_lock();
+ utrace = rcu_dereference(target->utrace);
@@ -2543,7 +2776,7 @@
+ if (flags & UTRACE_ATTACH_EXCLUSIVE) {
+ struct utrace_attached_engine *old;
+ old = matching_engine(utrace, flags, ops, data);
-+ if (!IS_ERR(old)) {
++ if (old) {
+ spin_unlock(&utrace->lock);
+ rcu_read_unlock();
+ kmem_cache_free(utrace_engine_cachep, engine);
@@ -2584,7 +2817,34 @@
+
+ return engine;
+}
-+EXPORT_SYMBOL_GPL(utrace_attach);
++EXPORT_SYMBOL_GPL(utrace_attach_task);
++
++/**
++ * utrace_attach_pid - attach new engine, or look up an attached engine
++ * @pid: &struct pid pointer representing thread to attach to
++ * @flags: flag bits combined with OR, see utrace_attach_task()
++ * @ops: callback table for new engine
++ * @data: engine private data pointer
++ *
++ * This is the same as utrace_attach_task(), but takes a &struct pid
++ * pointer rather than a &struct task_struct pointer. The caller must
++ * hold a ref on @pid, but does not need to worry about the task
++ * staying valid. If it's been reaped so that @pid points nowhere,
++ * then this call returns -%ESRCH.
++ */
++struct utrace_attached_engine *utrace_attach_pid(
++ struct pid *pid, int flags,
++ const struct utrace_engine_ops *ops, void *data)
++{
++ struct utrace_attached_engine *engine = ERR_PTR(-ESRCH);
++ struct task_struct *task = get_pid_task(pid, PIDTYPE_PID);
++ if (task) {
++ engine = utrace_attach_task(task, flags, ops, data);
++ put_task_struct(task);
++ }
++ return engine;
++}
++EXPORT_SYMBOL_GPL(utrace_attach_pid);
+
+static void __list_splice_tail(const struct list_head *list,
+ struct list_head *head)
@@ -2744,13 +3004,12 @@
+}
+
+/*
-+ * The engine is supposed to be attached. The caller really needs
-+ * rcu_read_lock if it wants to look at the engine struct
-+ * (e.g. engine->data), to be sure it hasn't been freed by utrace_reap
-+ * asynchronously--unless he has synchronized with his report_reap
-+ * callback, which would have happened before then. A simultaneous
-+ * UTRACE_DETACH also free the engine if rcu_read_lock is not held, but
-+ * that is in the tracing engine's power to avoid.
++ * The caller has to hold a ref on the engine. If the attached flag is
++ * true (all but utrace_barrier() calls), the engine is supposed to be
++ * attached. If the attached is flag is false (utrace_barrier() only),
++ * then return -ERESTARTSYS for an engine marked for detach but not yet
++ * fully detached. The task pointer can be invalid if the engine is
++ * detached.
+ *
+ * Get the utrace lock for the target task.
+ * Returns the struct if locked, or ERR_PTR(-errno).
@@ -2761,13 +3020,43 @@
+ * utrace_report_death
+ * utrace_release_task
+ */
-+static struct utrace *get_utrace_lock_attached(
-+ struct task_struct *target, struct utrace_attached_engine *engine)
++static struct utrace *get_utrace_lock(struct task_struct *target,
++ struct utrace_attached_engine *engine,
++ bool attached)
+ __acquires(utrace->lock)
+{
+ struct utrace *utrace;
+
++ /*
++ * You must hold a ref to be making a call. A call from within
++ * a report_* callback in @target might only have the ref for
++ * being attached, not a second one of its own.
++ */
++ if (unlikely(atomic_read(&engine->kref.refcount) < 1))
++ return ERR_PTR(-EINVAL);
++
+ rcu_read_lock();
++
++ /*
++ * If this engine was already detached, bail out before we look at
++ * the task_struct pointer at all. If it's detached after this
++ * check, then RCU is still keeping this task_struct pointer valid.
++ *
++ * The ops pointer is NULL when the engine is fully detached.
++ * It's &utrace_detached_ops when it's marked detached but still
++ * on the list. In the latter case, utrace_barrier() still works,
++ * since the target might be in the middle of an old callback.
++ */
++ if (unlikely(!engine->ops)) {
++ rcu_read_unlock();
++ return ERR_PTR(-ESRCH);
++ }
++
++ if (unlikely(engine->ops == &utrace_detached_ops)) {
++ rcu_read_unlock();
++ return attached ? ERR_PTR(-ESRCH) : ERR_PTR(-ERESTARTSYS);
++ }
++
+ utrace = rcu_dereference(target->utrace);
+ smp_rmb();
+ if (unlikely(!utrace) || unlikely(target->exit_state == EXIT_DEAD)) {
@@ -2775,13 +3064,13 @@
+ * If all engines detached already, utrace is clear.
+ * Otherwise, we're called after utrace_release_task might
+ * have started. A call to this engine's report_reap
-+ * callback might already be in progress or engine might
-+ * even have been freed already.
++ * callback might already be in progress.
+ */
+ utrace = ERR_PTR(-ESRCH);
+ } else {
+ spin_lock(&utrace->lock);
+ if (unlikely(rcu_dereference(target->utrace) != utrace) ||
++ unlikely(!engine->ops) ||
+ unlikely(engine->ops == &utrace_detached_ops)) {
+ /*
+ * By the time we got the utrace lock,
@@ -2789,6 +3078,8 @@
+ */
+ spin_unlock(&utrace->lock);
+ utrace = ERR_PTR(-ESRCH);
++ if (!attached && engine->ops == &utrace_detached_ops)
++ utrace = ERR_PTR(-ERESTARTSYS);
+ }
+ }
+ rcu_read_unlock();
@@ -2797,6 +3088,20 @@
+}
+
+/*
++ * Now that we don't hold any locks, run through any
++ * detached engines and free their references. Each
++ * engine had one implicit ref while it was attached.
++ */
++static void put_detached_list(struct list_head *list)
++{
++ struct utrace_attached_engine *engine, *next;
++ list_for_each_entry_safe(engine, next, list, entry) {
++ list_del_init(&engine->entry);
++ utrace_engine_put(engine);
++ }
++}
++
++/*
+ * Called with utrace->lock held.
+ * Notify and clean up all engines, then free utrace.
+ */
@@ -2805,32 +3110,38 @@
+{
+ struct utrace_attached_engine *engine, *next;
+ const struct utrace_engine_ops *ops;
++ LIST_HEAD(detached);
+
+restart:
+ splice_attaching(utrace);
+ list_for_each_entry_safe(engine, next, &utrace->attached, entry) {
-+ list_del(&engine->entry);
++ ops = engine->ops;
++ engine->ops = NULL;
++ list_move(&engine->entry, &detached);
+
+ /*
-+ * Now nothing else refers to this engine.
++ * If it didn't need a callback, we don't need to drop
++ * the lock. Now nothing else refers to this engine.
+ */
-+ if (engine->flags & UTRACE_EVENT(REAP)) {
-+ ops = rcu_dereference(engine->ops);
-+ spin_unlock(&utrace->lock);
-+ (*ops->report_reap)(engine, target);
-+ rcu_engine_free(engine);
-+ spin_lock(&utrace->lock);
-+ goto restart;
-+ }
++ if (!(engine->flags & UTRACE_EVENT(REAP)))
++ continue;
+
-+ /*
-+ * It didn't need a callback, so we don't need to drop
-+ * the lock. Just clean up quickly.
-+ */
-+ rcu_engine_free(engine);
++ utrace->reporting = engine;
++ spin_unlock(&utrace->lock);
++
++ (*ops->report_reap)(engine, target);
++
++ utrace->reporting = NULL;
++
++ put_detached_list(&detached);
++
++ spin_lock(&utrace->lock);
++ goto restart;
+ }
+
-+ rcu_utrace_free(utrace);
++ rcu_utrace_free(utrace); /* Releases the lock. */
++
++ put_detached_list(&detached);
+}
+
+#define DEATH_EVENTS (UTRACE_EVENT(DEATH) | UTRACE_EVENT(QUIESCE))
@@ -2918,7 +3229,13 @@
+ * If @target was stopped before the call, then after a successful call,
+ * no event callbacks not requested in @events will be made; if
+ * %UTRACE_EVENT(%QUIESCE) is included in @events, then a @report_quiesce
-+ * callback will be made when @target resumes.
++ * callback will be made when @target resumes. If @target was not stopped,
++ * and was about to make a callback to @engine, this returns -%EINPROGRESS.
++ * In this case, the callback in progress might be one excluded from the
++ * new @events setting. When this returns zero, you can be sure that no
++ * event callbacks you've disabled in @events can be made.
++ *
++ * To synchronize after an -%EINPROGRESS return, see utrace_barrier().
+ *
+ * These rules provide for coherent synchronization based on %UTRACE_STOP,
+ * even when %SIGKILL is breaking its normal simple rules.
@@ -2931,8 +3248,9 @@
+ unsigned long old_flags, old_utrace_flags, set_utrace_flags;
+ struct sighand_struct *sighand;
+ unsigned long flags;
++ int ret;
+
-+ utrace = get_utrace_lock_attached(target, engine);
++ utrace = get_utrace_lock(target, engine, true);
+ if (unlikely(IS_ERR(utrace)))
+ return PTR_ERR(utrace);
+
@@ -2993,9 +3311,16 @@
+ !(old_utrace_flags & UTRACE_EVENT_SYSCALL))
+ set_tsk_thread_flag(target, TIF_SYSCALL_TRACE);
+
++ ret = 0;
++ if (!utrace->stopped) {
++ smp_mb();
++ if (utrace->reporting == engine)
++ ret = -EINPROGRESS;
++ }
++
+ spin_unlock(&utrace->lock);
+
-+ return 0;
++ return ret;
+}
+EXPORT_SYMBOL_GPL(utrace_set_events);
+
@@ -3014,7 +3339,7 @@
+ */
+static void mark_engine_detached(struct utrace_attached_engine *engine)
+{
-+ rcu_assign_pointer(engine->ops, &utrace_detached_ops);
++ engine->ops = &utrace_detached_ops;
+ smp_wmb();
+ engine->flags = UTRACE_EVENT(QUIESCE);
+}
@@ -3107,6 +3432,7 @@
+{
+ struct utrace_attached_engine *engine, *next;
+ unsigned long flags = 0;
++ LIST_HEAD(detached);
+
+ splice_attaching(utrace);
+
@@ -3114,15 +3440,16 @@
+ * Update the set of events of interest from the union
+ * of the interests of the remaining tracing engines.
+ * For any engine marked detached, remove it from the list.
++ * We'll collect them on the detached list.
+ */
+ list_for_each_entry_safe(engine, next, &utrace->attached, entry) {
+ if (engine->ops == &utrace_detached_ops) {
-+ list_del(&engine->entry);
-+ continue;
++ engine->ops = NULL;
++ list_move(&engine->entry, &detached);
++ } else {
++ flags |= engine->flags | UTRACE_EVENT(REAP);
++ wake = wake && !engine_wants_stop(engine);
+ }
-+
-+ flags |= engine->flags | UTRACE_EVENT(REAP);
-+ wake = wake && !engine_wants_stop(engine);
+ }
+
+ if (task->exit_state) {
@@ -3144,7 +3471,7 @@
+ */
+ if (flags) {
+ spin_unlock(&utrace->lock);
-+ return;
++ goto done;
+ }
+
+ /*
@@ -3158,7 +3485,7 @@
+ if (unlikely(task->utrace != utrace)) {
+ task_unlock(task);
+ spin_unlock(&utrace->lock);
-+ return;
++ goto done;
+ }
+
+ rcu_assign_pointer(task->utrace, NULL);
@@ -3166,6 +3493,9 @@
+ task_unlock(task);
+
+ rcu_utrace_free(utrace);
++
++done:
++ put_detached_list(&detached);
+}
+
+/**
@@ -3196,7 +3526,10 @@
+ * begun, this fails with -%EALREADY.
+ *
+ * If @target is not already stopped, then a callback to this engine
-+ * might be in progress or about to start on another CPU.
++ * might be in progress or about to start on another CPU. If so,
++ * then this returns -%EINPROGRESS; the detach happens as soon as
++ * the pending callback is finished. To synchronize after an
++ * -%EINPROGRESS return, see utrace_barrier().
+ *
+ * If @target is properly stopped before utrace_control() is called,
+ * then after successful return it's guaranteed that no more callbacks
@@ -3283,14 +3616,13 @@
+ enum utrace_resume_action action)
+{
+ struct utrace *utrace;
-+ unsigned long old_flags, old_utrace_flags;
+ bool resume;
+ int ret;
+
+ if (unlikely(action > UTRACE_DETACH))
+ return -EINVAL;
+
-+ utrace = get_utrace_lock_attached(target, engine);
++ utrace = get_utrace_lock(target, engine, true);
+ if (unlikely(IS_ERR(utrace)))
+ return PTR_ERR(utrace);
+
@@ -3322,9 +3654,6 @@
+ }
+ }
+
-+ old_utrace_flags = target->utrace_flags;
-+ old_flags = engine->flags;
-+
+ resume = utrace->stopped;
+ ret = 0;
+
@@ -3340,6 +3669,12 @@
+ case UTRACE_DETACH:
+ mark_engine_detached(engine);
+ resume = resume || utrace_do_stop(target, utrace);
++ if (!resume) {
++ smp_mb();
++ if (utrace->reporting == engine)
++ ret = -EINPROGRESS;
++ break;
++ }
+ /* Fall through. */
+
+ case UTRACE_RESUME:
@@ -3447,6 +3782,54 @@
+}
+EXPORT_SYMBOL_GPL(utrace_control);
+
++/**
++ * utrace_barrier - synchronize with simultaneous tracing callbacks
++ * @target: thread to affect
++ * @engine: engine to affect (can be detached)
++ *
++ * This blocks while @target might be in the midst of making a callback to
++ * @engine. It can be interrupted by signals and will return -%ERESTARTSYS.
++ * A return value of zero means no callback from @target to @engine was
++ * in progress.
++ *
++ * It's not necessary to keep the @target pointer alive for this call.
++ * It's only necessary to hold a ref on @engine. This will return
++ * safely even if @target has been reaped and has no task refs.
++ *
++ * A successful return from utrace_barrier() guarantees its ordering
++ * with respect to utrace_set_events() and utrace_control() calls. If
++ * @target was not properly stopped, event callbacks just disabled might
++ * still be in progress; utrace_barrier() waits until there is no chance
++ * an unwanted callback can be in progress.
++ */
++int utrace_barrier(struct task_struct *target,
++ struct utrace_attached_engine *engine)
++{
++ struct utrace *utrace;
++ int ret = -ERESTARTSYS;
++
++ if (unlikely(target == current))
++ return 0;
++
++ do {
++ utrace = get_utrace_lock(target, engine, false);
++ if (unlikely(IS_ERR(utrace))) {
++ ret = PTR_ERR(utrace);
++ if (ret != -ERESTARTSYS)
++ break;
++ } else {
++ if (utrace->stopped || utrace->reporting != engine)
++ ret = 0;
++ spin_unlock(&utrace->lock);
++ if (!ret)
++ break;
++ }
++ schedule_timeout_interruptible(1);
++ } while (!signal_pending(current));
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(utrace_barrier);
+
+/*
+ * This is local state used for reporting loops, perhaps optimized away.
@@ -3520,6 +3903,8 @@
+{
+ enum utrace_resume_action action = utrace_resume_action(ret);
+
++ utrace->reporting = NULL;
++
+ /*
+ * This is a good place to make sure tracing engines don't
+ * introduce too much latency under voluntary preemption.
@@ -3527,14 +3912,17 @@
+ if (need_resched())
+ cond_resched();
+
-+ if (action == UTRACE_DETACH) {
-+ rcu_assign_pointer(engine->ops, &utrace_detached_ops);
++ report->result = ret & ~UTRACE_RESUME_MASK;
++
++ /*
++ * If utrace_control() was used, treat that like UTRACE_DETACH here.
++ */
++ if (action == UTRACE_DETACH || engine->ops == &utrace_detached_ops) {
++ engine->ops = &utrace_detached_ops;
+ report->detaches = true;
+ return true;
+ }
+
-+ report->result = ret & ~UTRACE_RESUME_MASK;
-+
+ if (action < report->action)
+ report->action = action;
+
@@ -3568,6 +3956,9 @@
+ const struct utrace_engine_ops *ops;
+ unsigned long want;
+
++ utrace->reporting = engine;
++ smp_mb();
++
+ /*
+ * This pairs with the barrier in mark_engine_detached().
+ * It makes sure that we never see the old ops vector with
@@ -3575,15 +3966,17 @@
+ */
+ want = engine->flags;
+ smp_rmb();
-+ ops = rcu_dereference(engine->ops);
++ ops = engine->ops;
+
+ if (want & UTRACE_EVENT(QUIESCE)) {
+ if (finish_callback(utrace, report, engine,
+ (*ops->report_quiesce)(report->action,
+ engine, task,
+ event)))
-+ return NULL;
++ goto nocall;
+
++ utrace->reporting = engine;
++ smp_mb();
+ want = engine->flags;
+ }
+
@@ -3595,6 +3988,8 @@
+ return ops;
+ }
+
++nocall:
++ utrace->reporting = NULL;
+ return NULL;
+}
+
@@ -3749,7 +4144,7 @@
+ rcu_read_lock();
+ utrace = rcu_dereference(task->utrace);
+ if (unlikely(!utrace)) {
-+ rcu_read_lock();
++ rcu_read_unlock();
+ return;
+ }
+ spin_lock(&utrace->lock);
@@ -4195,16 +4590,21 @@
+ * This reporting pass chooses what signal disposition we'll act on.
+ */
+ list_for_each_entry_safe(engine, next, &utrace->attached, entry) {
++ utrace->reporting = engine;
++ smp_mb();
++
+ /*
+ * This pairs with the barrier in mark_engine_detached(),
+ * see start_callback() comments.
+ */
+ want = engine->flags;
+ smp_rmb();
-+ ops = rcu_dereference(engine->ops);
++ ops = engine->ops;
+
-+ if ((want & (event | UTRACE_EVENT(QUIESCE))) == 0)
++ if ((want & (event | UTRACE_EVENT(QUIESCE))) == 0) {
++ utrace->reporting = NULL;
+ continue;
++ }
+
+ if (ops->report_signal)
+ ret = (*ops->report_signal)(
@@ -4376,11 +4776,10 @@
+ spin_unlock(&utrace->lock);
+}
+
-+
+/**
+ * utrace_prepare_examine - prepare to examine thread state
+ * @target: thread of interest, a &struct task_struct pointer
-+ * @engine: engine pointer returned by utrace_attach()
++ * @engine: engine pointer returned by utrace_attach_task()
+ * @exam: temporary state, a &struct utrace_examiner pointer
+ *
+ * This call prepares to safely examine the thread @target using
@@ -4400,44 +4799,49 @@
+ * (for %SIGKILL or a spurious wakeup), this call returns -%EAGAIN.
+ *
+ * When this call returns zero, it's safe to use &struct user_regset
-+ * calls, task_user_regset_view(), and task_current_syscall() on @target
-+ * and to examine some of its fields directly. When the examination is
-+ * complete, a utrace_finish_examine() call must follow to check whether
-+ * it was completed safely.
++ * calls and task_user_regset_view() on @target and to examine some of
++ * its fields directly. When the examination is complete, a
++ * utrace_finish_examine() call must follow to check whether it was
++ * completed safely.
+ */
+int utrace_prepare_examine(struct task_struct *target,
+ struct utrace_attached_engine *engine,
+ struct utrace_examiner *exam)
+{
++ int ret = 0;
++
+ if (unlikely(target == current))
+ return 0;
+
+ rcu_read_lock();
-+ if (unlikely(target->exit_state)) {
-+ rcu_read_unlock();
-+ return -ESRCH;
-+ }
-+ if (unlikely(!engine_wants_stop(engine))) {
-+ rcu_read_unlock();
-+ return -EINVAL;
++ if (unlikely(!engine_wants_stop(engine)))
++ ret = -EINVAL;
++ else if (unlikely(target->exit_state))
++ ret = -ESRCH;
++ else {
++ exam->state = target->state;
++ if (unlikely(exam->state == TASK_RUNNING))
++ ret = -EAGAIN;
++ else
++ get_task_struct(target);
+ }
+ rcu_read_unlock();
+
-+ exam->state = target->state;
-+ if (likely(exam->state != TASK_RUNNING)) {
++ if (likely(!ret)) {
+ exam->ncsw = wait_task_inactive(target, exam->state);
-+ if (likely(exam->ncsw))
-+ return 0;
++ put_task_struct(target);
++ if (unlikely(!exam->ncsw))
++ ret = -EAGAIN;
+ }
+
-+ return -EAGAIN;
++ return ret;
+}
+EXPORT_SYMBOL_GPL(utrace_prepare_examine);
+
+/**
+ * utrace_finish_examine - complete an examination of thread state
+ * @target: thread of interest, a &struct task_struct pointer
-+ * @engine: engine pointer returned by utrace_attach()
++ * @engine: engine pointer returned by utrace_attach_task()
+ * @exam: pointer passed to utrace_prepare_examine() call
+ *
+ * This call completes an examination on the thread @target begun by a
@@ -4448,22 +4852,37 @@
+ * another thread, this returns zero if @target has remained unscheduled
+ * since the paired utrace_prepare_examine() call returned zero.
+ *
-+ * When this returns an error (always -%EAGAIN), any examination done
-+ * since the paired utrace_prepare_examine() call is unreliable and the
-+ * data extracted should be discarded.
++ * When this returns an error, any examination done since the paired
++ * utrace_prepare_examine() call is unreliable and the data extracted
++ * should be discarded. The error is -%EINVAL is @engine is not
++ * 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_examiner *exam)
+{
++ int ret = 0;
++
+ if (unlikely(target == current))
+ return 0;
+
-+ if (likely(target->state == exam->state) &&
-+ likely(wait_task_inactive(target, exam->state) == exam->ncsw))
-+ return 0;
++ rcu_read_lock();
++ if (unlikely(!engine_wants_stop(engine)))
++ ret = -EINVAL;
++ else if (unlikely(target->state != exam->state))
++ ret = -EAGAIN;
++ else
++ get_task_struct(target);
++ rcu_read_unlock();
+
-+ return -EAGAIN;
++ if (likely(!ret)) {
++ unsigned long ncsw = wait_task_inactive(target, exam->state);
++ if (unlikely(ncsw != exam->ncsw))
++ ret = -EAGAIN;
++ put_task_struct(target);
++ }
++
++ return ret;
+}
+EXPORT_SYMBOL_GPL(utrace_finish_examine);
+
- Previous message (by thread): rpms/openoffice.org/devel openoffice.org.spec,1.1607,1.1608
- Next message (by thread): rpms/ruby-RRDtool/devel RubyRRDtool-0.6.0.patch, NONE, 1.1 import.log, NONE, 1.1 ruby-RRDtool.spec, NONE, 1.1 .cvsignore, 1.1, 1.2 sources, 1.1, 1.2
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
More information about the fedora-extras-commits
mailing list