request_mem_region() in Linux Drivers: Reserving I/O Memory the Right Way
Free Linux Kernel Programming Course • Hardware I/O Memory • Lecture 2
← Previous Lecture Next Lecture →
What You Will Learn
- Why a driver must reserve its I/O memory region before touching it
- How
request_mem_region()andrelease_mem_region()work in Linux drivers - The managed, modern alternative:
devm_request_mem_region() - How to read the reserved regions of a running system from
/proc/iomem - Common ownership conflicts and how the kernel protects against them
Prerequisites
- Completion of Lecture 1 on MMIO vs PMIO (or equivalent background)
- Basic understanding of Linux kernel modules and platform drivers
Why Reserve I/O Memory Before Using It
Before a Linux driver maps or touches any hardware register range, it is expected to formally reserve that range with the kernel’s resource tree. This step, request_mem_region() in Linux driver code, exists for one simple reason: multiple drivers must never be allowed to silently claim the same physical register range at the same time. Without this bookkeeping step, two competing drivers — or a buggy driver loaded twice — could both try to program the same hardware block, leading to unpredictable and hard-to-debug failures.
How the Kernel Resource Tree Works
Internally, the kernel keeps a tree of struct resource objects representing every physical
address range in the system — RAM, ROM, and every peripheral’s register block. When a driver calls
request_mem_region(), it is asking the kernel to insert a new leaf into this tree under the “iomem”
root. If the requested range overlaps an already-reserved leaf, the request fails, and the driver knows
immediately that something else already owns that hardware.
You can inspect this exact tree yourself on any running Linux system:
cat /proc/iomem
Every line in that output is one reserved struct resource, together with the driver name
that owns it — this is the same “name” string a driver passes to request_mem_region().
The Classic API
The traditional pair of functions has been part of the kernel for decades and still appears throughout the source tree:
struct resource *request_mem_region(resource_size_t start,
resource_size_t n,
const char *name);
void release_mem_region(resource_size_t start, resource_size_t n);
start is the physical address where the region begins, n is its length in
bytes, and name is a human-readable label (usually the driver name) that shows up in
/proc/iomem. A successful call returns a non-NULL struct resource *; a NULL
return means the region is already owned by someone else, and the driver should back off cleanly,
typically returning -EBUSY from its probe function.
The Modern, Managed Approach: devm_request_mem_region()
Writing correct cleanup paths by hand is a common source of bugs — it’s easy to forget to call release_mem_region() on every error path. Since the introduction of the “devm_” (device-managed) family of APIs, this has become the recommended approach in current kernels. A devm_-prefixed resource is automatically released by the kernel when the device is detached or the probe fails, with no manual cleanup required.
static int mychip_probe(struct platform_device *pdev)
{
struct resource *res;
struct device *dev = &pdev->dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
if (!devm_request_mem_region(dev, res->start,
resource_size(res), pdev->name)) {
dev_err(dev, "failed to reserve MMIO region\n");
return -EBUSY;
}
/* No manual release_mem_region() needed on cleanup —
devm_ handles it automatically. */
return 0;
}
Classic vs Managed API: Comparison
| Aspect | request_mem_region() | devm_request_mem_region() |
|---|---|---|
| Cleanup | Manual — must call release_mem_region() | Automatic, tied to device lifetime |
| Risk of leaks on error paths | Higher | Much lower |
| Recommended for new drivers | No, legacy pattern | Yes, current best practice |
Real-World Use Cases
- A platform driver reserving its register block before calling ioremap()
- Preventing two instances of the same driver from double-claiming shared hardware
- Diagnosing hardware conflicts by inspecting /proc/iomem during bring-up on new boards
Common Mistakes and Troubleshooting
- Skipping the reservation entirely — mapping a resource without requesting it first can mask real conflicts between drivers.
- Forgetting release_mem_region() on an error path when using the classic (non-devm) API, causing the region to stay “leaked” until reboot.
- Requesting the wrong length — always use
resource_size(res)rather than a manually typed constant. - -EBUSY at probe time — check /proc/iomem to find out which other driver already owns the range.
Best Practices
- Prefer devm_request_mem_region() in all new driver code targeting current kernels
- Always check the return value and fail the probe cleanly with a descriptive dev_err()
- Use a meaningful, unique name string so /proc/iomem is useful for debugging
- Never assume a region is free — always request it, even during early bring-up experiments
Performance and Security Considerations
Reserving a resource has negligible runtime cost — it is a one-time bookkeeping operation at probe time, not a per-access cost. From a security and stability standpoint, this reservation step is what prevents a poorly written or malicious module from silently taking over hardware that another driver already depends on, which could otherwise be used to destabilize the system.
Summary / Key Takeaways
- request_mem_region() in a Linux driver reserves a hardware register range in the kernel’s resource tree
- A NULL return means the region is already owned by another driver
- devm_request_mem_region() is the current best practice, with automatic cleanup
- /proc/iomem lets you inspect every reserved I/O memory region on a running system
Conclusion
Reserving I/O memory correctly is a small but essential step that protects your driver — and every other driver on the system — from silent hardware conflicts. With the region safely reserved, the next lecture in this free Linux device drivers course shows you how to actually map it into kernel virtual address space using ioremap(), so your driver can start reading and writing real hardware registers.
Frequently Asked Questions
Q1. What does request_mem_region() actually do?
It inserts a new entry into the kernel’s I/O memory resource tree, formally marking a physical address range as owned by your driver, and fails if the range is already claimed.
Q2. Do I still need to call ioremap() after request_mem_region()?
Yes. Requesting the region only reserves ownership; it does not make the registers accessible. You still need to map the physical range into kernel virtual address space, covered in the next lecture.
Q3. What is the difference between request_mem_region() and devm_request_mem_region()?
The devm_ variant ties the reservation to the device’s lifetime, so the kernel releases it automatically, removing the need for manual cleanup on every error and removal path.
Q4. What does it mean if request_mem_region() returns NULL?
It means the requested address range is already reserved by another driver; your probe function should fail cleanly, typically returning -EBUSY.
Q5. How can I see which driver owns a given I/O memory range?
Run cat /proc/iomem on the target system; each reserved range is listed together with the
name string passed to request_mem_region() or devm_request_mem_region().
Q6. Is request_mem_region() used for PCI devices too?
PCI drivers typically use the related pci_request_region() family instead, which understands PCI BARs, but the underlying resource-tree concept is the same.
Continue Your Free Linux Kernel Programming Course
This lecture is part of EmbeddedPathashala’s free Linux device drivers and kernel programming course.
Explore More Free Lectures
2 Comments