How to Use modprobe for Kernel Modules

How to Use modprobe for Kernel Modules with Softlinks and depmod

Stop manually tracking load order. Let modprobe read the dependency file and handle everything — softlinks, depmod, and automatic cleanup included. so let us discuss more about modprobe for Kernel Modules

⏱ 12 min read⚙ Beginner Friendly🐧 Linux Kernel
modprobe depmod modules.dep softlink insmod vs modprobe kernel module loading, modprobe for Kernel Modules.

01 The Problem with insmod

In the previous article we loaded our stacked modules using insmod. It worked, but we had to do everything manually — load mod1 first, verify the symbol in /proc/kallsyms, then load mod2. If we forgot the order, the kernel threw an Unknown symbol error.

Now imagine you are working on a production driver with five or six stacked layers. Remembering the exact load sequence every time you reboot — or asking a tester to do it — is a recipe for mistakes. There has to be a better way, and there is: modprobe. modprobe for Kernel Modules

❌ With insmod (Manual)

  • You must know and remember the load order
  • You must load each dependency separately
  • Easy to get wrong, especially after a reboot
  • Unloading is also manual and reversed

✅ With modprobe (Automatic)

  • Just say: modprobe mod2
  • modprobe reads the dependency map and loads mod1 automatically
  • No need to track order yourself
  • modprobe -r mod2 removes everything cleanly

02 What is modprobe?

modprobe is the smart module loader. Unlike insmod which blindly tries to load a single .ko file, modprobe first consults a pre-built dependency map called modules.dep. It reads which other modules your target module depends on, loads those first in the correct order, and only then loads the module you actually asked for.

Think of it like a package manager — when you install a package, it automatically pulls in all required dependencies. modprobe does the same for kernel modules.

How modprobe works internally
User types:  sudo modprobe mod2

           ┌────────────────────────────────────────┐
           │           modprobe                     │
           │  1. Open /lib/modules/$(uname -r)/     │
           │         modules.dep                    │
           │  2. Find entry for mod2.ko             │
           │  3. See: mod2.ko depends on mod1.ko    │
           │  4. Load mod1.ko first  (insmod)       │
           │  5. Load mod2.ko second (insmod)       │
           └────────────────────────────────────────┘

Result: both modules loaded, correct order, zero manual effort

💡

modprobe is actually a userspace tool, part of the kmod package. When you run it, it reads modules.dep, figures out the dependency chain, and internally calls insmod for each module in the right order. The kernel itself never sees modprobe — it only sees the individual insmod calls.

03 How modprobe Knows Dependencies — modules.dep

The brain of modprobe is a file called modules.dep. It lives here on your system: so let us study how modprobe for Kernel Modules works

Location of modules.dep path
/lib/modules/$(uname -r)/modules.dep

# For example on kernel 6.8.0-90-generic:
/lib/modules/6.8.0-90-generic/modules.dep

The format of this file is straightforward. Each line looks like this:

modules.dep — format text
# target_module: dependency1 dependency2 ...

kernel/drivers/misc/mod2.ko: kernel/drivers/misc/mod1.ko
kernel/drivers/misc/mod1.ko:

Read it like this: “To load mod2.ko, you must first load mod1.ko.” mod1.ko has no dependencies, so its line has nothing after the colon.

This file is not something you edit by hand. It is automatically generated by a tool called depmod, which we will look at in a moment. But first, we need to tell the kernel where our custom modules live — and that is where softlinks come in.

04 Creating Softlinks — Registering Your Module

Here is something important to understand: modprobe only looks for modules inside /lib/modules/$(uname -r)/. Your compiled .ko files are sitting in your home directory — modprobe has no idea they exist.

We have two options: copy the .ko files into the kernel module tree, or create a symbolic link (softlink) pointing from the module tree to our actual files. The softlink approach is much better during development because if you recompile the module, the link automatically points to the updated file — no copying needed.

What is a Softlink?

