[Date Prev][Date Next] [Chronological] [Thread] [Top]

Re: SLAPD deadlock (ITS#24)



Christian,

I am testing the following patch (against -devel) to resolve ITS#24 (and ITS#26).

Please let me know if it resolves your problems.

Kurt

Index: servers/slapd/acl.c
===================================================================
RCS file: /repo/OpenLDAP/pkg/ldap/servers/slapd/acl.c,v
retrieving revision 1.12
diff -u -r1.12 acl.c
--- acl.c	1998/12/20 23:21:58	1.12
+++ acl.c	1998/12/29 21:23:49
@@ -360,7 +360,9 @@
 			/* see if asker is listed in dnattr */
 			string_expand(buf, sizeof(buf), b->a_group, edn, matches);
 
-			if (be_group(be, buf, odn, b->a_objectclassvalue, b->a_groupattrname) == 0) {
+			if (be_group(be, e, buf, odn,
+				b->a_objectclassvalue, b->a_groupattrname) == 0)
+			{
 				Debug( LDAP_DEBUG_ACL,
 					"<= acl_access_allowed: matched by clause #%d (group) access granted\n",
 					i, 0, 0 );
Index: servers/slapd/backend.c
===================================================================
RCS file: /repo/OpenLDAP/pkg/ldap/servers/slapd/backend.c,v
retrieving revision 1.13
diff -u -r1.13 backend.c
--- backend.c	1998/12/29 20:45:08	1.13
+++ backend.c	1998/12/29 21:23:50
@@ -261,6 +261,7 @@
 int 
 be_group(
 	Backend	*be,
+	Entry	*e,
 	char	*bdn,
 	char	*edn,
 	char	*objectclassValue,
@@ -268,7 +269,8 @@
 )
 {
         if (be->be_group)
-                return(be->be_group(be, bdn, edn, objectclassValue, groupattrName));
+                return(be->be_group(be, e, bdn, edn,
+					objectclassValue, groupattrName));
         else
                 return(1);
 }
Index: servers/slapd/proto-slap.h
===================================================================
RCS file: /repo/OpenLDAP/pkg/ldap/servers/slapd/proto-slap.h,v
retrieving revision 1.12
diff -u -r1.12 proto-slap.h
--- proto-slap.h	1998/12/29 20:45:08	1.12
+++ proto-slap.h	1998/12/29 21:23:51
@@ -256,7 +256,8 @@
 extern struct objclass	*global_oc;
 extern time_t		currenttime;
 
-extern int	be_group LDAP_P((Backend *be, char *bdn, char *edn, char *objectclassValue, char *groupattrName));
+extern int	be_group LDAP_P((Backend *be, Entry *e,
+	char *bdn, char *edn, char *objectclassValue, char *groupattrName));
 extern void	init LDAP_P((void));
 extern void	be_unbind LDAP_P((Connection *conn, Operation *op));
 extern void	config_info LDAP_P((Connection *conn, Operation *op));
@@ -295,7 +296,8 @@
 extern void ldbm_back_config LDAP_P((Backend *be, char *fname, int lineno, int argc, char **argv ));
 extern void ldbm_back_init   LDAP_P((Backend *be));
 extern void ldbm_back_close  LDAP_P((Backend *be));
-extern int  ldbm_back_group  LDAP_P((Backend *be, char *bdn, char *edn, char *objectclassValue, char *groupattrName ));
+extern int  ldbm_back_group  LDAP_P((Backend *be, Entry *target,
+	char *bdn, char *edn, char *objectclassValue, char *groupattrName ));
 #endif
 
 #ifdef SLAPD_PASSWD
Index: servers/slapd/slap.h
===================================================================
RCS file: /repo/OpenLDAP/pkg/ldap/servers/slapd/slap.h,v
retrieving revision 1.15
diff -u -r1.15 slap.h
--- slap.h	1998/12/22 00:34:03	1.15
+++ slap.h	1998/12/29 21:23:53
@@ -249,7 +249,9 @@
 	void	(*be_close)  LDAP_P((Backend *be));
 
 #ifdef SLAPD_ACLGROUPS
-	int	(*be_group)  LDAP_P((Backend *be, char *bdn, char *edn, char *objectclassValue, char *groupattrName ));
+	int	(*be_group)  LDAP_P((Backend *be, Entry *e,
+		char *bdn, char *edn,
+		char *objectclassValue, char *groupattrName ));
 #endif
 };
 
Index: servers/slapd/back-ldbm/add.c
===================================================================
RCS file: /repo/OpenLDAP/pkg/ldap/servers/slapd/back-ldbm/add.c,v
retrieving revision 1.6
diff -u -r1.6 add.c
--- add.c	1998/11/27 19:21:55	1.6
+++ add.c	1998/12/29 21:23:54
@@ -28,22 +28,22 @@
 
 	Debug(LDAP_DEBUG_ARGS, "==> ldbm_back_add: %s\n", dn, 0, 0);
 
+	pthread_mutex_lock(&li->li_add_mutex);
+
 	if ( ( dn2id( be, dn ) ) != NOID ) {
+		pthread_mutex_unlock(&li->li_add_mutex);
 		entry_free( e );
 		free( dn );
 		send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, "", "" );
 		return( -1 );
 	}
 
-	/* XXX race condition here til we cache_add_entry_lock below XXX */
-
 	if ( global_schemacheck && oc_schema_check( e ) != 0 ) {
+		pthread_mutex_unlock(&li->li_add_mutex);
+
 		Debug( LDAP_DEBUG_TRACE, "entry failed schema check\n",
 			0, 0, 0 );
 
-		/* XXX this should be ok, no other thread should have access
-		 * because e hasn't been added to the cache yet
-		 */
 		entry_free( e );
 		free( dn );
 		send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION, "",
@@ -52,28 +52,6 @@
 	}
 
 	/*
-	 * Try to add the entry to the cache, assign it a new dnid
-	 * and mark it locked.  This should only fail if the entry
-	 * already exists.
-	 */
-
-	e->e_id = next_id( be );
-	if ( cache_add_entry_lock( &li->li_cache, e, ENTRY_STATE_CREATING )
-	    != 0 ) {
-		Debug( LDAP_DEBUG_ANY, "cache_add_entry_lock failed\n", 0, 0,
-		    0 );
-		next_id_return( be, e->e_id );
-                
-		/* XXX this should be ok, no other thread should have access
-		 * because e hasn't been added to the cache yet
-		 */
-		entry_free( e );
-		free( dn );
-		send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, "", "" );
-		return( -1 );
-	}
-
-	/*
 	 * Get the parent dn and see if the corresponding entry exists.
 	 * If the parent does not exist, only allow the "root" user to
 	 * add the entry.
@@ -85,6 +63,7 @@
 
 		/* get entry with reader lock */
 		if ( (p = dn2entry_r( be, pdn, &matched )) == NULL ) {
+			pthread_mutex_unlock(&li->li_add_mutex);
 			Debug( LDAP_DEBUG_TRACE, "parent does not exist\n", 0,
 			    0, 0 );
 			send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
@@ -94,33 +73,63 @@
 				free( matched );
 			}
 
