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


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);
 +




More information about the fedora-extras-commits mailing list