A softlink is like a shortcut. It is a special file that just points to another file located elsewhere. When the kernel reads the softlink, it transparently accesses the actual file at the target path.

Softlink — how it works
/lib/modules/6.8.0-90-generic/kernel/drivers/misc/
  mod1.ko  ──────────────────────────────────────────►  /home/raviteja/.../mod1.ko
  mod2.ko  ──────────────────────────────────────────►  /home/raviteja/.../mod2.ko

The .ko files stay in your project folder.
modprobe reads through the link transparently.

Creating the Softlinks

The command to create a softlink is ln -s <source> <destination>. We place the link inside the misc driver directory of the running kernel’s module tree:

Terminal — Create softlinks for mod1 and mod2

# First check where your .ko files are raviteja@Inspiron:~$ pwd /home/raviteja/lsyspg/kernel_programming/Day7/export_module raviteja@Inspiron:~$ ls Makefile mod1.c mod1.ko mod2.c mod2.ko module.c
# Create softlink for mod1.ko raviteja@Inspiron:~$ sudo ln -s \ /home/raviteja/lsyspg/kernel_programming/Day7/export_module/mod1.ko \ /lib/modules/6.8.0-90-generic/kernel/drivers/misc/mod1.ko
# Create softlink for mod2.ko raviteja@Inspiron:~$ sudo ln -s \ /home/raviteja/lsyspg/kernel_programming/Day7/export_module/mod2.ko \ /lib/modules/6.8.0-90-generic/kernel/drivers/misc/mod2.ko
# Verify the links are created raviteja@Inspiron:~$ ls -la /lib/modules/6.8.0-90-generic/kernel/drivers/misc/ | grep mod lrwxrwxrwx 1 root root … mod1.ko -> /home/raviteja/…/mod1.ko lrwxrwxrwx 1 root root … mod2.ko -> /home/raviteja/…/mod2.ko

⚠️

Use the full absolute path for both the source and destination in ln -s. If you use a relative path, the link breaks the moment you run the command from a different directory. Always start with /home/... not ./.

05 Running depmod -a — Rebuilding the Dependency Map

Now that the softlinks are in place, modprobe still does not know about our modules. Remember — modprobe reads from modules.dep, and that file has not been updated yet. We need to run depmod -a to regenerate it.

Terminal — Run depmod

raviteja@Inspiron:~$ sudo depmod -a # No output = success. depmod ran silently and updated modules.dep

What does depmod -a actually do? It walks the entire /lib/modules/$(uname -r)/ directory, reads every .ko file, looks at their unresolved symbols and exported symbols, and figures out who depends on whom. The result is written back into modules.dep.

Let us verify that our modules appeared in the file:

Terminal — Inspect modules.dep

 

viteja@raviteja-Inspiron-15-3511:/lib/modules/6.8.0-90-generic/kernel/drivers/misc$ grep mod /lib/modules/6.8.0-90-generic/modules.dep
kernel/drivers/misc/mod1.ko:
kernel/drivers/misc/mod2.ko: kernel/drivers/misc/mod1.ko
raviteja@Inspiron:~$ grep mod /lib/modules/6.8.0-90-generic/modules.dep kernel/drivers/misc/mod2.ko: kernel/drivers/misc/mod1.ko kernel/drivers/misc/mod1.ko:

There it is. modules.dep now knows that mod2 depends on mod1. modprobe will use this information every time someone asks it to load mod2.

Golden rule: Every time you create, remove, or update a softlink in the kernel module tree, run sudo depmod -a again. If you skip this step, modprobe works with stale dependency information and may fail or load the wrong version.

What is modules.dep.bin?

You might notice a modules.dep.bin file alongside modules.dep. This is just a binary-encoded version of the same information — modprobe reads the .bin version at runtime because it loads faster than parsing text. depmod -a generates both files automatically, so you never need to worry about .bin directly.

06 Loading with modprobe — Full Walkthrough

