FREE LINUX KERNEL DEVELOPMENT COURSE — EmbeddedPathashala
Linux Kernel Module Autoloading, modprobe, and systemd Explained
Understand how the Linux kernel automatically loads modules at boot, resolves dependencies, and lets you control which modules load — updated for Linux 6.x
Intermediate
Linux 6.x
Module Loading
Linux Kernel Module Autoloading, modprobe, and systemd — Free Linux Kernel Development Course
When you plug in a USB device or boot your Linux system, dozens of kernel modules load silently in the background without you typing a single command. How does that happen? The answer lies in a powerful trio: modprobe, modules.dep, and systemd. In this free Linux kernel development course lecture from EmbeddedPathashala, you will learn exactly how Linux autoloads kernel modules, resolves module dependencies, and lets you control or block specific modules — all updated for the modern Linux 6.x kernel.
What You Will Learn
- What kernel module autoloading means and why it matters
- How
modproberesolves and loads module dependencies automatically - What the
modules.depfile is and howdepmodgenerates it - How module stacking works and how dependencies are tracked
- How systemd autoloads modules at boot using
modules-load.d - How to blacklist a kernel module to prevent it from loading
- Useful kernel command-line parameters for debugging module loading
- What DKMS is and when you need it
Prerequisites
- Basic understanding of what a Linux kernel module is
- Familiarity with writing and compiling a simple kernel module (init/exit functions)
- Comfort with Linux terminal commands
- Basic awareness of module stacking and EXPORT_SYMBOL (covered in earlier lectures)
What Is Kernel Module Autoloading?
In Linux, a kernel module is a piece of code that you can load into the running kernel without rebooting. You have probably used insmod or modprobe to manually load a module. But in real-world embedded products and desktop Linux systems alike, modules need to load automatically — either when hardware is detected or when the system boots.
Kernel module autoloading is the mechanism by which the Linux kernel (and userspace tools like udev and systemd) automatically load the right kernel modules at the right time, without any manual intervention from the user.
insmod is a low-level tool that loads a single module with no dependency resolution. modprobe is smarter — it reads the dependency database and loads all required modules in the correct order. For production use, always prefer modprobe.
- Loads one module only
- No dependency resolution
- Fails if dependencies are missing
- Requires full path to .ko file
- Low-level tool
- Loads module + all dependencies
- Reads modules.dep database
- Loads in correct dependency order
- Works with just the module name
- Preferred for production use
Understanding modules.dep and the depmod Command
The secret behind modprobe‘s ability to resolve dependencies is a file called modules.dep. This file lives at /lib/modules/$(uname -r)/modules.dep and contains a complete dependency map for every kernel module installed on your system.
Who Creates modules.dep?
The modules.dep file is generated by a tool called depmod. When you run make install after building your kernel module, the install target typically calls depmod automatically. You can also run it manually at any time:
# Rebuild the module dependency database for the running kernel
sudo depmod -a
# Rebuild for a specific kernel version
sudo depmod -a 6.8.0-45-generic
depmod scans all installed .ko files, reads the symbols each module exports and imports, and writes the resulting dependency graph into modules.dep.
What modules.dep Looks Like
The format is simple: each line shows a module followed by a colon and then a list of modules it depends on. If module A depends on module B, the entry looks like:
extra/module_a.ko: extra/module_b.ko
This tells modprobe that before loading module_a.ko, it must first load module_b.ko. When you run modprobe module_a, it automatically loads module_b first, then loads module_a — all in the correct order.
modules.dep.bin at the same location. This is the same data in a faster binary format that modprobe reads by default. Both files are generated together by depmod.
Module Stacking and Dependency Resolution in Practice
Module stacking means building your kernel code as multiple modules where one module depends on another. A common pattern in embedded Linux kernel development is to split functionality into a “core” module that exports symbols, and one or more “user” modules that import those symbols.
When you use EXPORT_SYMBOL() in a module to export a function or variable, that symbol becomes available to other modules. Any module that calls an exported symbol from another module creates a dependency on that module.
modprobe user_lkm
Installing Stacked Modules and Verifying Dependencies
After building your stacked modules, installing them with make install copies the .ko files to the correct location under /lib/modules/$(uname -r)/extra/ and runs depmod to update the dependency database.
You can verify the recorded dependency like this:
# Check what modules.dep says about your module's dependencies
grep user_lkm /lib/modules/$(uname -r)/modules.dep
# Expected output:
# extra/user_lkm.ko: extra/core_lkm.ko
The colon-separated format tells you: the module on the left depends on every module listed on the right.
Module.symvers. This file records every symbol exported by your module (via EXPORT_SYMBOL) along with the symbol’s CRC checksum. When another module depends on your module, the kernel uses these CRCs to verify that the interface has not changed between builds. Always keep Module.symvers available when building dependent modules.
Checking What Is Currently Loaded
You can inspect the currently loaded modules and their dependencies at runtime using these commands:
# List all currently loaded modules
lsmod
# Show detailed info about a specific module including its dependencies
modinfo core_lkm
# Check which modules are using a given module (who depends on it)
lsmod | grep core_lkm
The lsmod output has three columns: the module name, its size in memory, and how many other modules are currently using it. If the “used by” count is non-zero, you cannot remove that module until its dependents are removed first.
Quick Reference: Module Management Commands in Linux 6.x
| Command | What It Does | When to Use |
|---|---|---|
modprobe <name> | Load module + all its dependencies | Always prefer this for loading |
modprobe -r <name> | Remove module + unneeded dependencies | Cleaner than rmmod for stacked modules |
insmod <path.ko> | Load single module, no dependency resolution | Quick testing only |
rmmod <name> | Remove single module | Simple cases with no dependents |
lsmod | List currently loaded modules | Checking what is active |
modinfo <name> | Show module metadata, parameters, dependencies | Inspecting any module |
depmod -a | Rebuild modules.dep dependency database | After installing new modules |
How systemd Autoloads Kernel Modules at Boot
On all modern Linux distributions — Ubuntu, Fedora, Debian, and their embedded variants — it is systemd that is responsible for loading kernel modules at system boot, not a legacy init script.
systemd does this through a service called systemd-modules-load.service. At boot, this service reads a set of configuration files to know which modules to load. These files live under /etc/modules-load.d/.
| 🚀 System Boot Starts | ||
| systemd starts | → | systemd-modules-load.service activates |
|
Reads module list from:
/etc/modules-load.d/*.conf
/usr/lib/modules-load.d/*.conf
/run/modules-load.d/*.conf
|
||
| 🔧 Calls modprobe for each listed module → modules load with full dependency resolution | ||
How to Make Your Kernel Module Load Automatically at Boot
If you want your custom kernel module to load every time the system boots, create a configuration file inside /etc/modules-load.d/:
# Create a config file to autoload your module at boot
# The filename can be anything ending in .conf
sudo nano /etc/modules-load.d/mydriver.conf
# Inside the file, just write the module name (one per line):
# mydriver
The file format is extremely simple: one module name per line. Lines starting with # are comments. After creating this file, systemd will call modprobe mydriver on every subsequent boot.
# Verify the service runs correctly
systemctl status systemd-modules-load.service
# Manually trigger it (useful for testing without rebooting)
sudo systemctl restart systemd-modules-load.service
/etc/modules-load.d/ with a product-specific .conf file rather than loading modules from a startup script. This gives you proper dependency ordering and boot-time error reporting through journald.
How to Blacklist a Kernel Module in Linux 6.x
Sometimes a module causes problems — it might make your system freeze, conflict with another driver, or simply not work correctly. In these situations, you want to prevent the module from loading automatically. This is called blacklisting.
There are two ways to blacklist a kernel module:
Method 1: Blacklist via /etc/modprobe.d/ (Permanent)
Create a file in /etc/modprobe.d/ with a .conf extension and add a blacklist line:
# Create a blacklist file
sudo nano /etc/modprobe.d/blacklist-problematic.conf
# Add this line inside the file:
# blacklist problematic_module
# After saving, update initramfs so the change takes effect on next boot
sudo update-initramfs -u # Debian/Ubuntu
# or
sudo dracut --force # Fedora/RHEL
Method 2: Blacklist via Kernel Command Line (Temporary/Recovery)
When a module causes boot problems and you cannot even reach the shell to edit files, you can blacklist it directly on the kernel command line. This is the fastest way to recover a system that hangs at boot:
# At the GRUB boot menu, press 'e' to edit the boot entry
# Add this to the end of the linux/linuxefi line:
module_blacklist=problematic_module
# To blacklist multiple modules:
module_blacklist=module1,module2,module3
/etc/modprobe.d/ method and update initramfs.
You can always check the current kernel command line to see what parameters were passed at boot:
cat /proc/cmdline
- Permanent — survives reboots
- Requires filesystem access
- Standard production method
- Needs initramfs update
- Temporary — single boot only
- Works even if system won’t boot
- Best for recovery/debugging
- No filesystem changes needed
Useful Kernel Command-Line Parameters for Debugging Module Loading
The kernel command line is a powerful place to control module loading behaviour during debugging. Beyond blacklisting, the Linux kernel provides several parameters that help you diagnose what is happening during initialization.
| Parameter | What It Does | When to Use It |
|---|---|---|
module_blacklist=mod1,mod2 | Prevents listed modules from loading | Module causes hangs or conflicts |
debug | Enables verbose kernel debugging output (all log levels) | General boot debugging |
initcall_debug | Prints every initcall as it runs at boot with timing | Diagnosing where boot hangs |
ignore_loglevel | Prints ALL kernel messages to console regardless of log level | When printk messages aren’t showing |
rd.break | Drops into a shell during initramfs stage | Debugging early boot |
nomodule | Disables all module loading entirely | Testing kernel without any external modules |
The initcall_debug parameter is especially valuable for embedded Linux developers. Every driver’s module_init() function is called through an initcall chain at boot. When the system hangs during boot, initcall_debug lets you pinpoint exactly which initcall is responsible.
# Add to GRUB kernel line for boot debugging:
initcall_debug ignore_loglevel
# After booting, search the journal for initcall timings:
journalctl -b | grep "initcall"
What Is DKMS — Dynamic Kernel Module Support?
One practical challenge with out-of-tree kernel modules (modules that are not part of the mainline kernel source) is that they need to be recompiled every time the kernel is updated. If you install a new kernel version without recompiling your module, the module simply will not load because the kernel ABI has changed.
DKMS (Dynamic Kernel Module Support) solves this problem automatically. It registers your module’s source code with the system, and whenever a new kernel is installed, DKMS automatically recompiles and installs your module for the new kernel version.
# Install DKMS on Ubuntu/Debian
sudo apt install dkms
# Register a module with DKMS (requires a dkms.conf file in your module source)
sudo dkms add -m mymodule -v 1.0
# Build for the current kernel
sudo dkms build -m mymodule -v 1.0
# Install it
sudo dkms install -m mymodule -v 1.0
# Verify installation
sudo dkms status
DKMS is widely used for Wi-Fi drivers, GPU drivers, VirtualBox guest additions, and other drivers that ship outside the mainline kernel. For embedded product development, DKMS is most relevant on development boards where you want module updates to survive kernel upgrades automatically.
sudo apt install linux-headers-$(uname -r). On embedded targets, you typically cross-compile instead and deploy pre-built modules.
Best Practices for Kernel Module Autoloading
- Always use modprobe, not insmod, for production module loading. modprobe handles dependencies correctly and integrates with the module database.
- Run
depmod -aafter installing any new module. Without this, modprobe will not know about your new module or its dependencies. - Use
/etc/modules-load.d/for persistent autoloading. Never putmodprobecalls in startup scripts when a proper configuration file location exists. - Keep your
Module.symversfile safe. Losing it between builds can cause symbol mismatch errors when loading dependent modules. - Test blacklisting on the kernel command line before making it permanent. Verify the system behaves as expected before editing
/etc/modprobe.d/. - Use DKMS for out-of-tree drivers in long-lived deployments. Manual rebuilds after every kernel update are error-prone.
- On embedded systems, prefer statically compiled drivers for truly critical hardware — modules can fail to load, static drivers cannot.
Common Mistakes and Troubleshooting
The module may not be installed under /lib/modules/$(uname -r)/. Run sudo make install then sudo depmod -a. modprobe only works with properly installed modules.
The dependency module is not loaded. Check modules.dep to verify the dependency is recorded. If you see an empty dependency list but the module imports symbols, run depmod -a again after reinstalling both modules.
You likely loaded it manually with modprobe but did not add it to /etc/modules-load.d/. Create a .conf file there with your module name to make it persistent.
Another module may be pulling it in as a dependency. Check with modprobe --show-depends <problematic_module>. Also check if udev has a rule that triggers loading. You may need to blacklist the parent module too, or use install problematic_module /bin/true in modprobe.d to completely disable loading via any path.
Key Takeaways
- modprobe is the correct tool for module loading — it resolves and loads all dependencies automatically using the
modules.depdatabase. - depmod builds the dependency database by scanning installed
.kofiles — always run it after installing new modules. - systemd handles module autoloading at boot via
systemd-modules-load.service, reading module names from/etc/modules-load.d/*.conf. - Blacklisting prevents a module from loading — use
/etc/modprobe.d/for permanent blacklisting or the kernel command line for temporary recovery. - DKMS automatically rebuilds out-of-tree modules when a new kernel is installed, solving the kernel update problem.
- Kernel command-line parameters like
initcall_debugandignore_loglevelare essential tools for debugging module loading failures at boot.
Frequently Asked Questions
insmod loads a single module from a full file path with no dependency resolution — if the module needs symbols from another module, you must manually load that other module first. modprobe reads the dependency database (modules.dep) and automatically loads all required dependency modules in the correct order. Always use modprobe in production and in scripts.
Create a file ending in .conf inside /etc/modules-load.d/ containing your module name. For example: echo "mydriver" | sudo tee /etc/modules-load.d/mydriver.conf. systemd’s systemd-modules-load.service will load it at every boot via modprobe.
modules.dep is a text file at /lib/modules/$(uname -r)/modules.dep that records the dependency relationships between all installed kernel modules. It is generated by running depmod -a, which scans all installed .ko files and determines which modules depend on which other modules by examining their exported and imported symbols.
Create a file in /etc/modprobe.d/ (for example blacklist.conf) and add the line blacklist modulename. Then run sudo update-initramfs -u (on Debian/Ubuntu) or sudo dracut --force (on Fedora/RHEL) to apply the change to the initramfs. The module will be blocked from loading on all subsequent boots.
DKMS (Dynamic Kernel Module Support) is a framework that keeps out-of-tree kernel modules automatically compiled and installed across kernel upgrades. Use it when you have a kernel module that is not part of the mainline Linux kernel and your system’s kernel gets updated regularly. Without DKMS, every kernel update would break your module until you manually recompile it.
Use modprobe --show-depends modulename to display the full list of modules that would be loaded, in order, when you load that module. You can also run modinfo modulename to see the “depends” field in the module’s metadata. Additionally, grep modulename /lib/modules/$(uname -r)/modules.dep shows the dependency line directly.
Adding initcall_debug to the kernel command line causes the kernel to print each initcall function name and how long it took to execute during the boot sequence. This is invaluable when your system hangs at boot — you can see exactly which driver’s initialization function is the last thing to run before the hang, narrowing down the problematic module quickly.
Yes. On systems without systemd (some embedded systems use BusyBox init or OpenRC), you can add modprobe modulename calls to your init scripts (such as /etc/rc.local on older systems or a custom init script). On OpenRC, add module names to /etc/conf.d/modules. The mechanism differs but the result is the same — modprobe is called during boot to load the required modules.
Conclusion
Understanding kernel module autoloading is a fundamental skill for anyone pursuing embedded Linux kernel development or Linux device driver engineering. The three key tools — depmod, modprobe, and systemd — work together to create a reliable, ordered module loading system that handles complex dependency chains automatically.
As you build more complex kernel modules for real embedded products, you will rely on these mechanisms daily: ensuring your custom drivers load in the right order, persisting through reboots, and surviving kernel updates through DKMS. Mastering module autoloading now will save you hours of debugging time later in your career.
In the next lecture, we cover kernel module security — a critical topic for anyone shipping Linux kernel modules in production products. You will learn how kernel address leaks work, what dmesg_restrict and kptr_restrict do, and how to write modules that do not inadvertently expose sensitive kernel information.
Continue Your Free Linux Kernel Development Journey
EmbeddedPathashala offers completely free, in-depth courses on Linux kernel programming, Linux device drivers, and embedded systems — for engineering students and professionals.
Visit EmbeddedPathashala