1/*	$NetBSD: sl_malloc.c,v 1.1.1.3 2010/12/12 15:22:45 adam Exp $	*/
2
3/* sl_malloc.c - malloc routines using a per-thread slab */
4/* OpenLDAP: pkg/ldap/servers/slapd/sl_malloc.c,v 1.39.2.13 2010/04/19 20:58:45 quanah Exp */
5/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 2003-2010 The OpenLDAP Foundation.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
12 * Public License.
13 *
14 * A copy of this license is available in the file LICENSE in the
15 * top-level directory of the distribution or, alternatively, at
16 * <http://www.OpenLDAP.org/license.html>.
17 */
18
19#include "portable.h"
20
21#include <stdio.h>
22#include <ac/string.h>
23
24#include "slap.h"
25
26static struct slab_object * slap_replenish_sopool(struct slab_heap* sh);
27#ifdef SLAPD_UNUSED
28static void print_slheap(int level, void *ctx);
29#endif
30
31void
32slap_sl_mem_destroy(
33	void *key,
34	void *data
35)
36{
37	struct slab_heap *sh = data;
38	int pad = 2*sizeof(int)-1, pad_shift;
39	int order_start = -1, i;
40	struct slab_object *so;
41
42	if (sh->sh_stack) {
43		ber_memfree_x(sh->sh_base, NULL);
44		ber_memfree_x(sh, NULL);
45	} else {
46		pad_shift = pad - 1;
47		do {
48			order_start++;
49		} while (pad_shift >>= 1);
50
51		for (i = 0; i <= sh->sh_maxorder - order_start; i++) {
52			so = LDAP_LIST_FIRST(&sh->sh_free[i]);
53			while (so) {
54				struct slab_object *so_tmp = so;
55				so = LDAP_LIST_NEXT(so, so_link);
56				LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, so_tmp, so_link);
57			}
58			ch_free(sh->sh_map[i]);
59		}
60		ch_free(sh->sh_free);
61		ch_free(sh->sh_map);
62
63		so = LDAP_LIST_FIRST(&sh->sh_sopool);
64		while (so) {
65			struct slab_object *so_tmp = so;
66			so = LDAP_LIST_NEXT(so, so_link);
67			if (!so_tmp->so_blockhead) {
68				LDAP_LIST_REMOVE(so_tmp, so_link);
69			}
70		}
71		so = LDAP_LIST_FIRST(&sh->sh_sopool);
72		while (so) {
73			struct slab_object *so_tmp = so;
74			so = LDAP_LIST_NEXT(so, so_link);
75			ch_free(so_tmp);
76		}
77		ber_memfree_x(sh->sh_base, NULL);
78		ber_memfree_x(sh, NULL);
79	}
80}
81
82BerMemoryFunctions slap_sl_mfuncs =
83	{ slap_sl_malloc, slap_sl_calloc, slap_sl_realloc, slap_sl_free };
84
85void
86slap_sl_mem_init()
87{
88	ber_set_option( NULL, LBER_OPT_MEMORY_FNS, &slap_sl_mfuncs );
89}
90
91#ifdef NO_THREADS
92static struct slab_heap *slheap;
93#endif
94
95/* This allocator always returns memory aligned on a 2-int boundary.
96 *
97 * The stack-based allocator stores the size as a ber_len_t at both
98 * the head and tail of the allocated block. When freeing a block, the
99 * tail length is ORed with 1 to mark it as free. Freed space can only
100 * be reclaimed from the tail forward. If the tail block is never freed,
101 * nothing else will be reclaimed until the slab is reset...
102 */
103void *
104slap_sl_mem_create(
105	ber_len_t size,
106	int stack,
107	void *ctx,
108	int new
109)
110{
111	struct slab_heap *sh;
112	ber_len_t size_shift;
113	int pad = 2*sizeof(int)-1, pad_shift;
114	int order = -1, order_start = -1, order_end = -1;
115	int i;
116	struct slab_object *so;
117
118#ifdef NO_THREADS
119	sh = slheap;
120#else
121	void *sh_tmp = NULL;
122	ldap_pvt_thread_pool_getkey(
123		ctx, (void *)slap_sl_mem_init, &sh_tmp, NULL );
124	sh = sh_tmp;
125#endif
126
127	if ( sh && !new )
128		return sh;
129
130	/* round up to doubleword boundary */
131	size += pad;
132	size &= ~pad;
133
134	if (stack) {
135		if (!sh) {
136			sh = ch_malloc(sizeof(struct slab_heap));
137			sh->sh_base = ch_malloc(size);
138#ifdef NO_THREADS
139			slheap = sh;
140#else
141			ldap_pvt_thread_pool_setkey(ctx, (void *)slap_sl_mem_init,
142				(void *)sh, slap_sl_mem_destroy, NULL, NULL);
143#endif
144		} else if ( size > (char *)sh->sh_end - (char *)sh->sh_base ) {
145			void	*newptr;
146
147			newptr = ch_realloc( sh->sh_base, size );
148			if ( newptr == NULL ) return NULL;
149			sh->sh_base = newptr;
150		}
151		/* insert dummy len */
152		{
153			ber_len_t *i = sh->sh_base;
154			*i++ = 0;
155			sh->sh_last = i;
156		}
157		sh->sh_end = (char *) sh->sh_base + size;
158		sh->sh_stack = stack;
159		return sh;
160	} else {
161		size_shift = size - 1;
162		do {
163			order_end++;
164		} while (size_shift >>= 1);
165
166		pad_shift = pad - 1;
167		do {
168			order_start++;
169		} while (pad_shift >>= 1);
170
171		order = order_end - order_start + 1;
172
173		if (!sh) {
174			sh = (struct slab_heap *) ch_malloc(sizeof(struct slab_heap));
175			sh->sh_base = ch_malloc(size);
176#ifdef NO_THREADS
177			slheap = sh;
178#else
179			ldap_pvt_thread_pool_setkey(ctx, (void *)slap_sl_mem_init,
180				(void *)sh, slap_sl_mem_destroy, NULL, NULL);
181#endif
182		} else {
183			for (i = 0; i <= sh->sh_maxorder - order_start; i++) {
184				so = LDAP_LIST_FIRST(&sh->sh_free[i]);
185				while (so) {
186					struct slab_object *so_tmp = so;
187					so = LDAP_LIST_NEXT(so, so_link);
188					LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, so_tmp, so_link);
189				}
190				ch_free(sh->sh_map[i]);
191			}
192			ch_free(sh->sh_free);
193			ch_free(sh->sh_map);
194
195			so = LDAP_LIST_FIRST(&sh->sh_sopool);
196			while (so) {
197				struct slab_object *so_tmp = so;
198				so = LDAP_LIST_NEXT(so, so_link);
199				if (!so_tmp->so_blockhead) {
200					LDAP_LIST_REMOVE(so_tmp, so_link);
201				}
202			}
203			so = LDAP_LIST_FIRST(&sh->sh_sopool);
204			while (so) {
205				struct slab_object *so_tmp = so;
206				so = LDAP_LIST_NEXT(so, so_link);
207				ch_free(so_tmp);
208			}
209
210			if (size > (char *)sh->sh_end - (char *)sh->sh_base) {
211				void	*newptr;
212
213				newptr = ch_realloc( sh->sh_base, size );
214				if ( newptr == NULL ) return NULL;
215				sh->sh_base = newptr;
216			}
217		}
218		sh->sh_end = (char *)sh->sh_base + size;
219		sh->sh_maxorder = order_end;
220
221		sh->sh_free = (struct sh_freelist *)
222						ch_malloc(order * sizeof(struct sh_freelist));
223		for (i = 0; i < order; i++) {
224			LDAP_LIST_INIT(&sh->sh_free[i]);
225		}
226
227		LDAP_LIST_INIT(&sh->sh_sopool);
228
229		if (LDAP_LIST_EMPTY(&sh->sh_sopool)) {
230			slap_replenish_sopool(sh);
231		}
232		so = LDAP_LIST_FIRST(&sh->sh_sopool);
233		LDAP_LIST_REMOVE(so, so_link);
234		so->so_ptr = sh->sh_base;
235
236		LDAP_LIST_INSERT_HEAD(&sh->sh_free[order-1], so, so_link);
237
238		sh->sh_map = (unsigned char **)
239					ch_malloc(order * sizeof(unsigned char *));
240		for (i = 0; i < order; i++) {
241			int shiftamt = order_start + 1 + i;
242			int nummaps = size >> shiftamt;
243			assert(nummaps);
244			nummaps >>= 3;
245			if (!nummaps) nummaps = 1;
246			sh->sh_map[i] = (unsigned char *) ch_malloc(nummaps);
247			memset(sh->sh_map[i], 0, nummaps);
248		}
249		sh->sh_stack = stack;
250		return sh;
251	}
252}
253
254void
255slap_sl_mem_detach(
256	void *ctx,
257	void *memctx
258)
259{
260#ifdef NO_THREADS
261	slheap = NULL;
262#else
263	/* separate from context */
264	ldap_pvt_thread_pool_setkey( ctx, (void *)slap_sl_mem_init,
265		NULL, 0, NULL, NULL );
266#endif
267}
268
269void *
270slap_sl_malloc(
271    ber_len_t	size,
272    void *ctx
273)
274{
275	struct slab_heap *sh = ctx;
276	int pad = 2*sizeof(int)-1, pad_shift;
277	ber_len_t *ptr, *newptr;
278
279#ifdef SLAP_NO_SL_MALLOC
280	newptr = ber_memalloc_x( size, NULL );
281	if ( newptr ) return newptr;
282	assert( 0 );
283	exit( EXIT_FAILURE );
284#endif
285
286	/* ber_set_option calls us like this */
287	if (!ctx) {
288		newptr = ber_memalloc_x( size, NULL );
289		if ( newptr ) return newptr;
290		assert( 0 );
291		exit( EXIT_FAILURE );
292	}
293
294	/* round up to doubleword boundary, plus space for len at head and tail */
295	size += 2*sizeof(ber_len_t) + pad;
296	size &= ~pad;
297
298	if (sh->sh_stack) {
299		if ((char *)sh->sh_last + size >= (char *)sh->sh_end) {
300			Debug(LDAP_DEBUG_TRACE,
301				"slap_sl_malloc of %lu bytes failed, using ch_malloc\n",
302				(long)size, 0, 0);
303			return ch_malloc(size);
304		}
305		newptr = sh->sh_last;
306		sh->sh_last = (char *) sh->sh_last + size;
307		size -= sizeof(ber_len_t);
308		*newptr++ = size;
309		*(ber_len_t *)((char *)sh->sh_last - sizeof(ber_len_t)) = size;
310		return( (void *)newptr );
311	} else {
312		struct slab_object *so_new, *so_left, *so_right;
313		ber_len_t size_shift;
314		int order = -1, order_start = -1;
315		unsigned long diff;
316		int i, j;
317
318		size_shift = size - 1;
319		do {
320			order++;
321		} while (size_shift >>= 1);
322
323		pad_shift = pad - 1;
324		do {
325			order_start++;
326		} while (pad_shift >>= 1);
327
328		for (i = order; i <= sh->sh_maxorder &&
329				LDAP_LIST_EMPTY(&sh->sh_free[i-order_start]); i++);
330
331		if (i == order) {
332			so_new = LDAP_LIST_FIRST(&sh->sh_free[i-order_start]);
333			LDAP_LIST_REMOVE(so_new, so_link);
334			ptr = so_new->so_ptr;
335			diff = (unsigned long)((char*)ptr -
336					(char*)sh->sh_base) >> (order + 1);
337			sh->sh_map[order-order_start][diff>>3] |= (1 << (diff & 0x7));
338			*ptr++ = size - sizeof(ber_len_t);
339			LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, so_new, so_link);
340			return((void*)ptr);
341		} else if (i <= sh->sh_maxorder) {
342			for (j = i; j > order; j--) {
343				so_left = LDAP_LIST_FIRST(&sh->sh_free[j-order_start]);
344				LDAP_LIST_REMOVE(so_left, so_link);
345				if (LDAP_LIST_EMPTY(&sh->sh_sopool)) {
346					slap_replenish_sopool(sh);
347				}
348				so_right = LDAP_LIST_FIRST(&sh->sh_sopool);
349				LDAP_LIST_REMOVE(so_right, so_link);
350				so_right->so_ptr = (void *)((char *)so_left->so_ptr + (1 << j));
351				if (j == order + 1) {
352					ptr = so_left->so_ptr;
353					diff = (unsigned long)((char*)ptr -
354							(char*)sh->sh_base) >> (order+1);
355					sh->sh_map[order-order_start][diff>>3] |=
356							(1 << (diff & 0x7));
357					*ptr++ = size - sizeof(ber_len_t);
358					LDAP_LIST_INSERT_HEAD(
359							&sh->sh_free[j-1-order_start], so_right, so_link);
360					LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, so_left, so_link);
361					return((void*)ptr);
362				} else {
363					LDAP_LIST_INSERT_HEAD(
364							&sh->sh_free[j-1-order_start], so_right, so_link);
365					LDAP_LIST_INSERT_HEAD(
366							&sh->sh_free[j-1-order_start], so_left, so_link);
367				}
368			}
369		} else {
370			Debug( LDAP_DEBUG_TRACE,
371				"sl_malloc %lu: ch_malloc\n",
372				(long)size, 0, 0);
373			return (void*)ch_malloc(size);
374		}
375	}
376
377	/* FIXME: missing return; guessing... */
378	return NULL;
379}
380
381void *
382slap_sl_calloc( ber_len_t n, ber_len_t size, void *ctx )
383{
384	void *newptr;
385
386	newptr = slap_sl_malloc( n*size, ctx );
387	if ( newptr ) {
388		memset( newptr, 0, n*size );
389	}
390	return newptr;
391}
392
393void *
394slap_sl_realloc(void *ptr, ber_len_t size, void *ctx)
395{
396	struct slab_heap *sh = ctx;
397	int pad = 2*sizeof(int) -1;
398	ber_len_t *p = (ber_len_t *)ptr, *newptr;
399
400	if (ptr == NULL)
401		return slap_sl_malloc(size, ctx);
402
403#ifdef SLAP_NO_SL_MALLOC
404	newptr = ber_memrealloc_x( ptr, size, NULL );
405	if ( newptr ) return newptr;
406	assert( 0 );
407	exit( EXIT_FAILURE );
408#endif
409
410	/* Not our memory? */
411	if (!sh || ptr < sh->sh_base || ptr >= sh->sh_end) {
412		/* duplicate of realloc behavior, oh well */
413		newptr = ber_memrealloc_x(ptr, size, NULL);
414		if (newptr) {
415			return newptr;
416		}
417		Debug(LDAP_DEBUG_ANY, "ch_realloc of %lu bytes failed\n",
418				(long) size, 0, 0);
419		assert(0);
420		exit( EXIT_FAILURE );
421	}
422
423	if (size == 0) {
424		slap_sl_free(ptr, ctx);
425		return NULL;
426	}
427
428	if (sh->sh_stack) {
429		/* round up to doubleword boundary */
430		size += pad + sizeof( ber_len_t );
431		size &= ~pad;
432
433		p--;
434
435		/* Never shrink blocks */
436		if (size <= p[0]) {
437			newptr = ptr;
438
439		/* If reallocing the last block, we can grow it */
440		} else if ((char *)ptr + p[0] == sh->sh_last &&
441			(char *)ptr + size < (char *)sh->sh_end ) {
442			newptr = ptr;
443			sh->sh_last = (char *)ptr + size;
444			p[0] = size;
445			p[size/sizeof(ber_len_t)] = size;
446
447		/* Nowhere to grow, need to alloc and copy */
448		} else {
449			newptr = slap_sl_malloc(size-sizeof(ber_len_t), ctx);
450			AC_MEMCPY(newptr, ptr, p[0]-sizeof(ber_len_t));
451			/* mark old region as free */
452			p[p[0]/sizeof(ber_len_t)] |= 1;
453		}
454		return newptr;
455	} else {
456		void *newptr2;
457
458		newptr2 = slap_sl_malloc(size, ctx);
459		if (size < p[-1]) {
460			AC_MEMCPY(newptr2, ptr, size);
461		} else {
462			AC_MEMCPY(newptr2, ptr, p[-1]);
463		}
464		slap_sl_free(ptr, ctx);
465		return newptr2;
466	}
467}
468
469void
470slap_sl_free(void *ptr, void *ctx)
471{
472	struct slab_heap *sh = ctx;
473	ber_len_t size;
474	ber_len_t *p = (ber_len_t *)ptr, *tmpp;
475
476	if (!ptr)
477		return;
478
479#ifdef SLAP_NO_SL_MALLOC
480	ber_memfree_x( ptr, NULL );
481	return;
482#endif
483
484	if (!sh || ptr < sh->sh_base || ptr >= sh->sh_end) {
485		ber_memfree_x(ptr, NULL);
486	} else if (sh->sh_stack) {
487		tmpp = (ber_len_t *)((char *)ptr + p[-1]);
488		/* mark it free */
489		tmpp[-1] |= 1;
490		/* reclaim free space off tail */
491		while ( tmpp == sh->sh_last ) {
492			if ( tmpp[-1] & 1 ) {
493				size = tmpp[-1] ^ 1;
494				ptr = (char *)tmpp - size;
495				p = (ber_len_t *)ptr;
496				p--;
497				sh->sh_last = p;
498				tmpp = sh->sh_last;
499			} else {
500				break;
501			}
502		}
503	} else {
504		int size_shift, order_size;
505		int pad = 2*sizeof(int)-1, pad_shift;
506		int order_start = -1, order = -1;
507		struct slab_object *so;
508		unsigned long diff;
509		int i, inserted = 0;
510
511		size = *(--p);
512		size_shift = size + sizeof(ber_len_t) - 1;
513		do {
514			order++;
515		} while (size_shift >>= 1);
516
517		pad_shift = pad - 1;
518		do {
519			order_start++;
520		} while (pad_shift >>= 1);
521
522		for (i = order, tmpp = p; i <= sh->sh_maxorder; i++) {
523			order_size = 1 << (i+1);
524			diff = (unsigned long)((char*)tmpp - (char*)sh->sh_base) >> (i+1);
525			sh->sh_map[i-order_start][diff>>3] &= (~(1 << (diff & 0x7)));
526			if (diff == ((diff>>1)<<1)) {
527				if (!(sh->sh_map[i-order_start][(diff+1)>>3] &
528						(1<<((diff+1)&0x7)))) {
529					so = LDAP_LIST_FIRST(&sh->sh_free[i-order_start]);
530					while (so) {
531						if ((char*)so->so_ptr == (char*)tmpp) {
532							LDAP_LIST_REMOVE( so, so_link );
533						} else if ((char*)so->so_ptr ==
534								(char*)tmpp + order_size) {
535							LDAP_LIST_REMOVE(so, so_link);
536							break;
537						}
538						so = LDAP_LIST_NEXT(so, so_link);
539					}
540					if (so) {
541						if (i < sh->sh_maxorder) {
542							inserted = 1;
543							so->so_ptr = tmpp;
544							LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start+1],
545									so, so_link);
546						}
547						continue;
548					} else {
549						if (LDAP_LIST_EMPTY(&sh->sh_sopool)) {
550							slap_replenish_sopool(sh);
551						}
552						so = LDAP_LIST_FIRST(&sh->sh_sopool);
553						LDAP_LIST_REMOVE(so, so_link);
554						so->so_ptr = tmpp;
555						LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start],
556								so, so_link);
557						break;
558
559						Debug(LDAP_DEBUG_TRACE, "slap_sl_free: "
560							"free object not found while bit is clear.\n",
561							0, 0, 0);
562						assert(so != NULL);
563
564					}
565				} else {
566					if (!inserted) {
567						if (LDAP_LIST_EMPTY(&sh->sh_sopool)) {
568							slap_replenish_sopool(sh);
569						}
570						so = LDAP_LIST_FIRST(&sh->sh_sopool);
571						LDAP_LIST_REMOVE(so, so_link);
572						so->so_ptr = tmpp;
573						LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start],
574								so, so_link);
575					}
576					break;
577				}
578			} else {
579				if (!(sh->sh_map[i-order_start][(diff-1)>>3] &
580						(1<<((diff-1)&0x7)))) {
581					so = LDAP_LIST_FIRST(&sh->sh_free[i-order_start]);
582					while (so) {
583						if ((char*)so->so_ptr == (char*)tmpp) {
584							LDAP_LIST_REMOVE(so, so_link);
585						} else if ((char*)tmpp == (char *)so->so_ptr + order_size) {
586							LDAP_LIST_REMOVE(so, so_link);
587							tmpp = so->so_ptr;
588							break;
589						}
590						so = LDAP_LIST_NEXT(so, so_link);
591					}
592					if (so) {
593						if (i < sh->sh_maxorder) {
594							inserted = 1;
595							LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start+1],									so, so_link);
596							continue;
597						}
598					} else {
599						if (LDAP_LIST_EMPTY(&sh->sh_sopool)) {
600							slap_replenish_sopool(sh);
601						}
602						so = LDAP_LIST_FIRST(&sh->sh_sopool);
603						LDAP_LIST_REMOVE(so, so_link);
604						so->so_ptr = tmpp;
605						LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start],
606								so, so_link);
607						break;
608
609						Debug(LDAP_DEBUG_TRACE, "slap_sl_free: "
610							"free object not found while bit is clear.\n",
611							0, 0, 0 );
612						assert(so != NULL);
613
614					}
615				} else {
616					if ( !inserted ) {
617						if (LDAP_LIST_EMPTY(&sh->sh_sopool)) {
618							slap_replenish_sopool(sh);
619						}
620						so = LDAP_LIST_FIRST(&sh->sh_sopool);
621						LDAP_LIST_REMOVE(so, so_link);
622						so->so_ptr = tmpp;
623						LDAP_LIST_INSERT_HEAD(&sh->sh_free[i-order_start],
624								so, so_link);
625					}
626					break;
627				}
628			}
629		}
630	}
631}
632
633void *
634slap_sl_context( void *ptr )
635{
636	struct slab_heap *sh;
637	void *ctx, *sh_tmp;
638
639	if ( slapMode & SLAP_TOOL_MODE ) return NULL;
640
641#ifdef NO_THREADS
642	sh = slheap;
643#else
644	ctx = ldap_pvt_thread_pool_context();
645
646	sh_tmp = NULL;
647	ldap_pvt_thread_pool_getkey(
648		ctx, (void *)slap_sl_mem_init, &sh_tmp, NULL);
649	sh = sh_tmp;
650#endif
651
652	if (sh && ptr >= sh->sh_base && ptr <= sh->sh_end) {
653		return sh;
654	}
655	return NULL;
656}
657
658static struct slab_object *
659slap_replenish_sopool(
660    struct slab_heap* sh
661)
662{
663    struct slab_object *so_block;
664    int i;
665
666    so_block = (struct slab_object *)ch_malloc(
667                    SLAP_SLAB_SOBLOCK * sizeof(struct slab_object));
668
669    if ( so_block == NULL ) {
670        return NULL;
671    }
672
673    so_block[0].so_blockhead = 1;
674    LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, &so_block[0], so_link);
675    for (i = 1; i < SLAP_SLAB_SOBLOCK; i++) {
676        so_block[i].so_blockhead = 0;
677        LDAP_LIST_INSERT_HEAD(&sh->sh_sopool, &so_block[i], so_link );
678    }
679
680    return so_block;
681}
682
683#ifdef SLAPD_UNUSED
684static void
685print_slheap(int level, void *ctx)
686{
687	struct slab_heap *sh = ctx;
688	int order_start = -1;
689	int pad = 2*sizeof(int)-1, pad_shift;
690	struct slab_object *so;
691	int i, j, once = 0;
692
693	if (!ctx) {
694		Debug(level, "NULL memctx\n", 0, 0, 0);
695		return;
696	}
697
698	pad_shift = pad - 1;
699	do {
700		order_start++;
701	} while (pad_shift >>= 1);
702
703	Debug(level, "sh->sh_maxorder=%d\n", sh->sh_maxorder, 0, 0);
704
705	for (i = order_start; i <= sh->sh_maxorder; i++) {
706		once = 0;
707		Debug(level, "order=%d\n", i, 0, 0);
708		for (j = 0; j < (1<<(sh->sh_maxorder-i))/8; j++) {
709			Debug(level, "%02x ", sh->sh_map[i-order_start][j], 0, 0);
710			once = 1;
711		}
712		if (!once) {
713			Debug(level, "%02x ", sh->sh_map[i-order_start][0], 0, 0);
714		}
715		Debug(level, "\n", 0, 0, 0);
716		Debug(level, "free list:\n", 0, 0, 0);
717		so = LDAP_LIST_FIRST(&sh->sh_free[i-order_start]);
718		while (so) {
719			Debug(level, "%lx\n", (unsigned long) so->so_ptr, 0, 0);
720			so = LDAP_LIST_NEXT(so, so_link);
721		}
722	}
723}
724#endif
725