
From: Rusty Russell <rusty@rustcorp.com.au>

Prevent errors in boot when cpus_possible() contains a cpu which is not
online (ie.  a cpu didn't come up).  This doesn't happen on x86, since a
boot failure makes that CPU no longer possible (hacky, but it works).

When the cpu fails to come up, some callbacks do kthread_stop(), which
doesn't work without keventd (which hasn't started yet).  Call it directly,
and take care that it restores signal state (note: do_sigaction does a
flush on blocked signals, so we don't need to repeat it).



---

 kernel/kthread.c |   27 +++++++++++++++------------
 1 files changed, 15 insertions(+), 12 deletions(-)

diff -puN kernel/kthread.c~kthread-handle-non-booting-CPUs kernel/kthread.c
--- 25/kernel/kthread.c~kthread-handle-non-booting-CPUs	2004-02-16 23:40:30.000000000 -0800
+++ 25-akpm/kernel/kthread.c	2004-02-16 23:40:30.000000000 -0800
@@ -101,15 +101,16 @@ static void keventd_stop_kthread(void *_
 {
 	struct kthread_stop_info *stop = _stop;
 	int status, pid;
-	sigset_t blocked;
-	struct k_sigaction sa;
+	sigset_t chldonly, oldset;
+	struct k_sigaction sa, oldsa;
 
 	/* Install a handler so SIGCHLD is actually delivered */
 	sa.sa.sa_handler = SIG_DFL;
 	sa.sa.sa_flags = 0;
 	siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD));
-	do_sigaction(SIGCHLD, &sa, (struct k_sigaction *)0);
-	allow_signal(SIGCHLD);
+	siginitset(&chldonly, sigmask(SIGCHLD));
+	do_sigaction(SIGCHLD, &sa, &oldsa);
+	sigprocmask(SIG_UNBLOCK, &chldonly, &oldset);
 
 	adopt_kthread(stop->k);
 	/* Grab pid now: after waitpid(), stop->k is invalid. */
@@ -124,12 +125,9 @@ static void keventd_stop_kthread(void *_
 	stop->result = -((status >> 8) & 0xFF);
 	complete(&stop->done);
 
-	/* Back to normal: block and flush all signals */
-	sigfillset(&blocked);
-	sigprocmask(SIG_BLOCK, &blocked, NULL);
-	flush_signals(current);
-	sa.sa.sa_handler = SIG_IGN;
-	do_sigaction(SIGCHLD, &sa, (struct k_sigaction *)0);
+	/* Return to normal, then reap any children who died in the race. */
+	sigprocmask(SIG_SETMASK, &oldset, NULL);
+	do_sigaction(SIGCHLD, &oldsa, NULL);
 	while (waitpid(-1, &status, __WALL|WNOHANG) > 0);
 }
 
@@ -180,7 +178,12 @@ int kthread_stop(struct task_struct *k)
 	stop.k = k;
 	init_completion(&stop.done);
 
-	schedule_work(&work);
-	wait_for_completion(&stop.done);
+	/* At boot, if CPUs fail to come up, this happens. */
+	if (!keventd_up())
+		work.func(work.data);
+	else {
+		schedule_work(&work);
+		wait_for_completion(&stop.done);
+	}
 	return stop.result;
 }

_
