Correct way to switch_root

2.6k views Asked by At

I'm having a ton (and a half) of problems setting up booting for my embedded target; situation is:

I have an embedded target with a rather small, but reliable, Flash (16M bytes) and a possibly large (currently 8GB), but rather unreliable, SD card.

Unreliability of SD card is mainly due to hardware setup (direct connection to power supply, so NO WAY to hardware reset it if it wakes up "badly") I cannot change. This is mainly affecting u-boot (Linux handling seems much more stable).

Since I need a relatively high reliability, even during/after software update, I opted for a dial system (update the dormant one, then reboot) with a "recovery" fallback.

Unfortunately I do not have enough space in Flash for a proper initramfs plus a full recovery system, so I'm trying to couple startup system with recovery.

I thus have a full flash system with a small /init script choosing startup mode.

/init script is something like:

#!/bin/ash
set -x
export PATH=/bin:/sbin:/usr/bin:/usr/sbin

boot_prod() {
  mount -t proc none /proc
  mount -t sysfs none /sys

  mount $1 /mnt && [ -x /mnt/sbin/init ] || return 1

  echo "switching to $1"
  cd /mnt
  mount --move /sys sys
  umount /proc # /proc is remounted by BusyBox /dev/inittab
  mount --move /dev dev

  config_set sys $2
  pivot_root . mnt
  umount mnt
  exec chroot . sbin/init <dev/console >dev/console 2>&1
}

case $tryboot; in
A)
  boot_prod /dev/mmcblk0p6 A
  ;;
B)
  boot_prod /dev/mmcblk0p7 B
  ;;
R)
  [ -x /mnt/sbin/init ] && exec /mnt/sbin/init
  ;;
*)
  ;;
esac

echo "Could not boot cleanly; running a shell"
mount -t proc none /proc
mount -t sysfs none /sys
exec setsid cttyhack sh

This is clearly started with bootargs containing tryboot=A/B/R.

I am not using Busybox switch_root because this is not a true initramfs, but a SquashFS living on Flash; my current u-Boot environment includes:

BOOT_A_GOOD=y
BOOT_CURRENT=B
SYSTEM_R=/dev/mtdblock5
boot_a=echo "Loading System A";part=A;run boot_x
boot_b=echo "Loading System B";part=B;run boot_x
boot_now=if test "${BOOT_CURRENT}" = A; then run boot_a; elif test "${BOOT_CURRENT}" = B; then run boot_b; fi; if env exists BOOT_A_GOOD; then run boot_a; fi; if env exists BOOT_B_GOOD; then run boot_b; fi; run boot_r
boot_r=echo "Loading Recovery";part=R;run boot_x
boot_x=setenv bootargs "${default_bootargs} mtdparts=${mtdparts} root=${part}" && bootm bc050000
bootcmd=rub boot_now
bootdelay=2
default_bootargs=earlyprintk rootwait console=ttyS2,115200
mtdids=nor0=spi0.0
mtdparts=spi0.0:312k(u-boot),4k(env),4k(factory),2368k(kernel),-(filesystem)

Current problem is system dies at exec chroot . sbin/init ... with a "Kernel panic - not syncing: Attempted to kill init !" error without printing the "culprit" + exec chroot . sbin/init <dev/console >dev/console 2>&1 line.

Note1: I made sure sbin/init exists on new root fs (it is a symlink to bin/busybox

Note2: Error persists even if I comment out previous umount mnt.

What am I doing wrong?

1

There are 1 answers

1
W Dean Stanton On

I have more experience with switch_root than pivot_root.

Attempted to kill init !

This means that the process with PID 1 exited or was killed. (PID 1 is called "init" because it is typically /init in an initial RAM disk.)

Does /mnt/sbin/init ever end or exit?