Subject: booting with root-on-md and "panic: init died"
To: None <tech-kern@netbsd.org>
From: Simon Burge <simonb@NetBSD.org>
List: tech-kern
Date: 02/17/2007 01:35:53
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.
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()?
Anyone have any ideas on what the right way to do this is?
Cheers,
Simon.