forked from tfgrid/zosbuilder
Implement proper recursive module dependency resolution
- Use depmod -av + modinfo -k approach for accurate dependency detection - Copy modules to container /lib/modules for proper modinfo -k usage - Recursive resolution until no more dependencies found - Copy resolved modules to initramfs + run final depmod in chroot context - Now properly finds missing core modules like virtio.ko, virtio_ring.ko - Validates symbol dependencies with proper module database - Fixed KERNEL_OUTPUT variable binding in build summary
This commit is contained in:
@@ -346,8 +346,16 @@ function main_build_process() {
|
|||||||
section_header "Build Complete"
|
section_header "Build Complete"
|
||||||
log_info "Build time: ${build_minutes}m ${build_seconds}s"
|
log_info "Build time: ${build_minutes}m ${build_seconds}s"
|
||||||
log_info "Output files:"
|
log_info "Output files:"
|
||||||
|
if [[ -n "${KERNEL_OUTPUT:-}" ]]; then
|
||||||
log_info " Kernel: ${KERNEL_OUTPUT} ($(get_file_size "$KERNEL_OUTPUT"))"
|
log_info " Kernel: ${KERNEL_OUTPUT} ($(get_file_size "$KERNEL_OUTPUT"))"
|
||||||
|
else
|
||||||
|
log_info " Kernel: ${DIST_DIR}/vmlinuz.efi ($(get_file_size "${DIST_DIR}/vmlinuz.efi" 2>/dev/null || echo "not found"))"
|
||||||
|
fi
|
||||||
|
if [[ -n "${INITRAMFS_ARCHIVE:-}" ]]; then
|
||||||
log_info " Initramfs: ${INITRAMFS_ARCHIVE} ($(get_file_size "$INITRAMFS_ARCHIVE"))"
|
log_info " Initramfs: ${INITRAMFS_ARCHIVE} ($(get_file_size "$INITRAMFS_ARCHIVE"))"
|
||||||
|
else
|
||||||
|
log_info " Initramfs: ${DIST_DIR}/initramfs.cpio.xz ($(get_file_size "${DIST_DIR}/initramfs.cpio.xz" 2>/dev/null || echo "not found"))"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Cleanup build artifacts
|
# Cleanup build artifacts
|
||||||
|
|||||||
@@ -183,114 +183,95 @@ function initramfs_setup_modules() {
|
|||||||
log_info " Total modules: ${stage1_count}"
|
log_info " Total modules: ${stage1_count}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Resolve module dependencies using built modules from initramfs
|
# Resolve module dependencies using proper depmod + modinfo -k approach
|
||||||
function initramfs_resolve_module_dependencies() {
|
function initramfs_resolve_module_dependencies() {
|
||||||
local modules=("$@")
|
local modules=("$@")
|
||||||
local resolved_modules=()
|
local resolved_modules=()
|
||||||
local processed_modules=()
|
local processed_modules=()
|
||||||
|
|
||||||
log_debug "Resolving dependencies for modules using built modules: ${modules[*]}"
|
log_debug "Resolving dependencies recursively using modinfo -k: ${modules[*]}"
|
||||||
|
|
||||||
# Use full kernel version from build process, not host kernel (uname -r)
|
# Use full kernel version from build process
|
||||||
local kernel_version="${KERNEL_FULL_VERSION:-${FULL_KERNEL_VERSION:-}}"
|
local kernel_version="${KERNEL_FULL_VERSION:-${FULL_KERNEL_VERSION:-}}"
|
||||||
if [[ -z "$kernel_version" ]]; then
|
if [[ -z "$kernel_version" ]]; then
|
||||||
# Fallback: calculate from KERNEL_VERSION + LOCALVERSION
|
|
||||||
source "${LIB_SCRIPT_DIR}/kernel.sh"
|
source "${LIB_SCRIPT_DIR}/kernel.sh"
|
||||||
kernel_version=$(kernel_get_full_version "${KERNEL_VERSION:-6.12.44}" "${PROJECT_ROOT}/config/kernel.config")
|
kernel_version=$(kernel_get_full_version "${KERNEL_VERSION:-6.12.44}" "${PROJECT_ROOT}/config/kernel.config")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Use the built modules from initramfs directory (host path)
|
# Set up container modules directory for proper modinfo -k usage
|
||||||
local modules_path="${PROJECT_ROOT}/initramfs/lib/modules/${kernel_version}"
|
local container_modules_path="/lib/modules/${kernel_version}"
|
||||||
|
local source_modules_path="${PROJECT_ROOT}/initramfs/lib/modules/${kernel_version}"
|
||||||
|
|
||||||
log_debug "Using target kernel version: ${kernel_version}"
|
log_debug "Using kernel version: ${kernel_version}"
|
||||||
log_debug "Looking for built modules at: ${modules_path}"
|
log_debug "Source modules: ${source_modules_path}"
|
||||||
|
log_debug "Container modules: ${container_modules_path}"
|
||||||
|
|
||||||
if [[ ! -d "$modules_path" ]]; then
|
# Verify source modules exist
|
||||||
log_warn "Built modules not found at: $modules_path"
|
if [[ ! -d "$source_modules_path" ]]; then
|
||||||
log_warn "Falling back to simple module list without dependencies"
|
log_warn "Built modules not found at: $source_modules_path"
|
||||||
|
log_warn "Falling back to simple module list"
|
||||||
printf '%s\n' "${modules[@]}"
|
printf '%s\n' "${modules[@]}"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Ensure depmod has been run on the built modules
|
# Copy modules to container /lib/modules for proper modinfo -k usage
|
||||||
if [[ ! -f "${modules_path}/modules.dep" ]]; then
|
log_info "Setting up container modules for dependency resolution"
|
||||||
log_info "Running depmod on built modules"
|
safe_mkdir "$container_modules_path"
|
||||||
depmod -a -b "${PROJECT_ROOT}/initramfs" "$kernel_version" 2>/dev/null || {
|
safe_execute cp -r "${source_modules_path}"/* "$container_modules_path/"
|
||||||
log_warn "depmod failed, using simple module list"
|
|
||||||
printf '%s\n' "${modules[@]}"
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
fi
|
|
||||||
|
|
||||||
log_debug "Using built modules from: $modules_path"
|
# Run depmod to build dependency database
|
||||||
|
log_info "Running depmod -av for dependency resolution"
|
||||||
|
safe_execute depmod -av "$kernel_version" >/dev/null
|
||||||
|
|
||||||
# Function to recursively resolve a single module's dependencies (with depth limit)
|
# Recursive dependency resolution function
|
||||||
function resolve_single_module() {
|
function resolve_single_module() {
|
||||||
local module="$1"
|
local module="$1"
|
||||||
local depth="${2:-0}"
|
local depth="${2:-0}"
|
||||||
local max_depth=3 # Limit dependency depth to prevent explosion
|
local max_depth=5 # Allow deeper recursion for proper resolution
|
||||||
|
|
||||||
# Skip if already processed
|
# Skip if already processed
|
||||||
if printf '%s\n' "${processed_modules[@]}" | grep -q "^${module}$"; then
|
if printf '%s\n' "${processed_modules[@]}" | grep -q "^${module}$"; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Skip if we've gone too deep
|
# Skip if too deep (prevent infinite loops)
|
||||||
if [[ $depth -gt $max_depth ]]; then
|
if [[ $depth -gt $max_depth ]]; then
|
||||||
log_debug "Skipping $module - dependency depth limit ($max_depth) reached"
|
log_debug "Skipping $module - depth limit ($max_depth) reached"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
processed_modules+=("$module")
|
processed_modules+=("$module")
|
||||||
|
|
||||||
# Get module dependencies using modinfo from built modules
|
# Use modinfo -k for proper dependency resolution
|
||||||
local deps=()
|
local deps=()
|
||||||
if command_exists "modinfo"; then
|
if command_exists "modinfo"; then
|
||||||
local modinfo_output
|
local depends_line
|
||||||
local module_found=false
|
# Use modinfo -k to query the properly indexed modules
|
||||||
|
if depends_line=$(modinfo -k "$kernel_version" "$module" 2>/dev/null | grep '^depends:' | head -1 | cut -d: -f2- | tr -d ' '); then
|
||||||
# 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
|
if [[ -n "$depends_line" && "$depends_line" != "-" ]]; then
|
||||||
IFS=',' read -ra deps <<< "$depends_line"
|
IFS=',' read -ra deps <<< "$depends_line"
|
||||||
if [[ ${#deps[@]} -gt 0 ]]; then
|
if [[ ${#deps[@]} -gt 0 ]]; then
|
||||||
log_debug "Module $module (depth $depth) depends on: ${deps[*]}"
|
log_debug "Module $module (depth $depth) depends on: ${deps[*]}"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
# Check if module might be built-in
|
# Check if module is built-in
|
||||||
if grep -q "^$module\$" "${modules_path}/modules.builtin" 2>/dev/null; then
|
if modinfo -k "$kernel_version" "$module" >/dev/null 2>&1; then
|
||||||
log_debug "Module $module is built-in (no .ko file needed)"
|
log_debug "Module $module found but no dependencies"
|
||||||
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
|
else
|
||||||
log_debug "Module $module not found - may be built-in or integrated"
|
log_debug "Module $module not found - likely built-in"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
else
|
|
||||||
log_warn "modinfo not available, skipping dependency resolution"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Recursively resolve dependencies first (with incremented depth)
|
# Recursively resolve dependencies first (depth-first)
|
||||||
for dep in "${deps[@]}"; do
|
for dep in "${deps[@]}"; do
|
||||||
if [[ -n "$dep" ]]; then
|
if [[ -n "$dep" ]]; then
|
||||||
resolve_single_module "$dep" $((depth + 1))
|
resolve_single_module "$dep" $((depth + 1))
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# Add current module to resolved list (after dependencies)
|
# Add current module to resolved list (after dependencies for correct load order)
|
||||||
resolved_modules+=("$module")
|
resolved_modules+=("$module")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,7 +280,7 @@ function initramfs_resolve_module_dependencies() {
|
|||||||
resolve_single_module "$module"
|
resolve_single_module "$module"
|
||||||
done
|
done
|
||||||
|
|
||||||
# Remove duplicates while preserving order
|
# Remove duplicates while preserving dependency order
|
||||||
local unique_modules=()
|
local unique_modules=()
|
||||||
local seen_modules=()
|
local seen_modules=()
|
||||||
|
|
||||||
@@ -310,7 +291,7 @@ function initramfs_resolve_module_dependencies() {
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
log_debug "Resolved ${#unique_modules[@]} unique modules with dependencies from container"
|
log_debug "Resolved ${#unique_modules[@]} unique modules with recursive dependencies"
|
||||||
printf '%s\n' "${unique_modules[@]}"
|
printf '%s\n' "${unique_modules[@]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -776,10 +757,18 @@ function initramfs_copy_resolved_modules() {
|
|||||||
|
|
||||||
log_info "Module copy complete: ${copied_count} copied, ${failed_count} failed"
|
log_info "Module copy complete: ${copied_count} copied, ${failed_count} failed"
|
||||||
|
|
||||||
# Run depmod in initramfs context if we have the tools
|
# Run depmod in initramfs context (chroot-like) for final dependency resolution
|
||||||
if command_exists "depmod" && [[ $copied_count -gt 0 ]]; then
|
if command_exists "depmod" && [[ $copied_count -gt 0 ]]; then
|
||||||
log_info "Running depmod for initramfs modules"
|
log_info "Running depmod in initramfs context for final module database"
|
||||||
safe_execute depmod -a -b "$initramfs_dir" "$kernel_version"
|
safe_execute depmod -av -b "$initramfs_dir" "$kernel_version"
|
||||||
|
|
||||||
|
# Verify modules.dep was created properly
|
||||||
|
if [[ -f "${initramfs_modules_dir}/modules.dep" ]]; then
|
||||||
|
local dep_count=$(wc -l < "${initramfs_modules_dir}/modules.dep")
|
||||||
|
log_info "✓ Initramfs modules.dep created with ${dep_count} entries"
|
||||||
|
else
|
||||||
|
log_warn "modules.dep not created in initramfs"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
Reference in New Issue
Block a user