How Does GFP_KERNEL Differ from GFP_ATOMIC? – Best Linux Device Drivers Training in Hyderabad

GFP_KERNEL vs GFP_ATOMIC: Understanding GFP Flags in the Linux Kernel
A free Linux kernel development course lesson from EmbeddedPathashala — Memory Management Series
Level: Intermediate
Reading time: 13 min
Kernel version: 6.x (current mainline)

« Previous Lecture  |  Next Lecture »

Every memory allocation call in the Linux kernel — kmalloc(), alloc_pages(), alloc_pages_exact(), and dozens of others — takes a mysterious first or second argument called a GFP mask. Get it wrong and your driver can silently corrupt the system, deadlock, or crash under a “sleeping in atomic context” bug. This lesson breaks down GFP_KERNEL vs GFP_ATOMIC in plain language, so you know exactly which one to reach for and why.

What You Will Learn
What “GFP” actually stands for
Process context vs interrupt context
Why sleeping matters to the allocator
GFP_KERNEL vs GFP_ATOMIC decision rule
GFP_NOIO and locking edge cases
Debugging atomic-sleep bugs

Prerequisites

This lesson assumes you already know the basics of writing a kernel module and have seen a memory allocation call like kmalloc() before. If you haven’t yet, start with our free Linux kernel development course module on kernel module programming first.

What Does GFP Actually Mean?

GFP stands for “Get Free Pages,” a nod to the low-level page allocator that ultimately backs every kernel memory request. Every allocation function accepts a gfp_t bitmask that tells the memory management subsystem how it is allowed to behave while trying to satisfy your request — most importantly, whether it is allowed to pause and wait for memory to become available.

Process Context vs Interrupt Context

To understand GFP flags, you first need to understand where your code is running when it asks for memory.

Two Kinds of Execution Context

Process Context

Your code runs on behalf of a task/thread — a syscall handler, a kernel thread, a workqueue. It is generally safe to pause and wait here.

Interrupt / Atomic Context

Your code runs as an interrupt handler, a softirq, a tasklet, or while holding a spinlock. It must never pause — it has to run to completion.

The kernel exposes helper macros so your code can check where it’s running: in_task() tells you whether you’re in process context, and in_atomic() tells you whether the current context must run to completion without interruption. Note the asymmetry — you can be in process context and still be atomic at the same time, for example while holding a spinlock, but the reverse is never true.

Why “Sleeping” Matters

A “blocking” or “sleeping” call is one where your code voluntarily gives up the CPU and waits for some event — a timer expiring, data arriving, or in this case, the kernel reclaiming enough memory to satisfy your allocation. Under the hood, sleeping happens by invoking the scheduler. That is only safe from a context where the scheduler is allowed to run something else in your place.

The Golden Rule

Never sleep in interrupt or atomic context. If your allocation might block, it must only be called from process context.

Violating this rule doesn’t always crash immediately — that’s what makes it dangerous. The kernel has a debug option, CONFIG_DEBUG_ATOMIC_SLEEP, that you should always enable on a development kernel; it flags exactly this class of bug at the moment it happens instead of letting it corrupt state silently.

GFP_KERNEL vs GFP_ATOMIC: The Decision Rule

This is the single most important rule in kernel memory allocation:

Choosing Your GFP Flag
Am I in process context, and is it safe to sleep here?
Yes → use GFP_KERNEL
No → use GFP_ATOMIC
Flag Can Sleep? Typical Use
GFP_KERNEL Yes Driver probe functions, ioctl handlers, workqueue callbacks, module init
GFP_ATOMIC No Interrupt handlers, softirqs, tasklets, code holding a spinlock

Code Example: Correct Flag Usage

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

/* Runs in process context - safe to sleep */
static int drv_probe(struct platform_device *pdev)
{
    struct drv_data *data;

    data = kzalloc(sizeof(*data), GFP_KERNEL);
    if (!data)
        return -ENOMEM;

    return 0;
}

/* Runs in interrupt context - must never sleep */
static irqreturn_t drv_irq_handler(int irq, void *dev_id)
{
    struct event_record *rec;

    rec = kmalloc(sizeof(*rec), GFP_ATOMIC);
    if (!rec)
        return IRQ_NONE;

    /* fill and queue rec for later processing */
    return IRQ_HANDLED;
}

A Special Case: GFP_NOIO

Beyond the basic pair, the kernel defines several more specialised flags for internal reclaim behaviour, such as __GFP_IO, __GFP_FS, and __GFP_DIRECT_RECLAIM. One practical variant every driver author should recognise is GFP_NOIO.

When you use GFP_KERNEL, the kernel is implicitly allowed to start disk or network I/O to reclaim memory if things get tight. That’s usually fine — but not if you’re already holding a lock that some I/O completion path also needs, because that can deadlock the system. A classic example is allocating memory while holding a USB device lock: several USB core code paths were fixed over the years specifically to use GFP_NOIO instead of GFP_KERNEL in that situation, to prevent the kernel from re-entering I/O while the device lock is already held.

