Fundamentals 18 min read

Simplify Linux Driver Probes with Device Resource Management (devm_ APIs)

This article explains how Linux kernel drivers can replace repetitive error‑handling and manual resource cleanup in probe functions by using the device‑resource‑management framework and its devm_ helper APIs, showing concrete code transformations, data‑structure details, and the underlying mechanisms that automate allocation and release.

Liangxu Linux
Liangxu Linux
Liangxu Linux
Simplify Linux Driver Probes with Device Resource Management (devm_ APIs)

1. Introduction

Linux driver developers often write probe functions that acquire many resources (IRQ, clock, memory, DMA, etc.) and must roll back each allocation on failure, resulting in long chains of if (error) { err = -XYZ; goto cleanup_label; } statements. The device‑resource‑management (devres) framework automates this cleanup, allowing drivers to request resources without writing explicit release code.

2. Using devm_ Helper Functions

By replacing standard allocation calls with their devm_ counterparts (e.g., devm_clk_get(), devm_kzalloc(), devm_ioremap_resource(), devm_request_irq()), the driver delegates both allocation and automatic release to the kernel. The function signatures remain the same except for the added struct device * argument.

static int __init mx1_camera_probe(struct platform_device *pdev)
{
    struct resource *res;
    int irq;
    struct clk *clk;
    struct pcdev *pcdev;
    void __iomem *base;

    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    irq = platform_get_irq(pdev, 0);
    if (!res || (int)irq <= 0)
        return -ENODEV;

    clk = devm_clk_get(&pdev->dev, "csi_clk");
    if (IS_ERR(clk))
        return PTR_ERR(clk);

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

    if (!devm_request_mem_region(&pdev->dev, res->start,
                                 resource_size(res), DRIVER_NAME))
        return -EBUSY;

    base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
    if (!base)
        return -ENOMEM;

    pcdev->dma_chan = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_HIGH);
    if (pcdev->dma_chan < 0)
        return -EBUSY;

    err = devm_request_irq(&pdev->dev, irq, handler, NULL, 0,
                           "mx1_camera", pcdev);
    if (err)
        return err;

    err = soc_camera_host_register(&pcdev->soc_host);
    if (err)
        return err;

    dev_info(&pdev->dev, "MX1 Camera driver loaded
");
    return 0;
}

3. Common devm_ Interfaces

Typical helper functions include:

void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp);
void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res);
struct clk *devm_clk_get(struct device *dev, const char *id);
int devm_gpio_request(struct device *dev, unsigned gpio, const char *label);
int devm_request_irq(struct device *dev, unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev_id);

4. What Is a Device Resource?

A device resource is any external condition a device needs to operate, such as power, clock, memory, GPIO, IRQ, DMA, or virtual address space. In the kernel, many of these are abstracted as resources managed by dedicated frameworks (regulator, clock, interrupt, gpio, pwm, etc.).

5. Device Resource Management Framework

The core of the framework lives in drivers/base/devres.c. It maintains a linked list ( devres_head) inside each struct device to track allocated resources. Each entry is a struct devres containing a devres_node (list linkage and a release callback) and a zero‑length array data[] that holds the actual resource data.

struct device {
    spinlock_t devres_lock;
    struct list_head devres_head;
    ...
};

struct devres {
    struct devres_node node;
    unsigned long data[]; // resource‑specific payload
};

struct devres_node {
    struct list_head entry;
    dr_release_t release;
#ifdef CONFIG_DEBUG_DEVRES
    const char *name;
    size_t size;
#endif
};

The zero‑length array allows the kernel to allocate a struct devres plus the exact size needed for the concrete resource, keeping the framework agnostic to the resource type.

5.1 Allocation and Registration

To register a resource, a driver calls devres_alloc() with a release callback and the size of the resource, then performs the actual allocation (e.g., request_threaded_irq()), and finally adds the devres to the device list with devres_add(). If any step fails, the allocated devres can be freed with devres_free().

5.2 Automatic Cleanup

When a probe fails or a driver is removed, the kernel invokes devres_release_all(). This walks the devres_head list, calls each stored release callback (e.g., free_irq()), and frees the devres structures, guaranteeing that all resources are released without explicit driver code.

6. Example: IRQ Resource Management

The IRQ framework provides devm_request_threaded_irq(), which internally allocates a devres, registers the IRQ, and adds the devres to the device. Its release callback simply calls free_irq().

static int devm_request_threaded_irq(struct device *dev, unsigned int irq,
                                      irq_handler_t handler, irq_handler_t thread_fn,
                                      unsigned long irqflags, const char *devname,
                                      void *dev_id)
{
    struct irq_devres *dr = devres_alloc(devm_irq_release,
                                         sizeof(*dr), GFP_KERNEL);
    if (!dr)
        return -ENOMEM;

    rc = request_threaded_irq(irq, handler, thread_fn, irqflags, devname, dev_id);
    if (rc) {
        devres_free(dr);
        return rc;
    }

    dr->irq = irq;
    dr->dev_id = dev_id;
    devres_add(dev, dr);
    return 0;
}

static void devm_irq_release(struct device *dev, void *res)
{
    struct irq_devres *this = res;
    free_irq(this->irq, this->dev_id);
}

7. Key Takeaways

Device‑resource‑management (devres) centralizes allocation and automatic release of driver resources.

Using devm_ helpers eliminates repetitive error‑handling and goto cleanup code.

The framework is generic: each resource type supplies a release callback, while devres stores only a pointer to that callback and the resource data.

Automatic cleanup occurs on probe failure or driver removal via devres_release_all(), ensuring no resource leaks.

kernel driverprobeResource CleanupDevice Resource Managementdevm
Liangxu Linux
Written by

Liangxu Linux

Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.