udev Automatic Device Node Creation (Part 1)
If you are learning Linux driver development, understanding udev automatic device node creation is one of the most important skills you can pick up early. In this free Linux device drivers course lecture, we explain how the kernel and udev work together to create /dev entries automatically, and we build a real, currently-working kernel module that uses the modern class_create() API. This lecture is beginner friendly, but it goes deep enough that even experienced driver developers will find the updated API notes useful.
Note on kernel versions: Some older tutorials online still show a two-argument class_create(THIS_MODULE, "name") call. Starting from Linux kernel 6.4, the owner argument was removed from class_create(). Every code sample in this lecture is written for kernel 6.4 and newer, with a note on how to handle older kernels as well.
Topics covered in this Free Embedded Systems Course lecture:
What You Will Learn
- Why manually creating device nodes with
mknoddoes not scale, and how udev automatic device node creation solves the problem - How the kernel, sysfs, and the udev daemon work together behind the scenes
- How to use the current (kernel 6.4+)
class_create()andclass_destroy()functions correctly - A complete, compilable kernel module and Makefile you can build and test today
- How to watch udev events live with
udevadm monitor
Prerequisites
- Basic C programming knowledge
- A Linux machine (native install or VM) with kernel headers installed
- Familiarity with writing and loading a basic “Hello World” kernel module (
module_init,module_exit) - Comfortable using the terminal with root/sudo access
Why Do We Need udev Automatic Device Node Creation?
In the earliest days of Linux, every possible device file was pre-created inside /dev, whether that hardware existed on your machine or not. A distribution had to ship thousands of static nodes covering every disk, terminal, and peripheral combination imaginable, just in case someone plugged in that hardware. This wasted disk space, cluttered the directory, and gave no guarantee that a node’s permissions or ownership matched the device actually present.
Modern Linux solves this with a much smarter approach. The kernel driver simply describes the device through sysfs, and a userspace daemon called udev watches for those descriptions and creates the matching /dev node automatically, with the correct name, permissions, and even symlinks, only for hardware that is actually present. This is the essence of udev automatic device node creation, and it is the standard approach used by every char, block, and misc driver written today.
How udev Automatic Device Node Creation Works
The relationship between your driver, sysfs, and udev can be broken down into four steps. Your driver never talks to /dev directly — it only ever talks to sysfs, and udev does the rest.
calls class_create() & device_create()
/sys/class/<name>/
detects the uevent
correct name & permissions
Because the driver only has to populate sysfs, and udev takes care of everything downstream, this design keeps drivers simple and keeps the naming/permission policy entirely in userspace, where it can be customised with udev rules without ever touching kernel code.
The class_create() Function
The first API a driver needs for udev automatic device node creation is class_create(). This function creates a struct class, which is the “category” your device will belong to under /sys/class/. Every device you later register with device_create() will appear under this class.
Updated Function Signature (Kernel 6.4 and Later)
#include <linux/device.h>
struct class *class_create(const char *name);
The single argument is the name of the class as it will appear under /sys/class/. On success it returns a valid pointer; on failure it returns an ERR_PTR() value, which should always be checked with IS_ERR().
Older Signature (Kernel 6.3 and Earlier)
struct class *class_create(struct module *owner, const char *name);
If you need your module to build across both older and newer kernels, wrap the call in a version check, as shown below.
Writing Code That Builds on Both Old and New Kernels
#include <linux/version.h>
#include <linux/device.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)
my_class = class_create("myclass");
#else
my_class = class_create(THIS_MODULE, "myclass");
#endif
| Kernel Version | class_create() Arguments | Notes |
|---|---|---|
| 6.3 and earlier | owner, name |
Owner module tracked for reference counting |
| 6.4 and later | name only |
Owner argument removed; kernel tracks the caller internally |
The class_destroy() Function
Whatever you create, you must clean up. class_destroy() removes the struct class you created earlier, and its signature has not changed across kernel versions.
void class_destroy(struct class *cls);
Call this from your module’s exit function, always after you have destroyed any devices you registered under that class with device_create() (covered in Part 2 of this lecture).
Complete Working Example
Below is a minimal, complete kernel module that demonstrates udev automatic device node creation using only class_create() and class_destroy(). It does not yet create a device node — that is covered with device_create() in Part 2 — but it is enough to see a real entry appear under /sys/class/ and to see udev react to it.
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/version.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("EmbeddedPathashala");
MODULE_DESCRIPTION("Demo module for udev automatic device node creation");
static struct class *demo_class;
static int __init demo_init(void)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)
demo_class = class_create("demo_class");
#else
demo_class = class_create(THIS_MODULE, "demo_class");
#endif
if (IS_ERR(demo_class)) {
pr_err("demo: failed to create class\n");
return PTR_ERR(demo_class);
}
pr_info("demo: class created, check /sys/class/demo_class\n");
return 0;
}
static void __exit demo_exit(void)
{
class_destroy(demo_class);
pr_info("demo: class destroyed\n");
}
module_init(demo_init);
module_exit(demo_exit);
Makefile
obj-m += demo.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules
clean:
make -C $(KDIR) M=$(PWD) clean
Build, Load, and Test
$ make
$ sudo insmod demo.ko
$ ls /sys/class/demo_class
$ sudo rmmod demo
After loading the module, the directory /sys/class/demo_class will exist. After removing the module, the directory disappears — this is udev automatic device node creation working at the class level, before we even add an actual device node in Part 2.
Real-World Use Case
Almost every character device driver you will ever write — from a simple GPIO character interface to a full sensor driver — follows this exact pattern: create a class once when the module loads, then create one or more devices under that class as hardware is detected. This is exactly how mainline drivers under drivers/char/, drivers/gpio/, and drivers/misc/ in the Linux kernel source tree register themselves so that udevd can create their /dev nodes without any manual mknod step.
Common Mistakes and Troubleshooting
| Mistake | Symptom | Fix |
|---|---|---|
| Using the old two-argument call on kernel 6.4+ | Compile error about incompatible pointer type | Switch to the single-argument form or use the version check shown above |
| Not checking the return value | Kernel oops when dereferencing an error pointer | Always wrap the call with IS_ERR() |
Forgetting class_destroy() in the exit function |
Stale entry left under /sys/class/ after unload, module reload fails |
Always pair every create with a destroy |
| Reusing a class name that already exists | insmod fails silently or returns -EEXIST |
Pick a unique class name per driver |
Best Practices
- Always check kernel version compatibility if your module targets more than one distribution
- Keep the class name short, lowercase, and descriptive of the driver’s purpose
- Free resources in the exact reverse order you allocated them
- Use
pr_info()andpr_err()generously while developing so you can trace class creation and teardown indmesg
Performance and Security Considerations
class_create() and class_destroy() are called only at module load and unload time, so they have no measurable runtime performance impact. From a security standpoint, remember that the class itself does not set permissions on the eventual device node — that is controlled separately (either through device_create() defaults, or through udev rules). Never assume a device node is automatically restricted to root; always verify permissions with a udev rule if the device exposes sensitive functionality.
Summary / Key Takeaways
- udev automatic device node creation removes the need to manually pre-create thousands of
/deventries - Drivers only need to talk to sysfs; udev handles the rest
class_create()lost itsownerargument starting in kernel 6.4 — always match your code to your target kernel- Every
class_create()call must be matched with aclass_destroy()call on module unload
What’s Next
In Part 2 of this lecture, we register an actual device under this class using device_create(), watch the node appear automatically in /dev, and observe the whole process live using udevadm monitor.
FAQ
Q1. What is udev in Linux?
udev is the userspace device manager daemon that listens for kernel events (uevents) and automatically creates, renames, or removes device nodes under /dev based on information the kernel exposes through sysfs.
Q2. Why did class_create() change in kernel 6.4?
The kernel maintainers removed the owner (module) argument because the kernel could already determine the calling module internally, simplifying the API for every driver that used it.
Q3. Do I need udev rules to use class_create() and device_create()?
No. udev will create a working device node with sensible defaults automatically. Custom udev rules are only needed if you want a specific name, permission, or symlink.
Q4. What happens if I forget to call class_destroy()?
The class entry under /sys/class/ will remain even after your module unloads, and attempting to reload a module that tries to recreate the same class name can fail.
Q5. Can I create multiple devices under one class?
Yes. A single class can have many devices registered under it, each created with its own call to device_create(), which is covered in Part 2.
Q6. Is this the same mechanism used by USB and PCI drivers?
Yes, the same class/sysfs/udev mechanism is used across almost all driver subsystems in the Linux kernel, including USB, PCI, GPIO, and misc device drivers.
Q7. Which kernel version should beginners use to follow this lecture?
Any kernel from 6.4 onward will work with the code exactly as shown. If you are on an older LTS kernel, use the version-check pattern provided in this lecture.
References
- Linux Kernel Documentation — Driver Model (kernel.org)
- Linux Kernel Source —
drivers/base/class.c - freedesktop.org — udev documentation