Everything is set up. Softlinks are created, depmod -a has run, and modules.dep has the dependency entry. Now watch how simple the load becomes:

1 Just load mod2 — do not load mod1 manually. Let modprobe figure it out.

2 Check lsmod — you will see both mod1 and mod2 are loaded, even though you only asked for mod2.

3 Check dmesg — both init functions ran, in the correct order: mod1 first, mod2 second.

Terminal — Full modprobe walkthrough

# Make sure nothing is loaded first raviteja@Inspiron:~$ lsmod | grep mod (no output — modules are not loaded yet)
# Load ONLY mod2. modprobe will auto-load mod1 first. raviteja@Inspiron:~$ sudo modprobe mod2
# Check what is loaded — BOTH modules are now live! raviteja@Inspiron:~$ lsmod | grep mod mod2 12288 0 mod1 12288 1 mod2
# Check the kernel log raviteja@Inspiron:~$ dmesg | tail -5 [ 9820.441100] mod1_init: mod1 loaded, myadd now in symbol table [ 9820.441350] mod2_init: mod2 init — calling myadd from mod1 [ 9820.441361] myadd: sum of 3 + 5 = 8 [ 9820.441364] mod2_init: myadd(3, 5) = 8

Look at the lsmod output carefully. The 1 in mod1’s row (third column) means it has one user — mod2. And the word mod2 at the end confirms which module is using it. This is the kernel’s built-in dependency tracking in action.

What Just Happened Under the Hood?

When you ran sudo modprobe mod2, here is the exact sequence of events:

modprobe internal execution flow
sudo modprobe mod2
       
       
┌─ modprobe reads modules.dep ──────────────────────┐
│  Found: mod2.ko depends on mod1.ko               │
└───────────────────────┬───────────────────────────┘
                        
       ┌────────────────┴─────────────────┐
                                       
┌── Step 1 ──────────┐          ┌── Step 2 ──────────┐
│  insmod mod1.ko    │    then  │  insmod mod2.ko    │
│  (dependency)      │   ──────►│  (requested)       │
└────────────────────┘          └────────────────────┘

Both modules loaded. Correct order. Zero effort from you.

07 Removing Modules with modprobe -r

Just like loading, unloading with modprobe is also automatic. You only need to ask it to remove mod2, and it will unload both modules in the correct reverse order — mod2 first, then mod1.

Terminal — Remove modules with modprobe -r

# Before removal — both loaded raviteja@Inspiron:~$ lsmod | grep mod mod2 12288 0 mod1 12288 1 mod2 # Remove using modprobe -r — only specify mod2 raviteja@Inspiron:~$ sudo modprobe -r mod2
# After removal — both are gone raviteja@Inspiron:~$ lsmod | grep mod (no output — both modules unloaded)
# Confirm in dmesg raviteja@Inspiron:~$ dmesg | tail -3 [ 9940.771200] mod2_exit: mod2 exit [ 9940.771430] mod1_exit: mod1 unloading — symbol myadd removed from table

💡

modprobe -r only removes a dependency module (mod1 in this case) if no other loaded module still needs it. If some other third module was also using mod1, modprobe would remove mod2 but leave mod1 in place. The reference count protects against accidental removal of shared modules.

08 insmod vs modprobe — When to Use Which

Both tools load kernel modules. Understanding when to reach for each one saves a lot of debugging time.

Feature insmod modprobe
Resolves dependencies ❌ No — you do it manually ✅ Yes — automatically
Needs module in /lib/modules ❌ No — works from any path ✅ Yes — or a softlink to it
Reads modules.dep ❌ No ✅ Yes
Needs full path to .ko ✅ Yes ❌ No — just use module name
Best for Quick single-module testing Multi-module drivers, production use
Unload command rmmod <module> modprobe -r <module>

During your early development sessions — editing code, recompiling, testing a single module — insmod is perfectly fine and faster. Once your driver has dependencies and you want to test it more realistically or share it with someone else, switch to modprobe.

