Kernel Modules
The Linux kernel is modular: most drivers and many optional features are not compiled into the kernel image at all. They ship as separate .ko files under /lib/modules/$(uname -r)/ and load into the running kernel on demand. A kernel module runs in ring 0 with full hardware access — it is kernel code, not a user-space program — yet it can be inserted and removed at runtime without rebooting. This is how the same generic kernel that Ubuntu installs boots on a laptop, a cloud VM, and a storage server: it carries thousands of modules and loads only the handful each machine actually needs.
The operational consequence is that hardware support and driver behavior are something you manage, not something fixed at build time. You add support for a new NIC by loading its module, tune a driver by passing it parameters, and stop a buggy or unwanted driver from ever loading by blacklisting it. The catch is that a module runs with kernel privileges, so a bad one panics the whole machine — and under Secure Boot an unsigned module is refused outright. The tools are lsmod, modinfo, and modprobe, plus the configuration directories under /etc/modprobe.d and /etc/modules-load.d.
Modules versus Built-in
A feature in the kernel is either built in — compiled directly into the vmlinuz image and always present — or built as a module that loads later. Distributions compile the small set of things needed to mount the root filesystem and bring the CPU up (the core scheduler, base memory management, the filesystem the root partition uses) directly into the image, and ship everything else — most filesystems, every network and storage driver, sound, USB, virtualization helpers — as modules. The reason is size and flexibility: a kernel with every driver compiled in would be enormous and would carry code for hardware no single machine has.
You can tell which is which. The kernel build config records the choice as =y (built in) or =m (module) in /boot/config-$(uname -r), and only modules ever appear in lsmod. This distinction matters when a feature refuses to behave as a runtime option: a parameter for a built-in driver cannot be changed with modprobe at all, only on the kernel command line at boot.
Managing Modules
lsmod lists what is currently loaded, with each module's memory size and its use count — how many other modules or open references depend on it. A module with a non-zero use count cannot be removed until its dependents are gone. modinfo <name> reads metadata straight out of the .ko file: the author, the description, the parameters it accepts, its dependencies, and whether it is signed. Reach for modinfo before loading an unfamiliar module to see what options it takes.
modprobe is the command to load and unload. The reason it exists rather than the lower-level insmod is dependency resolution: modprobe reads modules.dep (generated by depmod) and pulls in every prerequisite module in the right order, then loads the one you asked for. insmod takes a single .ko path and loads exactly that file — if it needs another module first, it simply fails with Unknown symbol. Removal is modprobe -r <name>, which also unloads now-unused dependencies; rmmod is its blunt equivalent.
# inspect, then load with dependencies resolved modinfo e1000e sudo modprobe e1000e lsmod | grep e1000e # unload it and any deps it pulled in sudo modprobe -r e1000e
On Red Hat and derivatives the commands are identical — kmod provides modprobe, lsmod, and modinfo on every modern distribution. What differs is only where vendor and third-party modules come from: Debian and Ubuntu use DKMS packages and linux-modules-extra, while RHEL ships extra drivers in kernel-modules-extra and signs out-of-tree modules through a different key-enrollment flow.
Loading at Boot and Blacklisting
Most modules load automatically: udev sees a device appear, looks up the module that claims its hardware ID, and loads it. When you need a module that has no triggering device — a tunable filesystem helper, a watchdog, an overlay driver for containers — list its name in a file under /etc/modules-load.d/ and systemd-modules-load.service loads it at every boot. One module name per line; the filename ends in .conf.
Blacklisting is the inverse, and the source of a recurring mistake. Putting blacklist <name> in a file under /etc/modprobe.d/ stops the module from being loaded automatically by udev or as a dependency — but it does not stop an explicit modprobe <name>, and it does not help if the module is already baked into the initramfs. To truly prevent loading, combine blacklist with an install <name> /bin/false line, then rebuild the initramfs so the early-boot environment carries the change too.
# /etc/modprobe.d/blacklist-nouveau.conf blacklist nouveau install nouveau /bin/false # then rebuild the initramfs so early boot honors it sudo update-initramfs -u # Debian/Ubuntu sudo dracut -f # RHEL/Fedora
Module Parameters
Drivers accept parameters that change their behavior. modinfo -p <name> lists them; /sys/module/<name>/parameters/ shows the live values of a loaded module, some of which are writable on the fly. For a one-off you pass options on the load line — modprobe usbcore autosuspend=-1 — but that lasts only until the next reboot or reload.
For a persistent parameter, write an options line into /etc/modprobe.d/ so it applies every time the module loads. As with blacklisting, if the module loads from the initramfs (a storage or filesystem driver, for example) the option only takes effect after an initramfs rebuild — the early-boot copy of the config is a snapshot, not a live read of /etc.
# /etc/modprobe.d/i915.conf — persistent driver option options i915 enable_guc=2
Signing and Secure Boot
With UEFI Secure Boot enabled, the kernel enforces a signature check on every module it loads. In-tree modules shipped by the distribution are signed with a key the firmware trusts, so they load normally. An out-of-tree module — an NVIDIA driver, a VirtualBox helper, anything built locally via DKMS — is unsigned by default and is refused with Required key not available in dmesg. The load silently fails and the hardware it drives simply does not work, which is a confusing symptom if you do not know to look for it.
The fix is to sign the module with a Machine Owner Key and enroll that key in the firmware. On Debian and Ubuntu, DKMS can generate a MOK and call mokutil --import for you; you confirm the enrollment in a blue MOK Manager screen on the next reboot, after which your locally built modules load. The alternative — disabling Secure Boot — works but trades away the boot-chain integrity that Secure Boot exists to provide.
- Loading with
insmod /path/to/foo.koinstead ofmodprobe foo—insmoddoes no dependency resolution, so the load fails withUnknown symbol in modulethe moment the driver needs a prerequisite that is not already loaded. - Blacklisting only with a
blacklistline and expecting it to be absolute — it stops automatic loading but not an explicitmodprobeor a dependency pull-in. Without the matchinginstall <name> /bin/falsethe module still loads when something asks for it by name. - Editing
/etc/modprobe.d/for a storage or filesystem driver and never rebuilding the initramfs — the early-boot environment keeps the old config, so the blacklist or option is ignored untilupdate-initramfs -u(ordracut -f) bakes the change in. - Trying to change a parameter on a built-in driver with a
modprobeoptions line — a=yfeature is never loaded as a module, so the option is silently inert; built-in parameters must go on the kernel command line in the bootloader instead. - Building an out-of-tree module on a Secure Boot machine and not signing it — the kernel refuses it with
Required key not available, the load fails silently, and the device it drives appears simply broken. - Forcing out a module that is still in use with
rmmod -f— yanking a driver with a non-zero use count can hang or panic the kernel;modprobe -rrespects dependencies and refuses when the module is busy.
- Use
modprobefor every load and unload — it resolves dependencies throughmodules.depand pulls in prerequisites in order. Keepinsmodandrmmodonly for testing a single freshly compiled.ko. - Run
modinfo <name>before loading an unfamiliar module to read its parameters, dependencies, and signature status straight from the file. - Blacklist with both
blacklist <name>andinstall <name> /bin/falsein a named file under/etc/modprobe.d/, then rebuild the initramfs so early boot honors it. - Persist module parameters as
options <name> key=valuein/etc/modprobe.d/rather than on the load command line, so the setting survives reboots and reloads. - Rebuild the initramfs with
update-initramfs -uon Debian/Ubuntu ordracut -fon RHEL after any change touching a module that loads during early boot. - On Secure Boot machines, sign locally built modules with an enrolled Machine Owner Key — let DKMS generate and
mokutil --importthe MOK rather than disabling Secure Boot. - List boot-time modules that have no triggering device in
/etc/modules-load.d/*.conf, one name per line, instead of scriptingmodprobecalls in a startup script.
kldload, kldunload, and kldstat manage loadable kernel modules on FreeBSDKnowledge Check
Why is modprobe foo preferred over insmod /lib/modules/.../foo.ko?
modprobereadsmodules.depand loads every prerequisite module in order, whileinsmodloads one file and fails withUnknown symbolif a dependency is missinginsmodcan only load features already compiled into the kernel image, whereasmodprobeis the sole command that knows how to locate and handle loadable.komodule filesmodprobeloads each module in user space for memory safety, whileinsmodinserts the very same code straight into ring 0insmodstrictly requires a valid Secure Boot signature, whilemodprobequietly bypasses the kernel signature check entirely
You add blacklist nouveau to /etc/modprobe.d/ but the driver still loads at boot. What is the most likely reason?
- The module is baked into the initramfs, so the early-boot environment never sees the new config — you must rebuild it with
update-initramfs -uand add aninstall ... /bin/falseline - A
blacklistline only ever takes effect once the module's in-kernel use count has dropped all the way to zero, which the GPU keeps above zero - Blacklisting directives have to live in
/etc/modules-load.d/instead of/etc/modprobe.d/, so the entry is being silently ignored at boot - The driver is compiled directly into the kernel image as a static built-in rather than a loadable module, so no configuration directory anywhere under
/etccan affect whether it loads at boot
Under UEFI Secure Boot, a locally built DKMS module fails with Required key not available in dmesg. What is happening?
- The module is not signed by a trusted key, so the kernel refuses to load it; signing it with an enrolled Machine Owner Key resolves it
- The kernel headers used to compile the module were from the wrong release, so its exported symbol table mismatches the version of the running kernel
- The module exceeded the strict maximum binary size that Secure Boot permits for any out-of-tree driver loaded at runtime
- DKMS-built modules simply can never load on a system with Secure Boot active, regardless of how they are signed
What is the correct way to make a module parameter persist across reboots?
- Write an
options <name> key=valueline in a file under/etc/modprobe.d/so it applies every time the module loads - Pass it just once on a
modprobecommand line; the kernel caches the value under/sys/module/and replays it automatically at every boot - Echo the value straight into
/sys/module/<name>/parameters/<key>, which the kernel then flushes back to disk automatically - Add the module name to a file in
/etc/modules-load.d/with the parameter appended after a space on the same line
You got correct