Skip to content

Linux Kernel Modules: Complete Guide

Overview

Kernel modules are pieces of code that can be loaded and unloaded into the kernel upon demand. They extend the kernel's functionality without requiring a system reboot, providing drivers for hardware, filesystem support, system calls, and network protocols.

Kernel Module Basics

What are Kernel Modules?

  • Loadable code segments that extend kernel functionality
  • Device drivers for hardware components
  • Filesystem implementations (ext4, btrfs, etc.)
  • Network protocols and filters
  • System call implementations
  • Security frameworks (SELinux, AppArmor modules)

Module vs Built-in

# Built-in: Compiled directly into kernel
# - Always available
# - Cannot be removed
# - Increases kernel size

# Modular: Loaded as needed
# - Loaded on demand
# - Can be unloaded
# - Reduces memory usage
# - Easier updates

Working with Kernel Modules

Listing Modules

# List all loaded modules
lsmod

# List with detailed information
lsmod | column -t

# Module information
modinfo module_name
modinfo e1000e

# Find module file location
modinfo -n module_name

# Show module dependencies
modinfo -F depends module_name

# List all available modules
find /lib/modules/$(uname -r) -name "*.ko" | head -20

Loading and Unloading Modules

# Load a module
sudo modprobe module_name
sudo modprobe e1000e

# Load module with parameters
sudo modprobe module_name parameter=value
sudo modprobe snd-hda-intel model=auto

# Load module file directly (not recommended)
sudo insmod /path/to/module.ko

# Unload a module
sudo modprobe -r module_name
sudo rmmod module_name

# Force unload (dangerous)
sudo rmmod -f module_name

Module Information and Dependencies

# Show module details
modinfo ext4
# Output includes:
# - filename: /lib/modules/5.15.0/kernel/fs/ext4/ext4.ko
# - description: Fourth Extended Filesystem
# - author: Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o
# - license: GPL
# - depends: mbcache,jbd2
# - parm: max_dir_size_kb:Maximum size of directory in KB

# Check if module is loaded
lsmod | grep module_name

# Show module usage count
cat /proc/modules | grep module_name

# Show module dependencies tree
modprobe --show-depends module_name

Module Configuration

Automatic Module Loading

