Linux Devres Managed Resources- Free Linux Device Drivers Tutorial

 

← PREV_LEC  |  NEXT_LEC →

Linux Devres Managed Resources

How the devm_ API automatically frees driver resources, and a full recap of the Kernel Memory Management chapter

Lecture 20
Kernel Memory Management
Chapter Finale

This final lecture of the chapter explains linux devres managed resources, the framework behind every devm_ function you have already used in this free linux kernel development course. It closes out the Kernel Memory Management chapter of our free embedded Linux course and free linux device drivers course series.

What You Will Learn

  • What devres is and the error-handling problem it solves in probe()/remove()
  • The devm_ naming convention and how parameters shift compared to the original function
  • An old-way vs devm-way comparison for IRQ registration
  • An original ep_devres_demo driver combining devm_kzalloc() and devm_request_irq()
  • A full recap of everything covered across this 20-lecture Kernel Memory Management chapter

Prerequisites

  • The kmalloc allocator family lecture earlier in this chapter
  • Basic platform driver probe()/remove() structure
linux devres managed resources
devm_kzalloc
devm_request_irq
free linux kernel development course
free embedded systems course

The Problem Devres Solves

A typical driver’s probe() function allocates several resources in sequence: memory, an IRQ line, an ioremap’d region, maybe a clock. If step three fails, the driver must manually unwind steps one and two in the correct reverse order before returning an error. Get this wrong, even once, and you leak memory or leave an IRQ handler registered against a device that no longer exists. Devres exists to remove this entire class of bugs.

Devres, short for “device resources,” is a kernel facility that automatically frees resources a driver allocates, tying each resource’s lifetime to the owning struct device instead of to manually written cleanup code. Internally, devres maintains a linked list of resource entries attached to the device; each entry carries its own release function, and every entry on that list is released automatically when the device is detached or the driver is unloaded, with zero cleanup code required from the driver author.

Devres Resource Lifecycle

devm_kzalloc() in probe()
Tracked in dev->devres_head
Driver detached / unloaded
Automatic release, no code needed

The devm_ Naming Convention

Almost every kernel resource allocator has a managed counterpart. The pattern is consistent: prefix the original function name with devm_, and add a struct device *dev as the first parameter (functions that already took a device pointer are the exception; their signature is otherwise unchanged).

void *kmalloc(size_t size, gfp_t flags);
void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp);

Common managed resources you can allocate this way include:

Category Examples
Memory devm_kzalloc(), devm_kmalloc(), devm_kfree(), devm_kcalloc(), devm_krealloc()
Interrupts devm_request_irq(), devm_free_irq()
Memory regions devm_request_mem_region(), devm_release_mem_region()
I/O mapping devm_ioremap(), devm_ioremap_resource(), devm_iounmap()
DMA dmam_alloc_coherent(), dmam_free_coherent()
Frameworks devm_clk_get(), devm_gpiod_get(), devm_regulator_get(), devm_pwm_get()

Verified current: the devm_ family, including devm_kzalloc(), devm_kfree(), devm_request_irq(), and devm_krealloc() (added later to fill a gap in the original API), remains fully documented and actively used in the mainline kernel driver model documentation today.

Old Way vs devm Way: IRQ Registration

Old way The devm way
ret = request_irq(irq, my_isr, 0,
                   my_name, my_data);
if (ret) {
    dev_err(dev, "IRQ request failed\n");
    ret = -ENODEV;
    goto unroll_irq;
}
ret = devm_request_irq(dev, irq, my_isr,
                        0, my_name, my_data);
if (ret) {
    dev_err(dev, "IRQ request failed\n");
    return -ENODEV;
}

Notice the devm version needs no goto label and no manual free_irq() anywhere in the driver: the return path is a single, flat check.

Original Driver: ep_devres_demo

The following original platform driver combines devm_kzalloc() and devm_request_irq() to show the pattern working together in a realistic probe()/remove() pair.

#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/slab.h>

struct ep_devres_priv {
    int irq;
    u32 irq_count;
};

static irqreturn_t ep_devres_isr(int irq, void *data)
{
    struct ep_devres_priv *priv = data;

    priv->irq_count++;
    return IRQ_HANDLED;
}

static int ep_devres_probe(struct platform_device *pdev)
{
    struct ep_devres_priv *priv;
    int ret;

    priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
    if (!priv)
        return -ENOMEM;

    priv->irq = platform_get_irq(pdev, 0);
    if (priv->irq < 0)
        return priv->irq;

    ret = devm_request_irq(&pdev->dev, priv->irq, ep_devres_isr,
                            0, "ep_devres_demo", priv);
    if (ret) {
        dev_err(&pdev->dev, "failed to request IRQ %d\n", priv->irq);
        return ret;
    }

    platform_set_drvdata(pdev, priv);
    dev_info(&pdev->dev, "ep_devres_demo probed on IRQ %d\n", priv->irq);
    return 0;
}

