Signed-off-by: Anil S Keshavamurthy --- include/linux/respool.h | 43 +++++++++ lib/Makefile | 1 lib/respool.c | 222 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 266 insertions(+) Index: linux-2.6.22-rc3/include/linux/respool.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.22-rc3/include/linux/respool.h 2007-06-06 11:33:24.000000000 -0700 @@ -0,0 +1,43 @@ +/* + * respool.c - library routines for handling generic pre-allocated pool of objects + * + * Copyright (c) 2006, Intel Corporation. + * + * This file is released under the GPLv2. + * + * Copyright (C) 2006 Anil S Keshavamurthy + * + */ + +#ifndef _RESPOOL_H_ +#define _RESPOOL_H_ + +#include +#include +#include +#include + +typedef void *(*rpool_alloc_t)(unsigned int, gfp_t); +typedef void (*rpool_free_t)(void *, unsigned int); + +struct resource_pool { + struct work_struct work; + spinlock_t pool_lock; /* pool lock to walk the pool_head */ + struct list_head pool_head; /* pool objects list head */ + unsigned int min_count; /* min count to maintain */ + unsigned int grow_count; /* grow by count when time to grow */ + unsigned int curr_count; /* count of current free objects */ + unsigned int alloc_size; /* objects size */ + rpool_alloc_t alloc_mem; /* pool mem alloc function pointer */ + rpool_free_t free_mem; /* pool mem free function pointer */ +}; + +void *get_resource_pool_obj(struct resource_pool *ppool); +void put_resource_pool_obj(void * vaddr, struct resource_pool *ppool); +void destroy_resource_pool(struct resource_pool *ppool); +int init_resource_pool(struct resource_pool *res, + unsigned int min_count, unsigned int alloc_size, + unsigned int grow_count, rpool_alloc_t alloc_fn, + rpool_free_t free_fn); + +#endif Index: linux-2.6.22-rc3/lib/Makefile =================================================================== --- linux-2.6.22-rc3.orig/lib/Makefile 2007-06-06 11:33:21.000000000 -0700 +++ linux-2.6.22-rc3/lib/Makefile 2007-06-06 11:33:24.000000000 -0700 @@ -58,6 +58,7 @@ obj-$(CONFIG_AUDIT_GENERIC) += audit.o obj-$(CONFIG_SWIOTLB) += swiotlb.o +obj-$(CONFIG_DMAR) += respool.o obj-$(CONFIG_FAULT_INJECTION) += fault-inject.o lib-$(CONFIG_GENERIC_BUG) += bug.o Index: linux-2.6.22-rc3/lib/respool.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.22-rc3/lib/respool.c 2007-06-06 11:34:46.000000000 -0700 @@ -0,0 +1,222 @@ +/* + * respool.c - library routines for handling generic pre-allocated pool of objects + * + * Copyright (c) 2006, Intel Corporation. + * + * This file is released under the GPLv2. + * + * Copyright (C) 2006 Anil S Keshavamurthy + */ + +#include + +/** + * get_resource_pool_obj - gets an object from the pool + * @ppool - resource pool in question + * This function gets an object from the pool and + * if the pool count drops below min_count, this + * function schedules work to grow the pool. If + * no elements are fount in the pool then this function + * tries to get memory from kernel. + */ +void * get_resource_pool_obj(struct resource_pool *ppool) +{ + unsigned long flags; + struct list_head *plist; + bool queue_work = 0; + + spin_lock_irqsave(&ppool->pool_lock, flags); + if (!list_empty(&ppool->pool_head)) { + plist = ppool->pool_head.next; + list_del(plist); + ppool->curr_count--; + } else { + /*Making sure that curr_count is 0 when list is empty */ + plist = NULL; + BUG_ON(ppool->curr_count != 0); + } + + /* Check if pool needs to grow */ + if (ppool->curr_count <= ppool->min_count) + queue_work = 1; + spin_unlock_irqrestore(&ppool->pool_lock, flags); + + if (queue_work) + schedule_work(&ppool->work); /* queue work to grow the pool */ + + + if (plist) { + memset(plist, 0, ppool->alloc_size); /* Zero out memory */ + return plist; + } + + /* Out of luck, try to get memory from kernel */ + plist = (struct list_head *)ppool->alloc_mem(ppool->alloc_size, + GFP_ATOMIC); + + return plist; +} + +/** + * put_resource_pool_obj - puts an object back to the pool + * @vaddr - object's address + * @ppool - resource pool in question. + * This function puts an object back to the pool. + */ +void put_resource_pool_obj(void * vaddr, struct resource_pool *ppool) +{ + unsigned long flags; + struct list_head *plist = (struct list_head *)vaddr; + bool queue_work = 0; + + BUG_ON(!vaddr); + BUG_ON(!ppool); + + spin_lock_irqsave(&ppool->pool_lock, flags); + list_add(plist, &ppool->pool_head); + ppool->curr_count++; + if (ppool->curr_count > (ppool->min_count + + ppool->grow_count * 2)) + queue_work = 1; + spin_unlock_irqrestore(&ppool->pool_lock, flags); + + if (queue_work) + schedule_work(&ppool->work); /* queue work to shrink the pool */ +} + +void +__grow_resource_pool(struct resource_pool *ppool, + unsigned int grow_count) +{ + unsigned long flags; + struct list_head *plist; + + while(grow_count) { + plist = (struct list_head *)ppool->alloc_mem(ppool->alloc_size, + GFP_KERNEL); + + if (!plist) + break; + + /* Add the element to the list */ + spin_lock_irqsave(&ppool->pool_lock, flags); + list_add(plist, &ppool->pool_head); + ppool->curr_count++; + spin_unlock_irqrestore(&ppool->pool_lock, flags); + grow_count--; + } +} + +void +__shrink_resource_pool(struct resource_pool *ppool, + unsigned int shrink_count) +{ + unsigned long flags; + struct list_head *plist; + + while (shrink_count) { + /* remove an object from the pool */ + spin_lock_irqsave(&ppool->pool_lock, flags); + if (list_empty(&ppool->pool_head)) { + spin_unlock_irqrestore(&ppool->pool_lock, flags); + break; + } + plist = ppool->pool_head.next; + list_del(plist); + ppool->curr_count--; + spin_unlock_irqrestore(&ppool->pool_lock, flags); + ppool->free_mem(plist, ppool->alloc_size); + shrink_count--; + } +} + + +/** + * resize_resource_pool - resize the given resource pool + * @work - work struct + * This functions gets the resource pool pointer from the + * work struct and grows the resource pool by grow_count. + */ +static void +resize_resource_pool(struct work_struct * work) +{ + struct resource_pool *ppool; + unsigned int min_count, grow_count = 0; + unsigned int shrink_count = 0; + unsigned long flags; + + ppool = container_of(work, struct resource_pool, work); + + /* compute the minimum count to grow */ + spin_lock_irqsave(&ppool->pool_lock, flags); + min_count = ppool->min_count + ppool->grow_count; + if (ppool->curr_count < min_count) + grow_count = min_count - ppool->curr_count; + else if (ppool->curr_count > min_count + ppool->grow_count) + shrink_count = ppool->curr_count - min_count; + spin_unlock_irqrestore(&ppool->pool_lock, flags); + + if (grow_count) + __grow_resource_pool(ppool, grow_count); + else if (shrink_count) + __shrink_resource_pool(ppool, shrink_count); +} + +/** + * destroy_resource_pool - destroys the given resource pool + * @ppool - resource pool in question. + * This function walks throuhg its list and frees up the + * preallocated objects. + */ +void +destroy_resource_pool(struct resource_pool *ppool) +{ + unsigned long flags; + struct list_head *plist; + + spin_lock_irqsave(&ppool->pool_lock, flags); + while (!list_empty(&ppool->pool_head)) { + plist = &ppool->pool_head; + list_del(plist); + + ppool->free_mem(plist, ppool->alloc_size); + + } + ppool->curr_count = 0; + spin_unlock_irqrestore(&ppool->pool_lock, flags); +} + +/** + * init_resource_pool - initializes the resource pool + * @res: resource pool in question. + * @min_count: count of objectes to pre-allocate + * @alloc_size: size of each objects + * @grow_count: count of objects to grow when required + * @alloc_fn: function which allocates memory + * @free_fn: function which frees memory + * + * This function initializes the given resource pool and + * populates the min_count of objects to begin with. + */ +int +init_resource_pool(struct resource_pool *res, + unsigned int min_count, unsigned int alloc_size, + unsigned int grow_count, rpool_alloc_t alloc_fn, + rpool_free_t free_fn) +{ + res->min_count = min_count; + res->alloc_size = alloc_size; + res->grow_count = grow_count; + res->curr_count = 0; + res->alloc_mem = alloc_fn; + res->free_mem = free_fn; + spin_lock_init(&res->pool_lock); + INIT_LIST_HEAD(&res->pool_head); + INIT_WORK(&res->work, resize_resource_pool); + + /* grow the pool */ + resize_resource_pool(&res->work); + + return (res->curr_count == 0); +} + -- - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/