- the code now uses completions instead of a semaphore and a waitqueue,
  attached to mm_struct:
        /* coredumping support */
        int core_waiters;
        struct completion *core_startup_done, core_done;
- extended the completion concept with a 'complete all' call - all pending
  threads are woken up in that case.
- core_waiters is a plain integer now - it's always accessed from under
  the mmap_sem. It's also used as the fastpath-check in the sys_exit() 
  path, instead of ->dumpable (which was incorrect).
- got rid of the ->core_waiter task flag - it's not needed anymore.
	Ingo
--- linux/fs/exec.c.orig	2002-12-02 08:36:35.000000000 +0100
+++ linux/fs/exec.c	2002-12-02 14:48:57.000000000 +0100
@@ -1235,49 +1235,58 @@
 {
 	struct task_struct *g, *p;
 
-	/* give other threads a chance to run: */
-	yield();
-
 	read_lock(&tasklist_lock);
 	do_each_thread(g,p)
-		if (mm == p->mm && !p->core_waiter)
+		if (mm == p->mm && p != current) {
 			force_sig_specific(SIGKILL, p);
+			mm->core_waiters++;
+		}
 	while_each_thread(g,p);
+
 	read_unlock(&tasklist_lock);
 }
 
 static void coredump_wait(struct mm_struct *mm)
 {
-	DECLARE_WAITQUEUE(wait, current);
+	DECLARE_COMPLETION(startup_done);
+
+	mm->core_waiters++; /* let other threads block */
+	mm->core_startup_done = &startup_done;
+
+	/* give other threads a chance to run: */
+	yield();
 
-	atomic_inc(&mm->core_waiters);
-	add_wait_queue(&mm->core_wait, &wait);
 	zap_threads(mm);
-	current->state = TASK_UNINTERRUPTIBLE;
-	if (atomic_read(&mm->core_waiters) != atomic_read(&mm->mm_users))
-		schedule();
-	else
-		current->state = TASK_RUNNING;
+	if (--mm->core_waiters) {
+		up_write(&mm->mmap_sem);
+		wait_for_completion(&startup_done);
+	} else
+		up_write(&mm->mmap_sem);
+	BUG_ON(mm->core_waiters);
 }
 
 int do_coredump(long signr, struct pt_regs * regs)
 {
-	struct linux_binfmt * binfmt;
 	char corename[CORENAME_MAX_SIZE + 1];
-	struct file * file;
+	struct mm_struct *mm = current->mm;
+	struct linux_binfmt * binfmt;
 	struct inode * inode;
+	struct file * file;
 	int retval = 0;
 
 	lock_kernel();
 	binfmt = current->binfmt;
 	if (!binfmt || !binfmt->core_dump)
 		goto fail;
-	if (!current->mm->dumpable)
+	down_write(&mm->mmap_sem);
+	if (!mm->dumpable) {
+		up_write(&mm->mmap_sem);
 		goto fail;
-	current->mm->dumpable = 0;
-	if (down_trylock(¤t->mm->core_sem))
-		BUG();
-	coredump_wait(current->mm);
+	}
+	mm->dumpable = 0;
+	init_completion(&mm->core_done);
+	coredump_wait(mm);
+
 	if (current->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump)
 		goto fail_unlock;
 
@@ -1305,7 +1314,7 @@
 close_fail:
 	filp_close(file, NULL);
 fail_unlock:
-	up(¤t->mm->core_sem);
+	complete_all(&mm->core_done);
 fail:
 	unlock_kernel();
 	return retval;
--- linux/include/linux/sched.h.orig	2002-12-02 09:48:09.000000000 +0100
+++ linux/include/linux/sched.h	2002-12-02 14:43:49.000000000 +0100
@@ -203,9 +203,8 @@
 	mm_context_t context;
 
 	/* coredumping support */
-	struct semaphore core_sem;
-	atomic_t core_waiters;
-	wait_queue_head_t core_wait;
+	int core_waiters;
+	struct completion *core_startup_done, core_done;
 
 	/* aio bits */
 	rwlock_t		ioctx_list_lock;
@@ -397,8 +396,6 @@
 	void *journal_info;
 	struct dentry *proc_dentry;
 	struct backing_dev_info *backing_dev_info;
-/* threaded coredumping support */
-	int core_waiter;
 
 	unsigned long ptrace_message;
 };
--- linux/include/linux/completion.h.orig	2002-12-02 14:05:12.000000000 +0100
+++ linux/include/linux/completion.h	2002-12-02 14:05:17.000000000 +0100
@@ -29,6 +29,7 @@
 
 extern void FASTCALL(wait_for_completion(struct completion *));
 extern void FASTCALL(complete(struct completion *));
+extern void FASTCALL(complete_all(struct completion *));
 
 #define INIT_COMPLETION(x)	((x).done = 0)
 
--- linux/kernel/sched.c.orig	2002-12-02 13:54:08.000000000 +0100
+++ linux/kernel/sched.c	2002-12-02 14:06:13.000000000 +0100
@@ -1192,6 +1192,16 @@
 	spin_unlock_irqrestore(&x->wait.lock, flags);
 }
 
+void complete_all(struct completion *x)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&x->wait.lock, flags);
+	x->done += UINT_MAX/2;
+	__wake_up_common(&x->wait, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 0, 0);
+	spin_unlock_irqrestore(&x->wait.lock, flags);
+}
+
 void wait_for_completion(struct completion *x)
 {
 	might_sleep();
--- linux/kernel/exit.c.orig	2002-12-02 09:50:27.000000000 +0100
+++ linux/kernel/exit.c	2002-12-02 14:44:31.000000000 +0100
@@ -425,14 +425,13 @@
 	/*
 	 * Serialize with any possible pending coredump:
 	 */
-	if (!mm->dumpable) {
-		current->core_waiter = 1;
-		atomic_inc(&mm->core_waiters);
-		if (atomic_read(&mm->core_waiters) ==atomic_read(&mm->mm_users))
-			wake_up(&mm->core_wait);
-		down(&mm->core_sem);
-		up(&mm->core_sem);
-		atomic_dec(&mm->core_waiters);
+	if (mm->core_waiters) {
+		down_write(&mm->mmap_sem);
+		if (!--mm->core_waiters)
+			complete(mm->core_startup_done);
+		up_write(&mm->mmap_sem);
+
+		wait_for_completion(&mm->core_done);
 	}
 	atomic_inc(&mm->mm_count);
 	if (mm != tsk->active_mm) BUG();
--- linux/kernel/fork.c.orig	2002-12-02 09:54:59.000000000 +0100
+++ linux/kernel/fork.c	2002-12-02 14:43:59.000000000 +0100
@@ -328,9 +328,7 @@
 	atomic_set(&mm->mm_users, 1);
 	atomic_set(&mm->mm_count, 1);
 	init_rwsem(&mm->mmap_sem);
-	init_MUTEX(&mm->core_sem);
-	init_waitqueue_head(&mm->core_wait);
-	atomic_set(&mm->core_waiters, 0);
+	mm->core_waiters = 0;
 	mm->page_table_lock = SPIN_LOCK_UNLOCKED;
 	mm->ioctx_list_lock = RW_LOCK_UNLOCKED;
 	mm->default_kioctx = (struct kioctx)INIT_KIOCTX(mm->default_kioctx, *mm);
@@ -799,7 +797,6 @@
 	p->start_time = jiffies;
 	p->security = NULL;
 
-	p->core_waiter = 0;
 	retval = -ENOMEM;
 	if (security_task_alloc(p))
 		goto bad_fork_cleanup;
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/