Update to 3.4-final.
[linux-flexiantxendom0-3.2.10.git] / mm / mempool.c
index 4398470..d904981 100644 (file)
@@ -10,7 +10,7 @@
 
 #include <linux/mm.h>
 #include <linux/slab.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/mempool.h>
 #include <linux/blkdev.h>
 #include <linux/writeback.h>
@@ -27,7 +27,15 @@ static void *remove_element(mempool_t *pool)
        return pool->elements[--pool->curr_nr];
 }
 
-static void free_pool(mempool_t *pool)
+/**
+ * mempool_destroy - deallocate a memory pool
+ * @pool:      pointer to the memory pool which was allocated via
+ *             mempool_create().
+ *
+ * Free all reserved elements in @pool and @pool itself.  This function
+ * only sleeps if the free_fn() function sleeps.
+ */
+void mempool_destroy(mempool_t *pool)
 {
        while (pool->curr_nr) {
                void *element = remove_element(pool);
@@ -36,6 +44,7 @@ static void free_pool(mempool_t *pool)
        kfree(pool->elements);
        kfree(pool);
 }
+EXPORT_SYMBOL(mempool_destroy);
 
 /**
  * mempool_create - create a memory pool
@@ -46,21 +55,27 @@ static void free_pool(mempool_t *pool)
  * @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
+ * 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
+ * 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_t *mempool_create(int min_nr, mempool_alloc_t *alloc_fn,
                                mempool_free_t *free_fn, void *pool_data)
 {
-       mempool_t *pool;
+       return  mempool_create_node(min_nr,alloc_fn,free_fn, pool_data,-1);
+}
+EXPORT_SYMBOL(mempool_create);
 
-       pool = kmalloc(sizeof(*pool), GFP_KERNEL);
+mempool_t *mempool_create_node(int min_nr, mempool_alloc_t *alloc_fn,
+                       mempool_free_t *free_fn, void *pool_data, int node_id)
+{
+       mempool_t *pool;
+       pool = kmalloc_node(sizeof(*pool), GFP_KERNEL | __GFP_ZERO, node_id);
        if (!pool)
                return NULL;
-       memset(pool, 0, sizeof(*pool));
-       pool->elements = kmalloc(min_nr * sizeof(void *), GFP_KERNEL);
+       pool->elements = kmalloc_node(min_nr * sizeof(void *),
+                                       GFP_KERNEL, node_id);
        if (!pool->elements) {
                kfree(pool);
                return NULL;
@@ -80,13 +95,14 @@ mempool_t * mempool_create(int min_nr, mempool_alloc_t *alloc_fn,
 
                element = pool->alloc(GFP_KERNEL, pool->pool_data);
                if (unlikely(!element)) {
-                       free_pool(pool);
+                       mempool_destroy(pool);
                        return NULL;
                }
                add_element(pool, element);
        }
        return pool;
 }
+EXPORT_SYMBOL(mempool_create_node);
 
 /**
  * mempool_resize - resize an existing memory pool
@@ -104,7 +120,7 @@ mempool_t * mempool_create(int min_nr, mempool_alloc_t *alloc_fn,
  * 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)
+int mempool_resize(mempool_t *pool, int new_min_nr, gfp_t gfp_mask)
 {
        void *element;
        void **new_elements;
@@ -113,8 +129,8 @@ int mempool_resize(mempool_t *pool, int new_min_nr, int gfp_mask)
        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) {
+       if (new_min_nr <= pool->min_nr) {
+               while (new_min_nr < pool->curr_nr) {
                        element = remove_element(pool);
                        spin_unlock_irqrestore(&pool->lock, flags);
                        pool->free(element, pool->pool_data);
@@ -131,6 +147,12 @@ int mempool_resize(mempool_t *pool, int new_min_nr, int gfp_mask)
                return -ENOMEM;
 
        spin_lock_irqsave(&pool->lock, flags);
+       if (unlikely(new_min_nr <= pool->min_nr)) {
+               /* Raced, other resize will do our work */
+               spin_unlock_irqrestore(&pool->lock, flags);
+               kfree(new_elements);
+               goto out;
+       }
        memcpy(new_elements, pool->elements,
                        pool->curr_nr * sizeof(*new_elements));
        kfree(pool->elements);
