From 48809ac24ebe4702e4ae39e7702e9bbe5eb46e49 Mon Sep 17 00:00:00 2001
From: Quanah Gibson-Mount <quanah@openldap.org>
Date: Thu, 13 Jan 2011 20:02:45 +0000
Subject: [PATCH] ITS#6787

---
 CHANGES                                       |  1 +
 servers/slapd/back-monitor/cache.c            |  8 ++
 servers/slapd/back-monitor/init.c             |  2 +-
 .../slapd/back-monitor/proto-back-monitor.h   |  6 ++
 servers/slapd/back-monitor/search.c           | 86 ++++++++++++-------
 5 files changed, 69 insertions(+), 34 deletions(-)

diff --git a/CHANGES b/CHANGES
index e9a5924518..ca680d0658 100644
--- a/CHANGES
+++ b/CHANGES
@@ -75,6 +75,7 @@ OpenLDAP 2.4.24 Engineering
 	Fixed slapd-meta matchedDN return code (ITS#6774)
 	Fixed slapd-monitor hasSubordinates generation (ITS#6712)
 	Fixed slapd-monitor abandon processing (ITS#6783)
+	Fixed slapd-monitor entry locks (ITS#6787)
 	Fixed slapd-sql with null objectClass (ITS#6616)
 	Fixed slapd-sql hasSubordinates generation (ITS#6712)
 	Fixed slapo-accesslog with controls (ITS#6652)
diff --git a/servers/slapd/back-monitor/cache.c b/servers/slapd/back-monitor/cache.c
index 23c2825b89..fa4d72ab07 100644
--- a/servers/slapd/back-monitor/cache.c
+++ b/servers/slapd/back-monitor/cache.c
@@ -439,3 +439,11 @@ monitor_cache_destroy(
 	return 0;
 }
 
+int monitor_back_release(
+	Operation *op,
+	Entry *e,
+	int rw )
+{
+	monitor_info_t	*mi = ( monitor_info_t * )op->o_bd->be_private;
+	return monitor_cache_release( mi, e );
+}
diff --git a/servers/slapd/back-monitor/init.c b/servers/slapd/back-monitor/init.c
index 0edbf6bc16..ef8b1eb376 100644
--- a/servers/slapd/back-monitor/init.c
+++ b/servers/slapd/back-monitor/init.c
@@ -2051,7 +2051,7 @@ monitor_back_initialize(
 
 	bi->bi_extended = 0;
 
-	bi->bi_entry_release_rw = 0;
+	bi->bi_entry_release_rw = monitor_back_release;
 	bi->bi_chk_referrals = 0;
 	bi->bi_operational = monitor_back_operational;
 
diff --git a/servers/slapd/back-monitor/proto-back-monitor.h b/servers/slapd/back-monitor/proto-back-monitor.h
index 356466662a..76e85ffbfd 100644
--- a/servers/slapd/back-monitor/proto-back-monitor.h
+++ b/servers/slapd/back-monitor/proto-back-monitor.h
@@ -77,6 +77,12 @@ extern int
 monitor_cache_destroy LDAP_P((
 	monitor_info_t		*mi ));
 
+extern int
+monitor_back_release(
+	Operation *op,
+	Entry *e,
+	int rw );
+
 /*
  * connections
  */
diff --git a/servers/slapd/back-monitor/search.c b/servers/slapd/back-monitor/search.c
index 1e3ed37eef..4df9d2ac87 100644
--- a/servers/slapd/back-monitor/search.c
+++ b/servers/slapd/back-monitor/search.c
@@ -30,29 +30,42 @@
 #include "back-monitor.h"
 #include "proto-back-monitor.h"
 
+static void
+monitor_find_children(
+	Operation *op,
+	SlapReply *rs,
+	Entry *e_parent,
+	Entry **nonv,
+	Entry **vol
+)
+{
+	monitor_info_t	*mi = ( monitor_info_t * )op->o_bd->be_private;
+	monitor_entry_t *mp;
+	
+	mp = ( monitor_entry_t * )e_parent->e_private;
+	*nonv = mp->mp_children;
+
+	if ( MONITOR_HAS_VOLATILE_CH( mp ) ) {
+		monitor_entry_create( op, rs, NULL, e_parent, vol );
+	}
+}
+
 static int
 monitor_send_children(
 	Operation	*op,
 	SlapReply	*rs,
-	Entry		*e_parent,
+	Entry		*e_nonvolatile,
+	Entry		*e_ch,
 	int		sub )
 {
 	monitor_info_t	*mi = ( monitor_info_t * )op->o_bd->be_private;
 	Entry 			*e,
-				*e_tmp,
-				*e_ch = NULL,
-				*e_nonvolatile = NULL;
+				*e_tmp;
 	monitor_entry_t *mp;
 	int			rc,
 				nonvolatile = 0;
 
-	mp = ( monitor_entry_t * )e_parent->e_private;
-	e_nonvolatile = e = mp->mp_children;
-
-	if ( MONITOR_HAS_VOLATILE_CH( mp ) ) {
-		monitor_entry_create( op, rs, NULL, e_parent, &e_ch );
-	}
-	monitor_cache_release( mi, e_parent );
+	e = e_nonvolatile;
 
 	/* no volatile entries? */
 	if ( e_ch == NULL ) {
@@ -84,7 +97,10 @@ monitor_send_children(
 	}
 
 	/* return entries */
-	for ( monitor_cache_lock( e ); e != NULL; ) {
+	for ( ; e != NULL; e = e_tmp ) {
+		Entry *sub_nv = NULL, *sub_ch = NULL;
+
+		monitor_cache_lock( e );
 		monitor_entry_update( op, rs, e );
 
 		if ( e == e_nonvolatile )
@@ -99,23 +115,31 @@ monitor_send_children(
 			goto freeout;
 		}
 
+		if ( sub )
+			monitor_find_children( op, rs, e, &sub_nv, &sub_ch );
+
 		rc = test_filter( op, e, op->oq_search.rs_filter );
 		if ( rc == LDAP_COMPARE_TRUE ) {
 			rs->sr_entry = e;
-			rs->sr_flags = 0;
+			rs->sr_flags = REP_ENTRY_MUSTRELEASE;
 			rc = send_search_entry( op, rs );
-			rs->sr_entry = NULL;
 			if ( rc ) {
-				monitor_cache_release( mi, e );
+				for ( e = sub_ch; e != NULL; e = sub_nv ) {
+					mp = ( monitor_entry_t * )e->e_private;
+					sub_nv = mp->mp_next;
+					monitor_cache_lock( e );
+					monitor_cache_release( mi, e );
+				}
 				goto freeout;
 			}
+		} else {
+			monitor_cache_release( mi, e );
 		}
 
 		if ( sub ) {
-			rc = monitor_send_children( op, rs, e, sub );
+			rc = monitor_send_children( op, rs, sub_nv, sub_ch, sub );
 			if ( rc ) {
 freeout:
-				/* FIXME: may leak generated children */
 				if ( nonvolatile == 0 ) {
 					for ( ; e_tmp != NULL; ) {
 						mp = ( monitor_entry_t * )e_tmp->e_private;
@@ -133,17 +157,6 @@ freeout:
 				return( rc );
 			}
 		}
-
-		if ( e_tmp != NULL ) {
-			monitor_cache_lock( e_tmp );
-		}
-
-		if ( !sub ) {
-			/* otherwise the recursive call already released */
-			monitor_cache_release( mi, e );
-		}
-
-		e = e_tmp;
 	}
 	
 	return LDAP_SUCCESS;
@@ -155,6 +168,7 @@ monitor_back_search( Operation *op, SlapReply *rs )
 	monitor_info_t	*mi = ( monitor_info_t * )op->o_bd->be_private;
 	int		rc = LDAP_SUCCESS;
 	Entry		*e = NULL, *matched = NULL;
+	Entry		*e_nv = NULL, *e_ch = NULL;
 	slap_mask_t	mask;
 
 	Debug( LDAP_DEBUG_TRACE, "=> monitor_back_search\n", 0, 0, 0 );
@@ -209,31 +223,37 @@ monitor_back_search( Operation *op, SlapReply *rs )
 		rc = test_filter( op, e, op->oq_search.rs_filter );
  		if ( rc == LDAP_COMPARE_TRUE ) {
 			rs->sr_entry = e;
-			rs->sr_flags = 0;
+			rs->sr_flags = REP_ENTRY_MUSTRELEASE;
 			send_search_entry( op, rs );
 			rs->sr_entry = NULL;
+		} else {
+			monitor_cache_release( mi, e );
 		}
 		rc = LDAP_SUCCESS;
-		monitor_cache_release( mi, e );
 		break;
 
 	case LDAP_SCOPE_ONELEVEL:
 	case LDAP_SCOPE_SUBORDINATE:
-		rc = monitor_send_children( op, rs, e,
+		monitor_find_children( op, rs, e, &e_nv, &e_ch );
+		monitor_cache_release( mi, e );
+		rc = monitor_send_children( op, rs, e_nv, e_ch,
 			op->oq_search.rs_scope == LDAP_SCOPE_SUBORDINATE );
 		break;
 
 	case LDAP_SCOPE_SUBTREE:
 		monitor_entry_update( op, rs, e );
+		monitor_find_children( op, rs, e, &e_nv, &e_ch );
 		rc = test_filter( op, e, op->oq_search.rs_filter );
 		if ( rc == LDAP_COMPARE_TRUE ) {
 			rs->sr_entry = e;
-			rs->sr_flags = 0;
+			rs->sr_flags = REP_ENTRY_MUSTRELEASE;
 			send_search_entry( op, rs );
 			rs->sr_entry = NULL;
+		} else {
+			monitor_cache_release( mi, e );
 		}
 
-		rc = monitor_send_children( op, rs, e, 1 );
+		rc = monitor_send_children( op, rs, e_nv, e_ch, 1 );
 		break;
 
 	default:
-- 
GitLab