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