fix: boot process improvements — dependency cycle, INIT_NOTIFY, probing loop, and log spam fixes
- Fix P15-8-init-cycle-detection.patch: replace visiting+error with seen+silent-skip to eliminate 11 false-positive 'dependency cycle detected' errors on shared deps - Fix P0-daemon-fix-init-notify-unwrap.patch: remove eprintln! for missing INIT_NOTIFY (expected for oneshot_async services, ~7 daemons affected) - Fix driver-manager hotplug loop: add PERMANENTLY_SKIPPED static set shared between hotplug handler and DriverConfig::probe() to stop infinite re-probing of Fatal/NotSupported/deferred-exhausted device+driver pairs (e.g. ided) - Fix driver-manager log_timeline: suppress repeated EPIPE/ENOENT errors with AtomicI32 dedup and AtomicBool one-shot guards for boot timeline JSON - Add driver-manager SIGTERM handler, ACPI bus registration, --status mode, driver reap loop, graceful shutdown, and reduced deferred retries (30→3)
This commit is contained in:
Executable
+97
@@ -0,0 +1,97 @@
|
||||
#!/bin/bash
|
||||
# gnulib-cross-fix.sh — Fix gnulib cross-compilation misdetections in config.h
|
||||
#
|
||||
# Usage: gnulib-cross-fix.sh <path/to/lib/config.h>
|
||||
#
|
||||
# gnulib's configure can't run test programs during cross-compilation for
|
||||
# x86_64-unknown-redox (relibc target). It assumes system headers/types are
|
||||
# missing and generates broken fallback #defines and replacement headers.
|
||||
#
|
||||
# This script patches the generated config.h to correct those misdetections,
|
||||
# telling gnulib that relibc provides standard POSIX headers and types.
|
||||
#
|
||||
# Call this AFTER configure but BEFORE make in any gnulib-based recipe:
|
||||
# "${COOKBOOK_CONFIGURE}" "${COOKBOOK_CONFIGURE_FLAGS[@]}"
|
||||
# gnulib-cross-fix.sh "${COOKBOOK_BUILD}/lib/config.h"
|
||||
# "${COOKBOOK_MAKE}" -j "${COOKBOOK_MAKE_JOBS}"
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
CONFIG_H="${1:?Usage: gnulib-cross-fix.sh <path/to/config.h>}"
|
||||
|
||||
if [ ! -f "$CONFIG_H" ]; then
|
||||
echo "gnulib-cross-fix: $CONFIG_H not found, skipping" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "gnulib-cross-fix: patching $CONFIG_H for relibc cross-compilation"
|
||||
|
||||
# Comment out broken type fallbacks (relibc provides these correctly)
|
||||
perl -pi -e 's,^#define gid_t int\b,/* #undef gid_t -- relibc provides */,' "$CONFIG_H"
|
||||
perl -pi -e 's,^#define uid_t int\b,/* #undef uid_t -- relibc provides */,' "$CONFIG_H"
|
||||
perl -pi -e 's,^#define intmax_t long long\b,/* #undef intmax_t -- relibc provides */,' "$CONFIG_H"
|
||||
perl -pi -e 's,^#define ssize_t int\b,/* #undef ssize_t -- relibc provides */,' "$CONFIG_H"
|
||||
perl -pi -e 's,^#define ptrdiff_t long\b,/* #undef ptrdiff_t -- relibc provides */,' "$CONFIG_H"
|
||||
perl -pi -e 's,^#define nlink_t int\b,/* #undef nlink_t -- relibc provides */,' "$CONFIG_H"
|
||||
perl -pi -e 's,^#define mbstate_t int\b,/* #undef mbstate_t -- relibc provides */,' "$CONFIG_H"
|
||||
|
||||
# Force HAVE_ macros for standard headers (gnulib can't detect these during cross-compilation)
|
||||
for macro in \
|
||||
HAVE_INTTYPES_H \
|
||||
HAVE_INTTYPES_H_WITH_UINTMAX \
|
||||
HAVE_INTMAX_T \
|
||||
HAVE_WCHAR_H \
|
||||
HAVE_WCTYPE_H \
|
||||
HAVE_STDLIB_H \
|
||||
HAVE_SPAWN_H \
|
||||
HAVE_POSIX_SPAWNATTR_T \
|
||||
HAVE_POSIX_SPAWN_FILE_ACTIONS_T \
|
||||
HAVE_SIGNED_WCHAR_T \
|
||||
HAVE_SIGSET_T \
|
||||
HAVE_SIGACTION \
|
||||
HAVE_SIGADDSET \
|
||||
HAVE_SIGDELSET \
|
||||
HAVE_SIGEMPTYSET \
|
||||
HAVE_SIGFILLSET \
|
||||
HAVE_SIGISMEMBER \
|
||||
HAVE_SIGPENDING \
|
||||
HAVE_SIGPROCMASK \
|
||||
HAVE_SIGSUSPEND \
|
||||
HAVE_BTOWC \
|
||||
HAVE_MBRTOWC \
|
||||
HAVE_MBSINIT \
|
||||
HAVE_WCRTOMB \
|
||||
HAVE_WCTOB \
|
||||
HAVE_WCWIDTH \
|
||||
HAVE_MBSRTOWCS \
|
||||
HAVE_WCSWIDTH \
|
||||
HAVE___FSETERR \
|
||||
HAVE_GETLOCALENAME_L \
|
||||
; do
|
||||
perl -pi -e "s,/\\* #undef ${macro} \\*/,#define ${macro} 1," "$CONFIG_H" || true
|
||||
done
|
||||
|
||||
# Also patch generated replacement headers to disable rpl_ function renames.
|
||||
# gnulib generates lib/wchar.h, lib/signal.h, lib/stdio.h etc. with #define func rpl_func
|
||||
# when REPLACE_* is 1. Since relibc provides these functions, we need to undo the renames.
|
||||
LIB_DIR="$(dirname "$CONFIG_H")"
|
||||
for hdr in "$LIB_DIR"/wchar.h "$LIB_DIR"/signal.h "$LIB_DIR"/stdio.h "$LIB_DIR"/stdlib.h "$LIB_DIR"/string.h; do
|
||||
if [ -f "$hdr" ]; then
|
||||
# Replace rpl_ function names with the originals in #define lines
|
||||
# e.g. #define btowc rpl_btowc → /* #define btowc rpl_btowc -- relibc provides */
|
||||
perl -pi -e 's,^#(\s*)define (\w+) rpl_\2,/* #$1define $2 rpl_$2 -- relibc provides */,' "$hdr" || true
|
||||
fi
|
||||
done
|
||||
|
||||
# NOTE: We do NOT replace #include_next directives. The cross-compiler (Clang)
|
||||
# supports #include_next natively and the sysroot include path is set up correctly
|
||||
# so that #include_next skips the build directory and finds relibc's system headers.
|
||||
#
|
||||
# Previous versions of this script replaced #include_next <X.h> with #include <X.h>,
|
||||
# but this caused self-recursion in newer gnulib (m4-1.14+, flex) that removed the
|
||||
# _GL_ALREADY_INCLUDING_WCHAR_H guard. The split double-inclusion guard pattern
|
||||
# (_GL_WCHAR_H etc.) prevents re-entry into the normal section, but the special
|
||||
# invocation section (for __need_mbstate_t/__need_wint_t) is unguarded and would
|
||||
# recurse if #include found the gnulib wrapper instead of the system header.
|
||||
|
||||
echo "gnulib-cross-fix: done"
|
||||
Executable
+214
@@ -0,0 +1,214 @@
|
||||
#!/usr/bin/env bash
|
||||
# rebuild-cascade.sh — Rebuild a package and all packages that depend on it
|
||||
#
|
||||
# Usage:
|
||||
# ./local/scripts/rebuild-cascade.sh <package> [package2 ...]
|
||||
# ./local/scripts/rebuild-cascade.sh --dry-run <package>
|
||||
#
|
||||
# When a low-level package (e.g. relibc) changes, every package that
|
||||
# transitively depends on it must be rebuilt. This script:
|
||||
# 1. Identifies all packages that depend on the target(s)
|
||||
# 2. Cooks the target package(s) first
|
||||
# 3. Cooks all dependents in dependency order
|
||||
# 4. Pushes all rebuilt packages to the sysroot
|
||||
#
|
||||
# A package is considered a dependent if its recipe.toml lists the target
|
||||
# in its [package].dependencies array, OR if its recipe.toml has
|
||||
# dependencies = [...] that includes the target.
|
||||
#
|
||||
# Exit codes:
|
||||
# 0 — all packages rebuilt and pushed successfully
|
||||
# 1 — one or more packages failed to build
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT_DIR="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||
REPO_BIN="${ROOT_DIR}/target/release/repo"
|
||||
|
||||
DRY_RUN=0
|
||||
PACKAGES=()
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--dry-run|-n)
|
||||
DRY_RUN=1
|
||||
;;
|
||||
--help|-h)
|
||||
echo "Usage: $0 [--dry-run] <package> [package2 ...]"
|
||||
echo ""
|
||||
echo "Rebuilds the named package(s) and all packages that transitively"
|
||||
echo "depend on them, then pushes all to the sysroot."
|
||||
exit 0
|
||||
;;
|
||||
-*)
|
||||
echo "Unknown option: $arg" >&2
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
PACKAGES+=("$arg")
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ ${#PACKAGES[@]} -eq 0 ]; then
|
||||
echo "Usage: $0 [--dry-run] <package> [package2 ...]" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Build the repo binary if needed
|
||||
if [ ! -x "${REPO_BIN}" ]; then
|
||||
echo "Building repo binary..."
|
||||
(cd "${ROOT_DIR}" && cargo build --release --bin repo)
|
||||
fi
|
||||
|
||||
cd "${ROOT_DIR}"
|
||||
|
||||
# Collect all recipe directories
|
||||
RECIPE_DIRS=()
|
||||
for pkg in "${PACKAGES[@]}"; do
|
||||
# Find the recipe directory
|
||||
found=0
|
||||
for dir in recipes/*/; do
|
||||
if [ -d "${dir}${pkg}" ]; then
|
||||
RECIPE_DIRS+=("${dir}${pkg}")
|
||||
found=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
# Also check local/recipes
|
||||
if [ $found -eq 0 ]; then
|
||||
for dir in local/recipes/*/; do
|
||||
if [ -d "${dir}${pkg}" ]; then
|
||||
RECIPE_DIRS+=("${dir}${pkg}")
|
||||
found=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if [ $found -eq 0 ]; then
|
||||
echo "ERROR: recipe not found for package '${pkg}'" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Find all recipes that depend on any of the target packages
|
||||
# by scanning their recipe.toml for dependency entries
|
||||
find_reverse_deps() {
|
||||
local target="$1"
|
||||
local result=()
|
||||
|
||||
# Search all recipe.toml files for dependencies
|
||||
while IFS= read -r -d '' recipe_toml; do
|
||||
# Get the package name from the directory
|
||||
pkg_dir="$(dirname "${recipe_toml}")"
|
||||
pkg_name="$(basename "${pkg_dir}")"
|
||||
|
||||
# Skip the target itself
|
||||
if [ "${pkg_name}" = "${target}" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check if this recipe depends on the target
|
||||
if grep -q "dependencies.*=.*\[.*${target}.*\]" "${recipe_toml}" 2>/dev/null; then
|
||||
result+=("${pkg_name}")
|
||||
fi
|
||||
done < <(find recipes/ local/recipes/ -name "recipe.toml" -print0 2>/dev/null)
|
||||
|
||||
printf '%s\n' "${result[@]}" | sort -u
|
||||
}
|
||||
|
||||
# Build a complete cascade set using BFS
|
||||
echo "=== Analyzing dependency cascade ==="
|
||||
CASCADE=()
|
||||
VISITED=()
|
||||
QUEUE=("${PACKAGES[@]}")
|
||||
|
||||
while [ ${#QUEUE[@]} -gt 0 ]; do
|
||||
current="${QUEUE[0]}"
|
||||
QUEUE=("${QUEUE[@]:1}")
|
||||
|
||||
# Skip if already visited
|
||||
for v in "${VISITED[@]}"; do
|
||||
if [ "$v" = "$current" ]; then
|
||||
continue 2
|
||||
fi
|
||||
done
|
||||
VISITED+=("$current")
|
||||
|
||||
# Find packages that depend on current
|
||||
mapfile -t rdeps < <(find_reverse_deps "$current" 2>/dev/null || true)
|
||||
|
||||
for dep in "${rdeps[@]}"; do
|
||||
CASCADE+=("${dep}")
|
||||
QUEUE+=("${dep}")
|
||||
done
|
||||
done
|
||||
|
||||
# Remove duplicates and sort
|
||||
UNIQUE_CASCADE=($(printf '%s\n' "${CASCADE[@]}" | sort -u))
|
||||
|
||||
# Build order: cook the target packages first, then dependents
|
||||
BUILD_ORDER=("${PACKAGES[@]}" "${UNIQUE_CASCADE[@]}")
|
||||
|
||||
TOTAL=${#BUILD_ORDER[@]}
|
||||
echo ""
|
||||
echo "=== Cascade rebuild plan (${TOTAL} packages) ==="
|
||||
for i in "${!BUILD_ORDER[@]}"; do
|
||||
pkg="${BUILD_ORDER[$i]}"
|
||||
if printf '%s\n' "${PACKAGES[@]}" | grep -q "^${pkg}$"; then
|
||||
echo " [$((i+1))/${TOTAL}] ${pkg} (ROOT)"
|
||||
else
|
||||
echo " [$((i+1))/${TOTAL}] ${pkg} (dependent)"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $DRY_RUN -eq 1 ]; then
|
||||
echo ""
|
||||
echo "=== Dry run — no packages will be built ==="
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== Starting cascade rebuild ==="
|
||||
FAILED=()
|
||||
BUILT=()
|
||||
|
||||
export REDOXER_TOOLCHAIN="${ROOT_DIR}/prefix/x86_64-unknown-redox/relibc-install"
|
||||
|
||||
for i in "${!BUILD_ORDER[@]}"; do
|
||||
pkg="${BUILD_ORDER[$i]}"
|
||||
echo ""
|
||||
echo "--- [$((i+1))/${TOTAL}] Building ${pkg} ---"
|
||||
|
||||
if "${REPO_BIN}" cook "${pkg}"; then
|
||||
BUILT+=("${pkg}")
|
||||
echo "--- ${pkg} built successfully ---"
|
||||
else
|
||||
FAILED+=("${pkg}")
|
||||
echo "ERROR: ${pkg} failed to build" >&2
|
||||
echo "Continuing with remaining packages..."
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "=== Pushing ${#BUILT[@]} built packages to sysroot ==="
|
||||
for pkg in "${BUILT[@]}"; do
|
||||
echo "Pushing ${pkg}..."
|
||||
"${REPO_BIN}" push "${pkg}" || echo "WARNING: push ${pkg} failed"
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "=== Cascade rebuild summary ==="
|
||||
echo " Built: ${#BUILT[@]}/${TOTAL}"
|
||||
echo " Failed: ${#FAILED[@]}/${TOTAL}"
|
||||
if [ ${#FAILED[@]} -gt 0 ]; then
|
||||
echo " Failed packages:"
|
||||
for pkg in "${FAILED[@]}"; do
|
||||
echo " - ${pkg}"
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo " All packages rebuilt and pushed successfully."
|
||||
exit 0
|
||||
Executable
+255
@@ -0,0 +1,255 @@
|
||||
#!/usr/bin/env bash
|
||||
# P19-1: Multi-Core Driver Stress Test for Red Bear OS
|
||||
#
|
||||
# Validates SMP stability under parallel I/O load:
|
||||
# - 4 CPU cores exercising scheduler (P17)
|
||||
# - Parallel disk I/O via dd (filesystem scheme)
|
||||
# - Parallel scheme reads (IPC paths)
|
||||
# - Concurrent process creation/teardown
|
||||
# - Panic/hang detection
|
||||
#
|
||||
# Usage:
|
||||
# ./local/scripts/test-smp-stress-qemu.sh [--check]
|
||||
# ./local/scripts/test-smp-stress-qemu.sh --duration 60
|
||||
#
|
||||
# Options:
|
||||
# --check Run full QEMU test (default)
|
||||
# --duration N Stress duration in seconds (default: 30)
|
||||
# --smp N Number of CPU cores (default: 4)
|
||||
# --help Show this help
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
|
||||
# Defaults
|
||||
DURATION=30
|
||||
SMP=4
|
||||
ACTION="check"
|
||||
IMAGE=""
|
||||
FIRMWARE="/usr/share/edk2/x64/OVMF_CODE.4m.fd"
|
||||
|
||||
# Parse arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--check) ACTION="check"; shift ;;
|
||||
--duration) DURATION="$2"; shift 2 ;;
|
||||
--smp) SMP="$2"; shift 2 ;;
|
||||
--image) IMAGE="$2"; shift 2 ;;
|
||||
--help)
|
||||
head -20 "$0" | grep '^#' | sed 's/^# \?//'
|
||||
exit 0
|
||||
;;
|
||||
*) echo "Unknown argument: $1"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Resolve image
|
||||
if [[ -z "$IMAGE" ]]; then
|
||||
IMAGE="$PROJECT_DIR/build/x86_64/redbear-mini.iso"
|
||||
fi
|
||||
|
||||
if [[ ! -f "$IMAGE" ]]; then
|
||||
echo "ERROR: Image not found: $IMAGE"
|
||||
echo "Run: make live CONFIG_NAME=redbear-mini"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$FIRMWARE" ]]; then
|
||||
echo "ERROR: OVMF firmware not found: $FIRMWARE"
|
||||
echo "Install: sudo pacman -S edk2-ovmf (or equivalent)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "=== P19-1: Multi-Core Driver Stress Test ==="
|
||||
echo "Image: $IMAGE"
|
||||
echo "Firmware: $FIRMWARE"
|
||||
echo "CPUs: $SMP"
|
||||
echo "Duration: ${DURATION}s"
|
||||
echo ""
|
||||
|
||||
# Create expect-based test script
|
||||
export DURATION SMP IMAGE FIRMWARE
|
||||
|
||||
expect <<'EXPECT_SCRIPT'
|
||||
log_user 1
|
||||
set timeout 300
|
||||
set duration $env(DURATION)
|
||||
set smp $env(SMP)
|
||||
set image $env(IMAGE)
|
||||
set firmware $env(FIRMWARE)
|
||||
|
||||
proc expect_or_fail {pattern description} {
|
||||
expect {
|
||||
-nocase -re $pattern { return }
|
||||
timeout {
|
||||
puts stderr "\nERROR: timed out waiting for $description"
|
||||
exit 1
|
||||
}
|
||||
eof {
|
||||
puts stderr "\nERROR: QEMU exited while waiting for $description"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Launch QEMU with 4 CPUs, network, serial console
|
||||
spawn qemu-system-x86_64 \
|
||||
-name "Red Bear OS SMP Stress Test" \
|
||||
-machine q35 \
|
||||
-smp $smp \
|
||||
-m 2048 \
|
||||
-drive if=pflash,format=raw,readonly=on,file=$firmware \
|
||||
-chardev stdio,id=debug,signal=off,mux=on \
|
||||
-serial chardev:debug \
|
||||
-mon chardev=debug \
|
||||
-nographic \
|
||||
-vga none \
|
||||
-device virtio-net-pci,netdev=net0 \
|
||||
-netdev user,id=net0 \
|
||||
-drive file=$image,format=raw,if=none,id=drv0,snapshot=on \
|
||||
-device virtio-blk-pci,drive=drv0 \
|
||||
-enable-kvm \
|
||||
-cpu host
|
||||
|
||||
# Wait for login prompt
|
||||
puts "\n>>> Waiting for boot..."
|
||||
expect_or_fail "login:" "login prompt"
|
||||
|
||||
# Login as root
|
||||
send "root\r"
|
||||
expect_or_fail "assword:" "password prompt"
|
||||
send "password\r"
|
||||
expect_or_fail "#|\\$" "shell prompt"
|
||||
sleep 1
|
||||
|
||||
# --- Phase 1: Verify multi-core boot ---
|
||||
puts "\n>>> Phase 1: Verifying multi-core boot..."
|
||||
send "cat /scheme/sys/cpu.log 2>/dev/null || echo 'no cpu.log'\r"
|
||||
expect_or_fail "#|\\$" "cpu.log output"
|
||||
sleep 1
|
||||
|
||||
send "ls /scheme/sys/ 2>/dev/null | head -20\r"
|
||||
expect_or_fail "#|\\$" "sys scheme listing"
|
||||
sleep 1
|
||||
|
||||
# --- Phase 2: Parallel disk I/O stress ---
|
||||
puts "\n>>> Phase 2: Starting parallel disk I/O stress (duration: ${duration}s)..."
|
||||
|
||||
# Launch 4 parallel dd writers to tmpfs (exercises filesystem scheme + IPC)
|
||||
send "dd if=/dev/zero of=/tmp/stress-a bs=1M count=50 2>/tmp/stress-a.err &\r"
|
||||
expect_or_fail "#|\\$" "dd writer A start"
|
||||
sleep 0.5
|
||||
|
||||
send "dd if=/dev/zero of=/tmp/stress-b bs=1M count=50 2>/tmp/stress-b.err &\r"
|
||||
expect_or_fail "#|\\$" "dd writer B start"
|
||||
sleep 0.5
|
||||
|
||||
send "dd if=/dev/zero of=/tmp/stress-c bs=512 count=100000 2>/tmp/stress-c.err &\r"
|
||||
expect_or_fail "#|\\$" "dd writer C start"
|
||||
sleep 0.5
|
||||
|
||||
send "dd if=/dev/zero of=/tmp/stress-d bs=4k count=50000 2>/tmp/stress-d.err &\r"
|
||||
expect_or_fail "#|\\$" "dd writer D start"
|
||||
sleep 0.5
|
||||
|
||||
# --- Phase 3: Parallel reads (exercises IPC) ---
|
||||
puts "\n>>> Phase 3: Starting parallel filesystem traversal..."
|
||||
|
||||
send "ls -laR / > /tmp/ls-out 2>/tmp/ls-err &\r"
|
||||
expect_or_fail "#|\\$" "ls traversal start"
|
||||
sleep 0.5
|
||||
|
||||
send "cat /etc/passwd > /dev/null 2>&1 &\r"
|
||||
expect_or_fail "#|\\$" "passwd read start"
|
||||
sleep 0.5
|
||||
|
||||
send "find /tmp -type f > /dev/null 2>&1 &\r"
|
||||
expect_or_fail "#|\\$" "find traversal start"
|
||||
sleep 0.5
|
||||
|
||||
# --- Phase 4: Wait for stress duration ---
|
||||
puts "\n>>> Phase 4: Running stress for ${duration}s..."
|
||||
sleep $duration
|
||||
|
||||
# --- Phase 5: Collect results ---
|
||||
puts "\n>>> Phase 5: Collecting results..."
|
||||
|
||||
# Wait for background jobs and check status
|
||||
send "wait 2>/dev/null; echo STRESS-WAIT-DONE\r"
|
||||
expect_or_fail "STRESS-WAIT-DONE" "background jobs completion"
|
||||
sleep 1
|
||||
|
||||
# Check if stress files were created
|
||||
send "ls -la /tmp/stress-* 2>/dev/null; echo STRESS-FILES-DONE\r"
|
||||
expect_or_fail "STRESS-FILES-DONE" "stress file listing"
|
||||
sleep 1
|
||||
|
||||
# Verify reads work on stress files (read-back test)
|
||||
send "dd if=/tmp/stress-a of=/dev/null bs=1M count=50 2>/tmp/readback-a.err; echo READBACK-A-STATUS=$?\r"
|
||||
expect_or_fail "READBACK-A-STATUS=0" "readback A"
|
||||
sleep 1
|
||||
|
||||
# --- Phase 6: Panic detection ---
|
||||
puts "\n>>> Phase 6: Checking for panics..."
|
||||
|
||||
send "dmesg 2>/dev/null | grep -ic PANIC; echo PANIC-CHECK-DONE\r"
|
||||
expect {
|
||||
-re "(\[0-9\]+)\r\n.*PANIC-CHECK-DONE" {
|
||||
set panic_count $expect_out(1,string)
|
||||
if {$panic_count > 0} {
|
||||
puts "\n>>> FAIL: $panic_count PANIC(S) detected in dmesg!"
|
||||
puts "\n>>> Dumping panic context:"
|
||||
send "dmesg | grep -i PANIC\r"
|
||||
expect "#|\\$"
|
||||
exit 1
|
||||
} else {
|
||||
puts "\n>>> PASS: No panics detected in dmesg"
|
||||
}
|
||||
}
|
||||
timeout {
|
||||
puts stderr "\nERROR: timed out during panic check"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
sleep 1
|
||||
|
||||
# --- Phase 7: Summary ---
|
||||
puts "\n>>> Phase 7: Final system state..."
|
||||
send "echo \"UPTIME:\"; uptime 2>/dev/null || cat /scheme/sys/time 2>/dev/null; echo UPTIME-DONE\r"
|
||||
expect_or_fail "UPTIME-DONE" "uptime output"
|
||||
sleep 1
|
||||
|
||||
send "echo \"PROCS:\"; ps 2>/dev/null || echo 'ps not available'; echo PROCS-DONE\r"
|
||||
expect_or_fail "PROCS-DONE" "process listing"
|
||||
sleep 1
|
||||
|
||||
# Clean shutdown
|
||||
puts "\n>>> Shutting down..."
|
||||
send "shutdown\r"
|
||||
sleep 5
|
||||
send "\r"
|
||||
sleep 2
|
||||
|
||||
puts "\n"
|
||||
puts "============================================"
|
||||
puts " P19-1 SMP STRESS TEST: PASSED"
|
||||
puts " CPUs: $smp | Duration: ${duration}s"
|
||||
puts " No panics, no hangs, I/O completed"
|
||||
puts "============================================"
|
||||
|
||||
expect eof
|
||||
EXPECT_SCRIPT
|
||||
|
||||
exit_code=$?
|
||||
|
||||
if [[ $exit_code -eq 0 ]]; then
|
||||
echo ""
|
||||
echo "P19-1: PASSED"
|
||||
else
|
||||
echo ""
|
||||
echo "P19-1: FAILED (exit code: $exit_code)"
|
||||
fi
|
||||
|
||||
exit $exit_code
|
||||
Reference in New Issue
Block a user