Re: Question on conversion from initrd to initramfs (1/2027 initrd support drop from kernel)
Jody Bruchon via busybox <[email protected]>
| Newsgroups | gmane.linux.busybox |
|---|---|
| Message-ID | <[email protected]> |
10+ years ago, I wanted to switch from initrd to initramfs. I had an
extremely difficult time getting it all correct because switch_root has
a lot of extremely specific requirements that you must meet before
calling it, and any failure immediately after calling switch_root can be
notoriously hard to debug. It's also critical that you use "cpio -o -H
newc" to make the initramfs, then any compression format that your
kernel supports can be used to compress it.
I don't mean to publicly advertise my work (mostly because I figured all
this out a long time ago and I'm sure some of it isn't up to my current
scripting standards) but I'm hoping that revealing some of my "secret
sauce" will help you (and others) figure out how to do it correctly.
PLEASE FEEL FREE TO STEAL THIS CODE! I am perfectly fine with you using
it however you please. I've attached the init "wrapper" script to place
in the root directory of the initramfs that unpacks the "real" tmpfs
root and switches to it, and below I'll paste the "make it" snippet that
packs my skeleton initramfs + packages (tarballs to unpack in the new
root directory) into an "initrd.gz" (really an initramfs but I conform
to DOS file restrictions for old boot loaders like SYSLINUX) that the
kernel understands. (TSS is "Tritech Service System," my custom
"embedded" Linux system I use for PC repair and maintenance.)
You can basically shove your existing initrd contents into a directory
containing the /init and cd into it and use "find . | cpio -o -H newc |
gzip -9 > initrd.gz" to make self-unpacking initramfs that changes from
a ramfs into a tmpfs (you care about this, TRUST ME) and executes
whatever init you choose (in the init wrapper change INIT=/init to
INIT=/sbin/init for sysvinit etc). Let me know if this is helpful! I
always like to know that someone else didn't suffer like I did.
--- snip ---
cp "$TSSDIR/kernels/modules-tss-std-$ARCH.tar.xz"
$DEST_FS/packages/modules-tss-std-${ARCH}_1.pkg.tar.xz
cp "$TSSDIR/kernels/firmware.tar.xz"
$DEST_FS/packages/firmware_1-all.pkg.tar.xz
cp "$TSSPKGDIR/$ARCH"/tritech-utils_* $DEST_FS/packages/
cp "$TSSPKGDIR/all"/tss-base-fs_* $DEST_FS/packages/
cp "$TSSPKGDIR/all"/tss-init_* $DEST_FS/packages/
cp "$TSSPKGDIR/all"/tss-configuration_* $DEST_FS/packages/
# Update early init script and build initramfs images in parallel
test -e init && cp -f init $DEST_FS/init && chmod 755 $DEST_FS/init
cd "$DEST_FS"
find . | cpio -o -H newc 2>/dev/null | gzip -9 >
$TSSDIR/initramfs/initramfs1-$ARCH.gz &
WAITS="$WAITS $!"
find . | \
grep -v '\./packages/modules-tss-.*\.tar\..*' | \
grep -v '\./packages/firmware\.tar\..*' | \
cpio -o -H newc 2>/dev/null | gzip -9 >
$TSSDIR/initramfs/initramfs2-$ARCH.gz &
WAITS="$WAITS $!"
--- snip ---
On 2026-03-04 2:16 PM, Michael D. Setzer II via busybox wrote:
> In doing a test with kernel 7.0.rc1 and later 7.0.rc2 noticed dmesg
> lines about initrd support being removed by 1/2027. So looked into
> doing the conversion.
>
> Tried about 20 things I found online, but many resulted in kernel
> panics. But final working solution resulted in minor changes.
>
> Original method would create ramdisk.lzma from a directory
> structor and the new method creates initramfs.lzma.
>
> Then changes included creating an init file that is a link to the
> origina etc/init.d/rcS2 which has one line added to end the earlier
> rcS init file. (Old setup goes back to 2004, when I took over
> project).
>
> The added line is.
> exec /sbin/init
>
> Seems that is to keep PID 1 running?
>
> Other change was to comment first line of
> cat etc/inittab
>
> #::sysinit:/etc/init.d/rcS
> ::ctrlaltdel:/sbin/reboot
> tty1::respawn:/bin/login g4l
> tty2::askfirst:/bin/login
> tty3::askfirst:/bin/login
> tty4::askfirst:/bin/login
> tty5::askfirst:/bin/login
>
> Then only change I've noted is that under old initrd boot the df
> command would show this
> Filesystem 1K-blocks Used Available Use% Mounted on
> /dev/root.old 127507 75746 51761 59% /
> with initramfs get this.
> Filesystem 1K-blocks Used Available Use% Mounted on
>
> The initramfs starts by this
> echo "Packing rootfs into cpio archive"
> (
> cd bootcd/rootfs
> # Include hidden files (.bash_profile etc.) via find so nothing is
> missed.
> find . | cpio --quiet -o -H newc
> ) > bootcd/isolinux/ramdisk.cpio
>
> later the is compressed
> lzma -v bootcd/isolinux/ramdisk.cpio
> mv bootcd/isolinux/ramdisk.cpio.lzma /boot/initramfs.lzma
> (will clean files names soon).
>
> So loading kernel and initramfs.lzma works from
> syslinux booting with hybrid image via cd or usb
> grub4dos bios and uefi usbs
> grub directly.
>
> linux /bz6x19.5
> initrd /initramfs.lzma
>
> Don't know if I missed anything? Or did something not necessary.
> Thanks.
>
>
> +------------------------------------------------------------+
> Michael D. Setzer II - Computer Science Instructor (Retired)
> mailto:[email protected]
> mailto:[email protected]
> mailto:[email protected]
> Guam - Where America's Day Begins
> G4L Disk Imaging Project maintainer
> http://sourceforge.net/projects/g4l/
> +------------------------------------------------------------+
>
>
>
> _______________________________________________
> busybox mailing list
> [email protected]
> https://lists.busybox.net/mailman/listinfo/busybox
_______________________________________________
busybox mailing list
[email protected]
https://lists.busybox.net/mailman/listinfo/busybox
init
(text/plain, 5.6 KB)
#!/bin/sh
# Wrapper init script for Tritech Service System
# Version 1.6 (2018-07-21)
# This script is responsible for unpacking the system
# into a tmpfs instance and switching into it.
# We must do this because initramfs is a ramfs instance
# which will crash the system if it accidentally fills.
# Packages that make up the system are put into place
# by this script, including kernel modules and firmware.
# The general procedure is as follows:
# 1. Mount a tmpfs instance to unpack to
# 2. Copy critical packages that are included in the wrapper
# to the tmpfs instance
# 3. Unpack package files in wrapper's /packages folder
# 4. Unpack kernel modules and firmware
# 5. Copy the home skeleton archive to the /etc/init folder
# 6. Switch into the tmpfs root permanently.
# If the last step fails, a failsafe shell will launch.
# Failsafe shell if init terminates prematurely
trap 'exec /bin/sh' EXIT
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
mkdir -p /proc /sys /dev /mnt
mount -t devtmpfs devtmpfs /dev
mount -t proc proc /proc
mount -t sysfs sysfs /sys
# Set all CPUs to maximum performance (if possible)
for X in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
do
test -e "$X" && echo "$MODE" > $X 2>/dev/null
done
V=0
INIT=/init
for X in $(tr ' ' '\n' < /proc/cmdline)
do case $X in
debug-init) V=1; echo "TSS init debugging enabled" ;;
root=*) ROOT=$(echo $X | sed 's/.*=//') ;;
init=*) INIT=$(echo $X | sed 's/.*=//') ;;
esac
done
# Root filesystem override capability for supporting "traditional" roots.
if [ ! -z "$ROOT" ]
then echo "Root device override: $ROOT"
# Linux allows mount by UUID but we need to verify it exists before trying.
test ! -e $ROOT && ROOT=$(blkid | grep -i "UUID=\"$ROOT\"" | sed 's/:.*//')
if [ -e $ROOT ]
then mount -t auto $ROOT /mnt && \
unset V X lzo gz bz2 xz lzma FLIST DECOMP ROOT BN && \
umount /proc /sys /dev 2>/dev/null && \
test -x /mnt/$INIT && exec /sbin/switch_root /mnt $INIT "$@"
echo "WARNING: Could not mount specified root device."
else echo "WARNING: Could not mount specified root device."
fi
fi
# Set up compressed swap for very low memory systems
setup_zramswap () {
SZ=/sys/block/zram0
DEV=/dev/zram0
RAM=$(grep MemTotal /proc/meminfo | awk '{print $2}')
grep -q "zramswap" /proc/cmdline || test $RAM -gt 500000
echo $(expr $RAM \* 1024) > $SZ/disksize
test ! -e $DEV && mknod $DEV b $(cat $SZ/dev | tr ":" " ")
mkswap $DEV 2>/dev/null >/dev/null
swapon $DEV 2>/dev/null >/dev/null
unset DEV SZ RAM
}
### End functions
# For low memory systems, we need zram swap working as soon as possible
setup_zramswap
# Mount tmpfs into which the system will be unpacked
mount -t tmpfs newroot /mnt -o size=80%
mkdir -p /mnt/packages/installed
# Be resilient if normal compression tools aren't present
test -x /usr/bin/unxz && xz='/usr/bin/unxz -c'
test -x /usr/bin/xz && xz='/usr/bin/xz -dc'
test -x /usr/bin/unlzop && lzo='/usr/bin/unlzop -c'
test -x /bin/lzop && lzo='/bin/lzop -dc'
test -x /usr/bin/lzop && lzo='/usr/bin/lzop -dc'
test -x /bin/gunzip && gz='/bin/gunzip -c'
test -x /bin/gzip && gz='/bin/gzip -dc'
test -x /usr/bin/gzip && gz='/usr/bin/gzip -dc'
test -x /bin/bunzip2 && bz2='/bin/bunzip2 -c'
test -x /bin/bzip2 && bz2='/bin/bzip2 -dc'
test -x /usr/bin/bzip2 && bz2='/usr/bin/bzip2 -dc'
echo -n "Loading: "
# For packages included in this wrapper, the package files
# need to be copied to the new root manually to achieve
# the same effect as if they were unpacked normally.
# The fastest way to do this is to tar and untar with
# a pipe since it can use lists.
for X in /packages/installed/*
do echo -n "."
cp "$X" "/mnt/$X"
tar -c -T "$X" 2>/dev/null | tar -C /mnt -xp 2>/dev/null || echo -n "[ERROR]"
done
for X in /packages/*.pkg.tar.* /modules.* /firmware.*
do
if [ -e "$X" ]
then echo -n "."
BN="$(basename "$X")"
DECOMP="$(echo "$BN" | sed 's/.*\.//')"
test "$DECOMP" = "txz" && DECOMP="xz"
DECOMP="$(eval "echo \$$DECOMP")"
FLIST="/mnt/packages/installed/$(echo "$BN" | sed 's/\.pkg\.tar\.[a-z]*$//')"
if eval $DECOMP "$X" | tar -C /mnt -xvp > $FLIST 2>/dev/null
then rm -f "$X"
else return 1
fi
fi
done
mkdir -p /mnt/lib/modules/$(/bin/uname -r)
echo -n "."
test -e /home-skel.tar.gz && mv /home-skel.tar.gz /mnt/etc/init/
echo -n "."
test -e /mnt/etc/tss/version && rm -f /mnt/etc/tss/version
mv /version /mnt/etc/tss/
echo 'party time! =)'
# BusyBox init fallback support
for X in 1 2 3 4
do test ! -e /mnt/dev/tty$X && mknod /mnt/dev/tty$X c 4 $X
done
test ! -x /mnt/etc/init.d/rcS && mkdir -p /mnt/etc/init.d && ln -s /bin/sh /mnt/etc/init.d/rcS
test "$V" = "1" && echo -e "\nEarly init debug shell." && /bin/sh
unset V X lzo gz bz2 xz lzma FLIST DECOMP ROOT
umount /proc /sys
# Switch into new root. This should generally never fail.
test -x /mnt/$INIT && exec /sbin/switch_root /mnt $INIT "$@"
# If there is no /init present, try /sbin/init
test -x /mnt/sbin/init && exec /sbin/switch_root /mnt /sbin/init "$@"
# Fall back to shells in the new root if that doesn't work out
echo "switch_root apparently could not run /init or /sbin/init"
echo "Trying to run a shell in the new root instead..."
test -x /mnt/bin/bash && exec /sbin/switch_root /mnt /bin/bash "$@"
test -x /mnt/bin/sh && exec /sbin/switch_root /mnt /bin/sh "$@"
###############################################################
# This section should never be reached.
echo "For some reason, switch_root couldn't be done at all."
echo "Since we can't proceed further because something is"
echo "wrong, you're getting dropped into an infinitely"
echo "respawning shell. Apologies for this awful inconvenience."
while true
do sleep 1
/bin/sh
done