[PATCH 3/4] utrace_reap: do not play with lock/unlock/restart

Oleg Nesterov oleg at redhat.com
Sun Sep 6 13:50:53 UTC 2009


(fix the subject)

>From the previous changelog:
>
> Once we drop utrace->lock, any other caller which takes this lock must
> see both ->exit_state and utrace->reap. This means utrace_control() or
> utrace_set_events() which sets/clears REAP must not succeed.

IOW, nobody change change engine->ops or REAP bit in flags. Nobody can
add the new engine or remove it from ->attached. We can do all work
lockless and without barriers.

To simplify the review, utrace_reap() becomes:

	static void utrace_reap(struct task_struct *target, struct utrace *utrace)
		__releases(utrace->lock)
	{
		struct utrace_engine *engine;

		splice_attaching(utrace);
		spin_unlock(&utrace->lock);
		/*
		 * We were called with utrace->reap set:
		 * nobody can set/clear UTRACE_EVENT(REAP) in engine->flags or
		 * change engine->ops, and nobody can change utrace->attached.
		 */
		list_for_each_entry(engine, &utrace->attached, entry) {
			if (engine->flags & UTRACE_EVENT(REAP))
				engine->ops->report_reap(engine, target);

			engine->ops = NULL;
			engine->flags = 0;

		}

		put_detached_list(&utrace->attached);
	}

Note that I changed the logic a bit, we set ->ops = NULL after
->report_reap(). Is it OK? If not, it is trivial to change.

Signed-off-by: Oleg Nesterov <oleg at redhat.com>
---

 kernel/utrace.c |   39 ++++++++++++---------------------------
 1 file changed, 12 insertions(+), 27 deletions(-)

--- __UTRACE/kernel/utrace.c~3_NO_LOCKING	2009-09-06 15:09:59.000000000 +0200
+++ __UTRACE/kernel/utrace.c	2009-09-06 15:06:23.000000000 +0200
@@ -408,40 +408,25 @@ static void put_detached_list(struct lis
 static void utrace_reap(struct task_struct *target, struct utrace *utrace)
 	__releases(utrace->lock)
 {
-	struct utrace_engine *engine, *next;
-	const struct utrace_engine_ops *ops;
-	unsigned long flags;
-	LIST_HEAD(detached);
+	struct utrace_engine *engine;
 
-restart:
 	splice_attaching(utrace);
-	list_for_each_entry_safe(engine, next, &utrace->attached, entry) {
-		ops = engine->ops;
-		flags = engine->flags;
+	spin_unlock(&utrace->lock);
+	/*
+	 * We were called with utrace->reap set:
+	 * nobody can set/clear UTRACE_EVENT(REAP) in engine->flags or
+	 * change engine->ops, and nobody can change utrace->attached.
+	 */
+	list_for_each_entry(engine, &utrace->attached, entry) {
+		if (engine->flags & UTRACE_EVENT(REAP))
+			engine->ops->report_reap(engine, target);
+
 		engine->ops = NULL;
 		engine->flags = 0;
-		list_move(&engine->entry, &detached);
 
-		/*
-		 * If it didn't need a callback, we don't need to drop
-		 * the lock.  Now nothing else refers to this engine.
-		 */
-		if (!(flags & UTRACE_EVENT(REAP)))
-			continue;
-
-		spin_unlock(&utrace->lock);
-
-		(*ops->report_reap)(engine, target);
-
-		put_detached_list(&detached);
-
-		spin_lock(&utrace->lock);
-		goto restart;
 	}
 
-	spin_unlock(&utrace->lock);
-
-	put_detached_list(&detached);
+	put_detached_list(&utrace->attached);
 }
 
 /*




More information about the utrace-devel mailing list