static void ep_devres_remove(struct platform_device *pdev)
{
    /* No manual kfree() or free_irq() needed here at all */
    dev_info(&pdev->dev, "ep_devres_demo removed cleanly\n");
}

static struct platform_driver ep_devres_driver = {
    .probe  = ep_devres_probe,
    .remove = ep_devres_remove,
    .driver = {
        .name = "ep_devres_demo",
    },
};

module_platform_driver(ep_devres_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Original devres demo for EmbeddedPathashala");

Build and Run Steps

make
sudo insmod ep_devres_demo.ko
dmesg | tail -n 2
sudo rmmod ep_devres_demo
dmesg | tail -n 1

Expected Output

ep_devres_demo probed on IRQ 42
ep_devres_demo removed cleanly

Notice there is no explicit free of priv and no explicit free_irq() call anywhere in the driver, yet both are guaranteed to be released the moment the device detaches. The devres framework did that work automatically.

Modernization note: the .remove callback above returns void rather than int, matching the modern platform driver signature adopted in current kernels, since a remove() call can no longer meaningfully fail.

Common Mistakes

Mistake Consequence
Mixing devm_kzalloc() with a manual kfree() call Double free when the device later detaches and devres releases the same memory again
Passing the wrong struct device pointer Resource lifetime gets tied to the wrong device, freeing too early or too late
Assuming devm_ functions can be used outside probe()/remove() context freely Works technically, but defeats the purpose if the resource actually needs a shorter lifetime than the device

Best Practices

  • Default to the devm_ variant of any allocator inside probe(), unless you have a specific reason the resource must outlive or be freed before the device detaches
  • Never call the manual free function (kfree, free_irq, iounmap) on a resource obtained through a devm_ call
  • Use plain, non-managed allocation only for resources whose lifetime is explicitly shorter than the device itself

Performance and Security Considerations

Devres adds a small, fixed bookkeeping overhead per resource, generally a few hundred bytes per device, which is negligible against the bugs it prevents. From a security standpoint, guaranteed cleanup on detach closes a real class of use-after-free and resource-leak vulnerabilities that manual unwind code is prone to introducing under error paths that are rarely exercised in testing.

Real World Use Cases

  • Platform drivers for embedded SoCs allocating per-device state, IRQs, and MMIO regions together
  • Hot-pluggable USB or PCI drivers where clean detach handling matters every single time, not just on the happy path
  • DMA-heavy drivers using dmam_alloc_coherent() to avoid leaking DMA-coherent buffers on error paths

Summary and Key Takeaways

  • Devres ties resource lifetime to a struct device and releases everything automatically on detach or driver unload
  • The devm_ prefix plus a leading struct device * parameter is the consistent naming pattern across the kernel
  • devm_request_irq() removes the need for manual goto-based unwind logic in probe()
  • Never mix a devm_ allocation with its manual, non-managed free function

Chapter Recap: Kernel Memory Management

This lecture closes the twenty-lecture Kernel Memory Management chapter. Across these lectures you moved from the fundamentals of virtual memory, zones, and page tables, through the page and buddy allocators, SLUB and kmalloc, vmalloc and Copy-on-Write, Port I/O versus MMIO, ioremap and kmap, implementing mmap() in a driver, the Linux page cache and CPU caches, write-back caching and modern flusher threads, and finally the devres managed resource framework you just learned here. Together these lectures form a complete, modernized path through how the Linux kernel manages memory on kernel 6.x. The next chapter in this free linux kernel development course moves into DMA (Direct Memory Access), building directly on the memory-mapping and cache concepts covered here.

Frequently Asked Questions

What is devres in the Linux kernel?

Devres is a kernel facility that automatically frees driver-allocated resources when the owning device is detached or the driver unloads, removing the need for manual cleanup code in error paths.

What does the devm_ prefix mean?

It marks the managed (devres-tracked) version of a resource allocator. The function behaves like its non-managed counterpart but ties the resource’s lifetime to a struct device and adds that device as its first parameter.

Can I mix devm_kzalloc() with a manual kfree()?

No. Doing so causes a double free when devres later releases the same memory automatically. Use devm_kfree() if you need to free it early, or let devres handle it on detach.

Is devm_request_irq() still current on modern kernels?

Yes, it remains part of the actively documented and used devres API in current mainline kernels.

Does devres add measurable overhead to a driver?

The bookkeeping overhead is small and fixed per resource, generally negligible compared to the bugs it prevents in error handling paths.

What comes after the Kernel Memory Management chapter?

The next chapter in this course covers DMA (Direct Memory Access), building on the memory mapping and caching concepts from this chapter.

 

Kernel Memory Management Chapter Complete

You have finished all 20 lectures of this chapter in the free linux kernel development course. Next up: Direct Memory Access (DMA).

← PREV_LEC  |  NEXT_LEC →

 

Leave a Reply

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