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.
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.
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.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
