udev Automatic Device Node Creation in Linux Kernel Drivers (Part 2): device_create() and udevadm monitor
This is Part 2 of our free Linux device drivers course lecture on udev automatic device node creation. In Part 1 we created a struct class using class_create(). Now we take the next step and register an actual device under that class with device_create(), watch a real /dev node appear without touching mknod, and observe the entire event live using udevadm monitor.
Quick recap: class_create() makes the category (/sys/class/<name>). device_create() makes an individual device inside that category, and it is this call that finally triggers udev to create the node under /dev.
What You Will Learn
- How
device_create()registers a device and triggers udev automatic device node creation - How to cleanly remove a device with
device_destroy() - How to watch kernel and udev events live using
udevadm monitor - A complete kernel module combining class and device creation, ready to build and test
Prerequisites
- Completion of Part 1 of this lecture (class_create and class_destroy)
- A working
struct classpointer from your driver - Basic understanding of
dev_t, major, and minor numbers
The device_create() Function
Once a class exists, device_create() is the function that actually causes udev automatic device node creation to produce a visible entry under /dev. It registers a struct device in sysfs under the class you created earlier, and this registration is exactly what udev is listening for.
#include <linux/device.h>
struct device *device_create(struct class *class, struct device *parent,
dev_t devt, void *drvdata,
const char *fmt, ...);
| Parameter | Meaning |
|---|---|
class |
The class this device should belong to (from class_create()) |
parent |
Optional parent device; pass NULL if this device has no parent in sysfs |
devt |
The dev_t (major/minor pair) this device represents, usually obtained from alloc_chrdev_region() |
drvdata |
Private driver data attached to this device, or NULL |
fmt, ... |
A printf-style format string for the device name that will appear under /dev |
This function signature has not changed across recent kernel versions, unlike class_create(), so the code below works the same on both older and newer kernels.
The device_destroy() Function
Cleanup is just as important as creation. device_destroy() removes the device you registered and, in turn, removes the /dev node that udev had created for it.
void device_destroy(struct class *class, dev_t devt);
Call this before class_destroy() in your exit function — always tear down devices before you tear down the class they belong to.
How the Pieces Fit Together
reserves major/minor numbers
/sys/class/<name>
/sys/class/<name>/<device>
/dev/<device>
Complete Working Example
This module allocates a device number, creates a class, and creates a device — resulting in a real, working entry appearing under /dev automatically, with no manual steps.
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/version.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("EmbeddedPathashala");
MODULE_DESCRIPTION("udev automatic device node creation demo with device_create");
#define DEVICE_NAME "demo_device"
#define CLASS_NAME "demo_class"
static dev_t dev_num;
static struct class *demo_class;
static struct device *demo_device;
static int __init demo_init(void)
{
int ret;
ret = alloc_chrdev_region(&dev_num, 0, 1, DEVICE_NAME);
if (ret < 0) {
pr_err("demo: failed to allocate device number\n");
return ret;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)
demo_class = class_create(CLASS_NAME);
#else
demo_class = class_create(THIS_MODULE, CLASS_NAME);
#endif
if (IS_ERR(demo_class)) {
unregister_chrdev_region(dev_num, 1);
pr_err("demo: failed to create class\n");
return PTR_ERR(demo_class);
}
demo_device = device_create(demo_class, NULL, dev_num, NULL, DEVICE_NAME);
if (IS_ERR(demo_device)) {
class_destroy(demo_class);
unregister_chrdev_region(dev_num, 1);
pr_err("demo: failed to create device\n");
return PTR_ERR(demo_device);
}
pr_info("demo: /dev/%s created automatically by udev\n", DEVICE_NAME);
return 0;
}
static void __exit demo_exit(void)
{
device_destroy(demo_class, dev_num);
class_destroy(demo_class);
unregister_chrdev_region(dev_num, 1);
pr_info("demo: cleaned up, /dev/%s removed\n", DEVICE_NAME);
}
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
Watching It Happen with udevadm monitor
udevadm monitor lets you watch, in real time, the exact kernel uevent and the resulting udev action — the clearest way to actually see udev automatic device node creation happen rather than just reading about it.
Step-by-Step Testing
# Terminal 1: start watching events
$ udevadm monitor
# Terminal 2: build and load the module
$ make
$ sudo insmod demo.ko
# Terminal 2: confirm the node exists
$ ls -l /dev/demo_device
# Terminal 2: unload and confirm cleanup
$ sudo rmmod demo
$ ls /dev/demo_device
In Terminal 1, loading the module produces a KERNEL line followed by a matching UDEV line for the add action on your device. Unloading the module produces the corresponding remove events, and the node disappears from /dev automatically — no manual deletion required.
| Event Source | Meaning |
|---|---|
KERNEL |
The raw uevent generated by the kernel the moment device_create() runs |
UDEV |
The action udev takes after processing its rules — this is the step that actually creates the /dev file |
Real-World Use Case
This exact create/destroy pattern is used by real drivers such as GPIO character device interfaces, sensor drivers exposing a simple read/write node, and misc drivers that need a single control device. Instead of documenting a manual mknod command for users, the driver itself guarantees the correct node appears the moment it is inserted, and disappears cleanly the moment it is removed.
Common Mistakes and Troubleshooting
| Mistake | Symptom | Fix |
|---|---|---|
Calling device_create() before class_create() succeeds |
Kernel oops using an invalid class pointer | Always check IS_ERR() after every allocation step, in order |
| Wrong cleanup order in the exit function | Warnings about a busy class, or leftover sysfs entries | Destroy in reverse: device first, then class, then chrdev region |
Reusing the same dev_t across two devices |
device_create() fails or the node behaves unpredictably |
Allocate a fresh dev_t per logical device |
No node appears in /dev despite no errors in dmesg |
udev daemon not running or systemd-udevd not started | Check systemctl status systemd-udevd |
Best Practices
- Always tear down resources in the exact reverse order they were created
- Use meaningful device names so users immediately understand what
/dev/<name>represents - Check every return value with
IS_ERR()and unwind partial initialisation correctly on failure - Use
udevadm monitorduring development to confirm your driver behaves as expected before writing any custom udev rules
Performance and Security Considerations
Like class_create(), device_create() and device_destroy() only run at load/unload or hotplug time, so there is no ongoing performance cost. On the security side, remember that the default permissions udev assigns to a new node may be broader than you want for a sensitive device. If your device should not be world-accessible, add a udev rule that sets explicit ownership and mode, rather than relying on defaults.
Summary / Key Takeaways
device_create()is the call that actually triggers udev automatic device node creation for an individual devicedevice_destroy()must always be called beforeclass_destroy()udevadm monitoris the best tool to visually confirm the kernel-to-udev-to-/dev pipeline is working- The full create/destroy cycle should always be checked for errors and unwound safely on failure
Conclusion
Across these two lectures, you have gone from understanding why udev automatic device node creation exists, to writing a complete kernel module that creates a class, registers a device, and lets udev handle the rest — with zero manual mknod commands and code that matches the current kernel API. This same pattern forms the backbone of nearly every character device driver in the Linux kernel, so mastering it here will pay off throughout the rest of this free Linux kernel development course.
FAQ
Q1. What is the difference between class_create() and device_create()?
class_create() creates the category under /sys/class/, while device_create() registers an individual device inside that category and is the call that actually causes a node to appear under /dev.
Q2. Does device_create() require a class_create() call first?
Yes. You must pass a valid struct class pointer to device_create(), so class_create() must succeed first.
Q3. What does udevadm monitor actually show?
It shows both the raw kernel uevent and the resulting udev action, letting you confirm in real time that your driver’s sysfs registration correctly triggers udev automatic device node creation.
Q4. Why did my /dev node not appear even though insmod succeeded?
Check that the udev/systemd-udevd service is running, and check dmesg for any error from device_create() — a silent IS_ERR() failure that was not logged is a common cause.
Q5. In what order should I clean up in the exit function?
Reverse of creation: call device_destroy() first, then class_destroy(), then unregister_chrdev_region().
Q6. Can I change the permissions of the automatically created device node?
Yes, either by setting a device attribute callback in the driver or, more commonly, by adding a udev rule that matches your device and sets the desired mode and ownership.
Q7. Is device_create() only for character devices?
It is most commonly used with character devices, but the class/device/sysfs mechanism itself is general-purpose and used across multiple driver subsystems for exposing devices to userspace.
References
- Linux Kernel Documentation — Driver Model (kernel.org)
- Linux Kernel Source —
drivers/base/core.c - freedesktop.org — udev and systemd-udevd documentation