# Modules loaded at boot
/etc/modules
/etc/modules-load.d/*.conf

# Example: /etc/modules-load.d/custom.conf
loop
dm-crypt
nvidia

# Prevent module loading
/etc/modprobe.d/blacklist.conf

# Example blacklist entry
blacklist nouveau
blacklist pcspkr
install pcspkr /bin/true

Module Parameters

# Set module parameters at load time
/etc/modprobe.d/custom.conf

# Examples:
options snd-hda-intel model=auto
options nouveau modeset=0
options kvm_intel nested=1
options zfs zfs_arc_max=8589934592

# View current parameters
systool -v -m module_name
cat /sys/module/module_name/parameters/*

# Runtime parameter modification (if supported)
echo value > /sys/module/module_name/parameters/parameter_name

Module Aliases

# Create module aliases
/etc/modprobe.d/aliases.conf

# Example aliases
alias eth0 e1000e
alias sound-slot-0 snd-hda-intel
alias char-major-10-135 rtc

Module Development

Simple "Hello World" Module

// hello.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

static int __init hello_init(void)
{
    printk(KERN_INFO "Hello, World! Module loaded.\n");
    return 0;
}

static void __exit hello_exit(void)
{
    printk(KERN_INFO "Goodbye, World! Module unloaded.\n");
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Hello World module");
MODULE_VERSION("1.0");

Makefile for Module Compilation

# Makefile
obj-m += hello.o

KDIR = /lib/modules/$(shell uname -r)/build

all:
    make -C $(KDIR) M=$(PWD) modules

clean:
    make -C $(KDIR) M=$(PWD) clean

install:
    make -C $(KDIR) M=$(PWD) modules_install

.PHONY: all clean install

Building and Installing Custom Module

# Install development tools
sudo apt install build-essential linux-headers-$(uname -r)  # Debian/Ubuntu
sudo yum groupinstall "Development Tools"                   # CentOS/RHEL
sudo yum install kernel-devel kernel-headers               # CentOS/RHEL

# Build module
make

# Load module
sudo insmod hello.ko

# Check module
lsmod | grep hello
dmesg | tail

# Unload module
sudo rmmod hello

# Install module system-wide
sudo make install
sudo depmod -a

Advanced Module Programming

Module with Parameters

// param_module.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/moduleparam.h>

static int debug_level = 1;
static char *device_name = "default";
static int port_array[4] = {1, 2, 3, 4};
static int port_count = 4;

module_param(debug_level, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug_level, "Debug level (default: 1)");

module_param(device_name, charp, S_IRUGO);
MODULE_PARM_DESC(device_name, "Device name");

module_param_array(port_array, int, &port_count, S_IRUGO);
MODULE_PARM_DESC(port_array, "Array of port numbers");

static int __init param_init(void)
{
    int i;
    printk(KERN_INFO "Debug level: %d\n", debug_level);
    printk(KERN_INFO "Device name: %s\n", device_name);
    printk(KERN_INFO "Port count: %d\n", port_count);

    for (i = 0; i < port_count; i++) {
        printk(KERN_INFO "Port[%d]: %d\n", i, port_array[i]);
    }

    return 0;
}

static void __exit param_exit(void)
{
    printk(KERN_INFO "Parameter module unloaded\n");
}

module_init(param_init);
module_exit(param_exit);

MODULE_LICENSE("GPL");

Character Device Driver Example

// char_dev.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/uaccess.h>

#define DEVICE_NAME "mychardev"
#define CLASS_NAME "mychar"

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple character device driver");
MODULE_VERSION("1.0");

static int major_number;
static char message[256] = {0};
static short message_size;
static int number_opens = 0;
static struct class* char_class = NULL;
static struct device* char_device = NULL;

// Function prototypes
static int dev_open(struct inode *, struct file *);
static int dev_release(struct inode *, struct file *);
static ssize_t dev_read(struct file *, char *, size_t, loff_t *);
static ssize_t dev_write(struct file *, const char *, size_t, loff_t *);

static struct file_operations fops = {
    .open = dev_open,
    .read = dev_read,
    .write = dev_write,
    .release = dev_release,
};

static int __init char_init(void)
{
    printk(KERN_INFO "MyCharDev: Initializing device\n");

    // Allocate major number
    major_number = register_chrdev(0, DEVICE_NAME, &fops);
    if (major_number < 0) {
        printk(KERN_ALERT "MyCharDev failed to register major number\n");
        return major_number;
    }

    // Register device class
    char_class = class_create(THIS_MODULE, CLASS_NAME);
    if (IS_ERR(char_class)) {
        unregister_chrdev(major_number, DEVICE_NAME);
        printk(KERN_ALERT "Failed to register device class\n");
        return PTR_ERR(char_class);
    }

    // Register device driver
    char_device = device_create(char_class, NULL, MKDEV(major_number, 0), NULL, DEVICE_NAME);
    if (IS_ERR(char_device)) {
        class_destroy(char_class);
        unregister_chrdev(major_number, DEVICE_NAME);
        printk(KERN_ALERT "Failed to create the device\n");
        return PTR_ERR(char_device);
    }

    printk(KERN_INFO "MyCharDev: device created correctly\n");
    return 0;
}

static void __exit char_exit(void)
{
    device_destroy(char_class, MKDEV(major_number, 0));
    class_unregister(char_class);
    class_destroy(char_class);
    unregister_chrdev(major_number, DEVICE_NAME);
    printk(KERN_INFO "MyCharDev: device unregistered\n");
}

static int dev_open(struct inode *inodep, struct file *filep)
{
    number_opens++;
    printk(KERN_INFO "MyCharDev: Device opened %d time(s)\n", number_opens);
    return 0;
}

static ssize_t dev_read(struct file *filep, char *buffer, size_t len, loff_t *offset)
{
    int error_count = 0;

    error_count = copy_to_user(buffer, message, message_size);

    if (error_count == 0) {
        printk(KERN_INFO "MyCharDev: Sent %d characters to user\n", message_size);
        return (message_size = 0);
    } else {
        printk(KERN_INFO "MyCharDev: Failed to send %d characters to user\n", error_count);
        return -EFAULT;
    }
}

static ssize_t dev_write(struct file *filep, const char *buffer, size_t len, loff_t *offset)
{
    sprintf(message, "%s(%zu letters)", buffer, len);
    message_size = strlen(message);
    printk(KERN_INFO "MyCharDev: Received %zu characters from user\n", len);
    return len;
}

static int dev_release(struct inode *inodep, struct file *filep)
{
    printk(KERN_INFO "MyCharDev: Device closed\n");
    return 0;
}

module_init(char_init);
module_exit(char_exit);

Common Module Categories

Network Modules

# Network interface drivers
e1000e          # Intel Ethernet
r8169           # Realtek Ethernet
iwlwifi         # Intel WiFi
ath9k           # Atheros WiFi

# Network protocols
tcp_bbr         # BBR congestion control
ip_tables       # Netfilter
nf_conntrack    # Connection tracking
bridge          # Bridge networking

# Load network module with parameters
modprobe e1000e InterruptThrottleRate=1,1,1,1

Storage Modules

# Filesystem modules
ext4            # Fourth extended filesystem
btrfs           # B-tree filesystem
xfs             # XFS filesystem
ntfs            # NTFS support
fuse            # Filesystem in userspace

# Block device drivers
ahci            # SATA AHCI
nvme            # NVMe SSD
mpt3sas         # LSI SAS controller
megaraid_sas    # MegaRAID controller

# Load storage module
modprobe btrfs

Hardware Drivers

# Graphics drivers
nvidia          # NVIDIA proprietary
nouveau         # NVIDIA open source
radeon          # AMD Radeon
i915            # Intel graphics

# Audio drivers
snd_hda_intel   # Intel HD Audio
snd_usb_audio   # USB audio
snd_ac97_codec  # AC97 codec

# USB drivers
usb_storage     # USB mass storage
usbhid          # USB HID devices
cdc_acm         # USB modem

Module Signing and Security

Module Signing

# Check if module signing is enabled
cat /proc/sys/kernel/modules_disabled
zcat /proc/config.gz | grep MODULE_SIG

# Generate signing key
openssl req -new -nodes -utf8 -sha256 -days 36500 -batch \
    -x509 -config x509.genkey -outform DER \
    -out signing_key.x509 -keyout signing_key.priv

# Sign module
/usr/src/linux/scripts/sign-file sha256 signing_key.priv signing_key.x509 module.ko

# Check module signature
modinfo module.ko | grep sig

Secure Boot and Modules

# Check Secure Boot status
mokutil --sb-state

# Enroll signing key for Secure Boot
sudo mokutil --import signing_key.der

# Check enrolled keys
mokutil --list-enrolled

Module Debugging and Troubleshooting

Debugging Techniques

# Enable dynamic debugging
echo 'module module_name +p' > /sys/kernel/debug/dynamic_debug/control

# Check module dependencies
lsmod | grep module_name
modprobe --show-depends module_name

# View module symbols
cat /proc/kallsyms | grep module_name

# Check module information
modinfo module_name
systool -v -m module_name

Common Issues and Solutions

# Module not found
# Solution: Install linux-headers package, check module name

# Module loading failed
dmesg | tail
journalctl -k | tail

# Dependency issues
depmod -a
modprobe --show-depends module_name

# Version mismatch
# Rebuild module for current kernel
uname -r
ls /lib/modules/

Using ftrace for Module Debugging

# Enable function tracing
echo function > /sys/kernel/debug/tracing/current_tracer

# Filter by module
echo ':mod:module_name' > /sys/kernel/debug/tracing/set_ftrace_filter

# Start tracing
echo 1 > /sys/kernel/debug/tracing/tracing_on

# Load/test module, then view trace
cat /sys/kernel/debug/tracing/trace

Performance and Memory Management

Module Memory Usage

# Check module memory usage
cat /proc/modules
grep module_name /proc/*/maps

