ctl_mem_pool.c revision 259065
1/*- 2 * Copyright (c) 2003, 2004 Silicon Graphics International Corp. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions, and the following disclaimer, 10 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * substantially similar to the "NO WARRANTY" disclaimer below 13 * ("Disclaimer") and any redistribution must be conditioned upon 14 * including a substantially similar Disclaimer requirement for further 15 * binary redistribution. 16 * 17 * NO WARRANTY 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGES. 29 * 30 * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_mem_pool.c#1 $ 31 */ 32/* 33 * CAM Target Layer memory pool code. 34 * 35 * Author: Ken Merry <ken@FreeBSD.org> 36 */ 37 38#include <sys/cdefs.h> 39__FBSDID("$FreeBSD: releng/10.0/sys/cam/ctl/ctl_mem_pool.c 229997 2012-01-12 00:34:33Z ken $"); 40 41#include <sys/param.h> 42#include <sys/systm.h> 43#include <sys/kernel.h> 44#include <sys/types.h> 45#include <sys/malloc.h> 46#include <sys/lock.h> 47#include <sys/mutex.h> 48#include <sys/condvar.h> 49#include <sys/queue.h> 50 51#include <cam/ctl/ctl_mem_pool.h> 52 53MALLOC_DEFINE(M_CTL_POOL, "ctlpool", "CTL memory pool"); 54 55int 56ctl_init_mem_pool(struct ctl_mem_pool *pool, int chunk_size, 57 ctl_mem_pool_flags flags, int grow_inc, 58 int initial_pool_size) 59{ 60 pool->flags = flags; 61 pool->chunk_size = chunk_size; 62 pool->grow_inc = grow_inc; 63 mtx_init(&pool->lock, "Pool mutex", NULL, MTX_DEF); 64 STAILQ_INIT(&pool->free_mem_list); 65 cv_init(&pool->wait_mem, "CTL mem pool"); 66 67 if (ctl_grow_mem_pool(pool, initial_pool_size, /*can_wait*/ 1) != 68 initial_pool_size) 69 return (1); 70 else 71 return (0); 72} 73 74struct ctl_mem_element * 75ctl_alloc_mem_element(struct ctl_mem_pool *pool, int can_wait) 76{ 77 struct ctl_mem_element *mem; 78 79 for (;;) { 80 mtx_lock(&pool->lock); 81 82 mem = STAILQ_FIRST(&pool->free_mem_list); 83 if (mem != NULL) { 84 STAILQ_REMOVE(&pool->free_mem_list, mem, 85 ctl_mem_element, links); 86 mem->flags = CTL_MEM_ELEMENT_PREALLOC; 87 } 88 mtx_unlock(&pool->lock); 89 90 if (mem != NULL) 91 return (mem); 92 93 /* 94 * Grow the pool permanantly by the requested increment 95 * instead of temporarily. This has the effect that 96 * whatever the high water mark of transactions is for 97 * this pool, we'll keep that much memory around. 98 */ 99 if (pool->flags & CTL_MEM_POOL_PERM_GROW) { 100 if (ctl_grow_mem_pool(pool, pool->grow_inc, 101 can_wait) != 0) 102 continue; 103 } 104 mem = (struct ctl_mem_element *)malloc(sizeof(*mem), 105 M_CTL_POOL, can_wait ? M_WAITOK : M_NOWAIT); 106 107 if (mem != NULL) { 108 mem->flags = CTL_MEM_ELEMENT_NONE; 109 mem->pool = pool; 110 111 mem->bytes = malloc(pool->chunk_size, M_CTL_POOL, 112 can_wait ? M_WAITOK : M_NOWAIT); 113 if (mem->bytes == NULL) { 114 free(mem, M_CTL_POOL); 115 mem = NULL; 116 } else { 117 return (mem); 118 } 119 } 120 121 if (can_wait == 0) 122 return (NULL); 123 124 cv_wait_unlock(&pool->wait_mem, &pool->lock); 125 } 126} 127 128void 129ctl_free_mem_element(struct ctl_mem_element *mem) 130{ 131 struct ctl_mem_pool *pool; 132 133 pool = mem->pool; 134 135 if (mem->flags & CTL_MEM_ELEMENT_PREALLOC) { 136 mtx_lock(&pool->lock); 137 STAILQ_INSERT_TAIL(&pool->free_mem_list, mem, links); 138 mtx_unlock(&pool->lock); 139 cv_broadcast(&pool->wait_mem); 140 } else 141 free(mem, M_CTL_POOL); 142} 143 144int 145ctl_grow_mem_pool(struct ctl_mem_pool *pool, int count, int can_wait) 146{ 147 int i; 148 149 for (i = 0; i < count; i++) { 150 struct ctl_mem_element *mem; 151 152 mem = (struct ctl_mem_element *)malloc(sizeof(*mem), 153 M_CTL_POOL, can_wait ? M_WAITOK : M_NOWAIT); 154 155 if (mem == NULL) 156 break; 157 158 mem->bytes = malloc(pool->chunk_size, M_CTL_POOL, can_wait ? 159 M_WAITOK : M_NOWAIT); 160 if (mem->bytes == NULL) { 161 free(mem, M_CTL_POOL); 162 break; 163 } 164 mem->flags = CTL_MEM_ELEMENT_PREALLOC; 165 mem->pool = pool; 166 mtx_lock(&pool->lock); 167 STAILQ_INSERT_TAIL(&pool->free_mem_list, mem, links); 168 mtx_unlock(&pool->lock); 169 } 170 171 return (i); 172} 173 174int 175ctl_shrink_mem_pool(struct ctl_mem_pool *pool) 176{ 177 struct ctl_mem_element *mem, *mem_next; 178 179 mtx_lock(&pool->lock); 180 for (mem = STAILQ_FIRST(&pool->free_mem_list); mem != NULL; 181 mem = mem_next) { 182 mem_next = STAILQ_NEXT(mem, links); 183 184 STAILQ_REMOVE(&pool->free_mem_list, mem, ctl_mem_element, 185 links); 186 free(mem->bytes, M_CTL_POOL); 187 free(mem, M_CTL_POOL); 188 } 189 mtx_unlock(&pool->lock); 190 191 return (0); 192} 193