From: Joe Thornber <thornber@sistina.com>
To: Joe Thornber <thornber@sistina.com>
Cc: Marcelo Tosatti <marcelo.tosatti@cyclades.com>,
Linux Mailing List <linux-kernel@vger.kernel.org>
Subject: [Patch 2/4] dm: mempool backport
Date: Tue, 9 Dec 2003 12:25:21 +0000 [thread overview]
Message-ID: <20031209122521.GD472@reti> (raw)
In-Reply-To: <20031209115806.GA472@reti>
Backport of mempool code.
--- diff/mm/Makefile 2002-08-05 14:57:44.000000000 +0100
+++ source/mm/Makefile 2003-12-09 10:34:55.000000000 +0000
@@ -9,12 +9,12 @@
O_TARGET := mm.o
-export-objs := shmem.o filemap.o memory.o page_alloc.o
+export-objs := shmem.o filemap.o memory.o page_alloc.o mempool.o
obj-y := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \
vmalloc.o slab.o bootmem.o swap.o vmscan.o page_io.o \
page_alloc.o swap_state.o swapfile.o numa.o oom_kill.o \
- shmem.o
+ shmem.o mempool.o
obj-$(CONFIG_HIGHMEM) += highmem.o
--- diff/include/linux/mempool.h 1970-01-01 01:00:00.000000000 +0100
+++ source/include/linux/mempool.h 2003-12-09 10:34:55.000000000 +0000
@@ -0,0 +1,31 @@
+/*
+ * memory buffer pool support
+ */
+#ifndef _LINUX_MEMPOOL_H
+#define _LINUX_MEMPOOL_H
+
+#include <linux/list.h>
+#include <linux/wait.h>
+
+struct mempool_s;
+typedef struct mempool_s mempool_t;
+
+typedef void * (mempool_alloc_t)(int gfp_mask, void *pool_data);
+typedef void (mempool_free_t)(void *element, void *pool_data);
+
+extern mempool_t * mempool_create(int min_nr, mempool_alloc_t *alloc_fn,
+ mempool_free_t *free_fn, void *pool_data);
+extern int mempool_resize(mempool_t *pool, int new_min_nr, int gfp_mask);
+extern void mempool_destroy(mempool_t *pool);
+extern void * mempool_alloc(mempool_t *pool, int gfp_mask);
+extern void mempool_free(void *element, mempool_t *pool);
+
+/*
+ * A mempool_alloc_t and mempool_free_t that get the memory from
+ * a slab that is passed in through pool_data.
+ */
+void *mempool_alloc_slab(int gfp_mask, void *pool_data);
+void mempool_free_slab(void *element, void *pool_data);
+
+
+#endif /* _LINUX_MEMPOOL_H */
--- diff/mm/mempool.c 1970-01-01 01:00:00.000000000 +0100
+++ source/mm/mempool.c 2003-12-09 10:34:55.000000000 +0000
@@ -0,0 +1,299 @@
+/*
+ * linux/mm/mempool.c
+ *
+ * memory buffer pool support. Such pools are mostly used
+ * for guaranteed, deadlock-free memory allocations during
+ * extreme VM load.
+ *
+ * started by Ingo Molnar, Copyright (C) 2001
+ */
+
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/mempool.h>
+
+struct mempool_s {
+ spinlock_t lock;
+ int min_nr; /* nr of elements at *elements */
+ int curr_nr; /* Current nr of elements at *elements */
+ void **elements;
+
+ void *pool_data;
+ mempool_alloc_t *alloc;
+ mempool_free_t *free;
+ wait_queue_head_t wait;
+};
+
+static void add_element(mempool_t *pool, void *element)
+{
+ BUG_ON(pool->curr_nr >= pool->min_nr);
+ pool->elements[pool->curr_nr++] = element;
+}
+
+static void *remove_element(mempool_t *pool)
+{
+ BUG_ON(pool->curr_nr <= 0);
+ return pool->elements[--pool->curr_nr];
+}
+
+static void free_pool(mempool_t *pool)
+{
+ while (pool->curr_nr) {
+ void *element = remove_element(pool);
+ pool->free(element, pool->pool_data);
+ }
+ kfree(pool->elements);
+ kfree(pool);
+}
+
+/**
+ * mempool_create - create a memory pool
+ * @min_nr: the minimum number of elements guaranteed to be
+ * allocated for this pool.
+ * @alloc_fn: user-defined element-allocation function.
+ * @free_fn: user-defined element-freeing function.
+ * @pool_data: optional private data available to the user-defined functions.
+ *
+ * this function creates and allocates a guaranteed size, preallocated
+ * memory pool. The pool can be used from the mempool_alloc and mempool_free
+ * functions. This function might sleep. Both the alloc_fn() and the free_fn()
+ * functions might sleep - as long as the mempool_alloc function is not called
+ * from IRQ contexts.
+ */
+mempool_t * mempool_create(int min_nr, mempool_alloc_t *alloc_fn,
+ mempool_free_t *free_fn, void *pool_data)
+{
+ mempool_t *pool;
+
+ pool = kmalloc(sizeof(*pool), GFP_KERNEL);
+ if (!pool)
+ return NULL;
+ memset(pool, 0, sizeof(*pool));
+ pool->elements = kmalloc(min_nr * sizeof(void *), GFP_KERNEL);
+ if (!pool->elements) {
+ kfree(pool);
+ return NULL;
+ }
+ spin_lock_init(&pool->lock);
+ pool->min_nr = min_nr;
+ pool->pool_data = pool_data;
+ init_waitqueue_head(&pool->wait);
+ pool->alloc = alloc_fn;
+ pool->free = free_fn;
+
+ /*
+ * First pre-allocate the guaranteed number of buffers.
+ */
+ while (pool->curr_nr < pool->min_nr) {
+ void *element;
+
+ element = pool->alloc(GFP_KERNEL, pool->pool_data);
+ if (unlikely(!element)) {
+ free_pool(pool);
+ return NULL;
+ }
+ add_element(pool, element);
+ }
+ return pool;
+}
+
+/**
+ * mempool_resize - resize an existing memory pool
+ * @pool: pointer to the memory pool which was allocated via
+ * mempool_create().
+ * @new_min_nr: the new minimum number of elements guaranteed to be
+ * allocated for this pool.
+ * @gfp_mask: the usual allocation bitmask.
+ *
+ * This function shrinks/grows the pool. In the case of growing,
+ * it cannot be guaranteed that the pool will be grown to the new
+ * size immediately, but new mempool_free() calls will refill it.
+ *
+ * Note, the caller must guarantee that no mempool_destroy is called
+ * while this function is running. mempool_alloc() & mempool_free()
+ * might be called (eg. from IRQ contexts) while this function executes.
+ */
+int mempool_resize(mempool_t *pool, int new_min_nr, int gfp_mask)
+{
+ void *element;
+ void **new_elements;
+ unsigned long flags;
+
+ BUG_ON(new_min_nr <= 0);
+
+ spin_lock_irqsave(&pool->lock, flags);
+ if (new_min_nr < pool->min_nr) {
+ while (pool->curr_nr > new_min_nr) {
+ element = remove_element(pool);
+ spin_unlock_irqrestore(&pool->lock, flags);
+ pool->free(element, pool->pool_data);
+ spin_lock_irqsave(&pool->lock, flags);
+ }
+ pool->min_nr = new_min_nr;
+ goto out_unlock;
+ }
+ spin_unlock_irqrestore(&pool->lock, flags);
+
+ /* Grow the pool */
+ new_elements = kmalloc(new_min_nr * sizeof(*new_elements), gfp_mask);
+ if (!new_elements)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&pool->lock, flags);
+ memcpy(new_elements, pool->elements,
+ pool->curr_nr * sizeof(*new_elements));
+ kfree(pool->elements);
+ pool->elements = new_elements;
+ pool->min_nr = new_min_nr;
+
+ while (pool->curr_nr < pool->min_nr) {
+ spin_unlock_irqrestore(&pool->lock, flags);
+ element = pool->alloc(gfp_mask, pool->pool_data);
+ if (!element)
+ goto out;
+ spin_lock_irqsave(&pool->lock, flags);
+ if (pool->curr_nr < pool->min_nr)
+ add_element(pool, element);
+ else
+ kfree(element); /* Raced */
+ }
+out_unlock:
+ spin_unlock_irqrestore(&pool->lock, flags);
+out:
+ return 0;
+}
+
+/**
+ * mempool_destroy - deallocate a memory pool
+ * @pool: pointer to the memory pool which was allocated via
+ * mempool_create().
+ *
+ * this function only sleeps if the free_fn() function sleeps. The caller
+ * has to guarantee that all elements have been returned to the pool (ie:
+ * freed) prior to calling mempool_destroy().
+ */
+void mempool_destroy(mempool_t *pool)
+{
+ if (pool->curr_nr != pool->min_nr)
+ BUG(); /* There were outstanding elements */
+ free_pool(pool);
+}
+
+/**
+ * mempool_alloc - allocate an element from a specific memory pool
+ * @pool: pointer to the memory pool which was allocated via
+ * mempool_create().
+ * @gfp_mask: the usual allocation bitmask.
+ *
+ * this function only sleeps if the alloc_fn function sleeps or
+ * returns NULL. Note that due to preallocation, this function
+ * *never* fails when called from process contexts. (it might
+ * fail if called from an IRQ context.)
+ */
+void * mempool_alloc(mempool_t *pool, int gfp_mask)
+{
+ void *element;
+ unsigned long flags;
+ int curr_nr;
+ DECLARE_WAITQUEUE(wait, current);
+ int gfp_nowait = gfp_mask & ~(__GFP_WAIT | __GFP_IO);
+
+repeat_alloc:
+ element = pool->alloc(gfp_nowait, pool->pool_data);
+ if (likely(element != NULL))
+ return element;
+
+ /*
+ * If the pool is less than 50% full then try harder
+ * to allocate an element:
+ */
+ if ((gfp_mask != gfp_nowait) && (pool->curr_nr <= pool->min_nr/2)) {
+ element = pool->alloc(gfp_mask, pool->pool_data);
+ if (likely(element != NULL))
+ return element;
+ }
+
+ /*
+ * Kick the VM at this point.
+ */
+ wakeup_bdflush();
+
+ spin_lock_irqsave(&pool->lock, flags);
+ if (likely(pool->curr_nr)) {
+ element = remove_element(pool);
+ spin_unlock_irqrestore(&pool->lock, flags);
+ return element;
+ }
+ spin_unlock_irqrestore(&pool->lock, flags);
+
+ /* We must not sleep in the GFP_ATOMIC case */
+ if (gfp_mask == gfp_nowait)
+ return NULL;
+
+ run_task_queue(&tq_disk);
+
+ add_wait_queue_exclusive(&pool->wait, &wait);
+ set_task_state(current, TASK_UNINTERRUPTIBLE);
+
+ spin_lock_irqsave(&pool->lock, flags);
+ curr_nr = pool->curr_nr;
+ spin_unlock_irqrestore(&pool->lock, flags);
+
+ if (!curr_nr)
+ schedule();
+
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&pool->wait, &wait);
+
+ goto repeat_alloc;
+}
+
+/**
+ * mempool_free - return an element to the pool.
+ * @element: pool element pointer.
+ * @pool: pointer to the memory pool which was allocated via
+ * mempool_create().
+ *
+ * this function only sleeps if the free_fn() function sleeps.
+ */
+void mempool_free(void *element, mempool_t *pool)
+{
+ unsigned long flags;
+
+ 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);
+}
+
+/*
+ * A commonly used alloc and free fn.
+ */
+void *mempool_alloc_slab(int gfp_mask, void *pool_data)
+{
+ kmem_cache_t *mem = (kmem_cache_t *) pool_data;
+ return kmem_cache_alloc(mem, gfp_mask);
+}
+
+void mempool_free_slab(void *element, void *pool_data)
+{
+ kmem_cache_t *mem = (kmem_cache_t *) pool_data;
+ kmem_cache_free(mem, element);
+}
+
+
+EXPORT_SYMBOL(mempool_create);
+EXPORT_SYMBOL(mempool_resize);
+EXPORT_SYMBOL(mempool_destroy);
+EXPORT_SYMBOL(mempool_alloc);
+EXPORT_SYMBOL(mempool_free);
+EXPORT_SYMBOL(mempool_alloc_slab);
+EXPORT_SYMBOL(mempool_free_slab);
next prev parent reply other threads:[~2003-12-09 12:37 UTC|newest]
Thread overview: 55+ messages / expand[flat|nested] mbox.gz Atom feed top
2003-12-09 11:58 Device-mapper submission for 2.4 Joe Thornber
2003-12-09 12:24 ` [Patch 1/4] fs.h: b_journal_head Joe Thornber
2003-12-09 23:46 ` Nathan Scott
2003-12-10 8:46 ` Joe Thornber
2003-12-10 12:06 ` Nathan Scott
2003-12-09 12:25 ` Joe Thornber [this message]
2003-12-09 12:26 ` [Patch 3/4] dm: core files Joe Thornber
2003-12-09 12:26 ` [Patch 4/4] dm: ioctl interface Joe Thornber
2003-12-09 13:15 ` Device-mapper submission for 2.4 Marcelo Tosatti
2003-12-09 13:45 ` Joe Thornber
2003-12-09 14:00 ` Måns Rullgård
2003-12-09 14:10 ` Muli Ben-Yehuda
2003-12-09 14:21 ` Måns Rullgård
2003-12-09 14:16 ` Joe Thornber
2003-12-09 14:24 ` Stefan Smietanowski
2003-12-09 14:10 ` Marcelo Tosatti
2003-12-09 14:34 ` Joe Thornber
2003-12-09 21:07 ` Paul Jakma
2003-12-09 22:26 ` Joe Thornber
2003-12-09 22:48 ` Marcelo Tosatti
2003-12-09 23:46 ` Paul Jakma
2003-12-09 23:58 ` William Lee Irwin III
2003-12-10 0:15 ` Paul Jakma
2003-12-10 11:49 ` Stephan von Krawczynski
2003-12-10 23:15 ` Dave Jones
2003-12-10 0:27 ` Jose Luis Domingo Lopez
2003-12-10 0:59 ` Tupshin Harper
2003-12-10 9:40 ` Wichert Akkerman
2003-12-10 2:44 ` Martin J. Bligh
2003-12-10 15:55 ` Paul Jakma
2003-12-10 16:54 ` venom
2003-12-10 17:00 ` Paul Jakma
2003-12-10 17:14 ` venom
2003-12-10 23:40 ` Mike Fedyk
2003-12-11 14:34 ` [linux-lvm] " Alasdair G Kergon
2003-12-11 19:48 ` Alasdair G Kergon
2003-12-16 19:15 ` bill davidsen
2003-12-16 19:01 ` bill davidsen
2003-12-10 8:45 ` Jens Axboe
2003-12-10 17:30 ` Paul Jakma
2003-12-10 17:44 ` Joe Thornber
2003-12-10 17:48 ` venom
2003-12-10 18:07 ` Paul Jakma
2003-12-10 19:30 ` Jens Axboe
2003-12-09 17:02 ` Bill Rugolsky Jr.
2003-12-09 22:53 ` Ciaran McCreesh
2003-12-10 3:38 ` Lincoln Dale
2003-12-10 6:12 ` Willy Tarreau
2003-12-10 6:35 ` viro
2003-12-09 17:45 ` Kevin Corry
2003-12-09 19:47 ` Paul P Komkoff Jr
2003-12-09 14:23 ` Stefan Smietanowski
2003-12-09 14:36 ` Joe Thornber
2003-12-09 19:50 ` William Lee Irwin III
2003-12-09 21:13 ` Paul Jakma
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20031209122521.GD472@reti \
--to=thornber@sistina.com \
--cc=linux-kernel@vger.kernel.org \
--cc=marcelo.tosatti@cyclades.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.