# Module memory layout
cat /sys/module/module_name/sections/.text
cat /sys/module/module_name/sections/.data
cat /sys/module/module_name/sections/.bss

# Memory debugging
echo 1 > /proc/sys/vm/drop_caches  # Clear cache before testing

Performance Monitoring

# Monitor module performance
perf record -e cycles -a sleep 10
perf report

# Trace module function calls
trace-cmd record -p function_graph -g module_function
trace-cmd report

# Profile specific module
perf record -e cycles:k -a --call-graph dwarf

Module Management Best Practices

Development Best Practices

// Always check return values
if (!ptr) {
    printk(KERN_ERR "Memory allocation failed\n");
    return -ENOMEM;
}

// Use proper cleanup in exit function
static void __exit cleanup_module(void) {
    // Cleanup in reverse order of initialization
    device_destroy(class, dev);
    class_destroy(class);
    unregister_chrdev(major, DEVICE_NAME);
}

// Use reference counting
struct kobject *kobj = kobject_get(obj);
// ... use object ...
kobject_put(kobj);

Production Best Practices

# 1. Test modules thoroughly in development
# 2. Use signed modules in production
# 3. Monitor module loading/unloading
# 4. Keep modules up to date
# 5. Document module dependencies
# 6. Use proper error handling
# 7. Implement proper cleanup
# 8. Monitor system stability

Advanced Module Topics

Module Versioning

# Check module version magic
modinfo module_name | grep vermagic

# Force load module (dangerous)
modprobe --force module_name

# Module version dependencies
depmod -A

Dynamic Module Loading

# Automatic hardware detection
udevadm info --export-db
udevadm test /sys/class/net/eth0

# Hotplug events
udevadm monitor --property

# Module autoloading rules
/etc/udev/rules.d/

Out-of-Tree Modules

# DKMS (Dynamic Kernel Module Support)
sudo apt install dkms

# Add module to DKMS
sudo dkms add -m module_name -v 1.0

# Build module
sudo dkms build -m module_name -v 1.0

# Install module
sudo dkms install -m module_name -v 1.0

# Check DKMS status
dkms status

Kernel modules provide the foundation for Linux's modular architecture, enabling dynamic system configuration, hardware support, and functionality extension without kernel rebuilds.