Etapa B (B1+B2): boot desde disco real ext4, sin switch_root
B1 — kernel con disco+FS: linux.toml añade VIRTIO_BLK/VIRTIO_PCI/VIRTIO_NET/EXT4_FS
built-in (=y, sin módulos), aditivo al path initramfs. B2 — infra de disco:
- scripts/disk-image.sh: empaqueta un rootfs como imagen ext4 booteable con
`mke2fs -d` bajo `unshare -r` (archivos root-owned sin sudo, como el cpio
--owner=root:root; evita EACCES en el copy-up de overlay del rebuild).
- scripts/drive-rebuild.py: modo DISK= ⇒ QEMU monta la imagen como virtio /dev/vda
y el kernel arranca con `root=/dev/vda rw rdinit=/sbin/init` — sin initramfs.
Verificado en QEMU/KVM: el kernel monta /dev/vda ext4 como root REAL y arje-zero
arranca como PID 1 DIRECTO, sin el hack /init+switch_root (el muro pivot_root del
path initramfs desaparece por construcción: / ya es un mount pivotable).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+6
-1
@@ -25,6 +25,10 @@
|
||||
# Config: defconfig x86_64 (base PC booteable en QEMU: 8250 serial, initrd, PCI) + ajustes monolíticos
|
||||
# - E1000/OVERLAY_FS/USER_NS =y (built-in): el builder usa e1000 (vendoring) + overlay (sandbox bwrap)
|
||||
# + user namespaces (bwrap). Built-in ⇒ sin inyección de .ko ni version-magic.
|
||||
# - VIRTIO_BLK/VIRTIO_PCI/VIRTIO_NET/EXT4_FS =y (Etapa B, imagen en disco real): permiten montar un
|
||||
# disco virtio (`/dev/vda`, ext4) como root sin initramfs ⇒ `root=/dev/vda rw` directo, sin el hack
|
||||
# /init+switch_root. Built-in (no módulos) porque no hay initramfs que cargue .ko antes del root.
|
||||
# Aditivos: no tocan el camino initramfs del selfhost-verify (que sigue booteando igual).
|
||||
# - MODULE_SIG/DEBUG_INFO_BTF off: evitan firma de módulos y pahole (BTF), ausente del toolchain.
|
||||
# - UNWINDER_FRAME_POINTER en vez de ORC: reduce objtool pero NO lo elimina — en x86_64 las
|
||||
# mitigaciones (RETHUNK/retpoline-validation) seleccionan CONFIG_OBJTOOL igual, y objtool necesita
|
||||
@@ -71,13 +75,14 @@ scripts/config -d MODULE_SIG -d MODULE_SIG_ALL -d DEBUG_INFO_BTF -d DEBUG_INFO \
|
||||
-e E1000 -e OVERLAY_FS -e USER_NS -e NAMESPACES \
|
||||
-e FANOTIFY -e FANOTIFY_ACCESS_PERMISSIONS \
|
||||
-e OVERLAY_FS_REDIRECT_DIR -e OVERLAY_FS_INDEX -e OVERLAY_FS_XINO_AUTO -e OVERLAY_FS_METACOPY \
|
||||
-e VIRTIO -e VIRTIO_PCI -e VIRTIO_BLK -e VIRTIO_NET -e EXT4_FS \
|
||||
-d DRM -d AGP -d FB -d BACKLIGHT_CLASS_DEVICE -d SOUND -d SND \
|
||||
-d USB_SUPPORT -d MEDIA_SUPPORT -d INFINIBAND -d BT -d NFC -d CAN \
|
||||
-d WLAN -d WIRELESS -d CFG80211 -d MAC80211 -d RFKILL \
|
||||
-d HID_SUPPORT -d HID -d INPUT_MOUSE -d INPUT_JOYSTICK -d INPUT_TABLET -d INPUT_TOUCHSCREEN \
|
||||
-d WATCHDOG -d THUNDERBOLT -d FIREWIRE -d HWMON -d POWER_SUPPLY -d MEMSTICK -d MMC \
|
||||
-d ATA -d SCSI -d NVME_CORE -d MD -d STAGING -d IIO -d PPS -d PTP_1588_CLOCK \
|
||||
-d EXT4_FS -d XFS_FS -d BTRFS_FS -d F2FS_FS -d JFS_FS -d REISERFS_FS -d GFS2_FS -d NTFS3_FS \
|
||||
-d XFS_FS -d BTRFS_FS -d F2FS_FS -d JFS_FS -d REISERFS_FS -d GFS2_FS -d NTFS3_FS \
|
||||
-d DRM_I915 -d DRM_AMDGPU -d DRM_NOUVEAU -d DRM_RADEON && \
|
||||
make ARCH=x86_64 olddefconfig
|
||||
"""
|
||||
|
||||
Executable
+53
@@ -0,0 +1,53 @@
|
||||
#!/bin/sh
|
||||
# disk-image.sh — Etapa B (imagen en disco real): empaqueta un rootfs como imagen ext4 booteable de
|
||||
# disco virtio (/dev/vda) en vez de initramfs. Con un kernel que trae VIRTIO_BLK+EXT4 built-in
|
||||
# (recipes/linux.toml), QEMU monta la imagen como root REAL y el kernel arranca con
|
||||
# `root=/dev/vda rw rdinit=/sbin/init` — sin initramfs, sin el wrapper /init+switch_root: `/` ya es un
|
||||
# mount ext4 pivotable (el muro pivot_root del path initramfs desaparece por construcción).
|
||||
#
|
||||
# `mke2fs -d <dir>` puebla la imagen DESDE un directorio sin montar nada y sin root (e2fsprogs >= 1.43).
|
||||
#
|
||||
# Uso:
|
||||
# ./scripts/disk-image.sh # crea work/hammer-disk.img desde work/builder-rootfs
|
||||
# BOOT=1 KERNEL=<bzImage> KVM=1 ./scripts/disk-image.sh # además bootea y corre rebuild-stage1
|
||||
#
|
||||
# Variables:
|
||||
# ROOTFS dir rootfs a empaquetar (default work/builder-rootfs, lo arma selfhost-verify)
|
||||
# IMG imagen de salida (default work/hammer-disk.img)
|
||||
# SIZE tamaño de la imagen (default 6G; el rootfs ronda ~2G + holgura para el rebuild)
|
||||
# BOOT 1 ⇒ bootea con drive-rebuild.py tras crear la imagen
|
||||
# KERNEL bzImage con VIRTIO_BLK+EXT4 (requerido si BOOT=1)
|
||||
# KVM/MEM/NET passthrough a drive-rebuild.py
|
||||
set -eu
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
cd "$ROOT"
|
||||
|
||||
ROOTFS="${ROOTFS:-work/builder-rootfs}"
|
||||
IMG="${IMG:-work/hammer-disk.img}"
|
||||
SIZE="${SIZE:-6G}"
|
||||
|
||||
[ -d "$ROOTFS" ] || { echo "no existe ROOTFS: $ROOTFS (corré selfhost-verify para armar el builder)" >&2; exit 1; }
|
||||
[ -x "$ROOTFS/sbin/init" ] || [ -L "$ROOTFS/sbin/init" ] || { echo "ROOTFS sin /sbin/init (arje-zero)" >&2; exit 1; }
|
||||
|
||||
echo "==> rootfs : $ROOTFS ($(du -sh "$ROOTFS" | cut -f1))"
|
||||
echo "==> imagen : $IMG ($SIZE, ext4, label hammer-root)"
|
||||
rm -f "$IMG"
|
||||
# Ownership root en la imagen (igual que el `--owner=root:root` del cpio): el rebuild usa bwrap+overlay
|
||||
# con un userns que mapea 0→0; si los ficheros van con el uid del host (1000) el copy-up falla EACCES.
|
||||
# `unshare -r` mapea nuestro uid→0, así los ficheros uid-1000 se ven como root y mke2fs escribe uid 0
|
||||
# en la imagen — sin sudo. mke2fs -d puebla desde el dir sin montar. Fallback a mke2fs directo si no hay
|
||||
# unshare (la imagen quedaría uid-host: bootea y da shell, pero el rebuild fallaría en el copy-up).
|
||||
if command -v unshare >/dev/null 2>&1 && unshare -r true 2>/dev/null; then
|
||||
unshare -r mke2fs -q -t ext4 -L hammer-root -d "$ROOTFS" "$IMG" "$SIZE"
|
||||
else
|
||||
echo " (sin unshare -r: imagen con uid del host; el rebuild in-VM podría fallar el copy-up)" >&2
|
||||
mke2fs -q -t ext4 -L hammer-root -d "$ROOTFS" "$IMG" "$SIZE"
|
||||
fi
|
||||
echo "==> imagen creada: $(du -h "$IMG" | cut -f1)"
|
||||
|
||||
if [ "${BOOT:-0}" = 1 ]; then
|
||||
[ -n "${KERNEL:-}" ] || { echo "BOOT=1 requiere KERNEL=<bzImage con VIRTIO_BLK+EXT4>" >&2; exit 1; }
|
||||
echo "==> booteando de disco (root=/dev/vda, sin initramfs ni switch_root)"
|
||||
DISK="$IMG" KERNEL="$KERNEL" KVM="${KVM:-0}" MEM="${MEM:-6144}" NET="${NET:-1}" \
|
||||
python3 scripts/drive-rebuild.py
|
||||
fi
|
||||
@@ -8,6 +8,10 @@
|
||||
#
|
||||
# Variables de entorno (todas opcionales):
|
||||
# BUILDER_CPIO initramfs del builder (default work/builder.cpio.gz)
|
||||
# DISK imagen ext4 a bootear como ROOT real (Etapa B). Si está seteada, se ignora el
|
||||
# initramfs: QEMU monta la imagen como disco virtio (/dev/vda) y el kernel arranca con
|
||||
# `root=/dev/vda rw rdinit=/sbin/init` — sin initramfs ni switch_root (/ ya es un mount
|
||||
# ext4 real, pivotable). Requiere un kernel con VIRTIO_BLK+EXT4 (recipes/linux.toml).
|
||||
# KERNEL bzImage/vmlinuz a bootear (default /boot/vmlinuz-linux)
|
||||
# MEM RAM de la VM en MiB (default 6144)
|
||||
# CPU modelo de CPU TCG (default Broadwell; AVX2 sin KVM)
|
||||
@@ -29,6 +33,9 @@ def envpath(name, default):
|
||||
|
||||
|
||||
CPIO = envpath("BUILDER_CPIO", "work/builder.cpio.gz")
|
||||
DISK = os.environ.get("DISK", "") # Etapa B: si está, booteamos de disco real en vez de initramfs.
|
||||
if DISK and not os.path.isabs(DISK):
|
||||
DISK = os.path.join(ROOT, DISK)
|
||||
KERNEL = os.environ.get("KERNEL", "/boot/vmlinuz-linux")
|
||||
LOG = envpath("LOG", "work/rebuild-run.log")
|
||||
MEM = os.environ.get("MEM", "6144")
|
||||
@@ -37,7 +44,8 @@ DEADLINE = int(os.environ.get("DEADLINE", "14400"))
|
||||
WANT_KVM = os.environ.get("KVM", "0") == "1"
|
||||
WANT_NET = os.environ.get("NET", "1") == "1"
|
||||
|
||||
for p, what in [(CPIO, "initramfs del builder"), (KERNEL, "kernel")]:
|
||||
_needed = [(DISK, "imagen de disco")] if DISK else [(CPIO, "initramfs del builder")]
|
||||
for p, what in _needed + [(KERNEL, "kernel")]:
|
||||
if not os.path.exists(p):
|
||||
sys.exit(f"no existe {what}: {p}")
|
||||
|
||||
@@ -54,12 +62,19 @@ net = ["-netdev", "user,id=n0", "-device", "e1000,netdev=n0"] if WANT_NET else [
|
||||
# (p.ej. el frente kernel-from-source: el bzImage hammer bootea pero bwrap falla en pivot_root porque /
|
||||
# es el rootfs absoluto del namespace; `rootfstype=tmpfs` NO lo arregla — la causa es que / no tiene
|
||||
# mount padre, no el tipo de fs). Override con APPEND="…".
|
||||
APPEND = os.environ.get("APPEND", "console=ttyS0 rdinit=/sbin/init")
|
||||
# Boot de disco (Etapa B) vs initramfs. En disco / ya es un mount ext4 real ⇒ rdinit=/sbin/init directo
|
||||
# (arje-zero PID1), sin el wrapper switch_root del path initramfs.
|
||||
if DISK:
|
||||
APPEND = os.environ.get("APPEND", "console=ttyS0 root=/dev/vda rw rdinit=/sbin/init")
|
||||
media = ["-drive", f"file={DISK},if=virtio,format=raw", "-append", APPEND]
|
||||
else:
|
||||
APPEND = os.environ.get("APPEND", "console=ttyS0 rdinit=/sbin/init")
|
||||
media = ["-initrd", CPIO, "-append", APPEND]
|
||||
QEMU = (["qemu-system-x86_64", "-m", MEM, "-no-reboot", "-nographic"] + accel + net +
|
||||
["-kernel", KERNEL, "-initrd", CPIO, "-append", APPEND])
|
||||
["-kernel", KERNEL] + media)
|
||||
|
||||
print(f"==> kernel : {KERNEL}")
|
||||
print(f"==> initramfs : {CPIO}")
|
||||
print(f"==> {'disco ' if DISK else 'initramfs '}: {DISK or CPIO}")
|
||||
print(f"==> mem : {MEM} MiB deadline: {DEADLINE}s net: {'sí' if WANT_NET else 'no'}")
|
||||
print(f"==> log : {LOG}")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user