@@ -143,32 +165,20 @@ int mempool_resize(mempool_t *pool, int new_min_nr, int gfp_mask)
                if (!element)
                        goto out;
                spin_lock_irqsave(&pool->lock, flags);
-               if (pool->curr_nr < pool->min_nr)
+               if (pool->curr_nr < pool->min_nr) {
                        add_element(pool, element);
-               else
-                       kfree(element);         /* Raced */
+               } else {
+                       spin_unlock_irqrestore(&pool->lock, flags);
+                       pool->free(element, pool->pool_data);   /* Raced */
+                       goto out;
+               }
        }
 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);
-}
+EXPORT_SYMBOL(mempool_resize);
 
 /**
  * mempool_alloc - allocate an element from a specific memory pool
@@ -176,63 +186,73 @@ void mempool_destroy(mempool_t *pool)
  *             mempool_create().
  * @gfp_mask:  the usual allocation bitmask.
  *
- * this function only sleeps if the alloc_fn function sleeps or
+ * 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 * mempool_alloc(mempool_t *pool, gfp_t gfp_mask)
 {
        void *element;
        unsigned long flags;
-       DEFINE_WAIT(wait);
-       int gfp_nowait = gfp_mask & ~(__GFP_WAIT | __GFP_IO);
-       int pf_flags = current->flags;
+       wait_queue_t wait;
+       gfp_t gfp_temp;
+
+       might_sleep_if(gfp_mask & __GFP_WAIT);
+
+       gfp_mask |= __GFP_NOMEMALLOC;   /* don't allocate emergency reserves */
+       gfp_mask |= __GFP_NORETRY;      /* don't loop in __alloc_pages */
+       gfp_mask |= __GFP_NOWARN;       /* failures are OK */
+
+       gfp_temp = gfp_mask & ~(__GFP_WAIT|__GFP_IO);
 
 repeat_alloc:
-       current->flags |= PF_NOWARN;
-       element = pool->alloc(gfp_nowait, pool->pool_data);
-       current->flags = pf_flags;
+
+       element = pool->alloc(gfp_temp, pool->pool_data);
        if (likely(element != NULL))
                return element;
 