09 Common Mistakes and Fixes

Problem Why it happens How to fix it
modprobe: FATAL: Module mod2 not found Softlink not created or depmod not run Create softlinks then run sudo depmod -a
modprobe loads old version of module Recompiled module but forgot to rerun depmod Always run sudo depmod -a after recompiling
Softlink created but modprobe still fails Relative path used in ln -s — link is broken Delete and recreate link with full absolute path
modprobe -r only removes mod2, not mod1 Another module is also using mod1 (use count > 0) Normal behaviour — remove all users of mod1 first
Softlink destination already exists error Softlink from a previous session still exists Remove old link: sudo rm /lib/modules/.../mod1.ko

🚫

Never delete or overwrite real kernel module files in /lib/modules/. Only create softlinks to your custom modules in the misc or a dedicated subdirectory. Accidentally removing a system module can make your kernel unbootable. so now you know how modprobe for Kernel Modules works.

10 Summary

What We Covered in This Article

  • insmod is manual — you track load order yourself. modprobe is smart — it reads a dependency map and handles everything.
  • modules.dep is the dependency map file. It lives in /lib/modules/$(uname -r)/ and maps each module to its required dependencies.
  • Softlinks let you register your out-of-tree module with the kernel module tree without copying the file. Use ln -s <full_src_path> <dest_in_module_tree>.
  • depmod -a walks the module tree, figures out dependencies from exported and undefined symbols, and rebuilds modules.dep. Always run it after creating or updating links.
  • modprobe mod2 automatically loads mod1 first (because modules.dep says so), then mod2. No manual ordering needed.
  • modprobe -r mod2 removes both modules cleanly in reverse order — mod2 first, then mod1 — as long as mod1 has no other users.
  • Use lsmod to verify loaded modules and their use counts. Use dmesg to see init/exit log messages and confirm everything ran in the right order.

Final summary:

raviteja@raviteja-Inspiron-15-3511:~/lsyspg/kernel_programming/Day7/export_module$ ls
Makefile  mod1.c  mod1.ko  mod1.mod  mod1.mod.c  mod1.mod.o  mod1.o  mod2.c  mod2.ko  mod2.mod  mod2.mod.c  mod2.mod.o  mod2.o  module.c  modules.order  Module.symvers
raviteja@raviteja-Inspiron-15-3511:~/lsyspg/kernel_programming/Day7/export_module$ uname -r
6.8.0-106-generic
raviteja@raviteja-Inspiron-15-3511:~/lsyspg/kernel_programming/Day7/export_module$ sudo ln -s /home/raviteja/lsyspg/kernel_programming/Day7/export_module/mod1.ko \
  /lib/modules/6.8.0-106-generic/kernel/drivers/misc/mod1.ko
raviteja@raviteja-Inspiron-15-3511:~/lsyspg/kernel_programming/Day7/export_module$ sudo ln -s /home/raviteja/lsyspg/kernel_programming/Day7/export_module/mod2.ko \
  /lib/modules/6.8.0-106-generic/kernel/drivers/misc/mod2.ko
raviteja@raviteja-Inspiron-15-3511:~/lsyspg/kernel_programming/Day7/export_module$ sudo depmod -a
raviteja@raviteja-Inspiron-15-3511:~/lsyspg/kernel_programming/Day7/export_module$ sudo modprobe mod2
raviteja@raviteja-Inspiron-15-3511:~/lsyspg/kernel_programming/Day7/export_module$ 

output in dmesg

 [ 5583.250528] module1_init:module 1 init 
[ 5583.251779] mod2_init: in mod2 init
[ 5583.251790] myadd sum of 3+5=8
[ 5583.251794] mod2_init: add=8

hope you understood how simple the modprobe for Kernel Modules is

Free learning to all!!

EmbeddedPathashala.

Leave a Reply

Your email address will not be published. Required fields are marked *