-			rc = -1;
-			goto return_results;
+			entry_free( e );
+			free( dn );
+			return -1;
 		}
 
 		if ( ! access_allowed( be, conn, op, p, "children", NULL,
-		    op->o_dn, ACL_WRITE ) ) {
+		    op->o_dn, ACL_WRITE ) )
+		{
+			pthread_mutex_unlock(&li->li_add_mutex);
 			Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
 			    0, 0 );
 			send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
 			    "", "" );
 
-			rc = -1;
-			goto return_results;
+			entry_free( e );
+			free( dn );
+			return -1;
 		}
+
 	} else {
 		if ( ! be_isroot( be, op->o_dn ) ) {
+			pthread_mutex_unlock(&li->li_add_mutex);
 			Debug( LDAP_DEBUG_TRACE, "no parent & not root\n", 0,
 			    0, 0 );
 			send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
 			    "", "" );
 
-			rc = -1;
-			goto return_results;
+			entry_free( e );
+			free( dn );
+			return -1;
 		}
 	}
 
 	/*
+	 * Try to add the entry to the cache, assign it a new dnid
+	 * and mark it locked.  This should only fail if the entry
+	 * already exists.
+	 */
+
+	e->e_id = next_id( be );
+	if ( cache_add_entry_lock( &li->li_cache, e, ENTRY_STATE_CREATING ) != 0 ) {
+		pthread_mutex_unlock(&li->li_add_mutex);
+
+		Debug( LDAP_DEBUG_ANY, "cache_add_entry_lock failed\n", 0, 0,
+		    0 );
+		next_id_return( be, e->e_id );
+                
+		/* XXX this should be ok, no other thread should have access
+		 * because e hasn't been added to the cache yet
+		 */
+		entry_free( e );
+		free( dn );
+		send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, "", "" );
+		return( -1 );
+	}
+
+	/*
 	 * add it to the id2children index for the parent
 	 */
 
@@ -191,6 +200,9 @@
 	if (p != NULL) {
 		cache_return_entry_r( &li->li_cache, p ); 
 	}
+
+	/* it might actually be okay to release this lock sooner */
+	pthread_mutex_unlock(&li->li_add_mutex);
 
 	return( rc );
 }