-       /*
-        * If the pool is less than 50% full and we can perform effective
-        * page reclaim then try harder to allocate an element.
-        */
-       if ((gfp_mask & __GFP_FS) && (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(0);
-
        spin_lock_irqsave(&pool->lock, flags);
        if (likely(pool->curr_nr)) {
                element = remove_element(pool);
                spin_unlock_irqrestore(&pool->lock, flags);
+               /* paired with rmb in mempool_free(), read comment there */
+               smp_wmb();
                return element;
        }
-       spin_unlock_irqrestore(&pool->lock, flags);
 
-       /* We must not sleep in the GFP_ATOMIC case */
-       if (gfp_mask == gfp_nowait)
-               return NULL;
+       /*
+        * We use gfp mask w/o __GFP_WAIT or IO for the first round.  If
+        * alloc failed with that and @pool was empty, retry immediately.
+        */
+       if (gfp_temp != gfp_mask) {
+               spin_unlock_irqrestore(&pool->lock, flags);
+               gfp_temp = gfp_mask;
+               goto repeat_alloc;
+       }
 
-       blk_run_queues();
+       /* We must not sleep if !__GFP_WAIT */
+       if (!(gfp_mask & __GFP_WAIT)) {
+               spin_unlock_irqrestore(&pool->lock, flags);
+               return NULL;
+       }
 
+       /* Let's wait for someone else to return an element to @pool */
+       init_wait(&wait);
        prepare_to_wait(&pool->wait, &wait, TASK_UNINTERRUPTIBLE);
-       if (!pool->curr_nr)
-               io_schedule();
-       finish_wait(&pool->wait, &wait);
 
+       spin_unlock_irqrestore(&pool->lock, flags);
+
+       /*
+        * FIXME: this should be io_schedule().  The timeout is there as a
+        * workaround for some DM problems in 2.6.18.
+        */
+       io_schedule_timeout(5*HZ);
+
+       finish_wait(&pool->wait, &wait);
        goto repeat_alloc;
 }
+EXPORT_SYMBOL(mempool_alloc);
 
 /**
  * mempool_free - return an element to the pool.
@@ -246,6 +266,42 @@ void mempool_free(void *element, mempool_t *pool)
 {
        unsigned long flags;
 
+       if (unlikely(element == NULL))
+               return;
+
+       /*
+        * Paired with the wmb in mempool_alloc().  The preceding read is
+        * for @element and the following @pool->curr_nr.  This ensures
+        * that the visible value of @pool->curr_nr is from after the
+        * allocation of @element.  This is necessary for fringe cases
+        * where @element was passed to this task without going through
+        * barriers.
+        *
+        * For example, assume @p is %NULL at the beginning and one task
+        * performs "p = mempool_alloc(...);" while another task is doing
+        * "while (!p) cpu_relax(); mempool_free(p, ...);".  This function
+        * may end up using curr_nr value which is from before allocation
+        * of @p without the following rmb.
+        */
+       smp_rmb();
+
+       /*
+        * For correctness, we need a test which is guaranteed to trigger
+        * if curr_nr + #allocated == min_nr.  Testing curr_nr < min_nr
+        * without locking achieves that and refilling as soon as possible
+        * is desirable.
+        *
+        * Because curr_nr visible here is always a value after the
+        * allocation of @element, any task which decremented curr_nr below
+        * min_nr is guaranteed to see curr_nr < min_nr unless curr_nr gets
+        * incremented to min_nr afterwards.  If curr_nr gets incremented
+        * to min_nr after the allocation of @element, the elements
+        * allocated after that are subject to the same guarantee.
+        *
+        * Waiters happen iff curr_nr is 0 and the above guarantee also
+        * ensures that there will be frees which return elements to the
+        * pool waking up the waiters.
+        */
        if (pool->curr_nr < pool->min_nr) {
                spin_lock_irqsave(&pool->lock, flags);
                if (pool->curr_nr < pool->min_nr) {
@@ -258,9 +314,56 @@ void mempool_free(void *element, mempool_t *pool)
        }
        pool->free(element, pool->pool_data);
 }
-
-EXPORT_SYMBOL(mempool_create);
-EXPORT_SYMBOL(mempool_resize);
-EXPORT_SYMBOL(mempool_destroy);
-EXPORT_SYMBOL(mempool_alloc);
 EXPORT_SYMBOL(mempool_free);
+
+/*
+ * A commonly used alloc and free fn.
+ */
+void *mempool_alloc_slab(gfp_t gfp_mask, void *pool_data)
+{
+       struct kmem_cache *mem = pool_data;
+       return kmem_cache_alloc(mem, gfp_mask);
+}
+EXPORT_SYMBOL(mempool_alloc_slab);
+
+void mempool_free_slab(void *element, void *pool_data)
+{
+       struct kmem_cache *mem = pool_data;
+       kmem_cache_free(mem, element);
+}
+EXPORT_SYMBOL(mempool_free_slab);
+
+/*
+ * A commonly used alloc and free fn that kmalloc/kfrees the amount of memory
+ * specified by pool_data
+ */
+void *mempool_kmalloc(gfp_t gfp_mask, void *pool_data)
+{
+       size_t size = (size_t)pool_data;
+       return kmalloc(size, gfp_mask);
+}
+EXPORT_SYMBOL(mempool_kmalloc);
+
+void mempool_kfree(void *element, void *pool_data)
+{
+       kfree(element);
+}
+EXPORT_SYMBOL(mempool_kfree);
+
+/*
+ * A simple mempool-backed page allocator that allocates pages
+ * of the order specified by pool_data.
+ */
+void *mempool_alloc_pages(gfp_t gfp_mask, void *pool_data)
+{
+       int order = (int)(long)pool_data;
+       return alloc_pages(gfp_mask, order);
+}
+EXPORT_SYMBOL(mempool_alloc_pages);
+
+void mempool_free_pages(void *element, void *pool_data)
+{
+       int order = (int)(long)pool_data;
+       __free_pages(element, order);
+}
+EXPORT_SYMBOL(mempool_free_pages);