rpms/kernel/devel kernel-2.6.spec, 1.3197, 1.3198 linux-2.6-utrace.patch, 1.59, 1.60
Dave Jones (davej)
fedora-extras-commits at redhat.com
Fri Jun 1 23:40:40 UTC 2007
Author: davej
Update of /cvs/pkgs/rpms/kernel/devel
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv14265
Modified Files:
kernel-2.6.spec linux-2.6-utrace.patch
Log Message:
* Fri Jun 01 2007 Dave Jones <davej at redhat.com>
- Update utrace to latest.
Index: kernel-2.6.spec
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/devel/kernel-2.6.spec,v
retrieving revision 1.3197
retrieving revision 1.3198
diff -u -r1.3197 -r1.3198
--- kernel-2.6.spec 1 Jun 2007 23:33:37 -0000 1.3197
+++ kernel-2.6.spec 1 Jun 2007 23:37:01 -0000 1.3198
@@ -2052,6 +2052,9 @@
%changelog
* Fri Jun 01 2007 Dave Jones <davej at redhat.com>
+- Update utrace to latest.
+
+* Fri Jun 01 2007 Dave Jones <davej at redhat.com>
- 2.6.22-rc3-git6
* Thu May 31 2007 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.59
retrieving revision 1.60
diff -u -r1.59 -r1.60
--- linux-2.6-utrace.patch 28 May 2007 01:22:43 -0000 1.59
+++ linux-2.6-utrace.patch 1 Jun 2007 23:37:01 -0000 1.60
@@ -8281,7 +8281,7 @@
BLANK();
--- linux-2.6/arch/alpha/kernel/entry.S
+++ linux-2.6/arch/alpha/kernel/entry.S
-@@ -879,14 +879,14 @@ sys_getxpid:
+@@ -878,14 +878,14 @@ sys_getxpid:
/* See linux/kernel/timer.c sys_getppid for discussion
about this loop. */
ldq $3, TASK_GROUP_LEADER($2)
@@ -9620,7 +9620,7 @@
static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
--- linux-2.6/arch/sparc64/kernel/process.c
+++ linux-2.6/arch/sparc64/kernel/process.c
-@@ -815,9 +815,6 @@ asmlinkage int sparc_execve(struct pt_re
+@@ -819,9 +819,6 @@ asmlinkage int sparc_execve(struct pt_re
current_thread_info()->xfsr[0] = 0;
current_thread_info()->fpsaved[0] = 0;
regs->tstate &= ~TSTATE_PEF;
@@ -12475,10 +12475,10 @@
repeat:
+ tracehook_release_task(p);
atomic_dec(&p->user->processes);
++ BUG_ON(tracehook_check_released(p));
write_lock_irq(&tasklist_lock);
- ptrace_unlink(p);
- BUG_ON(!list_empty(&p->ptrace_list) || !list_empty(&p->ptrace_children));
-+ BUG_ON(tracehook_check_released(p));
__exit_signal(p);
/*
@@ -12966,7 +12966,7 @@
* For a WNOHANG return, clear out all the fields
--- linux-2.6/kernel/utrace.c
+++ linux-2.6/kernel/utrace.c
-@@ -0,0 +1,2096 @@
+@@ -0,0 +1,2141 @@
+/*
+ * utrace infrastructure interface for debugging user processes
+ *
@@ -13027,7 +13027,9 @@
+
+ struct list_head engines;
+ spinlock_t lock;
++#ifdef UTRACE_DEBUG
+ atomic_t check_dead;
++#endif
+};
+
+static struct kmem_cache *utrace_cachep;
@@ -13165,12 +13167,14 @@
+
+/*
+ * Remove the utrace pointer from the task, unless there is a pending
-+ * forced signal (or it's quiescent in utrace_get_signal).
++ * forced signal (or it's quiescent in utrace_get_signal). We know it's
++ * quiescent now, and so are guaranteed it will have to take utrace->lock
++ * before it can set ->exit_state if it's not set now.
+ */
+static inline void
+utrace_clear_tsk(struct task_struct *tsk, struct utrace *utrace)
+{
-+ if (utrace->u.live.signal == NULL) {
++ if (tsk->exit_state || utrace->u.live.signal == NULL) {
+ task_lock(tsk);
+ if (likely(tsk->utrace != NULL)) {
+ rcu_assign_pointer(tsk->utrace, NULL);
@@ -13196,6 +13200,8 @@
+}
+
+
++#define DEATH_EVENTS (UTRACE_EVENT(DEATH) | UTRACE_EVENT(QUIESCE))
++
+/*
+ * Called with utrace locked, after remove_engine may have run.
+ * Passed the flags from all remaining engines, i.e. zero if none
@@ -13275,8 +13281,10 @@
+ tsk->utrace_flags = flags;
+ if (flags)
+ spin_unlock(&utrace->lock);
-+ else
++ else {
++ BUG_ON(tsk->utrace == utrace);
+ rcu_utrace_free(utrace);
++ }
+
+ /*
+ * Now we're finished updating the utrace state.
@@ -13304,7 +13312,6 @@
+ release_task(tsk);
+}
+
-+
+/*
+ * Get the target thread to quiesce. Return nonzero if it's already quiescent.
+ * Return zero if it will report a QUIESCE event soon.
@@ -13319,14 +13326,18 @@
+ target->utrace_flags |= UTRACE_ACTION_QUIESCE;
+ read_barrier_depends();
+
-+ quiescent = (target->exit_state
-+ || target->state & (TASK_TRACED | TASK_STOPPED));
++ if (target->exit_state)
++ goto dead;
+
++ quiescent = target->state & (TASK_TRACED | TASK_STOPPED);
+ if (!quiescent) {
+ spin_lock_irq(&target->sighand->siglock);
-+ quiescent = (unlikely(target->exit_state)
-+ || unlikely(target->state
-+ & (TASK_TRACED | TASK_STOPPED)));
++ if (unlikely(target->exit_state)) {
++ spin_unlock_irq(&target->sighand->siglock);
++ goto dead;
++ }
++ quiescent = unlikely(target->state
++ & (TASK_TRACED | TASK_STOPPED));
+ if (!quiescent) {
+ if (interrupt)
+ signal_wake_up(target, 0);
@@ -13339,6 +13350,13 @@
+ }
+
+ return quiescent;
++
++dead:
++ /*
++ * On the exit path, it's only truly quiescent if it has
++ * already been through utrace_report_death, or never will.
++ */
++ return !(target->utrace_flags & DEATH_EVENTS);
+}
+
+
@@ -13675,9 +13693,16 @@
+ if (unlikely(IS_ERR(utrace)))
+ return PTR_ERR(utrace);
+
++ /*
++ * On the exit path, DEATH and QUIESCE event bits are set only
++ * before utrace_report_death has taken the lock. At that point,
++ * the death report will come soon, so disallow detach until it's
++ * done. This prevents us from racing with it detaching itself.
++ */
+ if (target->exit_state
-+ && unlikely(utrace->u.exit.flags & (EXIT_FLAG_DEATH
-+ | EXIT_FLAG_REAP))) {
++ && (unlikely(target->utrace_flags & DEATH_EVENTS)
++ || unlikely(utrace->u.exit.flags & (EXIT_FLAG_DEATH
++ | EXIT_FLAG_REAP)))) {
+ /*
+ * We have already started the death report, or
+ * even entered release_task. We can't prevent
@@ -13750,7 +13775,7 @@
+ struct utrace *utrace;
+
+ task_lock(target);
-+ utrace = target->utrace;
++ utrace = rcu_dereference(target->utrace);
+ rcu_assign_pointer(target->utrace, NULL);
+ task_unlock(target);
+
@@ -13758,10 +13783,19 @@
+ return;
+
+ spin_lock(&utrace->lock);
-+ utrace->u.exit.flags |= EXIT_FLAG_REAP;
++ /*
++ * If the list is empty, utrace is already on its way to be freed.
++ * We raced with detach and we won the task_lock race but lost the
++ * utrace->lock race. All we have to do is let RCU run.
++ */
++ if (!unlikely(list_empty(&utrace->engines))) {
++ utrace->u.exit.flags |= EXIT_FLAG_REAP;
++
++ if (!(target->utrace_flags & DEATH_EVENTS)) {
++ utrace_reap(target, utrace); /* Unlocks and frees. */
++ return;
++ }
+
-+ if (target->utrace_flags & (UTRACE_EVENT(DEATH)
-+ | UTRACE_EVENT(QUIESCE)))
+ /*
+ * The target will do some final callbacks but hasn't
+ * finished them yet. We know because it clears these
@@ -13770,9 +13804,8 @@
+ * delay the REAP report and the teardown until after the
+ * target finishes its death reports.
+ */
-+ spin_unlock(&utrace->lock);
-+ else
-+ utrace_reap(target, utrace); /* Unlocks and frees. */
++ }
++ spin_unlock(&utrace->lock);
+}
+
+/**
@@ -13833,11 +13866,9 @@
+ if (target->exit_state
+ && (((flags &~ old_flags) & (UTRACE_ACTION_QUIESCE
+ | UTRACE_ACTION_NOREAP
-+ | UTRACE_EVENT(DEATH)
-+ | UTRACE_EVENT(QUIESCE)))
++ | DEATH_EVENTS))
+ || ((utrace->u.exit.flags & EXIT_FLAG_DEATH)
-+ && ((old_flags &~ flags) & (UTRACE_EVENT(DEATH) |
-+ UTRACE_EVENT(QUIESCE))))
++ && ((old_flags &~ flags) & DEATH_EVENTS))
+ || ((utrace->u.exit.flags & EXIT_FLAG_REAP)
+ && ((old_flags &~ flags) & UTRACE_EVENT(REAP))))) {
+ spin_unlock(&utrace->lock);
@@ -13855,8 +13886,7 @@
+ * that it won't.
+ */
+ if ((flags &~ old_utrace_flags) & (UTRACE_ACTION_NOREAP
-+ | UTRACE_EVENT(DEATH)
-+ | UTRACE_EVENT(QUIESCE))) {
++ | DEATH_EVENTS)) {
+ read_lock(&tasklist_lock);
+ if (unlikely(target->exit_state)) {
+ read_unlock(&tasklist_lock);
@@ -13879,11 +13909,11 @@
+ spin_unlock(&utrace->lock);
+ }
+ else
-+ wake_quiescent(old_flags, utrace, target);
++ goto wake;
+ }
+ else if (((old_flags &~ flags) & UTRACE_ACTION_NOREAP)
+ && target->exit_state)
-+ wake_quiescent(old_flags, utrace, target);
++ goto wake;
+ else {
+ /*
+ * If we're asking for single-stepping or syscall tracing,
@@ -13929,6 +13959,21 @@
+ }
+
+ return ret;
++
++wake:
++ /*
++ * It's quiescent now and needs to wake up.
++ *
++ * On the exit path, it's only truly quiescent if it has
++ * already been through utrace_report_death, or never will.
++ */
++ if (unlikely(target->exit_state)
++ && unlikely(target->utrace_flags & DEATH_EVENTS))
++ spin_unlock(&utrace->lock);
++ else
++ wake_quiescent(old_flags, utrace, target);
++
++ return ret;
+}
+EXPORT_SYMBOL_GPL(utrace_set_flags);
+
@@ -17779,7 +17824,7 @@
# According to Alan Modra <alan at linuxcare.com.au>, the -fno-omit-frame-pointer is
--- linux-2.6/kernel/timer.c
+++ linux-2.6/kernel/timer.c
-@@ -935,9 +935,9 @@ asmlinkage long sys_getpid(void)
+@@ -943,9 +943,9 @@ asmlinkage long sys_getpid(void)
}
/*
@@ -17791,7 +17836,7 @@
* release_task()->call_rcu(delayed_put_task_struct).
*/
asmlinkage long sys_getppid(void)
-@@ -945,7 +945,7 @@ asmlinkage long sys_getppid(void)
+@@ -953,7 +953,7 @@ asmlinkage long sys_getppid(void)
int pid;
rcu_read_lock();
@@ -18487,7 +18532,7 @@
.sibling = LIST_HEAD_INIT(tsk.sibling), \
--- linux-2.6/include/linux/tracehook.h
+++ linux-2.6/include/linux/tracehook.h
-@@ -0,0 +1,689 @@
+@@ -0,0 +1,701 @@
+/*
+ * Tracing hooks
+ *
@@ -18851,11 +18896,23 @@
+ * Return nonzero to trigger a BUG_ON crash in release_task.
+ * This should verify that there is no tracing-related state
+ * still affecting the task_struct about to be released.
-+ * Called with tasklist_lock held for writing.
+ */
+static inline int tracehook_check_released(struct task_struct *p)
+{
-+ return unlikely(tsk_utrace_struct(p) != NULL);
++ int bad = 0;
++ BUG_ON(p->exit_state != EXIT_DEAD);
++ if (unlikely(tsk_utrace_struct(p) != NULL)) {
++ /*
++ * In a race condition, utrace_attach will temporarily set
++ * it, but then check p->exit_state and clear it. It does
++ * all this under task_lock, so we take the lock to check
++ * that there is really a bug and not just that known race.
++ */
++ task_lock(p);
++ bad = unlikely(tsk_utrace_struct(p) != NULL);
++ task_unlock(p);
++ }
++ return bad;
+}
+
+/*
More information about the fedora-extras-commits
mailing list