Index: servers/slapd/back-ldbm/back-ldbm.h
===================================================================
RCS file: /repo/OpenLDAP/pkg/ldap/servers/slapd/back-ldbm/back-ldbm.h,v
retrieving revision 1.6
diff -u -r1.6 back-ldbm.h
--- back-ldbm.h	1998/12/27 23:44:15	1.6
+++ back-ldbm.h	1998/12/29 21:23:54
@@ -106,6 +106,7 @@
 
 struct ldbminfo {
 	ID			li_nextid;
+	pthread_mutex_t		li_add_mutex;
 	pthread_mutex_t		li_nextid_mutex;
 	int			li_mode;
 	char			*li_directory;
Index: servers/slapd/back-ldbm/group.c
===================================================================
RCS file: /repo/OpenLDAP/pkg/ldap/servers/slapd/back-ldbm/group.c,v
retrieving revision 1.9
diff -u -r1.9 group.c
--- group.c	1998/11/23 19:08:25	1.9
+++ group.c	1998/12/29 21:23:55
@@ -20,6 +20,7 @@
 int
 ldbm_back_group(
 	Backend     *be,
+	Entry	*target,
         char        *bdn,
         char        *edn,
         char        *objectclassValue,
@@ -28,6 +29,7 @@
 {
         struct ldbminfo *li = (struct ldbminfo *) be->be_private;    
         Entry        *e;
+		char		*tdn;
         char        *matched;
         Attribute   *objectClass;
         Attribute   *member;
@@ -38,15 +40,30 @@
 	Debug( LDAP_DEBUG_TRACE, "=> ldbm_back_group: objectClass: %s attrName: %s\n", 
                 objectclassValue, groupattrName, 0 ); 
 
-        /* can we find bdn entry with reader lock */
-        if ((e = dn2entry_r(be, bdn, &matched )) == NULL) {
-                Debug( LDAP_DEBUG_TRACE, "=> ldbm_back_group: cannot find bdn: %s matched: %s\n", bdn, (matched ? matched : ""), 0 ); 
-                if (matched != NULL)
-                        free(matched);
-                return( 1 );
+	tdn = dn_normalize_case( ch_strdup( target->e_dn ) );
+	if (strcmp(tdn, bdn) == 0) {
+		/* we already have a LOCKED copy of the entry */
+		e = target;
+        	Debug( LDAP_DEBUG_ARGS,
+			"=> ldbm_back_group: target is bdn: %s\n",
+			bdn, 0, 0 ); 
+	} else {
+		/* can we find bdn entry with reader lock */
+		if ((e = dn2entry_r(be, bdn, &matched )) == NULL) {
+			Debug( LDAP_DEBUG_TRACE,
+				"=> ldbm_back_group: cannot find bdn: %s matched: %s\n",
+					bdn, (matched ? matched : ""), 0 ); 
+			if (matched != NULL)
+				free(matched);
+			free(tdn);
+			return( 1 );
+		}
+        	Debug( LDAP_DEBUG_ARGS,
+			"=> ldbm_back_group: found bdn: %s\n",
+			bdn, 0, 0 ); 
         }
+	free(tdn);
 
-        Debug( LDAP_DEBUG_ARGS, "=> ldbm_back_group: found bdn: %s\n", bdn, 0, 0 ); 
 
         /* check for deleted */
 
@@ -90,8 +107,10 @@
             }
         }
 
-        /* free entry and reader lock */
-        cache_return_entry_r( &li->li_cache, e );                 
+	if( target != e ) {
+		/* free entry and reader lock */
+		cache_return_entry_r( &li->li_cache, e );                 
+	}
         Debug( LDAP_DEBUG_ARGS, "ldbm_back_group: rc: %d\n", rc, 0, 0 ); 
         return(rc);
 }
Index: servers/slapd/back-ldbm/init.c
===================================================================
RCS file: /repo/OpenLDAP/pkg/ldap/servers/slapd/back-ldbm/init.c,v
retrieving revision 1.7
diff -u -r1.7 init.c
--- init.c	1998/12/29 20:45:08	1.7
+++ init.c	1998/12/29 21:23:55
@@ -63,6 +63,7 @@
 	free( argv[ 1 ] );
 
 	/* initialize various mutex locks & condition variables */
+	pthread_mutex_init( &li->li_add_mutex, pthread_mutexattr_default );
 	pthread_mutex_init( &li->li_cache.c_mutex, pthread_mutexattr_default );
 	pthread_mutex_init( &li->li_nextid_mutex, pthread_mutexattr_default );
 	pthread_mutex_init( &li->li_dbcache_mutex, pthread_mutexattr_default );