udev Automatic Device Node Creation in Linux Kernel Drivers (Part 2):

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.

Topics covered in this Free Linux Kernel Development Course lecture:

device_create device_destroy udevadm monitor sysfs dev_t char device

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 class pointer 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

class_create() + device_create() -> /dev Node
alloc_chrdev_region()
reserves major/minor numbers
class_create()
/sys/class/<name>
device_create()
/sys/class/<name>/<device>
udev creates node
/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 monitor during 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 device
  • device_destroy() must always be called before class_destroy()
  • udevadm monitor is 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

Leave a Reply

Your email address will not be published. Required fields are marked *