How Do GFP Flags Work in Linux? – Linux Device Drivers Course Online


Linux Kernel Page Allocator APIs and GFP Flags (Free Linux Device Drivers Course)
A practical, beginner-friendly lecture from EmbeddedPathashala’s Free Linux Kernel Development Course

This lecture continues EmbeddedPathashala’s free Linux kernel development course and is also a core building block of our free Linux device drivers course and free embedded systems course. Having understood the buddy system theory in the previous lecture, we now move to the practical side: the actual page allocator APIs every kernel module and driver developer calls to get physical memory, and the GFP flags that control how those calls behave.

We’ll keep the explanation simple, beginner-friendly, and aligned with how these APIs behave on current, actively maintained Linux kernels.

📘 What You Will Learn
The four core low-level page allocator APIs
The difference between page-frame APIs and page-structure APIs
How to convert a page structure pointer into a usable address
GFP_KERNEL vs GFP_ATOMIC and when to use each
How modern kernels relate folios to these classic APIs

✅ Prerequisites
The buddy system / page allocator internals lecture (previous lecture)
Comfort writing and building a basic Linux kernel module
Basic pointer and address concepts in C

The Core Page Allocator APIs

The kernel exposes a small family of exported, low-level allocation routines that any module or driver can call. They all live under include/linux/gfp.h and ultimately route through the buddy allocator we studied previously. Every one of them takes two key ideas as input: a GFP mask (explained below) describing the allocation context, and (for the “pages” variants) an order describing how many page frames to grab.

API What It Returns Content of Memory
__get_free_page() Kernel logical address of one page Uninitialised / random
__get_free_pages() Kernel logical address of 2^order pages Uninitialised / random
get_zeroed_page() Kernel logical address of one page Zeroed out
alloc_page() / alloc_pages() Pointer to the page structure (metadata) Uninitialised / random

The single most important gotcha for beginners: alloc_page() and alloc_pages() do not hand you a usable memory address directly. They return a pointer to the kernel’s internal bookkeeping structure that describes that memory — generally called the page structure. To turn that into a real, usable kernel logical address, you must pass it through the address-conversion helper that every Linux kernel textbook and the kernel source itself documents, commonly known by the name page_address().

Two Different Return Styles (Inline HTML Diagram)
__get_free_pages()
↓
Usable kernel address directly
alloc_pages()
↓
Page structure pointer
↓ (convert)
Usable kernel address

A Note for Modern Kernels: Folios

If you go digging through a very recent kernel source tree, you’ll notice memory-management code increasingly working with a newer data structure called a folio rather than directly with struct page. This is part of an ongoing, multi-year kernel-wide effort to simplify and shrink page-tracking metadata. For driver and module developers today, the classic APIs in the table above still work exactly as documented and remain the right starting point to learn the page allocator; folios mainly matter once you start working deep inside filesystem or core memory-management code.

Understanding GFP Flags

Every page allocator API call requires a GFP mask as its first argument — short for “Get Free Page” flags. GFP flags tell the memory-management subsystem how it is allowed to behave while trying to satisfy your request: can it pause and wait for memory to free up? Can it trigger reclaim? Which zone should it prefer?

There are many GFP flags used internally by core kernel code, but as a module or driver developer, two flags cover the overwhelming majority of real situations.

Flag When To Use
GFP_KERNEL Normal process context where it is safe for the call to sleep while memory is reclaimed.
GFP_ATOMIC Interrupt handlers, spinlock-held sections, or any other context where sleeping is forbidden.
Choosing the Right GFP Flag (Inline HTML Diagram)
Am I in process context and safe to sleep?
→
Yes → use GFP_KERNEL
No (interrupt / atomic context) → use GFP_ATOMIC

Why this rule matters so much: calling a sleeping-capable GFP_KERNEL allocation from inside an interrupt handler can deadlock or crash the kernel, because there’s no process context to put to sleep and resume later. Always match the flag to the context you are actually running in.

A Simple Kernel Module Example

Below is an original, simple example skeleton showing how these APIs typically appear together inside a kernel module’s init and exit functions. Build and test this only inside a disposable virtual machine while you’re learning.

#include <linux/module.h>
#include <linux/init.h>
#include <linux/gfp.h>
#include <linux/mm.h>

static unsigned long my_page;
static struct page *my_struct_page;

