lkml.org 
[lkml]   [2007]   [Jun]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[Intel-IOMMU 02/10] Library routine for pre-allocat pool handling
    Signed-off-by: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
    ---
    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 <anil.s.keshavamurthy@intel.com>
    + *
    + */
    +
    +#ifndef _RESPOOL_H_
    +#define _RESPOOL_H_
    +
    +#include <linux/types.h>
    +#include <linux/kernel.h>
    +#include <linux/slab.h>
    +#include <linux/workqueue.h>
    +
    +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 <anil.s.keshavamurthy@intel.com>
    + */
    +
    +#include <linux/respool.h>
    +
    +/**
    + * 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/

    \
     
     \ /
      Last update: 2007-06-06 21:19    [W:0.033 / U:35.116 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site