Skip to contentSkip to conversation

2.4 and 2.5: remove Alt-Sysrq-L

PATCH Nicholas Berry 4 participants 6 messages Mar 15, 2002 – Mar 20, 2002

lore
Share & tools
lore
#0 lore raw
Quoted 3 lines

I distinctly recall it working perfectly OK in around 2.1.50. I had boxen where /sbin/init was a shell script which would bring up the interfaces, enable routing, and exit.

That's a different thing, I think.

That is, 'init exiting' versus 'all the code to prevent init being killed is bypassed and init is killed'

#1 lore raw
Quoted 8 lines · Nicholas Berry
Quoted 3 lines

I distinctly recall it working perfectly OK in around 2.1.50. I had boxen where /sbin/init was a shell script which would bring up the interfaces, enable routing, and exit.

That's a different thing, I think.

That is, 'init exiting' versus 'all the code to prevent init being killed is bypassed and init is killed'

Very true.

With all recent kernels, init exiting causes the last of these to trigger:

NORET_TYPE void do_exit(long code)

{
        struct task_struct *tsk = current;

        if (in_interrupt())
                panic("Aiee, killing interrupt handler!");
        if (!tsk->pid)
                panic("Attempted to kill the idle task!");
        if (tsk->pid == 1)
                panic("Attempted to kill init!");

It is this very test that Alt-SysRQ-L is attempting to bypass which causes the problem.

Signature · 2 lines
Russell King ([email protected])                The developer of ARM Linux
             http://www.arm.linux.org.uk/personal/aboutme.html
#2 lore raw
In reply to Nicholas Berry
Quoted 4 lines · Russell King

With all recent kernels, init exiting causes the last of these to trigger:

NORET_TYPE void do_exit(long code)

Quoted 9 lines
{
        struct task_struct *tsk = current;

        if (in_interrupt())
                panic("Aiee, killing interrupt handler!");
        if (!tsk->pid)
                panic("Attempted to kill the idle task!");
        if (tsk->pid == 1)
                panic("Attempted to kill init!");

Why actually panic because of an attempt to kill init?

Of course a message should be printed, but after that couldn't do_exit enter a loop where it just handles signals and zombies?

Signature · 2 lines
Kasper Dupont -- der bruger for meget tid på usenet.
For sending spam use mailto:[email protected]
#3 lore raw
In reply to Nicholas Berry
Quoted 15 lines · Kasper Dupont
Quoted 4 lines · Russell King

With all recent kernels, init exiting causes the last of these to trigger:

NORET_TYPE void do_exit(long code)

Quoted 9 lines
{
        struct task_struct *tsk = current;

        if (in_interrupt())
                panic("Aiee, killing interrupt handler!");
        if (!tsk->pid)
                panic("Attempted to kill the idle task!");
        if (tsk->pid == 1)
                panic("Attempted to kill init!");
Quoted 5 lines

Why actually panic because of an attempt to kill init?

Of course a message should be printed, but after that couldn't do_exit enter a loop where it just handles signals and zombies?

Examine the LKML archive around 23rd December 2001, where Alan Cox wrote:

| pid1 ends up trying to kill pid1 and it goes deeply down the toilet from | that point onwards. The Unix traditional world reboots when pid 1 dies.

Signature · 2 lines
Russell King ([email protected])                The developer of ARM Linux
             http://www.arm.linux.org.uk/personal/aboutme.html
#4 lore raw
In reply to Nicholas Berry
Quoted 5 lines · Russell King
Quoted 3 lines · Kasper Dupont

Why actually panic because of an attempt to kill init?

Quoted 8 lines
Quoted 3 lines

Of course a message should be printed, but after that couldn't do_exit enter a loop where it just handles signals and zombies?

Examine the LKML archive around 23rd December 2001, where Alan Cox wrote:

| pid1 ends up trying to kill pid1 and it goes deeply down the toilet from | that point onwards. The Unix traditional world reboots when pid 1 dies.

Thank you for pointing that out. But I'm afraid it doesn't answer my question. I understand that a system where init has died cannot be expected to continue working like if nothing was wrong.

What to do in this case might be a matter of taste, of course a panic or a reboot does make sense. But trying to recover as much as posible would also make sense. This could be caused by a problem in userspace, the kernel does not have to be corrupted already.

If we agree that this is a matter of taste lets not try to argue about whose taste is the best.

I was really just wondering if the patch below would work. Well I just tested it, and it did work like I expected. If I killed init (by replacing /sbin/init with something else and telling init to reexecute itself) I got the warning. But the system continued to work.

Of course init would no longer respawn processes, and I could not change runlevel. But I could login, kill processes, and remount filesystems read-only. And no processes became zombies.

Signature · 2 lines
Kasper Dupont -- der bruger for meget tid på usenet.
For sending spam use mailto:[email protected]
exit.c renamed from exit.c~ +36 -2
@@ -429,6 +429,38 @@
 	write_unlock_irq(&tasklist_lock);
 }
 
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+NORET_TYPE void flush_child_loop(struct task_struct *curtask)
+{
+	struct k_sigaction sa;
+	daemonize();
+
+	spin_lock_irq(&curtask->sigmask_lock);
+	siginitsetinv(&curtask->blocked, sigmask(SIGCHLD));
+	recalc_sigpending(curtask);
+	spin_unlock_irq(&curtask->sigmask_lock);
+
+	/* Install a handler so SIGCLD is delivered */
+	sa.sa.sa_handler = SIG_IGN;
+	sa.sa.sa_flags = 0;
+	siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD));
+	do_sigaction(SIGCHLD, &sa, (struct k_sigaction *)0);
+
+	for (;;) {
+		set_task_state(curtask, TASK_INTERRUPTIBLE);
+		schedule();
+		if (signal_pending(curtask)) {
+			while (waitpid(-1, (unsigned int *)0, __WALL|WNOHANG) > 0)
+				;
+			spin_lock_irq(&curtask->sigmask_lock);
+			flush_signals(curtask);
+			recalc_sigpending(curtask);
+			spin_unlock_irq(&curtask->sigmask_lock);
+		}
+	}
+}
+
 NORET_TYPE void do_exit(long code)
 {
 	struct task_struct *tsk = current;
@@ -437,8 +469,10 @@
 		panic("Aiee, killing interrupt handler!");
 	if (!tsk->pid)
 		panic("Attempted to kill the idle task!");
-	if (tsk->pid == 1)
-		panic("Attempted to kill init!");
+	if (tsk->pid == 1) {
+		printk(KERN_EMERG "Attempted to kill init!\n");
+		flush_child_loop(tsk);
+	}
 	tsk->flags |= PF_EXITING;
 	del_timer_sync(&tsk->real_timer);
 
#5 lore raw

exit.c line 475

Quoted 5 lines
exit.c renamed from exit.c~ +4 -1
-		panic("Attempted to kill init!");
+	if (tsk->pid == 1) {
+		printk(KERN_EMERG "Attempted to kill init!\n");
+		flush_child_loop(tsk);
+	}

This can occur in IRQ path - your code won't handle that. Otherwise it seems to have potential