From abf81c8c676bb8997efe4d92a6e4369dcdd6961a Mon Sep 17 00:00:00 2001 From: Bruce Ashfield Date: Fri, 23 Jan 2026 15:46:16 -0500 Subject: vcontainer: add tiny initramfs image infrastructure Add proper Yocto image recipes for the tiny initramfs used by vdkr/vpdmn in the switch_root boot flow: - vcontainer-tiny-initramfs-image.inc: Shared image configuration - vcontainer-preinit_1.0.bb: Preinit script package (shared) - vdkr-tiny-initramfs-image.bb: Tiny initramfs for vdkr - vpdmn-tiny-initramfs-image.bb: Tiny initramfs for vpdmn The tiny initramfs contains only busybox and a preinit script that: 1. Mounts devtmpfs, proc, sysfs 2. Mounts the squashfs rootfs.img from /dev/vda 3. Creates tmpfs overlay for writes 4. Performs switch_root to the real rootfs This replaces ad-hoc file extraction with proper image-based builds, improving reproducibility and maintainability. Signed-off-by: Bruce Ashfield --- .../vcontainer/files/vcontainer-preinit.sh | 133 +++++++++++++++++++++ .../vcontainer/files/vdkr-preinit.sh | 133 --------------------- .../vcontainer/vcontainer-preinit_1.0.bb | 43 +++++++ .../vcontainer/vcontainer-tiny-initramfs-image.inc | 70 +++++++++++ .../vcontainer/vdkr-tiny-initramfs-image.bb | 13 ++ .../vcontainer/vpdmn-tiny-initramfs-image.bb | 13 ++ 6 files changed, 272 insertions(+), 133 deletions(-) create mode 100644 recipes-containers/vcontainer/files/vcontainer-preinit.sh delete mode 100644 recipes-containers/vcontainer/files/vdkr-preinit.sh create mode 100644 recipes-containers/vcontainer/vcontainer-preinit_1.0.bb create mode 100644 recipes-containers/vcontainer/vcontainer-tiny-initramfs-image.inc create mode 100644 recipes-containers/vcontainer/vdkr-tiny-initramfs-image.bb create mode 100644 recipes-containers/vcontainer/vpdmn-tiny-initramfs-image.bb (limited to 'recipes-containers/vcontainer') diff --git a/recipes-containers/vcontainer/files/vcontainer-preinit.sh b/recipes-containers/vcontainer/files/vcontainer-preinit.sh new file mode 100644 index 00000000..6f1b7e09 --- /dev/null +++ b/recipes-containers/vcontainer/files/vcontainer-preinit.sh @@ -0,0 +1,133 @@ +#!/bin/sh +# SPDX-FileCopyrightText: Copyright (C) 2025 Bruce Ashfield +# +# SPDX-License-Identifier: GPL-2.0-only +# +# vcontainer-preinit.sh +# Minimal init for initramfs - mounts rootfs and does switch_root +# +# This script runs from the initramfs and: +# 1. Mounts essential filesystems +# 2. Finds and mounts the rootfs.img (squashfs, read-only) +# 3. Creates overlayfs with tmpfs for writes +# 4. Executes switch_root to the overlay root filesystem +# +# The real init (/init or /sbin/init on rootfs) then continues boot + +# Mount essential filesystems first (needed to check cmdline) +mount -t proc proc /proc +mount -t sysfs sysfs /sys +mount -t devtmpfs devtmpfs /dev + +# Check for quiet mode (interactive) +QUIET=0 +for param in $(cat /proc/cmdline 2>/dev/null); do + case "$param" in + docker_interactive=1) QUIET=1 ;; + esac +done + +log() { + [ "$QUIET" = "0" ] && echo "$@" +} + +log "=== vcontainer preinit (squashfs) ===" + +# Wait for block devices to appear +log "Waiting for block devices..." +sleep 2 + +# Show available block devices +log "Block devices:" +[ "$QUIET" = "0" ] && ls -la /dev/vd* 2>/dev/null || log "No virtio block devices found" + +# The rootfs.img is always the first virtio-blk device (/dev/vda) +# Additional devices (input, state) come after +ROOTFS_DEV="/dev/vda" + +if [ ! -b "$ROOTFS_DEV" ]; then + echo "ERROR: Rootfs device $ROOTFS_DEV not found!" + echo "Available devices:" + ls -la /dev/ + sleep 10 + reboot -f +fi + +# Create mount points for overlay setup +mkdir -p /mnt/lower # squashfs (read-only) +mkdir -p /mnt/upper # tmpfs for overlay upper +mkdir -p /mnt/work # tmpfs for overlay work +mkdir -p /mnt/root # final overlayfs mount + +# Mount squashfs read-only +log "Mounting squashfs rootfs from $ROOTFS_DEV..." + +if ! mount -t squashfs -o ro "$ROOTFS_DEV" /mnt/lower; then + # Fallback to ext4 for backwards compatibility + log "squashfs mount failed, trying ext4..." + if ! mount -t ext4 -o ro "$ROOTFS_DEV" /mnt/lower; then + echo "ERROR: Failed to mount rootfs (tried squashfs and ext4)!" + sleep 10 + reboot -f + fi + # ext4 fallback - just use it directly without overlay + log "Using ext4 rootfs directly (no overlay)" + mount --move /mnt/lower /mnt/root +else + log "Squashfs mounted successfully" + + # Create tmpfs for overlay upper/work directories + # Size is generous since container operations need temp space + log "Creating tmpfs overlay..." + mount -t tmpfs -o size=1G tmpfs /mnt/upper + mkdir -p /mnt/upper/upper + mkdir -p /mnt/upper/work + + # Create overlayfs combining squashfs (lower) + tmpfs (upper) + log "Mounting overlayfs..." + if ! mount -t overlay overlay -o lowerdir=/mnt/lower,upperdir=/mnt/upper/upper,workdir=/mnt/upper/work /mnt/root; then + echo "ERROR: Failed to mount overlayfs!" + sleep 10 + reboot -f + fi + + log "Overlayfs mounted successfully" +fi + +if [ "$QUIET" = "0" ]; then + echo "Contents:" + ls -la /mnt/root/ +fi + +# Verify init exists on rootfs +if [ ! -x /mnt/root/init ] && [ ! -x /mnt/root/sbin/init ]; then + echo "ERROR: No init found on rootfs!" + sleep 10 + reboot -f +fi + +# Move filesystems to new root before switch_root +# This way they persist across switch_root and the new init doesn't need to remount +mkdir -p /mnt/root/proc /mnt/root/sys /mnt/root/dev +mount --move /proc /mnt/root/proc +mount --move /sys /mnt/root/sys +mount --move /dev /mnt/root/dev + +# Switch to real root +# switch_root will: +# 1. Mount the new root +# 2. chroot into it +# 3. Execute the new init +# 4. Delete everything in the old initramfs +log "Switching to real root..." + +if [ -x /mnt/root/init ]; then + exec switch_root /mnt/root /init +elif [ -x /mnt/root/sbin/init ]; then + exec switch_root /mnt/root /sbin/init +fi + +# If we get here, switch_root failed +echo "ERROR: switch_root failed!" +sleep 10 +reboot -f diff --git a/recipes-containers/vcontainer/files/vdkr-preinit.sh b/recipes-containers/vcontainer/files/vdkr-preinit.sh deleted file mode 100644 index 08738022..00000000 --- a/recipes-containers/vcontainer/files/vdkr-preinit.sh +++ /dev/null @@ -1,133 +0,0 @@ -#!/bin/sh -# SPDX-FileCopyrightText: Copyright (C) 2025 Bruce Ashfield -# -# SPDX-License-Identifier: GPL-2.0-only -# -# vdkr-preinit.sh -# Minimal init for initramfs - mounts rootfs and does switch_root -# -# This script runs from the initramfs and: -# 1. Mounts essential filesystems -# 2. Finds and mounts the rootfs.img (squashfs, read-only) -# 3. Creates overlayfs with tmpfs for writes -# 4. Executes switch_root to the overlay root filesystem -# -# The real init (/init or /sbin/init on rootfs) then runs vdkr-init.sh logic - -# Mount essential filesystems first (needed to check cmdline) -mount -t proc proc /proc -mount -t sysfs sysfs /sys -mount -t devtmpfs devtmpfs /dev - -# Check for quiet mode (interactive) -QUIET=0 -for param in $(cat /proc/cmdline 2>/dev/null); do - case "$param" in - docker_interactive=1) QUIET=1 ;; - esac -done - -log() { - [ "$QUIET" = "0" ] && echo "$@" -} - -log "=== vdkr preinit (squashfs) ===" - -# Wait for block devices to appear -log "Waiting for block devices..." -sleep 2 - -# Show available block devices -log "Block devices:" -[ "$QUIET" = "0" ] && ls -la /dev/vd* 2>/dev/null || log "No virtio block devices found" - -# The rootfs.img is always the first virtio-blk device (/dev/vda) -# Additional devices (input, state) come after -ROOTFS_DEV="/dev/vda" - -if [ ! -b "$ROOTFS_DEV" ]; then - echo "ERROR: Rootfs device $ROOTFS_DEV not found!" - echo "Available devices:" - ls -la /dev/ - sleep 10 - reboot -f -fi - -# Create mount points for overlay setup -mkdir -p /mnt/lower # squashfs (read-only) -mkdir -p /mnt/upper # tmpfs for overlay upper -mkdir -p /mnt/work # tmpfs for overlay work -mkdir -p /mnt/root # final overlayfs mount - -# Mount squashfs read-only -log "Mounting squashfs rootfs from $ROOTFS_DEV..." - -if ! mount -t squashfs -o ro "$ROOTFS_DEV" /mnt/lower; then - # Fallback to ext4 for backwards compatibility - log "squashfs mount failed, trying ext4..." - if ! mount -t ext4 -o ro "$ROOTFS_DEV" /mnt/lower; then - echo "ERROR: Failed to mount rootfs (tried squashfs and ext4)!" - sleep 10 - reboot -f - fi - # ext4 fallback - just use it directly without overlay - log "Using ext4 rootfs directly (no overlay)" - mount --move /mnt/lower /mnt/root -else - log "Squashfs mounted successfully" - - # Create tmpfs for overlay upper/work directories - # Size is generous since container operations need temp space - log "Creating tmpfs overlay..." - mount -t tmpfs -o size=1G tmpfs /mnt/upper - mkdir -p /mnt/upper/upper - mkdir -p /mnt/upper/work - - # Create overlayfs combining squashfs (lower) + tmpfs (upper) - log "Mounting overlayfs..." - if ! mount -t overlay overlay -o lowerdir=/mnt/lower,upperdir=/mnt/upper/upper,workdir=/mnt/upper/work /mnt/root; then - echo "ERROR: Failed to mount overlayfs!" - sleep 10 - reboot -f - fi - - log "Overlayfs mounted successfully" -fi - -if [ "$QUIET" = "0" ]; then - echo "Contents:" - ls -la /mnt/root/ -fi - -# Verify init exists on rootfs -if [ ! -x /mnt/root/init ] && [ ! -x /mnt/root/sbin/init ]; then - echo "ERROR: No init found on rootfs!" - sleep 10 - reboot -f -fi - -# Move filesystems to new root before switch_root -# This way they persist across switch_root and the new init doesn't need to remount -mkdir -p /mnt/root/proc /mnt/root/sys /mnt/root/dev -mount --move /proc /mnt/root/proc -mount --move /sys /mnt/root/sys -mount --move /dev /mnt/root/dev - -# Switch to real root -# switch_root will: -# 1. Mount the new root -# 2. chroot into it -# 3. Execute the new init -# 4. Delete everything in the old initramfs -log "Switching to real root..." - -if [ -x /mnt/root/init ]; then - exec switch_root /mnt/root /init -elif [ -x /mnt/root/sbin/init ]; then - exec switch_root /mnt/root /sbin/init -fi - -# If we get here, switch_root failed -echo "ERROR: switch_root failed!" -sleep 10 -reboot -f diff --git a/recipes-containers/vcontainer/vcontainer-preinit_1.0.bb b/recipes-containers/vcontainer/vcontainer-preinit_1.0.bb new file mode 100644 index 00000000..078a5617 --- /dev/null +++ b/recipes-containers/vcontainer/vcontainer-preinit_1.0.bb @@ -0,0 +1,43 @@ +# SPDX-FileCopyrightText: Copyright (C) 2025 Bruce Ashfield +# +# SPDX-License-Identifier: MIT +# +# vcontainer-preinit_1.0.bb +# =========================================================================== +# Package containing the preinit script for vcontainer tiny initramfs +# =========================================================================== +# +# This package installs the preinit script as /init for use in a tiny +# initramfs. The script: +# 1. Mounts essential filesystems (/proc, /sys, /dev) +# 2. Mounts the squashfs rootfs from /dev/vda with overlayfs +# 3. Executes switch_root to the real root filesystem +# +# Used by: vdkr-tiny-initramfs-image.bb, vpdmn-tiny-initramfs-image.bb +# + +SUMMARY = "Preinit script for vcontainer initramfs" +DESCRIPTION = "Minimal init script that mounts squashfs rootfs with overlayfs \ + and performs switch_root for vcontainer QEMU environment." +HOMEPAGE = "https://git.yoctoproject.org/meta-virtualization/" +LICENSE = "GPL-2.0-only" +LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0-only;md5=801f80980d171dd6425610833a22dbe6" + +SRC_URI = "file://vcontainer-preinit.sh" + +S = "${UNPACKDIR}" + +# This package only provides the init script - no dependencies +# The initramfs image will pull in busybox separately +RDEPENDS:${PN} = "" + +do_install() { + install -d ${D} + install -m 0755 ${S}/vcontainer-preinit.sh ${D}/init +} + +# Package the /init script +FILES:${PN} = "/init" + +# Prevent QA warnings about /init location +INSANE_SKIP:${PN} += "file-rdeps" diff --git a/recipes-containers/vcontainer/vcontainer-tiny-initramfs-image.inc b/recipes-containers/vcontainer/vcontainer-tiny-initramfs-image.inc new file mode 100644 index 00000000..1fef7822 --- /dev/null +++ b/recipes-containers/vcontainer/vcontainer-tiny-initramfs-image.inc @@ -0,0 +1,70 @@ +# SPDX-FileCopyrightText: Copyright (C) 2025 Bruce Ashfield +# +# SPDX-License-Identifier: MIT +# +# vcontainer-tiny-initramfs-image.inc +# =========================================================================== +# Shared tiny initramfs image for vdkr/vpdmn switch_root boot flow +# =========================================================================== +# +# This produces a minimal cpio.gz initramfs containing only: +# - busybox (for mount, switch_root, sh, etc.) +# - vcontainer-preinit (the /init script) +# +# Boot flow: +# QEMU boots kernel + this initramfs +# -> /init (vcontainer-preinit) mounts squashfs rootfs.img from /dev/vda +# -> switch_root into rootfs.img with overlayfs +# -> ${runtime}-init.sh runs with full container tools +# + +SUMMARY = "Tiny initramfs for vcontainer switch_root" +DESCRIPTION = "Minimal initramfs containing busybox and preinit script for \ + mounting squashfs rootfs and performing switch_root." +LICENSE = "MIT" +LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302" + +inherit core-image + +# Minimal packages: just busybox and the preinit script +# busybox provides: mount, switch_root, sh, mkdir, sleep, cat, ls, echo, reboot +PACKAGE_INSTALL = "busybox vcontainer-preinit" + +# No extra features - keep it tiny +IMAGE_FEATURES = "" + +# Don't include kernel in initramfs +PACKAGE_EXCLUDE = "kernel-image-*" + +# Output as cpio.gz (standard initramfs format) +IMAGE_FSTYPES = "${INITRAMFS_FSTYPES}" + +# Keep the image small +IMAGE_ROOTFS_SIZE = "8192" +IMAGE_ROOTFS_EXTRA_SPACE = "0" + +# No locales needed +IMAGE_LINGUAS = "" + +# Suppress the suffix for cleaner naming +IMAGE_NAME_SUFFIX = "" + +# Compatible with x86_64 and aarch64 targets +COMPATIBLE_HOST = "(x86_64|aarch64).*-linux" + +# Create required directories that busybox/preinit expect +ROOTFS_POSTPROCESS_COMMAND += "create_initramfs_dirs;" + +create_initramfs_dirs() { + # Create mount points used by preinit + install -d ${IMAGE_ROOTFS}/proc + install -d ${IMAGE_ROOTFS}/sys + install -d ${IMAGE_ROOTFS}/dev + install -d ${IMAGE_ROOTFS}/mnt/lower + install -d ${IMAGE_ROOTFS}/mnt/upper + install -d ${IMAGE_ROOTFS}/mnt/work + install -d ${IMAGE_ROOTFS}/mnt/root + + # Create console device node (needed before /dev is mounted) + mknod -m 622 ${IMAGE_ROOTFS}/dev/console c 5 1 2>/dev/null || true +} diff --git a/recipes-containers/vcontainer/vdkr-tiny-initramfs-image.bb b/recipes-containers/vcontainer/vdkr-tiny-initramfs-image.bb new file mode 100644 index 00000000..42aa8637 --- /dev/null +++ b/recipes-containers/vcontainer/vdkr-tiny-initramfs-image.bb @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: Copyright (C) 2025 Bruce Ashfield +# +# SPDX-License-Identifier: MIT +# +# vdkr-tiny-initramfs-image.bb - Tiny initramfs for vdkr +# +# Build with: +# bitbake mc:vruntime-aarch64:vdkr-tiny-initramfs-image +# bitbake mc:vruntime-x86-64:vdkr-tiny-initramfs-image +# +# Output: ${DEPLOY_DIR_IMAGE}/vdkr-tiny-initramfs-image-${MACHINE}.cpio.gz + +require vcontainer-tiny-initramfs-image.inc diff --git a/recipes-containers/vcontainer/vpdmn-tiny-initramfs-image.bb b/recipes-containers/vcontainer/vpdmn-tiny-initramfs-image.bb new file mode 100644 index 00000000..c407f013 --- /dev/null +++ b/recipes-containers/vcontainer/vpdmn-tiny-initramfs-image.bb @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: Copyright (C) 2025 Bruce Ashfield +# +# SPDX-License-Identifier: MIT +# +# vpdmn-tiny-initramfs-image.bb - Tiny initramfs for vpdmn +# +# Build with: +# bitbake mc:vruntime-aarch64:vpdmn-tiny-initramfs-image +# bitbake mc:vruntime-x86-64:vpdmn-tiny-initramfs-image +# +# Output: ${DEPLOY_DIR_IMAGE}/vpdmn-tiny-initramfs-image-${MACHINE}.cpio.gz + +require vcontainer-tiny-initramfs-image.inc -- cgit v1.2.3-54-g00ecf