static int __init my_alloc_init(void)
{
    my_page = get_zeroed_page(GFP_KERNEL);
    if (!my_page)
        return -ENOMEM;

    my_struct_page = alloc_page(GFP_KERNEL);
    if (!my_struct_page) {
        free_page(my_page);
        return -ENOMEM;
    }

    pr_info("ep_alloc: zeroed page at %lx\n", my_page);
    pr_info("ep_alloc: page_address = %lx\n",
            (unsigned long)page_address(my_struct_page));
    return 0;
}

static void __exit my_alloc_exit(void)
{
    free_page(my_page);
    __free_page(my_struct_page);
    pr_info("ep_alloc: memory released\n");
}

module_init(my_alloc_init);
module_exit(my_alloc_exit);
MODULE_LICENSE("GPL");

Notice the discipline: every successful allocation has a matching free call in the exit path, and every failure path frees whatever was already allocated before returning an error. This pairing discipline is one of the most important habits to build early as a kernel developer.

Common Mistakes and Troubleshooting

Treating the return value of alloc_page()/alloc_pages() as a usable address directly without calling page_address()
Using GFP_KERNEL inside an interrupt handler, which can hang or crash the system
Forgetting to free memory on an error path, causing a memory leak
Requesting too high an order, which can fail under memory pressure since large contiguous blocks become rare over time

Best Practices

Always check the return value of every allocation call for NULL before using it
Prefer GFP_KERNEL whenever your code path allows sleeping — it gives the kernel far more freedom to satisfy your request
Keep order as low as practical to reduce the chance of allocation failure
Free memory in the exact reverse order you allocated it, especially across multiple resources

Performance and Security Considerations

Performance: because these APIs go straight to the buddy allocator, they are extremely fast (logarithmic complexity), but high-order requests become progressively less likely to succeed instantly as the system runs and memory fragments — plan accordingly for long-running embedded deployments.

Security: remember that __get_free_page(), __get_free_pages(), alloc_page(), and alloc_pages() all return memory with random leftover content. Never share such memory with user space or another subsystem without explicitly zeroing it first — use get_zeroed_page() or an explicit memset when the destination is untrusted, to avoid leaking stale kernel data.

Summary / Key Takeaways

Four core APIs cover the vast majority of low-level page allocation needs
alloc_page()/alloc_pages() return a page structure, not a usable address — convert with page_address()
GFP_KERNEL for sleepable process context, GFP_ATOMIC for interrupt/atomic context
Always pair every allocation with a matching free, including on error paths
Folios are the modern internal evolution of struct page, but classic APIs remain the correct starting point for learning

Conclusion

You now know how to call the kernel’s low-level page allocator APIs correctly, how to pick the right GFP flag for your context, and the most common mistakes to avoid. This knowledge directly carries into driver development, where DMA buffers, ring buffers, and other contiguous-memory needs are built on exactly these primitives. In the next lecture of this free Linux kernel development course, we will look at the SLAB/SLUB allocator that sits on top of the buddy system for smaller, more frequent allocations.

Frequently Asked Questions

Q1. What is the difference between GFP_KERNEL and GFP_ATOMIC?
GFP_KERNEL is for normal process context where the allocator is allowed to sleep while reclaiming memory. GFP_ATOMIC is for interrupt or atomic contexts where sleeping is not allowed.

Q2. Why does alloc_page() not return a usable pointer directly?
Because it returns a pointer to the page’s metadata structure, not the memory itself; you must convert it using page_address().

Q3. Which page allocator API gives zeroed memory?
get_zeroed_page() returns a single page whose contents are already zeroed out.

Q4. Can I free memory allocated with alloc_pages() using free_page()?
No — memory obtained through the page-structure family should be freed with the matching __free_page()/__free_pages() functions, not free_page()/free_pages(), which pair with the address-based APIs.

Q5. What happens if I use GFP_KERNEL inside an interrupt handler?
It can cause the kernel to attempt to sleep in a context where sleeping is not allowed, leading to warnings, instability, or a crash.

Q6. Are these page allocator APIs still relevant on the latest kernels?
Yes — they remain the documented, exported, and supported low-level interfaces for module and driver developers, even as internal memory-management code increasingly moves toward folios.

Q7. What is the safest default choice if I’m not sure which GFP flag to use?
If your code definitely runs in normal process context (most module init/exit code, ioctl handlers, etc.), GFP_KERNEL is almost always correct.

Continue Your Free Linux Kernel Development Journey

This lecture is part of EmbeddedPathashala’s free Linux kernel development course, free Linux device drivers course, and free embedded systems course.

Browse All Free Courses
Join the Community

Leave a Reply

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