From: Nadezhda Ivanova Date: Thu, 23 May 2024 12:54:04 +0000 (+0300) Subject: ITS#10218 Disabling and re-enabling an asyncmeta database via cn=config leaks memory X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5740d1747d05acff9e812468b9f3c4c51a6738aa;p=thirdparty%2Fopenldap.git ITS#10218 Disabling and re-enabling an asyncmeta database via cn=config leaks memory Make sure asyncmeta frees the pending operations structures, resets all connections, frees connection structures and stops the timeout-loop. --- diff --git a/servers/slapd/back-asyncmeta/back-asyncmeta.h b/servers/slapd/back-asyncmeta/back-asyncmeta.h index 038d2fa90a..dafc040f64 100644 --- a/servers/slapd/back-asyncmeta/back-asyncmeta.h +++ b/servers/slapd/back-asyncmeta/back-asyncmeta.h @@ -427,6 +427,7 @@ typedef struct a_metainfo_t { a_metaconn_t *mi_conns; struct berval mi_suffix; + volatile int mi_disabled; } a_metainfo_t; typedef enum meta_op_type { @@ -780,6 +781,9 @@ asyncmeta_db_has_mscs(a_metainfo_t *mi); void asyncmeta_target_free(a_metatarget_t *mt); +void +asyncmeta_back_clear_miconns(a_metainfo_t *mi); + /* The the maximum time in seconds after a result has been received on a connection, * after which it can be reset if a sender error occurs. Should this be configurable? */ #define META_BACK_RESULT_INTERVAL (2) diff --git a/servers/slapd/back-asyncmeta/init.c b/servers/slapd/back-asyncmeta/init.c index def4494745..ba95f60735 100644 --- a/servers/slapd/back-asyncmeta/init.c +++ b/servers/slapd/back-asyncmeta/init.c @@ -240,13 +240,13 @@ asyncmeta_back_db_open( char msg[SLAP_TEXT_BUFLEN]; int i; + mi->mi_disabled = 0; if ( mi->mi_ntargets == 0 ) { Debug( LDAP_DEBUG_ANY, "asyncmeta_back_db_open: no targets defined\n" ); } - mi->mi_num_conns = 0; for ( i = 0; i < mi->mi_ntargets; i++ ) { a_metatarget_t *mt = mi->mi_targets[ i ]; if ( asyncmeta_target_finish( mi, mt, @@ -255,31 +255,34 @@ asyncmeta_back_db_open( } } - mi->mi_num_conns = (mi->mi_max_target_conns == 0) ? META_BACK_CFG_MAX_TARGET_CONNS : mi->mi_max_target_conns; - assert(mi->mi_num_conns > 0); - mi->mi_conns = ch_calloc( mi->mi_num_conns, sizeof( a_metaconn_t )); - for (i = 0; i < mi->mi_num_conns; i++) { - a_metaconn_t *mc = &mi->mi_conns[i]; - ldap_pvt_thread_mutex_init( &mc->mc_om_mutex); - mc->mc_authz_target = META_BOUND_NONE; + if ( mi->mi_conns == NULL ) { + mi->mi_num_conns = (mi->mi_max_target_conns == 0) ? META_BACK_CFG_MAX_TARGET_CONNS : mi->mi_max_target_conns; + assert(mi->mi_num_conns > 0); + mi->mi_conns = ch_calloc( mi->mi_num_conns, sizeof( a_metaconn_t )); + for (i = 0; i < mi->mi_num_conns; i++) { + a_metaconn_t *mc = &mi->mi_conns[i]; + ldap_pvt_thread_mutex_init( &mc->mc_om_mutex); + mc->mc_authz_target = META_BOUND_NONE; - if ( mi->mi_ntargets > 0 ) { - mc->mc_conns = ch_calloc( mi->mi_ntargets, sizeof( a_metasingleconn_t )); - } else { - mc->mc_conns = NULL; - } + if ( mi->mi_ntargets > 0 ) { + mc->mc_conns = ch_calloc( mi->mi_ntargets, sizeof( a_metasingleconn_t )); + } else { + mc->mc_conns = NULL; + } - mc->mc_info = mi; - LDAP_STAILQ_INIT( &mc->mc_om_list ); - } + mc->mc_info = mi; + LDAP_STAILQ_INIT( &mc->mc_om_list ); + } - ber_dupbv ( &mi->mi_suffix, &be->be_suffix[0] ); - if ( ( slapMode & SLAP_SERVER_MODE ) && mi->mi_ntargets > 0 ) { - ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); - mi->mi_task = ldap_pvt_runqueue_insert( &slapd_rq, 1, - asyncmeta_timeout_loop, mi, "asyncmeta_timeout_loop", mi->mi_suffix.bv_val ); - ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); + ber_dupbv ( &mi->mi_suffix, &be->be_suffix[0] ); + + if ( ( slapMode & SLAP_SERVER_MODE ) && mi->mi_ntargets > 0 ) { + ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); + mi->mi_task = ldap_pvt_runqueue_insert( &slapd_rq, 1, + asyncmeta_timeout_loop, mi, "asyncmeta_timeout_loop", mi->mi_suffix.bv_val ); + ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); + } } return 0; } @@ -301,28 +304,26 @@ asyncmeta_back_conn_free( free( mc ); } -static void -asyncmeta_back_stop_miconns( a_metainfo_t *mi ) -{ - - /*Todo do any other mc cleanup here if necessary*/ -} - -static void +void asyncmeta_back_clear_miconns( a_metainfo_t *mi ) { int i, j; a_metaconn_t *mc; - for (i = 0; i < mi->mi_num_conns; i++) { - mc = &mi->mi_conns[i]; - /* todo clear the message queue */ - for (j = 0; j < mi->mi_ntargets; j ++) { - asyncmeta_clear_one_msc(NULL, mc, j, 1, __FUNCTION__); + if ( mi->mi_conns != NULL ) { + for (i = 0; i < mi->mi_num_conns; i++) { + mc = &mi->mi_conns[i]; + for (j = 0; j < mi->mi_ntargets; j ++) { + asyncmeta_clear_one_msc(NULL, mc, j, 1, __FUNCTION__); + } + + if ( mc->mc_conns ) + free( mc->mc_conns ); + ldap_pvt_thread_mutex_destroy( &mc->mc_om_mutex ); } - free(mc->mc_conns); - ldap_pvt_thread_mutex_destroy( &mc->mc_om_mutex ); + free(mi->mi_conns); } - free(mi->mi_conns); + mi->mi_conns = NULL; + mi->mi_num_conns = 0; } void @@ -392,17 +393,22 @@ asyncmeta_back_db_close( if ( be->be_private ) { mi = ( a_metainfo_t * )be->be_private; - if ( mi->mi_task != NULL ) { - ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); - if ( ldap_pvt_runqueue_isrunning( &slapd_rq, mi->mi_task )) { - ldap_pvt_runqueue_stoptask( &slapd_rq, mi->mi_task); - } - ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); - mi->mi_task = NULL; + mi->mi_disabled = 1; + /* there are no pending ops so we can free up the connections and stop the timeout loop + * else timeout_loop will clear up the ops and connections and not reschedule */ + if ( asyncmeta_db_has_pending_ops( mi ) == 0 ) { + ldap_pvt_thread_mutex_lock( &mi->mi_mc_mutex ); + asyncmeta_back_clear_miconns(mi); + ldap_pvt_thread_mutex_unlock( &mi->mi_mc_mutex ); + if ( mi->mi_task != NULL ) { + ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); + if ( ldap_pvt_runqueue_isrunning( &slapd_rq, mi->mi_task )) { + ldap_pvt_runqueue_stoptask( &slapd_rq, mi->mi_task); + } + ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); + mi->mi_task = NULL; + } } - ldap_pvt_thread_mutex_lock( &mi->mi_mc_mutex ); - asyncmeta_back_stop_miconns( mi ); - ldap_pvt_thread_mutex_unlock( &mi->mi_mc_mutex ); } return 0; } diff --git a/servers/slapd/back-asyncmeta/meta_result.c b/servers/slapd/back-asyncmeta/meta_result.c index 80a02c8c2d..fd5b52f41a 100644 --- a/servers/slapd/back-asyncmeta/meta_result.c +++ b/servers/slapd/back-asyncmeta/meta_result.c @@ -1487,6 +1487,11 @@ asyncmeta_op_handle_result(void *ctx, void *arg) bm_context_t *bc; void *oldctx; +/* exit if the database is disabled, this will let timeout_loop + * do it's job faster */ + if ( mc->mc_info->mi_disabled > 0 ) + return NULL; + ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); rc = ++mc->mc_active; ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); @@ -1661,6 +1666,14 @@ void* asyncmeta_timeout_loop(void *ctx, void *arg) LDAP_STAILQ_INIT( &timeout_list ); Debug( asyncmeta_debug, "asyncmeta_timeout_loop[%p] start at [%ld] \n", rtask, current_time ); + if ( mi->mi_disabled > 0 && asyncmeta_db_has_pending_ops( mi ) == 0 ) { + Debug( asyncmeta_debug, "asyncmeta_timeout_loop[%p] database disabled, clearing connections [%ld] \n", rtask, current_time ); + ldap_pvt_thread_mutex_lock( &mi->mi_mc_mutex ); + asyncmeta_back_clear_miconns( mi ); + mi->mi_task = NULL; + ldap_pvt_thread_mutex_unlock( &mi->mi_mc_mutex ); + return NULL; + } void *oldctx = slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, ctx, 0); for (i=0; imi_num_conns; i++) { a_metaconn_t * mc= &mi->mi_conns[i]; @@ -1671,6 +1684,10 @@ void* asyncmeta_timeout_loop(void *ctx, void *arg) continue; } + if (mi->mi_disabled > 0) { + bc->bc_invalid = 1; + } + if (bc->op->o_abandon ) { Operation *op = bc->op;