Subject: kern/35699: root-on-md can panic with "panic: init died"
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: Simon Burge <simonb@NetBSD.org>
List: netbsd-bugs
Date: 02/19/2007 06:55:00
>Number:         35699
>Category:       kern
>Synopsis:       root-on-md can panic with "panic: init died"
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon Feb 19 06:55:00 +0000 2007
>Originator:     Simon Burge
>Release:        -current from mid Feb 2007
>Organization:
>Environment:
	PowerPC ports, maybe others?
>Description:

        I've found a problem where starting up a PPC system with root on
        a md(4) memory disk gets:

Process (pid 1) got signal 6
panic: init died (signal 0, exit 1)

        while trying to start up.  I've tracked this down to this change
        in kern_sysctl.c:

revision 1.191
date: 2006/03/15 16:12:07;  author: drochner;  state: Exp;  lines: +10 -2
branches:  1.191.2;
Check the "oldlen" argument to sysctl(2) before passing it
to vslock(9). This prevents a local DOS.
(The checks against system and user limits for wired
memory should be centralized in UVM; for now prefer a less
invasive fix which can be pulled pulled up into releases.)

	which is:

        if (l != NULL && oldp != NULL && savelen) {
+               /*
+                * be lazy - memory is locked for short time only, so
+                * just do a basic check against system limit
+                */
+               if (uvmexp.wired + atop(savelen) > uvmexp.wiredmax) {
+                       lockmgr(&sysctl_treelock, LK_RELEASE, NULL);
+                       return (ENOMEM);
+               }
                error = uvm_vslock(l->l_proc, oldp, savelen, VM_PROT_WRITE);

        What's happening is that uvmexp.wiredmax is initialised by the
        pagedaemon kthread, and with root-on-md the pagedaemon thread
        hasn't had a chance to run.  This means that sysctl_lock()
        decides it can't lock down any memory so the machdep.cacheinfo
        sysctl fails, and syncicache() calls abort() because it's not
        happy.

        Usually, this system uses root-on-NFS and while we're waiting
        for the dhcp dance to finish, the pagedaemon thread runs and
        sets up uvmexp.wiredmax before /sbin/init starts.

        With root-on-md there's no delays before /sbin/init starts
        up.  There are no disks or USB or any devices that would be
        configured in config_interrupts() which can also introduce a
        delay for the pagedaemon thread to run - another PPC system that
        has a USB bus boots up fine with root-on-md, but init fails the
        same way if USB is removed from the kernel config file.

>How-To-Repeat:

        Make a root-on-md system that has nothing "fancy" configured
        with config_interrupts().

>Fix:

        The patch I'm using to work around this is:

-               if (uvmexp.wired + atop(savelen) > uvmexp.wiredmax) {
+               if (uvmexp.wiredmax &&
+                   uvmexp.wired + atop(savelen) > uvmexp.wiredmax) {

        but this obviously isn't right.

        I'm not sure if the correct fix is to call uvmpd_tune() (in
        uvm_pdaemon.c) before kthreads run, or have something like
        uvm_page_physload() update uvmexp.wiredmax directly?  Or maybe
        changes in sysctl_lock()?