Linux Kernel Module Loading and Unloading: A Practical Guide
How to load, unload, and manage kernel modules on Linux, including insmod, modprobe, and module configuration for custom drivers.
Introduction
The Linux kernel is modular by design. Rather than compiling every possible driver and feature into the kernel image, most functionality is loaded on demand as kernel modules. This keeps the base kernel small and allows hardware support and features to be added without rebooting. Understanding how modules work is essential for hardware troubleshooting, driver management, and kernel development.
Environment
The examples use a Debian 12 system running kernel 6.1 LTS. The system has several custom modules loaded for a specialized network interface card.
uname -r
# 6.1.0-23-amd64
lsmod | wc -l
# 342Problem
You need to load a custom kernel module for a piece of hardware, but the module fails to load:
sudo insmod /lib/modules/6.1.0-23-amd64/kernel/drivers/net/ethernet/custom/nic.ko
# insmod: ERROR: could not insert module nic.ko: Invalid module formatOr the module loads but causes a kernel panic on certain operations.
Analysis
Kernel modules interact directly with the kernel's internal APIs. A module must be compiled against the exact kernel version and configuration it will be loaded into. The Invalid module format error means the module's version magic does not match the running kernel.
Check module information:
modinfo /lib/modules/6.1.0-23-amd64/kernel/drivers/net/ethernet/custom/nic.ko
# filename: /lib/modules/6.1.0-23-amd64/kernel/drivers/net/ethernet/custom/nic.ko
# vermagic: 6.1.0-23-amd64 SMP preempt mod_unload
# depends: mii
# alias: pci:v00001234d00005678sv*sd*bc02sc00i*Compare with your running kernel:
cat /proc/version
# Linux version 6.1.0-23-amd64 (debian-kernel@lists.debian.org) (gcc-12 (Debian 12.2.0-14) 12.2.0, GNU ld (GNU Binutils for Debian) 2.40) #1 SMP PREEMPT_DYNAMIC Debian 6.1.0-23Solution
1. Load a module with insmod (basic)
sudo insmod /path/to/module.koinsmod loads a module directly from a file path. It does not resolve dependencies.
2. Load a module with modprobe (recommended)
sudo modprobe nicmodprobe automatically resolves dependencies and loads required modules first. It searches /lib/modules/$(uname -r)/.
3. List loaded modules
lsmod
# Module Size Used by
# nic 131072 0
# mii 16384 1 nic
# usbcore 311296 04. Remove a module
sudo modprobe -r nicOr using rmmod (does not handle dependencies):
sudo rmmod nic5. Auto-load modules at boot
echo "nic" | sudo tee /etc/modules-load.d/nic.confOr add to /etc/modules:
echo "nic" | sudo tee -a /etc/modules6. Blacklist unwanted modules
echo "blacklist nouveau" | sudo tee /etc/modprobe.d/blacklist-nouveau.confThis prevents the module from loading automatically.
7. Pass parameters to modules
# At load time
sudo modprobe nic parameter=value
# Persistently
echo "options nic parameter=value" | sudo tee /etc/modprobe.d/nic.conf8. Check module dependencies
modprobe --show-depends nic
# /lib/modules/6.1.0-23-amd64/kernel/drivers/net/mii/mii.ko
# /lib/modules/6.1.0-23-amd64/kernel/drivers/net/ethernet/custom/nic.ko9. Build module dependencies
After installing new modules:
sudo depmod -a10. Debug module loading issues
# Check kernel logs for module-related messages
dmesg | tail -50
# Check for taint flags
cat /proc/sys/kernel/tainted
# 0 = clean, nonzero = tainted by proprietary modules or other issues11. Use modinfo for detailed module information
modinfo -p nic
# parm: debug:Debug level (0=none, 5=all) (int)
# parm: speed:Link speed in Mbps (int)12. Module versioning and kernel headers
To compile modules against your running kernel:
sudo apt-get install linux-headers-$(uname -r)
ls /lib/modules/$(uname -r)/build/
# Makefile Module.symvers include/13. Check for live references before unloading
lsmod | grep nic
# nic 131072 0 # The 0 means no other modules reference itIf the count is non-zero, another module depends on it and it cannot be unloaded until the dependent is removed first.
Lessons Learned
Kernel module management is fundamental to Linux system administration. Always use modprobe over insmod for production work because it handles dependencies correctly. Compile modules against the exact kernel headers of your running kernel. And always check dmesg after loading a module to catch errors or warnings that may not be immediately apparent. A module that loads successfully may still have runtime bugs that only surface under specific conditions.
This blog does not accept any external sponsorships, affiliate marketing, or ad revenue.