From 95b9dc631b74fd0c6b96ecaae382c7f4b9845fb3 Mon Sep 17 00:00:00 2001 From: Quanah Gibson-Mount <quanah@openldap.org> Date: Wed, 18 Nov 2009 02:22:22 +0000 Subject: [PATCH] ITS#6380 --- CHANGES | 1 + servers/slapd/sl_malloc.c | 95 +++++++++++++++++++++++++++------------ servers/slapd/syncrepl.c | 7 +-- 3 files changed, 71 insertions(+), 32 deletions(-) diff --git a/CHANGES b/CHANGES index 29c9a6259f..544a0189e9 100644 --- a/CHANGES +++ b/CHANGES @@ -17,6 +17,7 @@ OpenLDAP 2.4.20 Engineering Fixed slapd inclusion of ac/unistd.h (ITS#6342) Fixed slapd invalid dn log message (ITS#6309) Fixed slapd lockup on shutdown (ITS#6372) + Fixed slapd sl_free to better reclaim memory (ITS#6380) Fixed slapd termination for one level DNs (ITS#6338) Fixed slapd tls_accept to retry in certain cases (ITS#6304) Fixed slapd unused parameter (ITS#6356) diff --git a/servers/slapd/sl_malloc.c b/servers/slapd/sl_malloc.c index 998d50bd8a..b4e0ac6146 100644 --- a/servers/slapd/sl_malloc.c +++ b/servers/slapd/sl_malloc.c @@ -90,6 +90,14 @@ slap_sl_mem_init() static struct slab_heap *slheap; #endif +/* This allocator always returns memory aligned on a 2-int boundary. + * + * The stack-based allocator stores the size as a ber_len_t at both + * the head and tail of the allocated block. When freeing a block, the + * tail length is ORed with 1 to mark it as free. Freed space can only + * be reclaimed from the tail forward. If the tail block is never freed, + * nothing else will be reclaimed until the slab is reset... + */ void * slap_sl_mem_create( ber_len_t size, @@ -114,7 +122,7 @@ slap_sl_mem_create( sh = sh_tmp; #endif - if ( !new ) + if ( sh && !new ) return sh; /* round up to doubleword boundary */ @@ -138,7 +146,12 @@ slap_sl_mem_create( if ( newptr == NULL ) return NULL; sh->sh_base = newptr; } - sh->sh_last = sh->sh_base; + /* insert dummy len */ + { + ber_len_t *i = sh->sh_base; + *i++ = 0; + sh->sh_last = i; + } sh->sh_end = (char *) sh->sh_base + size; sh->sh_stack = stack; return sh; @@ -258,13 +271,8 @@ slap_sl_malloc( ) { struct slab_heap *sh = ctx; - ber_len_t size_shift; int pad = 2*sizeof(int)-1, pad_shift; - int order = -1, order_start = -1; - struct slab_object *so_new, *so_left, *so_right; ber_len_t *ptr, *newptr; - unsigned long diff; - int i, j; #ifdef SLAP_NO_SL_MALLOC newptr = ber_memalloc_x( size, NULL ); @@ -281,8 +289,8 @@ slap_sl_malloc( exit( EXIT_FAILURE ); } - /* round up to doubleword boundary */ - size += sizeof(ber_len_t) + pad; + /* round up to doubleword boundary, plus space for len at head and tail */ + size += 2*sizeof(ber_len_t) + pad; size &= ~pad; if (sh->sh_stack) { @@ -293,10 +301,18 @@ slap_sl_malloc( return ch_malloc(size); } newptr = sh->sh_last; - *newptr++ = size - sizeof(ber_len_t); sh->sh_last = (char *) sh->sh_last + size; + size -= sizeof(ber_len_t); + *newptr++ = size; + *(ber_len_t *)((char *)sh->sh_last - sizeof(ber_len_t)) = size; return( (void *)newptr ); } else { + struct slab_object *so_new, *so_left, *so_right; + ber_len_t size_shift; + int order = -1, order_start = -1; + unsigned long diff; + int i, j; + size_shift = size - 1; do { order++; @@ -412,21 +428,26 @@ slap_sl_realloc(void *ptr, ber_len_t size, void *ctx) size += pad + sizeof( ber_len_t ); size &= ~pad; + p--; + /* Never shrink blocks */ - if (size <= p[-1]) { - newptr = p; + if (size <= p[0]) { + newptr = ptr; /* If reallocing the last block, we can grow it */ - } else if ((char *)ptr + p[-1] == sh->sh_last && + } else if ((char *)ptr + p[0] == sh->sh_last && (char *)ptr + size < (char *)sh->sh_end ) { - newptr = p; - sh->sh_last = (char *)sh->sh_last + size - p[-1]; - p[-1] = size; - + newptr = ptr; + sh->sh_last = (char *)ptr + size; + p[0] = size; + p[size/sizeof(ber_len_t)] = size; + /* Nowhere to grow, need to alloc and copy */ } else { - newptr = slap_sl_malloc(size, ctx); - AC_MEMCPY(newptr, ptr, p[-1]); + newptr = slap_sl_malloc(size-sizeof(ber_len_t), ctx); + AC_MEMCPY(newptr, ptr, p[0]-sizeof(ber_len_t)); + /* mark old region as free */ + p[p[0]/sizeof(ber_len_t)] |= 1; } return newptr; } else { @@ -447,13 +468,8 @@ void slap_sl_free(void *ptr, void *ctx) { struct slab_heap *sh = ctx; - int size, size_shift, order_size; - int pad = 2*sizeof(int)-1, pad_shift; + ber_len_t size; ber_len_t *p = (ber_len_t *)ptr, *tmpp; - int order_start = -1, order = -1; - struct slab_object *so; - unsigned long diff; - int i, inserted = 0; if (!ptr) return; @@ -465,10 +481,31 @@ slap_sl_free(void *ptr, void *ctx) if (!sh || ptr < sh->sh_base || ptr >= sh->sh_end) { ber_memfree_x(ptr, NULL); - } else if (sh->sh_stack && (char *)ptr + p[-1] == sh->sh_last) { - p--; - sh->sh_last = p; - } else if (!sh->sh_stack) { + } else if (sh->sh_stack) { + tmpp = (ber_len_t *)((char *)ptr + p[-1]); + /* mark it free */ + tmpp[-1] |= 1; + /* reclaim free space off tail */ + while ( tmpp == sh->sh_last ) { + if ( tmpp[-1] & 1 ) { + size = tmpp[-1] ^ 1; + ptr = (char *)tmpp - size; + p = (ber_len_t *)ptr; + p--; + sh->sh_last = p; + tmpp = sh->sh_last; + } else { + break; + } + } + } else { + int size_shift, order_size; + int pad = 2*sizeof(int)-1, pad_shift; + int order_start = -1, order = -1; + struct slab_object *so; + unsigned long diff; + int i, inserted = 0; + size = *(--p); size_shift = size + sizeof(ber_len_t) - 1; do { diff --git a/servers/slapd/syncrepl.c b/servers/slapd/syncrepl.c index e098251824..4933933935 100644 --- a/servers/slapd/syncrepl.c +++ b/servers/slapd/syncrepl.c @@ -579,8 +579,9 @@ do_syncrep1( { ber_len_t ssf; /* ITS#5403, 3864 LDAP_OPT_X_SASL_SSF probably ought to use sasl_ssf_t but currently uses ber_len_t */ - ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &ssf ); - op->o_sasl_ssf = ssf; + if ( ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &ssf ) + == LDAP_SUCCESS ) + op->o_sasl_ssf = ssf; } op->o_ssf = ( op->o_sasl_ssf > op->o_tls_ssf ) ? op->o_sasl_ssf : op->o_tls_ssf; @@ -1322,7 +1323,7 @@ do_syncrepl( if ( SLAP_GLUE_SUBORDINATE( be ) && !overlay_is_inst( be, "syncprov" )) { BackendDB * top_be = select_backend( &be->be_nsuffix[0], 1 ); if ( overlay_is_inst( top_be, "syncprov" )) - si->si_wbe = select_backend( &be->be_nsuffix[0], 1 ); + si->si_wbe = top_be; else si->si_wbe = be; } else { -- GitLab