Right, so you’ve compiled your first kernel module. You feel like a proper wizard, conjuring hardware into existence with a simple insmod. But then you realize you have to pass it an argument. And then you have to do it again after a reboot. And suddenly, typing insmod /lib/modules/$(uname -r)/kernel/drivers/misc/my_awesome_module.ko magic_option=1 every time feels less like wizardry and more like manual labor. This is where we stop being peasants and start acting like sysadmins. We automate.

The kernel gives us two main ways to handle this: the quick-and-dirty modprobe command line and the persistent, “this is how we do it professionally” method using the modprobe.d directory. We’ll cover both, because you need to know the escape hatch before you learn the proper landing sequence.

Passing Parameters on the Fly with modprobe

First, forget insmod exists for loading modules. insmod requires a full path and does absolutely zero dependency resolution. modprobe is its smarter, more sociable cousin. It looks in the standard module directories, understands dependencies (if module foo needs module bar, modprobe foo will load both), and crucially, it lets you pass parameters easily.

Let’s say you have a module called useless_debug.ko that has a parameter named verbosity_level. To load it and set that level to a truly ridiculous value, you’d run:

sudo modprobe useless_debug verbosity_level=7

The syntax is dead simple: modprobe <module_name> <parameter_name>=<value>. No spaces around the equals sign. This is fantastic for testing, but it’s ephemeral. The moment you reboot, that command is history. For anything that needs to stick, we go to the config file.

The modprobe.d Directory: Your Persistent Config Hub

This is the real trick. The /etc/modprobe.d/ directory is where you drop configuration files that modprobe reads automatically. This isn’t just for parameters; it’s also for blacklisting modules, defining aliases, and running custom commands. The beauty is its simplicity: each file is a .conf file (usually named for its purpose, like my-module-settings.conf), and the syntax inside is straightforward.

Let’s create a config file to make our useless_debug module always load with verbosity_level=3 and a second parameter, enable_telemetry=Y.

sudo nano /etc/modprobe.d/useless-debug.conf

Inside this new file, you’d write:

# This is a comment. Lines starting with '#' are ignored.
# The syntax is: options <modulename> <param1>=<value> <param2>=<value> ...
options useless_debug verbosity_level=3 enable_telemetry=Y

Save the file. Now, the magic happens. The next time your system boots, or the next time you run sudo modprobe useless_debug (without any arguments!), it will automatically pick up those options. It’s that simple. The system works by reading all the .conf files in /etc/modprobe.d/ in alphabetical order and assembling the configuration. This means later files can override options set in earlier ones, which is both a feature and a foot-cannon. Name your files carefully (I often start with a number, like 00-my-config.conf) to control the order.

Blacklisting: Telling the Kernel to “Go Away”

Another superpower in modprobe.d is blacklisting. This is crucial when the kernel automatically loads a module for hardware you don’t want to use, or when you have a replacement driver (e.g., the open-source nouveau vs. the proprietary nvidia driver).

Let’s say your system keeps loading the pcspkr module, which is responsible for that awful, shrill system beep. You want to silence it permanently. Create a file:

sudo nano /etc/modprobe.d/nobeep.conf

And put this inside:

# Prevent the pcspkr module from loading at all
blacklist pcspkr

The blacklist directive does exactly what you think: it prevents modprobe from loading the module. However, a word of warning here: blacklisting a module does not prevent the kernel from loading it itself during the early boot process if it’s built-in or a dependency of another module. For truly stubborn modules, you might also need to use install <modulename> /bin/false which tells modprobe to run /bin/false (which does nothing and fails) instead of actually loading the module, effectively blocking it.

The Gotchas and Professional-Grade Tips

  1. Finding Parameters: Don’t guess a module’s parameters. Use modinfo <module_name> to get a list of all accepted parameters, their type, and a description. It’s your best friend.

    modinfo useless_debug
    
  2. Quoting Values: Generally, you don’t need quotes. But if a value has a space in it (yes, some parameters accept strings), you must wrap the entire value in double quotes.

    options my_module description="This is a string with spaces"
    
  3. Overriding is a Feature: You can have multiple options lines for the same module across different files. The last one read wins. This is useful for having a base configuration and then environment-specific overrides (e.g., a 10-base.conf and a 90-production-override.conf).

  4. The --remove Trap: When you run modprobe -r <module> to remove it, modprobe does not read the modprobe.d config files. The options you defined there were only for insertion. Removal is handled by the module’s own .exit() function. This is a common source of confusion.

The modprobe.d system is a perfect example of the Unix philosophy: a simple, text-file-based configuration system that’s incredibly powerful and reliable. It’s survived decades because it just works. Use it, and stop typing those long command lines.