sl_malloc.c revision 1.1.1.3 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
26 static struct slab_object * slap_replenish_sopool(struct slab_heap* sh);
27 #ifdef SLAPD_UNUSED
28 static void print_slheap(int level, void *ctx);
29 #endif
30
31 void
32 slap_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
82 BerMemoryFunctions slap_sl_mfuncs =
83 { slap_sl_malloc, slap_sl_calloc, slap_sl_realloc, slap_sl_free };
84
85 void
86 slap_sl_mem_init()
87 {
88 ber_set_option( NULL, LBER_OPT_MEMORY_FNS, &slap_sl_mfuncs );
89 }
90
91 #ifdef NO_THREADS
92 static 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 */
103 void *
104 slap_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
254 void
255 slap_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
269 void *
270 slap_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
381 void *
382 slap_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
393 void *
394 slap_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
469 void
470 slap_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
633 void *
634 slap_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
658 static struct slab_object *
659 slap_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
684 static void
685 print_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