usb_lock_device(udev);

/* Not GFP_KERNEL here - could trigger IO reclaim
 * while the device lock is held */
buf = kmalloc(size, GFP_NOIO);

usb_unlock_device(udev);

Real-World Use Cases

Scenario Correct Flag
Network driver receive interrupt (NAPI poll off-loaded) GFP_ATOMIC inside the hard IRQ handler; GFP_KERNEL in the softirq/NAPI poll if not atomic
Character device open()/ioctl() GFP_KERNEL
Timer callback (legacy non-threaded) GFP_ATOMIC
Block layer or filesystem code under a lock reachable from writeback GFP_NOIO or GFP_NOFS as appropriate

Common Mistakes and Troubleshooting

  • Using GFP_KERNEL inside an interrupt handler: This is a textbook “sleeping in atomic context” bug. Turn on CONFIG_DEBUG_ATOMIC_SLEEP in your development kernel config to catch it immediately.
  • Using GFP_ATOMIC everywhere out of caution: Atomic allocations dip into a smaller emergency memory pool and are more likely to fail under pressure. Use it only where it’s actually required.
  • Allocating memory while holding a lock also used by the reclaim/I-O path: Use GFP_NOIO (or GFP_NOFS) instead of GFP_KERNEL in these cases.
  • Assuming atomic context only happens in interrupt handlers: Holding a spinlock in process context is also atomic context. Check with in_atomic() if unsure.

Best Practices

  • Default to GFP_KERNEL whenever you are certain you’re in process context and hold no atomic locks.
  • Reserve GFP_ATOMIC strictly for interrupt/softirq/tasklet code or code under a spinlock.
  • Enable atomic-sleep debugging during development, never rely on catching it in production.
  • Always check the return value of every allocation — atomic allocations especially can fail more often.

Performance and Security Considerations

GFP_ATOMIC allocations draw from a smaller reserved memory pool specifically so that critical low-level code doesn’t starve during memory pressure; overusing it in non-critical paths can exhaust that reserve and cause otherwise-avoidable allocation failures elsewhere in the system. From a security and stability standpoint, an unguarded sleep in atomic context isn’t just a performance bug — it can hang interrupt processing system-wide, so this is one of the few kernel bug classes worth treating as a hard blocker in code review.

Summary / Key Takeaways

  • GFP flags tell the allocator whether it’s allowed to sleep while satisfying your request.
  • Use GFP_KERNEL in process context where sleeping is safe.
  • Use GFP_ATOMIC in interrupt context or while holding a spinlock.
  • Use GFP_NOIO when holding a lock that could deadlock against I/O-triggered reclaim.
  • Enable CONFIG_DEBUG_ATOMIC_SLEEP during development to catch violations early.

Conclusion

Choosing the right GFP flag is one of the most fundamental skills in Linux kernel and device driver programming. Get the context right, and the rest follows: GFP_KERNEL when you can sleep, GFP_ATOMIC when you cannot, and the more specialised flags like GFP_NOIO for the trickier locking situations. Understanding this one rule prevents an entire category of hard-to-reproduce kernel bugs.

FAQ

What happens if I use GFP_KERNEL inside an interrupt handler?

You risk sleeping in atomic context, which is a serious kernel bug that can hang or crash the system. Always use GFP_ATOMIC there instead.

Is GFP_ATOMIC slower than GFP_KERNEL?

It’s not inherently slower, but it draws from a smaller reserved memory pool and is more likely to fail under heavy memory pressure, so it should only be used where sleeping is genuinely unsafe.

How do I check if my code is running in atomic context?

Use the in_atomic() macro to check, and in_task() to check whether you’re in process context at all.

What is GFP_NOIO used for?

It’s used when you’re in process context but holding a lock that could deadlock if the allocator tried to reclaim memory via disk or network I/O.

Can I be in process context and still unable to sleep?

Yes. Holding a spinlock while in process context still makes that code atomic, so sleeping is unsafe even though you are technically in a process’s context.

Does this apply to kmalloc() as well as the page allocator?

Yes, every kernel allocator that accepts a gfp_t mask follows the same rule, including kmalloc(), vmalloc() variants, and alloc_pages()-family functions.

Where can I learn more about kernel memory management for free?

EmbeddedPathashala’s free Linux kernel development course and free Linux device drivers course cover GFP flags, the page allocator, and the slab allocator in depth with hands-on labs.

Continue Learning for Free

This lesson is part of EmbeddedPathashala’s free Linux kernel development course and free Linux device drivers course — covering memory management, synchronization, and driver internals from the ground up.

« Previous Lecture  |  Next Lecture »

Leave a Reply

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