xref: /freebsd/contrib/ofed/opensm/complib/cl_pool.c (revision d0b2dbfa0ecf2bbc9709efc5e20baf8e4b44bbbf)
1 /*
2  * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3  * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5  *
6  * This software is available to you under a choice of one of two
7  * licenses.  You may choose to be licensed under the terms of the GNU
8  * General Public License (GPL) Version 2, available from the file
9  * COPYING in the main directory of this source tree, or the
10  * OpenIB.org BSD license below:
11  *
12  *     Redistribution and use in source and binary forms, with or
13  *     without modification, are permitted provided that the following
14  *     conditions are met:
15  *
16  *      - Redistributions of source code must retain the above
17  *        copyright notice, this list of conditions and the following
18  *        disclaimer.
19  *
20  *      - Redistributions in binary form must reproduce the above
21  *        copyright notice, this list of conditions and the following
22  *        disclaimer in the documentation and/or other materials
23  *        provided with the distribution.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32  * SOFTWARE.
33  *
34  */
35 
36 /*
37  * Abstract:
38  *	Implementation of the grow pools.  The grow pools manage a pool of objects.
39  *	The pools can grow to meet demand, limited only by system memory.
40  *
41  */
42 
43 #if HAVE_CONFIG_H
44 #  include <config.h>
45 #endif				/* HAVE_CONFIG_H */
46 
47 #include <stdlib.h>
48 #include <string.h>
49 #include <complib/cl_qcomppool.h>
50 #include <complib/cl_comppool.h>
51 #include <complib/cl_qpool.h>
52 #include <complib/cl_pool.h>
53 #include <complib/cl_math.h>
54 
55 /*
56  * IMPLEMENTATION OF QUICK COMPOSITE POOL
57  */
58 void cl_qcpool_construct(IN cl_qcpool_t * const p_pool)
59 {
60 	CL_ASSERT(p_pool);
61 
62 	memset(p_pool, 0, sizeof(cl_qcpool_t));
63 
64 	p_pool->state = CL_UNINITIALIZED;
65 }
66 
67 cl_status_t cl_qcpool_init(IN cl_qcpool_t * const p_pool,
68 			   IN const size_t min_size, IN const size_t max_size,
69 			   IN const size_t grow_size,
70 			   IN const size_t * const component_sizes,
71 			   IN const uint32_t num_components,
72 			   IN cl_pfn_qcpool_init_t pfn_initializer OPTIONAL,
73 			   IN cl_pfn_qcpool_dtor_t pfn_destructor OPTIONAL,
74 			   IN const void *const context)
75 {
76 	cl_status_t status;
77 	uint32_t i;
78 
79 	CL_ASSERT(p_pool);
80 	/* Must have a minimum of 1 component. */
81 	CL_ASSERT(num_components);
82 	/* A component size array is required. */
83 	CL_ASSERT(component_sizes);
84 	/*
85 	 * If no initializer is provided, the first component must be large
86 	 * enough to hold a pool item.
87 	 */
88 	CL_ASSERT(pfn_initializer ||
89 		  (component_sizes[0] >= sizeof(cl_pool_item_t)));
90 
91 	cl_qcpool_construct(p_pool);
92 
93 	if (num_components > 1 && !pfn_initializer)
94 		return (CL_INVALID_SETTING);
95 
96 	if (max_size && max_size < min_size)
97 		return (CL_INVALID_SETTING);
98 
99 	/*
100 	 * Allocate the array of component sizes and component pointers all
101 	 * in one allocation.
102 	 */
103 	p_pool->component_sizes = (size_t *) malloc((sizeof(size_t) +
104 						     sizeof(void *)) *
105 						    num_components);
106 
107 	if (!p_pool->component_sizes)
108 		return (CL_INSUFFICIENT_MEMORY);
109 	else
110 		memset(p_pool->component_sizes, 0,
111 		       (sizeof(size_t) + sizeof(void *)) * num_components);
112 
113 	/* Calculate the pointer to the array of pointers, used for callbacks. */
114 	p_pool->p_components =
115 	    (void **)(p_pool->component_sizes + num_components);
116 
117 	/* Copy the user's sizes into our array for future use. */
118 	memcpy(p_pool->component_sizes, component_sizes,
119 	       sizeof(component_sizes[0]) * num_components);
120 
121 	/* Store the number of components per object. */
122 	p_pool->num_components = num_components;
123 
124 	/* Round up and store the size of the components. */
125 	for (i = 0; i < num_components; i++) {
126 		/*
127 		 * We roundup each component size so that all components
128 		 * are aligned on a natural boundary.
129 		 */
130 		p_pool->component_sizes[i] =
131 		    ROUNDUP(p_pool->component_sizes[i], sizeof(uintptr_t));
132 	}
133 
134 	p_pool->max_objects = max_size ? max_size : ~(size_t) 0;
135 	p_pool->grow_size = grow_size;
136 
137 	/* Store callback function pointers. */
138 	p_pool->pfn_init = pfn_initializer;	/* may be NULL */
139 	p_pool->pfn_dtor = pfn_destructor;	/* may be NULL */
140 	p_pool->context = context;
141 
142 	cl_qlist_init(&p_pool->alloc_list);
143 
144 	cl_qlist_init(&p_pool->free_list);
145 
146 	/*
147 	 * We are now initialized.  We change the initialized flag before
148 	 * growing since the grow function asserts that we are initialized.
149 	 */
150 	p_pool->state = CL_INITIALIZED;
151 
152 	/* Allocate the minimum number of objects as requested. */
153 	if (!min_size)
154 		return (CL_SUCCESS);
155 
156 	status = cl_qcpool_grow(p_pool, min_size);
157 	/* Trap for error and cleanup if necessary. */
158 	if (status != CL_SUCCESS)
159 		cl_qcpool_destroy(p_pool);
160 
161 	return (status);
162 }
163 
164 void cl_qcpool_destroy(IN cl_qcpool_t * const p_pool)
165 {
166 	/* CL_ASSERT that a non-NULL pointer was provided. */
167 	CL_ASSERT(p_pool);
168 	/* CL_ASSERT that we are in a valid state (not uninitialized memory). */
169 	CL_ASSERT(cl_is_state_valid(p_pool->state));
170 
171 	if (p_pool->state == CL_INITIALIZED) {
172 		/*
173 		 * Assert if the user hasn't put everything back in the pool
174 		 * before destroying it
175 		 * if they haven't, then most likely they are still using memory
176 		 * that will be freed, and the destructor will not be called!
177 		 */
178 #ifdef _DEBUG_
179 		/* but we do not want "free" version to assert on this one */
180 		CL_ASSERT(cl_qcpool_count(p_pool) == p_pool->num_objects);
181 #endif
182 		/* call the user's destructor for each object in the pool */
183 		if (p_pool->pfn_dtor) {
184 			while (!cl_is_qlist_empty(&p_pool->free_list)) {
185 				p_pool->pfn_dtor((cl_pool_item_t *)
186 						 cl_qlist_remove_head(&p_pool->
187 								      free_list),
188 						 (void *)p_pool->context);
189 			}
190 		} else {
191 			cl_qlist_remove_all(&p_pool->free_list);
192 		}
193 
194 		/* Free all allocated memory blocks. */
195 		while (!cl_is_qlist_empty(&p_pool->alloc_list))
196 			free(cl_qlist_remove_head(&p_pool->alloc_list));
197 
198 		if (p_pool->component_sizes) {
199 			free(p_pool->component_sizes);
200 			p_pool->component_sizes = NULL;
201 		}
202 	}
203 
204 	p_pool->state = CL_UNINITIALIZED;
205 }
206 
207 cl_status_t cl_qcpool_grow(IN cl_qcpool_t * const p_pool, IN size_t obj_count)
208 {
209 	cl_status_t status = CL_SUCCESS;
210 	uint8_t *p_objects;
211 	cl_pool_item_t *p_pool_item;
212 	uint32_t i;
213 	size_t obj_size;
214 
215 	CL_ASSERT(p_pool);
216 	CL_ASSERT(p_pool->state == CL_INITIALIZED);
217 	CL_ASSERT(obj_count);
218 
219 	/* Validate that growth is possible. */
220 	if (p_pool->num_objects == p_pool->max_objects)
221 		return (CL_INSUFFICIENT_MEMORY);
222 
223 	/* Cap the growth to the desired maximum. */
224 	if (obj_count > (p_pool->max_objects - p_pool->num_objects))
225 		obj_count = p_pool->max_objects - p_pool->num_objects;
226 
227 	/* Calculate the size of an object. */
228 	obj_size = 0;
229 	for (i = 0; i < p_pool->num_components; i++)
230 		obj_size += p_pool->component_sizes[i];
231 
232 	/* Allocate the buffer for the new objects. */
233 	p_objects = (uint8_t *)
234 	    malloc(sizeof(cl_list_item_t) + (obj_size * obj_count));
235 
236 	/* Make sure the allocation succeeded. */
237 	if (!p_objects)
238 		return (CL_INSUFFICIENT_MEMORY);
239 	else
240 		memset(p_objects, 0,
241 		       sizeof(cl_list_item_t) + (obj_size * obj_count));
242 
243 	/* Insert the allocation in our list. */
244 	cl_qlist_insert_tail(&p_pool->alloc_list, (cl_list_item_t *) p_objects);
245 	p_objects += sizeof(cl_list_item_t);
246 
247 	/* initialize the new elements and add them to the free list */
248 	while (obj_count--) {
249 		/* Setup the array of components for the current object. */
250 		p_pool->p_components[0] = p_objects;
251 		for (i = 1; i < p_pool->num_components; i++) {
252 			/* Calculate the pointer to the next component. */
253 			p_pool->p_components[i] =
254 			    (uint8_t *) p_pool->p_components[i - 1] +
255 			    p_pool->component_sizes[i - 1];
256 		}
257 
258 		/*
259 		 * call the user's initializer
260 		 * this can fail!
261 		 */
262 		if (p_pool->pfn_init) {
263 			p_pool_item = NULL;
264 			status = p_pool->pfn_init(p_pool->p_components,
265 						  p_pool->num_components,
266 						  (void *)p_pool->context,
267 						  &p_pool_item);
268 			if (status != CL_SUCCESS) {
269 				/*
270 				 * User initialization failed
271 				 * we may have only grown the pool by some partial amount
272 				 * Invoke the destructor for the object that failed
273 				 * initialization.
274 				 */
275 				if (p_pool->pfn_dtor)
276 					p_pool->pfn_dtor(p_pool_item,
277 							 (void *)p_pool->
278 							 context);
279 
280 				/* Return the user's status. */
281 				return (status);
282 			}
283 			CL_ASSERT(p_pool_item);
284 		} else {
285 			/*
286 			 * If no initializer is provided, assume that the pool item
287 			 * is stored at the beginning of the first component.
288 			 */
289 			p_pool_item =
290 			    (cl_pool_item_t *) p_pool->p_components[0];
291 		}
292 
293 #ifdef _DEBUG_
294 		/*
295 		 * Set the pool item's pool pointer to this pool so that we can
296 		 * check that items get returned to the correct pool.
297 		 */
298 		p_pool_item->p_pool = p_pool;
299 #endif
300 
301 		/* Insert the new item in the free list, traping for failure. */
302 		cl_qlist_insert_head(&p_pool->free_list,
303 				     &p_pool_item->list_item);
304 
305 		p_pool->num_objects++;
306 
307 		/* move the pointer to the next item */
308 		p_objects += obj_size;
309 	}
310 
311 	return (status);
312 }
313 
314 cl_pool_item_t *cl_qcpool_get(IN cl_qcpool_t * const p_pool)
315 {
316 	cl_list_item_t *p_list_item;
317 
318 	CL_ASSERT(p_pool);
319 	CL_ASSERT(p_pool->state == CL_INITIALIZED);
320 
321 	if (cl_is_qlist_empty(&p_pool->free_list)) {
322 		/*
323 		 * No object is available.
324 		 * Return NULL if the user does not want automatic growth.
325 		 */
326 		if (!p_pool->grow_size)
327 			return (NULL);
328 
329 		/* We ran out of elements.  Get more */
330 		cl_qcpool_grow(p_pool, p_pool->grow_size);
331 		/*
332 		 * We may not have gotten everything we wanted but we might have
333 		 * gotten something.
334 		 */
335 		if (cl_is_qlist_empty(&p_pool->free_list))
336 			return (NULL);
337 	}
338 
339 	p_list_item = cl_qlist_remove_head(&p_pool->free_list);
340 	/* OK, at this point we have an object */
341 	CL_ASSERT(p_list_item != cl_qlist_end(&p_pool->free_list));
342 	return ((cl_pool_item_t *) p_list_item);
343 }
344 
345 cl_pool_item_t *cl_qcpool_get_tail(IN cl_qcpool_t * const p_pool)
346 {
347 	cl_list_item_t *p_list_item;
348 
349 	CL_ASSERT(p_pool);
350 	CL_ASSERT(p_pool->state == CL_INITIALIZED);
351 
352 	if (cl_is_qlist_empty(&p_pool->free_list)) {
353 		/*
354 		 * No object is available.
355 		 * Return NULL if the user does not want automatic growth.
356 		 */
357 		if (!p_pool->grow_size)
358 			return (NULL);
359 
360 		/* We ran out of elements.  Get more */
361 		cl_qcpool_grow(p_pool, p_pool->grow_size);
362 		/*
363 		 * We may not have gotten everything we wanted but we might have
364 		 * gotten something.
365 		 */
366 		if (cl_is_qlist_empty(&p_pool->free_list))
367 			return (NULL);
368 	}
369 
370 	p_list_item = cl_qlist_remove_tail(&p_pool->free_list);
371 	/* OK, at this point we have an object */
372 	CL_ASSERT(p_list_item != cl_qlist_end(&p_pool->free_list));
373 	return ((cl_pool_item_t *) p_list_item);
374 }
375 
376 /*
377  * IMPLEMENTATION OF QUICK GROW POOL
378  */
379 
380 /*
381  * Callback to translate quick composite to quick grow pool
382  * initializer callback.
383  */
384 static cl_status_t __cl_qpool_init_cb(IN void **const p_comp_array,
385 				      IN const uint32_t num_components,
386 				      IN void *const context,
387 				      OUT cl_pool_item_t ** const pp_pool_item)
388 {
389 	cl_qpool_t *p_pool = (cl_qpool_t *) context;
390 
391 	CL_ASSERT(p_pool);
392 	CL_ASSERT(p_pool->pfn_init);
393 	CL_ASSERT(num_components == 1);
394 
395 	UNUSED_PARAM(num_components);
396 
397 	return (p_pool->pfn_init(p_comp_array[0], (void *)p_pool->context,
398 				 pp_pool_item));
399 }
400 
401 /*
402  * Callback to translate quick composite to quick grow pool
403  * destructor callback.
404  */
405 static void __cl_qpool_dtor_cb(IN const cl_pool_item_t * const p_pool_item,
406 			       IN void *const context)
407 {
408 	cl_qpool_t *p_pool = (cl_qpool_t *) context;
409 
410 	CL_ASSERT(p_pool);
411 	CL_ASSERT(p_pool->pfn_dtor);
412 
413 	p_pool->pfn_dtor(p_pool_item, (void *)p_pool->context);
414 }
415 
416 void cl_qpool_construct(IN cl_qpool_t * const p_pool)
417 {
418 	memset(p_pool, 0, sizeof(cl_qpool_t));
419 
420 	cl_qcpool_construct(&p_pool->qcpool);
421 }
422 
423 cl_status_t cl_qpool_init(IN cl_qpool_t * const p_pool,
424 			  IN const size_t min_size, IN const size_t max_size,
425 			  IN const size_t grow_size,
426 			  IN const size_t object_size,
427 			  IN cl_pfn_qpool_init_t pfn_initializer OPTIONAL,
428 			  IN cl_pfn_qpool_dtor_t pfn_destructor OPTIONAL,
429 			  IN const void *const context)
430 {
431 	cl_status_t status;
432 
433 	CL_ASSERT(p_pool);
434 
435 	p_pool->pfn_init = pfn_initializer;	/* may be NULL */
436 	p_pool->pfn_dtor = pfn_destructor;	/* may be NULL */
437 	p_pool->context = context;
438 
439 	status = cl_qcpool_init(&p_pool->qcpool, min_size, max_size, grow_size,
440 				&object_size, 1,
441 				pfn_initializer ? __cl_qpool_init_cb : NULL,
442 				pfn_destructor ? __cl_qpool_dtor_cb : NULL,
443 				p_pool);
444 
445 	return (status);
446 }
447 
448 /*
449  * IMPLEMENTATION OF COMPOSITE POOL
450  */
451 
452 /*
453  * Callback to translate quick composite to compsite pool
454  * initializer callback.
455  */
456 static cl_status_t __cl_cpool_init_cb(IN void **const p_comp_array,
457 				      IN const uint32_t num_components,
458 				      IN void *const context,
459 				      OUT cl_pool_item_t ** const pp_pool_item)
460 {
461 	cl_cpool_t *p_pool = (cl_cpool_t *) context;
462 	cl_pool_obj_t *p_pool_obj;
463 	cl_status_t status = CL_SUCCESS;
464 
465 	CL_ASSERT(p_pool);
466 
467 	/*
468 	 * Set our pointer to the list item, which is stored at the beginning of
469 	 * the first component.
470 	 */
471 	p_pool_obj = (cl_pool_obj_t *) p_comp_array[0];
472 	/* Set the pool item pointer for the caller. */
473 	*pp_pool_item = &p_pool_obj->pool_item;
474 
475 	/* Calculate the pointer to the user's first component. */
476 	p_comp_array[0] = ((uint8_t *) p_comp_array[0]) + sizeof(cl_pool_obj_t);
477 
478 	/*
479 	 * Set the object pointer in the pool object to point to the first of the
480 	 * user's components.
481 	 */
482 	p_pool_obj->p_object = p_comp_array[0];
483 
484 	/* Invoke the user's constructor callback. */
485 	if (p_pool->pfn_init) {
486 		status = p_pool->pfn_init(p_comp_array, num_components,
487 					  (void *)p_pool->context);
488 	}
489 
490 	return (status);
491 }
492 
493 /*
494  * Callback to translate quick composite to composite pool
495  * destructor callback.
496  */
497 static void __cl_cpool_dtor_cb(IN const cl_pool_item_t * const p_pool_item,
498 			       IN void *const context)
499 {
500 	cl_cpool_t *p_pool = (cl_cpool_t *) context;
501 
502 	CL_ASSERT(p_pool);
503 	CL_ASSERT(p_pool->pfn_dtor);
504 	CL_ASSERT(((cl_pool_obj_t *) p_pool_item)->p_object);
505 
506 	/* Invoke the user's destructor callback. */
507 	p_pool->pfn_dtor((void *)((cl_pool_obj_t *) p_pool_item)->p_object,
508 			 (void *)p_pool->context);
509 }
510 
511 void cl_cpool_construct(IN cl_cpool_t * const p_pool)
512 {
513 	CL_ASSERT(p_pool);
514 
515 	memset(p_pool, 0, sizeof(cl_cpool_t));
516 
517 	cl_qcpool_construct(&p_pool->qcpool);
518 }
519 
520 cl_status_t cl_cpool_init(IN cl_cpool_t * const p_pool,
521 			  IN const size_t min_size, IN const size_t max_size,
522 			  IN const size_t grow_size,
523 			  IN size_t * const component_sizes,
524 			  IN const uint32_t num_components,
525 			  IN cl_pfn_cpool_init_t pfn_initializer OPTIONAL,
526 			  IN cl_pfn_cpool_dtor_t pfn_destructor OPTIONAL,
527 			  IN const void *const context)
528 {
529 	cl_status_t status;
530 
531 	CL_ASSERT(p_pool);
532 	CL_ASSERT(num_components);
533 	CL_ASSERT(component_sizes);
534 
535 	/* Add the size of the pool object to the first component. */
536 	component_sizes[0] += sizeof(cl_pool_obj_t);
537 
538 	/* Store callback function pointers. */
539 	p_pool->pfn_init = pfn_initializer;	/* may be NULL */
540 	p_pool->pfn_dtor = pfn_destructor;	/* may be NULL */
541 	p_pool->context = context;
542 
543 	status = cl_qcpool_init(&p_pool->qcpool, min_size, max_size, grow_size,
544 				component_sizes, num_components,
545 				__cl_cpool_init_cb,
546 				pfn_destructor ? __cl_cpool_dtor_cb : NULL,
547 				p_pool);
548 
549 	/* Restore the original value of the first component. */
550 	component_sizes[0] -= sizeof(cl_pool_obj_t);
551 
552 	return (status);
553 }
554 
555 /*
556  * IMPLEMENTATION OF GROW POOL
557  */
558 
559 /*
560  * Callback to translate quick composite to grow pool constructor callback.
561  */
562 static cl_status_t __cl_pool_init_cb(IN void **const pp_obj,
563 				     IN const uint32_t count,
564 				     IN void *const context,
565 				     OUT cl_pool_item_t ** const pp_pool_item)
566 {
567 	cl_pool_t *p_pool = (cl_pool_t *) context;
568 	cl_pool_obj_t *p_pool_obj;
569 	cl_status_t status = CL_SUCCESS;
570 
571 	CL_ASSERT(p_pool);
572 	CL_ASSERT(pp_obj);
573 	CL_ASSERT(count == 1);
574 
575 	UNUSED_PARAM(count);
576 
577 	/*
578 	 * Set our pointer to the list item, which is stored at the beginning of
579 	 * the first component.
580 	 */
581 	p_pool_obj = (cl_pool_obj_t *) * pp_obj;
582 	*pp_pool_item = &p_pool_obj->pool_item;
583 
584 	/* Calculate the pointer to the user's first component. */
585 	*pp_obj = ((uint8_t *) * pp_obj) + sizeof(cl_pool_obj_t);
586 
587 	/*
588 	 * Set the object pointer in the pool item to point to the first of the
589 	 * user's components.
590 	 */
591 	p_pool_obj->p_object = *pp_obj;
592 
593 	/* Invoke the user's constructor callback. */
594 	if (p_pool->pfn_init)
595 		status = p_pool->pfn_init(*pp_obj, (void *)p_pool->context);
596 
597 	return (status);
598 }
599 
600 /*
601  * Callback to translate quick composite to grow pool destructor callback.
602  */
603 static void __cl_pool_dtor_cb(IN const cl_pool_item_t * const p_pool_item,
604 			      IN void *const context)
605 {
606 	cl_pool_t *p_pool = (cl_pool_t *) context;
607 
608 	CL_ASSERT(p_pool);
609 	CL_ASSERT(p_pool->pfn_dtor);
610 	CL_ASSERT(((cl_pool_obj_t *) p_pool_item)->p_object);
611 
612 	/* Invoke the user's destructor callback. */
613 	p_pool->pfn_dtor((void *)((cl_pool_obj_t *) p_pool_item)->p_object,
614 			 (void *)p_pool->context);
615 }
616 
617 void cl_pool_construct(IN cl_pool_t * const p_pool)
618 {
619 	CL_ASSERT(p_pool);
620 
621 	memset(p_pool, 0, sizeof(cl_pool_t));
622 
623 	cl_qcpool_construct(&p_pool->qcpool);
624 }
625 
626 cl_status_t cl_pool_init(IN cl_pool_t * const p_pool, IN const size_t min_size,
627 			 IN const size_t max_size, IN const size_t grow_size,
628 			 IN const size_t object_size,
629 			 IN cl_pfn_pool_init_t pfn_initializer OPTIONAL,
630 			 IN cl_pfn_pool_dtor_t pfn_destructor OPTIONAL,
631 			 IN const void *const context)
632 {
633 	cl_status_t status;
634 	size_t total_size;
635 
636 	CL_ASSERT(p_pool);
637 
638 	/* Add the size of the list item to the first component. */
639 	total_size = object_size + sizeof(cl_pool_obj_t);
640 
641 	/* Store callback function pointers. */
642 	p_pool->pfn_init = pfn_initializer;	/* may be NULL */
643 	p_pool->pfn_dtor = pfn_destructor;	/* may be NULL */
644 	p_pool->context = context;
645 
646 	/*
647 	 * We need an initializer in all cases for quick composite pool, since
648 	 * the user pointer must be manipulated to hide the prefixed cl_pool_obj_t.
649 	 */
650 	status = cl_qcpool_init(&p_pool->qcpool, min_size, max_size, grow_size,
651 				&total_size, 1, __cl_pool_init_cb,
652 				pfn_destructor ? __cl_pool_dtor_cb : NULL,
653 				p_pool);
654 
655 	return (status);
656 }
657