Fundamentals 8 min read

How Linux Kernel Memory Pools Work: Structures, Creation, and Allocation

This article explains the concept of Linux kernel memory pools, details the mempool_t structure, shows how to create and destroy a mempool, and walks through the allocation and free functions with code examples, highlighting their role in preventing allocation failures under memory pressure.

ITPUB
ITPUB
ITPUB
How Linux Kernel Memory Pools Work: Structures, Creation, and Allocation

Memory pools (mempool) allocate a set of equal‑sized blocks in advance so that later requests can be satisfied quickly and with reduced fragmentation. In the Linux kernel, mempools act as a backup cache that keeps a list of free objects ready for emergency use, while normal allocations still come from the general memory pool.

mempool_t Structure

typedef struct mempool_s {
    spinlock_t lock;          /* protects the pool */
    int min_nr;              /* minimum number of elements the pool must keep */
    int curr_nr;             /* current number of free elements */
    void **elements;         /* array of element pointers */
    void *pool_data;          /* underlying memory source (e.g., a cache) */
    mempool_alloc_t *alloc;   /* function to allocate an element */
    mempool_free_t *free;     /* function to free an element */
    wait_queue_head_t wait;  /* wait queue for threads blocked on the pool */
} mempool_t;

Creating a Memory Pool

The creation function mempool_create receives the minimum number of elements, allocation and free callbacks, and an optional memory source. It internally calls mempool_create_node to allocate the pool object and then fills the pool with min_nr elements using the provided alloc method.

mempool_t *mempool_create(int min_nr, mempool_alloc_t *alloc_fn,
                         mempool_free_t *free_fn, void *pool_data)
{
    return mempool_create_node(min_nr, alloc_fn, free_fn, pool_data, -1);
}

Destroying a Memory Pool

The destroy function iterates over all remaining elements, returns each to the underlying source via the free callback, and finally frees the pool’s internal arrays and the pool object itself.

void mempool_destroy(mempool_t *pool)
{
    while (pool->curr_nr) {
        void *element = remove_element(pool);
        pool->free(element, pool->pool_data);
    }
    kfree(pool->elements);
    kfree(pool);
}

Allocating an Object: mempool_alloc

The allocation routine first tries to obtain an element from the underlying source via pool->alloc. If that fails, it falls back to extracting an element from the pool’s free list under a spinlock. The function returns the element if successful; otherwise the caller may be put to sleep on pool->wait until an object becomes available.

void *mempool_alloc(mempool_t *pool, gfp_t gfp_mask)
{
    element = pool->alloc(gfp_temp, pool->pool_data);
    if (likely(element != NULL))
        return element;
    spin_lock_irqsave(&pool->lock, flags);
    if (likely(pool->curr_nr)) {
        element = remove_element(pool);
        spin_unlock_irqrestore(&pool->lock, flags);
        smp_wmb();
        return element;
    }
    /* block on wait queue if needed */
    ...
}

Freeing an Object: mempool_free

When returning an object, the function checks whether the pool still needs to keep the minimum number of free elements. If the pool is below min_nr, the element is added back to the pool and any waiting threads are woken up. Otherwise, the element is passed to the underlying free callback.

void mempool_free(void *element, mempool_t *pool)
{
    if (pool->curr_nr < pool->min_nr) {
        spin_lock_irqsave(&pool->lock, flags);
        if (pool->curr_nr < pool->min_nr) {
            add_element(pool, element);
            spin_unlock_irqrestore(&pool->lock, flags);
            wake_up(&pool->wait);
            return;
        }
        spin_unlock_irqrestore(&pool->lock, flags);
    }
    pool->free(element, pool->pool_data);
}

Standard Alloc/Free Implementations Used by Mempool

void *mempool_alloc_slab(gfp_t gfp_mask, void *pool_data)

– allocates from a kmem cache. void mempool_free_slab(void *element, void *pool_data) – frees to a kmem cache. void *mempool_kmalloc(gfp_t gfp_mask, void *pool_data) – allocates a block of the size stored in pool_data via kmalloc. void mempool_kfree(void *element, void *pool_data) – frees memory allocated by kmalloc. void *mempool_alloc_pages(gfp_t gfp_mask, void *pool_data) – allocates pages of order stored in pool_data. void mempool_free_pages(void *element, void *pool_data) – frees pages of the given order.

Overall, the Linux kernel mempool implementation is concise yet powerful, providing a lightweight mechanism to guarantee allocation success in critical paths by maintaining a reserve of pre‑allocated objects.

C++memory poolMempool
ITPUB
Written by

ITPUB

Official ITPUB account sharing technical insights, community news, and exciting events.

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.