Fix module dependency resolution issues

- Fix dependency resolution to use built modules from /lib/modules/6.12.44-Zero-OS instead of fresh container
- Fix stage1/stage2 configuration mismatch (only using stage1 modules as intended)
- Fix firmware parsing to ignore comments in modules.conf
- Fix variable binding issues for incremental builds (FULL_KERNEL_VERSION, KERNEL_OUTPUT)
- Module resolution now properly expands 31 → 48 modules with dependencies
- Firmware requirements reduced from 157 bogus → 3 correct packages
- All 48/48 resolved modules validated as available .ko files
This commit is contained in:
2025-09-03 17:06:57 +02:00
parent b9f94105cf
commit f7c67ee5dd
3 changed files with 368 additions and 115 deletions

View File

@@ -118,9 +118,11 @@ function initramfs_setup_modules() {
local stage1_modules=()
local stage1_firmware=()
while IFS=: read -r stage module firmware; do
while IFS=: read -r stage module firmware_line; do
if [[ "$stage" == "stage1" && -n "$module" ]]; then
stage1_modules+=("$module")
# Extract firmware package name (before any comment)
local firmware=$(echo "$firmware_line" | sed 's/[[:space:]]*#.*//' | tr -d ' ')
if [[ -n "$firmware" && "$firmware" != "none" ]]; then
stage1_firmware+=("$firmware")
required_firmware+=("$firmware")
@@ -131,44 +133,25 @@ function initramfs_setup_modules() {
local stage1_with_deps=()
if [[ ${#stage1_modules[@]} -gt 0 ]]; then
log_info "Resolving dependencies for ${#stage1_modules[@]} stage1 modules: ${stage1_modules[*]}"
stage1_with_deps=($(initramfs_resolve_module_dependencies "${stage1_modules[@]}"))
log_info "Stage1 expanded to ${#stage1_with_deps[@]} modules (including dependencies)"
fi
# Write stage1 list with dependencies
printf '%s\n' "${stage1_with_deps[@]}" > "${modules_dir}/stage1.list"
# Create stage2 module list with dependencies and firmware
log_info "Resolving stage2 module dependencies (extended hardware)"
local stage2_modules=()
local stage2_firmware=()
while IFS=: read -r stage module firmware; do
if [[ "$stage" == "stage2" && -n "$module" ]]; then
stage2_modules+=("$module")
if [[ -n "$firmware" && "$firmware" != "none" ]]; then
stage2_firmware+=("$firmware")
required_firmware+=("$firmware")
log_debug "Module $module requires firmware: $firmware"
fi
fi
done < <(grep "^stage2:" "$modules_conf")
local stage2_with_deps=()
if [[ ${#stage2_modules[@]} -gt 0 ]]; then
stage2_with_deps=($(initramfs_resolve_module_dependencies "${stage2_modules[@]}"))
# Remove stage1 modules from stage2 to avoid duplicates
local stage2_unique=()
for mod in "${stage2_with_deps[@]}"; do
if ! printf '%s\n' "${stage1_with_deps[@]}" | grep -q "^${mod}$"; then
stage2_unique+=("$mod")
fi
done
stage2_with_deps=("${stage2_unique[@]}")
# Debug: show what's in stage1 list
if [[ ${#stage1_with_deps[@]} -gt 50 ]]; then
log_warn "Stage1 module list unexpectedly large: ${#stage1_with_deps[@]} modules"
log_warn "This may indicate excessive dependency resolution"
log_debug "First 10 stage1 modules: ${stage1_with_deps[@]:0:10}"
fi
# Write stage2 list with unique dependencies
printf '%s\n' "${stage2_with_deps[@]}" > "${modules_dir}/stage2.list"
# Create empty stage2 list (stage2 not used, only stage1)
log_info "Creating empty stage2 list (only using stage1 modules)"
echo > "${modules_dir}/stage2.list"
local stage2_with_deps=()
# Create firmware requirements list (remove duplicates)
local unique_firmware=($(printf '%s\n' "${required_firmware[@]}" | sort -u))
@@ -191,58 +174,119 @@ function initramfs_setup_modules() {
# Report final counts
local stage1_count=${#stage1_with_deps[@]}
local stage2_count=${#stage2_with_deps[@]}
local firmware_count=${#unique_firmware[@]}
log_info "Module configuration complete:"
log_info " Stage1 (critical + deps): ${stage1_count} modules"
log_info " Stage2 (extended + deps): ${stage2_count} modules"
log_info " Stage2: disabled (only using stage1)"
log_info " Required firmware packages: ${firmware_count}"
log_info " Total unique modules: $((stage1_count + stage2_count))"
log_info " Total modules: ${stage1_count}"
}
# Resolve module dependencies recursively using modinfo
# Resolve module dependencies using built modules from initramfs
function initramfs_resolve_module_dependencies() {
local modules=("$@")
local resolved_modules=()
local processed_modules=()
log_debug "Resolving dependencies for modules: ${modules[*]}"
log_debug "Resolving dependencies for modules using built modules: ${modules[*]}"
# Function to recursively resolve a single module's dependencies
# Use full kernel version from build process, not host kernel (uname -r)
local kernel_version="${KERNEL_FULL_VERSION:-${FULL_KERNEL_VERSION:-}}"
if [[ -z "$kernel_version" ]]; then
# Fallback: calculate from KERNEL_VERSION + LOCALVERSION
source "${LIB_SCRIPT_DIR}/kernel.sh"
kernel_version=$(kernel_get_full_version "${KERNEL_VERSION:-6.12.44}" "${PROJECT_ROOT}/config/kernel.config")
fi
# Use the built modules from initramfs directory (host path)
local modules_path="${PROJECT_ROOT}/initramfs/lib/modules/${kernel_version}"
log_debug "Using target kernel version: ${kernel_version}"
log_debug "Looking for built modules at: ${modules_path}"
if [[ ! -d "$modules_path" ]]; then
log_warn "Built modules not found at: $modules_path"
log_warn "Falling back to simple module list without dependencies"
printf '%s\n' "${modules[@]}"
return 0
fi
# Ensure depmod has been run on the built modules
if [[ ! -f "${modules_path}/modules.dep" ]]; then
log_info "Running depmod on built modules"
depmod -a -b "${PROJECT_ROOT}/initramfs" "$kernel_version" 2>/dev/null || {
log_warn "depmod failed, using simple module list"
printf '%s\n' "${modules[@]}"
return 0
}
fi
log_debug "Using built modules from: $modules_path"
# Function to recursively resolve a single module's dependencies (with depth limit)
function resolve_single_module() {
local module="$1"
local depth="${2:-0}"
local max_depth=3 # Limit dependency depth to prevent explosion
# Skip if already processed
if printf '%s\n' "${processed_modules[@]}" | grep -q "^${module}$"; then
return 0
fi
# Skip if we've gone too deep
if [[ $depth -gt $max_depth ]]; then
log_debug "Skipping $module - dependency depth limit ($max_depth) reached"
return 0
fi
processed_modules+=("$module")
# Get module dependencies using modinfo
# Get module dependencies using modinfo from built modules
local deps=()
if command_exists "modinfo"; then
# Try to get dependencies - modinfo may fail for built-in modules
local modinfo_output
if modinfo_output=$(modinfo "$module" 2>/dev/null); then
# Extract depends line and parse comma-separated dependencies
local depends_line=$(echo "$modinfo_output" | grep '^depends:' | head -1 | cut -d: -f2- | tr -d ' ')
if [[ -n "$depends_line" && "$depends_line" != "-" ]]; then
IFS=',' read -ra deps <<< "$depends_line"
local module_found=false
# Find the actual module file
local module_file=$(find "$modules_path" -name "${module}.ko*" -type f | head -1)
if [[ -n "$module_file" && -f "$module_file" ]]; then
# Use direct file path for modinfo
if modinfo_output=$(modinfo "$module_file" 2>/dev/null); then
module_found=true
# Extract depends line and parse comma-separated dependencies
local depends_line=$(echo "$modinfo_output" | grep '^depends:' | head -1 | cut -d: -f2- | tr -d ' ')
if [[ -n "$depends_line" && "$depends_line" != "-" ]]; then
IFS=',' read -ra deps <<< "$depends_line"
if [[ ${#deps[@]} -gt 0 ]]; then
log_debug "Module $module (depth $depth) depends on: ${deps[*]}"
fi
fi
fi
else
log_debug "modinfo failed for module: $module (may be built-in)"
# Check if module might be built-in
if grep -q "^$module\$" "${modules_path}/modules.builtin" 2>/dev/null; then
log_debug "Module $module is built-in (no .ko file needed)"
module_found=true
elif [[ "$module" == "virtio" || "$module" == "virtio_ring" ]]; then
# Special case: virtio core components may be integrated into virtio_pci in newer kernels
log_debug "Module $module is likely integrated into virtio subsystem (skipping dependency)"
module_found=true
else
log_debug "Module $module not found - may be built-in or integrated"
fi
fi
else
log_warn "modinfo not available, skipping dependency resolution"
fi
# Recursively resolve dependencies first
# Recursively resolve dependencies first (with incremented depth)
for dep in "${deps[@]}"; do
if [[ -n "$dep" ]]; then
log_debug "Module $module depends on: $dep"
resolve_single_module "$dep"
resolve_single_module "$dep" $((depth + 1))
fi
done
@@ -266,7 +310,7 @@ function initramfs_resolve_module_dependencies() {
fi
done
log_debug "Resolved ${#unique_modules[@]} unique modules with dependencies"
log_debug "Resolved ${#unique_modules[@]} unique modules with dependencies from container"
printf '%s\n' "${unique_modules[@]}"
}
@@ -622,7 +666,126 @@ function initramfs_test_archive() {
log_info "Archive integrity test passed"
}
# Copy resolved modules from container to initramfs
function initramfs_copy_resolved_modules() {
local initramfs_dir="$1"
local kernel_version="${2:-$(uname -r)}"
log_info "ENTRY: initramfs_copy_resolved_modules called with:"
log_info " initramfs_dir: ${initramfs_dir}"
log_info " kernel_version: ${kernel_version}"
log_info " CONTAINER_MODULES_PATH: ${CONTAINER_MODULES_PATH:-not-set}"
section_header "Copying Resolved Modules to Initramfs"
local container_modules_path="${CONTAINER_MODULES_PATH:-/lib/modules/${kernel_version}}"
local initramfs_modules_dir="${initramfs_dir}/lib/modules/${kernel_version}"
log_info "Container modules path: ${container_modules_path}"
log_info "Initramfs modules dir: ${initramfs_modules_dir}"
if [[ ! -d "$container_modules_path" ]]; then
log_error "Container modules not found: $container_modules_path"
log_info "Available module directories:"
ls -la /lib/modules/ 2>/dev/null || log_error "No /lib/modules directory"
return 1
fi
log_info "Container modules directory exists, proceeding..."
# Create initramfs modules directory
safe_mkdir "$initramfs_modules_dir"
# Read the stage1 module list (only using stage1, no stage2)
local stage1_modules=()
if [[ -f "${initramfs_modules_dir}/stage1.list" ]]; then
while IFS= read -r module; do
[[ -n "$module" ]] && stage1_modules+=("$module")
done < "${initramfs_modules_dir}/stage1.list"
fi
local all_modules=("${stage1_modules[@]}")
if [[ ${#all_modules[@]} -eq 0 ]]; then
log_warn "No modules to copy (empty stage1 module list)"
return 0
fi
log_info "Copying ${#all_modules[@]} stage1 modules to initramfs"
log_info "Stage1 modules: ${#stage1_modules[@]} (stage2 disabled)"
# Debug: show what we're copying if the list is reasonable
if [[ ${#all_modules[@]} -lt 200 ]]; then
log_debug "Modules to copy: ${all_modules[*]}"
else
log_warn "Module list is very large (${#all_modules[@]}), showing sample:"
log_debug "First 10: ${all_modules[@]:0:10}"
log_debug "Last 10: ${all_modules[@]:-10}"
fi
# Copy essential module metadata first
local essential_files=(
"modules.order"
"modules.builtin"
"modules.builtin.modinfo"
"modules.dep"
"modules.dep.bin"
"modules.symbols"
"modules.symbols.bin"
"modules.alias"
"modules.alias.bin"
"modules.devname"
)
for file in "${essential_files[@]}"; do
if [[ -f "${container_modules_path}/${file}" ]]; then
safe_execute cp "${container_modules_path}/${file}" "${initramfs_modules_dir}/"
log_debug "Copied module metadata: $file"
fi
done
# Copy actual module files
local copied_count=0
local failed_count=0
for module in "${all_modules[@]}"; do
local module_found=false
# Try to find module file
local module_file=$(find "$container_modules_path" -name "${module}.ko*" -type f | head -1)
if [[ -n "$module_file" && -f "$module_file" ]]; then
# Preserve directory structure
local rel_path="${module_file#${container_modules_path}/}"
local target_dir="${initramfs_modules_dir}/$(dirname "$rel_path")"
safe_mkdir "$target_dir"
safe_execute cp "$module_file" "${initramfs_modules_dir}/${rel_path}"
log_debug "Copied module: $module from $rel_path"
((copied_count++))
module_found=true
fi
if [[ "$module_found" == "false" ]]; then
log_warn "Module not found in container: $module"
((failed_count++))
fi
done
log_info "Module copy complete: ${copied_count} copied, ${failed_count} failed"
# Run depmod in initramfs context if we have the tools
if command_exists "depmod" && [[ $copied_count -gt 0 ]]; then
log_info "Running depmod for initramfs modules"
safe_execute depmod -a -b "$initramfs_dir" "$kernel_version"
fi
return 0
}
# Export all functions at the end after they're all defined
export -f initramfs_setup_zinit initramfs_setup_modules initramfs_resolve_module_dependencies
export -f initramfs_install_init_script initramfs_create_module_scripts initramfs_strip_and_upx
export -f initramfs_create_cpio initramfs_validate initramfs_test_archive
export -f initramfs_create_cpio initramfs_validate initramfs_test_archive initramfs_copy_resolved_modules