From 7561998f7ad3307c9bdf50c6c03ec2fa88d83007 Mon Sep 17 00:00:00 2001
From: Quanah Gibson-Mount <quanah@openldap.org>
Date: Fri, 30 Oct 2009 19:19:12 +0000
Subject: [PATCH] ITS#6335

---
 CHANGES                           |  1 +
 servers/slapd/overlays/syncprov.c | 18 +++++++++++++-----
 2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/CHANGES b/CHANGES
index 2f9cbe3ed8..af333bb407 100644
--- a/CHANGES
+++ b/CHANGES
@@ -5,6 +5,7 @@ OpenLDAP 2.4.20 Engineering
 	Fixed slapd debug handling of LDAP_DEBUG_ANY (ITS#6324)
 	Fixed slapd-ldap leak (ITS#6326)
 	Fixed slapo-memberof operational attr updates (ITS#6329)
+	Fixed slapo-syncprov deadlock (ITS#6335)
 	Documentation
 		ldap_get_dn(3) typos (ITS#5366)
 
diff --git a/servers/slapd/overlays/syncprov.c b/servers/slapd/overlays/syncprov.c
index ddb060d888..651973c8d4 100644
--- a/servers/slapd/overlays/syncprov.c
+++ b/servers/slapd/overlays/syncprov.c
@@ -1324,15 +1324,14 @@ syncprov_op_cleanup( Operation *op, SlapReply *rs )
 	/* Remove op from lock table */
 	mt = opc->smt;
 	if ( mt ) {
-		modinst *mi = mt->mt_mods;
-
+		ldap_pvt_thread_mutex_lock( &mt->mt_mutex );
+		mt->mt_mods = mt->mt_mods->mi_next;
 		/* If there are more, promote the next one */
-		if ( mi->mi_next ) {
-			ldap_pvt_thread_mutex_lock( &mt->mt_mutex );
-			mt->mt_mods = mi->mi_next;
+		if ( mt->mt_mods ) {
 			mt->mt_op = mt->mt_mods->mi_op;
 			ldap_pvt_thread_mutex_unlock( &mt->mt_mutex );
 		} else {
+			ldap_pvt_thread_mutex_unlock( &mt->mt_mutex );
 			ldap_pvt_thread_mutex_lock( &si->si_mods_mutex );
 			avl_delete( &si->si_mods, mt, sp_avl_cmp );
 			ldap_pvt_thread_mutex_unlock( &si->si_mods_mutex );
@@ -1946,6 +1945,15 @@ syncprov_op_mod( Operation *op, SlapReply *rs )
 		mt = avl_find( si->si_mods, &mtdummy, sp_avl_cmp );
 		if ( mt ) {
 			ldap_pvt_thread_mutex_lock( &mt->mt_mutex );
+			if ( mt->mt_mods == NULL ) {
+				/* Cannot reuse this mt, as another thread is about
+				 * to release it in syncprov_op_cleanup.
+				 */
+				ldap_pvt_thread_mutex_unlock( &mt->mt_mutex );
+				mt = NULL;
+			}
+		}
+		if ( mt ) {
 			ldap_pvt_thread_mutex_unlock( &si->si_mods_mutex );
 			mt->mt_tail->mi_next = mi;
 			mt->mt_tail = mi;
-- 
GitLab