From: Howard Chu Date: Tue, 7 Oct 2008 00:29:54 +0000 (+0000) Subject: ITS#5728 release entries before send_ldap_ber() X-Git-Tag: ACLCHECK_0~1286 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=599d83c7cd010f0b764d2799d844f5a01d69214e;p=openldap ITS#5728 release entries before send_ldap_ber() --- diff --git a/servers/slapd/back-bdb/back-bdb.h b/servers/slapd/back-bdb/back-bdb.h index 3fa4053adf..19c30cc5e1 100644 --- a/servers/slapd/back-bdb/back-bdb.h +++ b/servers/slapd/back-bdb/back-bdb.h @@ -238,17 +238,21 @@ struct bdb_info { struct bdb_lock_info { struct bdb_lock_info *bli_next; - ID bli_id; DB_LOCK bli_lock; + ID bli_id; + int bli_flag; }; +#define BLI_DONTFREE 1 struct bdb_op_info { OpExtra boi_oe; DB_TXN* boi_txn; - u_int32_t boi_err; - int boi_acl_cache; struct bdb_lock_info *boi_locks; /* used when no txn */ + u_int32_t boi_err; + char boi_acl_cache; + char boi_flag; }; +#define BOI_DONTFREE 1 #define DB_OPEN(db, file, name, type, flags, mode) \ ((db)->open)(db, file, name, type, flags, mode) diff --git a/servers/slapd/back-bdb/id2entry.c b/servers/slapd/back-bdb/id2entry.c index 79c6f88a23..d585bfdcd5 100644 --- a/servers/slapd/back-bdb/id2entry.c +++ b/servers/slapd/back-bdb/id2entry.c @@ -267,13 +267,18 @@ int bdb_entry_release( if ( bli->bli_id == e->e_id ) { bdb_cache_return_entry_rw( bdb, e, rw, &bli->bli_lock ); prev->bli_next = bli->bli_next; - op->o_tmpfree( bli, op->o_tmpmemctx ); + /* Cleanup, or let caller know we unlocked */ + if ( bli->bli_flag & BLI_DONTFREE ) + bli->bli_flag = 0; + else + op->o_tmpfree( bli, op->o_tmpmemctx ); break; } } if ( !boi->boi_locks ) { LDAP_SLIST_REMOVE( &op->o_extra, &boi->boi_oe, OpExtra, oe_next ); - op->o_tmpfree( boi, op->o_tmpmemctx ); + if ( !(boi->boi_flag & BOI_DONTFREE)) + op->o_tmpfree( boi, op->o_tmpmemctx ); } } } else { diff --git a/servers/slapd/back-bdb/search.c b/servers/slapd/back-bdb/search.c index 646493948c..bbff1f4ebe 100644 --- a/servers/slapd/back-bdb/search.c +++ b/servers/slapd/back-bdb/search.c @@ -857,6 +857,13 @@ fetch_entry_retry: op->oq_search.rs_scope == LDAP_SCOPE_ONELEVEL ? LDAP_SCOPE_BASE : LDAP_SCOPE_SUBTREE ); + /* free reader lock */ +#ifdef SLAP_ZONE_ALLOC + slap_zn_runlock(bdb->bi_cache.c_zctx, e); +#endif + bdb_cache_return_entry_r( bdb, e, &lock ); + e = NULL; + send_search_reference( op, rs ); ber_bvarray_free( rs->sr_ref ); @@ -889,14 +896,55 @@ fetch_entry_retry: } if (e) { + struct bdb_op_info bois; + struct bdb_lock_info blis; + + /* Must set lockinfo so that entry_release will work */ + if (!opinfo) { + bois.boi_oe.oe_key = bdb; + bois.boi_txn = NULL; + bois.boi_err = 0; + bois.boi_acl_cache = op->o_do_not_cache; + bois.boi_flag = BOI_DONTFREE; + bois.boi_locks = &blis; + blis.bli_next = NULL; + LDAP_SLIST_INSERT_HEAD( &op->o_extra, &bois.boi_oe, + oe_next ); + } else { + blis.bli_next = opinfo->boi_locks; + opinfo->boi_locks = &blis; + } + blis.bli_id = e->e_id; + blis.bli_lock = lock; + blis.bli_flag = BLI_DONTFREE; + /* safe default */ rs->sr_attrs = op->oq_search.rs_attrs; rs->sr_operational_attrs = NULL; rs->sr_ctrls = NULL; - rs->sr_flags = 0; + rs->sr_flags = REP_ENTRY_MUSTRELEASE; rs->sr_err = LDAP_SUCCESS; rs->sr_err = send_search_entry( op, rs ); + /* send_search_entry will usually free it. + * an overlay might leave its own copy here; + * bli_flag will be 0 if lock was already released. + */ + if ( blis.bli_flag ) { +#ifdef SLAP_ZONE_ALLOC + slap_zn_runlock(bdb->bi_cache.c_zctx, e); +#endif + bdb_cache_return_entry_r(bdb, e, &lock); + if ( opinfo ) { + opinfo->boi_locks = blis.bli_next; + } else { + LDAP_SLIST_REMOVE( &op->o_extra, &bois.boi_oe, + OpExtra, oe_next ); + } + } + rs->sr_entry = NULL; + e = NULL; + switch ( rs->sr_err ) { case LDAP_SUCCESS: /* entry sent ok */ break; @@ -904,12 +952,6 @@ fetch_entry_retry: break; case LDAP_UNAVAILABLE: case LDAP_SIZELIMIT_EXCEEDED: -#ifdef SLAP_ZONE_ALLOC - slap_zn_runlock(bdb->bi_cache.c_zctx, e); -#endif - bdb_cache_return_entry_r(bdb, e, &lock); - e = NULL; - rs->sr_entry = NULL; if ( rs->sr_err == LDAP_SIZELIMIT_EXCEEDED ) { rs->sr_ref = rs->sr_v2ref; send_ldap_result( op, rs );