diff --git a/rigforge.sh b/rigforge.sh index b82d1da..979150c 100755 --- a/rigforge.sh +++ b/rigforge.sh @@ -56,6 +56,20 @@ append_once() { grep -qFx "$line" "$file" 2>/dev/null || echo "$line" | sudo tee -a "$file" > /dev/null } +# Merge the HugePage/MSR kernel params we manage into an existing GRUB cmdline, preserving every +# other parameter and replacing only the ones we own (so re-runs don't accumulate). Echoes the merged +# cmdline. Usage: grub_merge_cmdline "" "" +grub_merge_cmdline() { + local managed="$1" current="$2" preserved="" tok + for tok in $current; do + case "$tok" in + hugepagesz=*|hugepages=*|default_hugepagesz=*|msr.allow_writes=*) ;; # ours — drop, re-added below + *) preserved="${preserved:+$preserved }$tok" ;; + esac + done + echo "${preserved:+$preserved }$managed" +} + check_prerequisites() { log "Verifying system prerequisites..." if ! command -v jq &> /dev/null; then @@ -504,14 +518,20 @@ tune_kernel() { log "Configuring bootloader (GRUB) for persistent HugePages..." if [ -f "$SCRIPT_DIR/util/proposed-grub.sh" ] && [ -f "$GRUB_DEFAULT" ]; then - NEW_PARAMS=$("$SCRIPT_DIR/util/proposed-grub.sh" -q) + # proposed-grub.sh prints a generic "quiet splash" prefix plus the HugePage/MSR params we + # manage. Keep only the params we manage and MERGE them into the existing cmdline so we don't + # clobber other kernel parameters the user/distro set (#19 — boot-safety). + MANAGED=$("$SCRIPT_DIR/util/proposed-grub.sh" -q) + MANAGED="${MANAGED#quiet splash }" + + CURRENT=$(sed -n 's/^GRUB_CMDLINE_LINUX_DEFAULT="\(.*\)"$/\1/p' "$GRUB_DEFAULT" | head -n1) + MERGED=$(grub_merge_cmdline "$MANAGED" "$CURRENT") - # Check if GRUB is already configured - if grep -Fq "GRUB_CMDLINE_LINUX_DEFAULT=\"$NEW_PARAMS\"" "$GRUB_DEFAULT"; then + if [ "$CURRENT" = "$MERGED" ]; then log "GRUB is already configured with optimal HugePages settings." else sudo cp "$GRUB_DEFAULT" "$GRUB_DEFAULT.bak" - sudo sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=.*|GRUB_CMDLINE_LINUX_DEFAULT=\"$NEW_PARAMS\"|" "$GRUB_DEFAULT" + sudo sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=.*|GRUB_CMDLINE_LINUX_DEFAULT=\"$MERGED\"|" "$GRUB_DEFAULT" if command -v update-grub >/dev/null; then sudo update-grub REBOOT_REQUIRED=true diff --git a/tests/e2e/in-container.sh b/tests/e2e/in-container.sh index 05b4c8a..dc41ba8 100644 --- a/tests/e2e/in-container.sh +++ b/tests/e2e/in-container.sh @@ -88,6 +88,7 @@ assert_contains "service rendered by real envsubst" "$(cat /etc/systemd/system/x assert_contains "limits: fstab hugepages written" "$(cat /etc/fstab)" "hugetlbfs /dev/hugepages" assert_contains "limits: memlock written" "$(cat /etc/security/limits.conf)" "soft memlock unlimited" assert_contains "grub: hugepages configured" "$(cat /etc/default/grub)" "hugepages" +assert_contains "grub: preserves existing params" "$(cat /etc/default/grub)" "quiet splash" if [ "$ARCH" = x86_64 ]; then assert_contains "kernel: msr module enabled (x86)" "$(cat /etc/modules-load.d/msr.conf 2>/dev/null)" "msr" else diff --git a/tests/run.sh b/tests/run.sh index f5d0f7d..cc26aa0 100644 --- a/tests/run.sh +++ b/tests/run.sh @@ -330,6 +330,22 @@ printf '4\n' > "$SANDBOX/nr_4" out="$(PATH="$STUBS:$PATH" STUB_L3="32 MiB" STUB_SOCKETS=1 HUGEPAGES_1G_NR="$SANDBOX/nr_4" bash "$PG" --runtime)" assert_eq "grub --runtime: 1G allocated" "$out" "154" +# --------------------------------------------------------------------------- +# tune_kernel must MERGE its HugePage/MSR params into the existing GRUB cmdline, not overwrite it +# wholesale (#19 — overwriting drops other kernel params; a boot-safety risk). +echo "== unit: grub_merge_cmdline preserves other kernel params (#19) ==" +m="$( source "$SCRIPT"; grub_merge_cmdline "default_hugepagesz=2M hugepages=1234 msr.allow_writes=on" "quiet splash nomodeset" )" +assert_contains "merge keeps quiet" "$m" "quiet" +assert_contains "merge keeps custom nomodeset" "$m" "nomodeset" +assert_contains "merge adds hugepages" "$m" "hugepages=1234" +assert_contains "merge adds msr.allow_writes" "$m" "msr.allow_writes=on" +m2="$( source "$SCRIPT"; grub_merge_cmdline "default_hugepagesz=2M hugepages=1234 msr.allow_writes=on" "$m" )" +assert_eq "merge is idempotent" "$m2" "$m" +m3="$( source "$SCRIPT"; grub_merge_cmdline "hugepages=2000" "quiet hugepages=999 default_hugepagesz=2M" )" +assert_contains "stale managed param replaced" "$m3" "hugepages=2000" +assert_absent "old managed param dropped" "$m3" "hugepages=999" +assert_contains "non-managed param kept" "$m3" "quiet" + # --------------------------------------------------------------------------- # Pinned-build verification (#18): compile_xmrig clones the pinned XMRIG_VERSION and aborts if the # cloned HEAD doesn't match XMRIG_COMMIT. STUB_GIT_HEAD makes the git stub report a tampered commit @@ -429,6 +445,7 @@ if [ "$HOST_OS" = Linux ]; then assert_contains "limits: fstab 2M mount written" "$(cat "$W/etc/fstab")" "hugetlbfs /dev/hugepages" assert_contains "limits: memlock unlimited written" "$(cat "$W/etc/security/limits.conf")" "soft memlock unlimited" assert_contains "grub: hugepages params written" "$(cat "$W/etc/default/grub")" "default_hugepagesz=2M" + assert_contains "grub: preserves existing params (#19)" "$(cat "$W/etc/default/grub")" "quiet splash" else assert_eq "deploy: macOS huge-pages off" "$(J "$BUILD/config.json" '.cpu."huge-pages"')" "false" assert_eq "deploy: macOS http host all v6" "$(J "$BUILD/config.json" '.http.host')" "::"