andykimpe / rpms / 389-ds-base

Forked from rpms/389-ds-base 5 months ago
Clone
dc8c34
From e2ee8bba6ff5e0f733142889e0ccaa08cebbdb75 Mon Sep 17 00:00:00 2001
dc8c34
From: Noriko Hosoi <nhosoi@redhat.com>
dc8c34
Date: Mon, 25 Mar 2013 14:37:18 -0700
dc8c34
Subject: [PATCH 40/42] Ticket #627 - ns-slapd crashes sporadically with
dc8c34
 segmentation fault in libslapd.so
dc8c34
dc8c34
Bug Description: Schema reload task (schema-reload.pl) was not
dc8c34
thread safe.
dc8c34
dc8c34
Fix Description: Attribute Syntax is stored in the hash and
dc8c34
retrieved based upon the attribute syntax.  When Schema reload
dc8c34
task is invoked, the attribute syntax objects were completely
dc8c34
replaced ignoring the lock protection.  This patch protects
dc8c34
the attribute syntax replacement (attr_syntax_delete_all_for_
dc8c34
schemareload) with the write lock.  Also, attribute syntax
dc8c34
object maintains the reference count.  The schema reload
dc8c34
respects the reference count instead of blindly deleting them.
dc8c34
dc8c34
https://fedorahosted.org/389/ticket/627
dc8c34
dc8c34
Reviewed by Rich (Thank you!!)
dc8c34
(cherry picked from commit 81b997480956b2b6fa3a5d0e8d6abf5113a06400)
dc8c34
---
dc8c34
 ldap/servers/slapd/attrsyntax.c | 116 +++++++++++++++++++++++++++++-----------
dc8c34
 ldap/servers/slapd/proto-slap.h |   3 ++
dc8c34
 ldap/servers/slapd/schema.c     |  48 ++++++++++-------
dc8c34
 3 files changed, 117 insertions(+), 50 deletions(-)
dc8c34
dc8c34
diff --git a/ldap/servers/slapd/attrsyntax.c b/ldap/servers/slapd/attrsyntax.c
dc8c34
index ff137a8..2dabf1f 100644
dc8c34
--- a/ldap/servers/slapd/attrsyntax.c
dc8c34
+++ b/ldap/servers/slapd/attrsyntax.c
dc8c34
@@ -96,12 +96,27 @@ attr_syntax_read_lock(void)
dc8c34
 }
dc8c34
 
dc8c34
 void
dc8c34
+attr_syntax_write_lock(void)
dc8c34
+{
dc8c34
+	if (0 != attr_syntax_init()) return;
dc8c34
+
dc8c34
+	AS_LOCK_WRITE(oid2asi_lock);
dc8c34
+	AS_LOCK_WRITE(name2asi_lock);
dc8c34
+}
dc8c34
+
dc8c34
+void
dc8c34
 attr_syntax_unlock_read(void)
dc8c34
 {
dc8c34
-	if(name2asi_lock) AS_UNLOCK_READ(name2asi_lock);
dc8c34
-	if(oid2asi_lock) AS_UNLOCK_READ(oid2asi_lock);
dc8c34
+	AS_UNLOCK_READ(name2asi_lock);
dc8c34
+	AS_UNLOCK_READ(oid2asi_lock);
dc8c34
 }
dc8c34
 
dc8c34
+void
dc8c34
+attr_syntax_unlock_write(void)
dc8c34
+{
dc8c34
+	AS_UNLOCK_WRITE(name2asi_lock);
dc8c34
+	AS_UNLOCK_WRITE(oid2asi_lock);
dc8c34
+}
dc8c34
 
dc8c34
 
dc8c34
 #if 0
dc8c34
@@ -255,13 +270,17 @@ attr_syntax_get_by_oid_locking_optional( const char *oid, PRBool use_lock )
dc8c34
 	struct asyntaxinfo *asi = 0;
dc8c34
 	if (oid2asi)
dc8c34
 	{
dc8c34
-		if ( use_lock ) AS_LOCK_READ(oid2asi_lock);
dc8c34
+		if ( use_lock ) {
dc8c34
+			AS_LOCK_READ(oid2asi_lock);
dc8c34
+		}
dc8c34
 		asi = (struct asyntaxinfo *)PL_HashTableLookup_const(oid2asi, oid);
dc8c34
 		if (asi)
dc8c34
 		{
dc8c34
 			PR_AtomicIncrement( &asi->asi_refcnt );
dc8c34
 		}
dc8c34
-		if ( use_lock ) AS_UNLOCK_READ(oid2asi_lock);
dc8c34
+		if ( use_lock ) {
dc8c34
+			AS_UNLOCK_READ(oid2asi_lock);
dc8c34
+		}
dc8c34
 	}
dc8c34
 
dc8c34
 	return asi;
dc8c34
@@ -279,13 +298,15 @@ attr_syntax_add_by_oid(const char *oid, struct asyntaxinfo *a, int lock)
dc8c34
 {
dc8c34
 	if (0 != attr_syntax_init()) return;
dc8c34
 
dc8c34
-	if (lock)
dc8c34
+	if (lock) {
dc8c34
 		AS_LOCK_WRITE(oid2asi_lock);
dc8c34
+	}
dc8c34
 
dc8c34
 	PL_HashTableAdd(oid2asi, oid, a);
dc8c34
 
dc8c34
-	if (lock)
dc8c34
+	if (lock) {
dc8c34
 		AS_UNLOCK_WRITE(oid2asi_lock);
dc8c34
+	}
dc8c34
 }
dc8c34
 
dc8c34
 /*
dc8c34
@@ -317,12 +338,16 @@ attr_syntax_get_by_name_locking_optional(const char *name, PRBool use_lock)
dc8c34
 	struct asyntaxinfo *asi = 0;
dc8c34
 	if (name2asi)
dc8c34
 	{
dc8c34
-		if ( use_lock ) AS_LOCK_READ(name2asi_lock);
dc8c34
+		if ( use_lock ) {
dc8c34
+			AS_LOCK_READ(name2asi_lock);
dc8c34
+		}
dc8c34
 		asi = (struct asyntaxinfo *)PL_HashTableLookup_const(name2asi, name);
dc8c34
 		if ( NULL != asi ) {
dc8c34
 			PR_AtomicIncrement( &asi->asi_refcnt );
dc8c34
 		}
dc8c34
-		if ( use_lock ) AS_UNLOCK_READ(name2asi_lock);
dc8c34
+		if ( use_lock ) {
dc8c34
+			AS_UNLOCK_READ(name2asi_lock);
dc8c34
+		}
dc8c34
 	}
dc8c34
 	if (!asi) /* given name may be an OID */
dc8c34
 		asi = attr_syntax_get_by_oid_locking_optional(name, use_lock);
dc8c34
@@ -344,30 +369,38 @@ attr_syntax_return( struct asyntaxinfo *asi )
dc8c34
 }
dc8c34
 
dc8c34
 void
dc8c34
-attr_syntax_return_locking_optional( struct asyntaxinfo *asi, PRBool use_lock )
dc8c34
+attr_syntax_return_locking_optional(struct asyntaxinfo *asi, PRBool use_lock)
dc8c34
 {
dc8c34
+	int locked = 0;
dc8c34
+	if(use_lock) {
dc8c34
+		AS_LOCK_READ(name2asi_lock);
dc8c34
+		locked = 1;
dc8c34
+	}
dc8c34
 	if ( NULL != asi ) {
dc8c34
-		if ( 0 == PR_AtomicDecrement( &asi->asi_refcnt ))
dc8c34
-		{
dc8c34
-			PRBool		delete_it;
dc8c34
-
dc8c34
-			if(use_lock) AS_LOCK_READ(name2asi_lock);
dc8c34
+		PRBool		delete_it = PR_FALSE;
dc8c34
+		if ( 0 == PR_AtomicDecrement( &asi->asi_refcnt )) {
dc8c34
 			delete_it = asi->asi_marked_for_delete;
dc8c34
-			if(use_lock) AS_UNLOCK_READ(name2asi_lock);
dc8c34
-
dc8c34
-			if ( delete_it )
dc8c34
-			{
dc8c34
-				AS_LOCK_WRITE(name2asi_lock);		/* get a write lock */
dc8c34
-				if ( asi->asi_marked_for_delete )	/* one final check */
dc8c34
-				{
dc8c34
-					/* ref count is 0 and it's flagged for
dc8c34
-					 * deletion, so it's safe to free now */
dc8c34
-					attr_syntax_free(asi);
dc8c34
+		}
dc8c34
+
dc8c34
+		if (delete_it) {
dc8c34
+			if ( asi->asi_marked_for_delete ) {	/* one final check */
dc8c34
+				if(use_lock) {
dc8c34
+					AS_UNLOCK_READ(name2asi_lock);
dc8c34
+					AS_LOCK_WRITE(name2asi_lock);
dc8c34
+				}
dc8c34
+				/* ref count is 0 and it's flagged for
dc8c34
+				 * deletion, so it's safe to free now */
dc8c34
+				attr_syntax_free(asi);
dc8c34
+				if(use_lock) {
dc8c34
+					AS_UNLOCK_WRITE(name2asi_lock);
dc8c34
+					locked = 0;
dc8c34
 				}
dc8c34
-				AS_UNLOCK_WRITE(name2asi_lock);
dc8c34
 			}
dc8c34
 		}
dc8c34
 	}
dc8c34
+	if(locked) {
dc8c34
+		AS_UNLOCK_READ(name2asi_lock);
dc8c34
+	}
dc8c34
 }
dc8c34
 
dc8c34
 /*
dc8c34
@@ -384,8 +417,9 @@ attr_syntax_add_by_name(struct asyntaxinfo *a, int lock)
dc8c34
 {
dc8c34
 	if (0 != attr_syntax_init()) return;
dc8c34
 
dc8c34
-	if (lock)
dc8c34
+	if (lock) {
dc8c34
 		AS_LOCK_WRITE(name2asi_lock);
dc8c34
+	}
dc8c34
 
dc8c34
 	PL_HashTableAdd(name2asi, a->asi_name, a);
dc8c34
 	if ( a->asi_aliases != NULL ) {
dc8c34
@@ -396,8 +430,9 @@ attr_syntax_add_by_name(struct asyntaxinfo *a, int lock)
dc8c34
 		}
dc8c34
 	}
dc8c34
 
dc8c34
-	if (lock)
dc8c34
+	if (lock) {
dc8c34
 		AS_UNLOCK_WRITE(name2asi_lock);
dc8c34
+	}
dc8c34
 }
dc8c34
 
dc8c34
 
dc8c34
@@ -943,11 +978,11 @@ attr_syntax_enumerate_attrs(AttrEnumFunc aef, void *arg, PRBool writelock )
dc8c34
 	attr_syntax_enumerate_attrs_ext(oid2asi, aef, arg);
dc8c34
 
dc8c34
 	if ( writelock ) {
dc8c34
-		AS_UNLOCK_WRITE(oid2asi_lock);
dc8c34
 		AS_UNLOCK_WRITE(name2asi_lock);
dc8c34
+		AS_UNLOCK_WRITE(oid2asi_lock);
dc8c34
 	} else {
dc8c34
-		AS_UNLOCK_READ(oid2asi_lock);
dc8c34
 		AS_UNLOCK_READ(name2asi_lock);
dc8c34
+		AS_UNLOCK_READ(oid2asi_lock);
dc8c34
 	}
dc8c34
 }
dc8c34
 
dc8c34
@@ -1045,6 +1080,21 @@ attr_syntax_delete_all()
dc8c34
 				(void *)&fi, PR_TRUE );
dc8c34
 }
dc8c34
 
dc8c34
+/*
dc8c34
+ * Delete all attribute definitions without attr_syntax lock.
dc8c34
+ * The caller is responsible for the lock.
dc8c34
+ */
dc8c34
+void
dc8c34
+attr_syntax_delete_all_for_schemareload(unsigned long flag)
dc8c34
+{
dc8c34
+	struct attr_syntax_enum_flaginfo fi;
dc8c34
+
dc8c34
+	memset(&fi, 0, sizeof(fi));
dc8c34
+	fi.asef_flag = flag;
dc8c34
+	attr_syntax_enumerate_attrs_ext(oid2asi, attr_syntax_delete_if_not_flagged,
dc8c34
+	                                (void *)&fi);
dc8c34
+}
dc8c34
+
dc8c34
 static int
dc8c34
 attr_syntax_init(void)
dc8c34
 {
dc8c34
@@ -1165,13 +1215,19 @@ static int
dc8c34
 attr_syntax_internal_asi_add(struct asyntaxinfo *asip, void *arg)
dc8c34
 {
dc8c34
 	struct asyntaxinfo *asip_copy;
dc8c34
+	int rc = 0;
dc8c34
+
dc8c34
 	if (!asip) {
dc8c34
 		return 1;
dc8c34
 	}
dc8c34
 	/* Copy is needed since when reloading the schema,
dc8c34
 	 * existing syntax info is cleaned up. */
dc8c34
 	asip_copy = attr_syntax_dup(asip);
dc8c34
-	return attr_syntax_add(asip_copy);
dc8c34
+	rc = attr_syntax_add(asip_copy);
dc8c34
+	if (LDAP_SUCCESS != rc) {
dc8c34
+		attr_syntax_free(asip_copy);
dc8c34
+	}
dc8c34
+	return rc;
dc8c34
 }
dc8c34
 
dc8c34
 /* Reload internal attribute syntax stashed in the internalasi hashtable. */
dc8c34
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
dc8c34
index bdcef9a..5112471 100644
dc8c34
--- a/ldap/servers/slapd/proto-slap.h
dc8c34
+++ b/ldap/servers/slapd/proto-slap.h
dc8c34
@@ -113,7 +113,9 @@ int attrlist_replace_with_flags(Slapi_Attr **alist, const char *type, struct ber
dc8c34
  * attrsyntax.c
dc8c34
  */
dc8c34
 void attr_syntax_read_lock(void);
dc8c34
+void attr_syntax_write_lock(void);
dc8c34
 void attr_syntax_unlock_read(void);
dc8c34
+void attr_syntax_unlock_write(void);
dc8c34
 int attr_syntax_exists (const char *attr_name);
dc8c34
 void attr_syntax_delete ( struct asyntaxinfo *asip );
dc8c34
 #define SLAPI_SYNTAXLENGTH_NONE		(-1)	/* for syntaxlength parameter */
dc8c34
@@ -139,6 +141,7 @@ struct asyntaxinfo *attr_syntax_get_by_name_locking_optional ( const char *name,
dc8c34
 void attr_syntax_return( struct asyntaxinfo *asi );
dc8c34
 void attr_syntax_return_locking_optional( struct asyntaxinfo *asi, PRBool use_lock );
dc8c34
 void attr_syntax_delete_all(void);
dc8c34
+void attr_syntax_delete_all_for_schemareload(unsigned long flag);
dc8c34
 
dc8c34
 /*
dc8c34
  * value.c
dc8c34
diff --git a/ldap/servers/slapd/schema.c b/ldap/servers/slapd/schema.c
dc8c34
index 12f11c3..1768c7e 100644
dc8c34
--- a/ldap/servers/slapd/schema.c
dc8c34
+++ b/ldap/servers/slapd/schema.c
dc8c34
@@ -1406,7 +1406,7 @@ slapi_schema_list_attribute_names(unsigned long flag)
dc8c34
         aew.flag=flag;
dc8c34
 
dc8c34
         attr_syntax_enumerate_attrs(schema_list_attributes_callback, &aew,
dc8c34
-					PR_FALSE);
dc8c34
+                                    PR_FALSE);
dc8c34
         return aew.attrs;
dc8c34
 }
dc8c34
 
dc8c34
@@ -2409,8 +2409,9 @@ static int
dc8c34
 schema_replace_attributes ( Slapi_PBlock *pb, LDAPMod *mod, char *errorbuf,
dc8c34
 		size_t errorbufsize )
dc8c34
 {
dc8c34
-	int									i, rc = LDAP_SUCCESS;
dc8c34
-	struct asyntaxinfo					*newasip, *oldasip;
dc8c34
+	int                i, rc = LDAP_SUCCESS;
dc8c34
+	struct asyntaxinfo *newasip, *oldasip;
dc8c34
+	PRUint32           schema_flags = 0;
dc8c34
 
dc8c34
 	if ( NULL == mod->mod_bvalues ) {
dc8c34
 		schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
dc8c34
@@ -2418,8 +2419,11 @@ schema_replace_attributes ( Slapi_PBlock *pb, LDAPMod *mod, char *errorbuf,
dc8c34
 		return LDAP_UNWILLING_TO_PERFORM;
dc8c34
 	}
dc8c34
 
dc8c34
-	/* clear all of the "keep" flags */
dc8c34
-	attr_syntax_all_clear_flag( SLAPI_ATTR_FLAG_KEEP );
dc8c34
+	slapi_pblock_get(pb, SLAPI_SCHEMA_FLAGS, &schema_flags);
dc8c34
+	if (!(schema_flags & (DSE_SCHEMA_NO_LOAD|DSE_SCHEMA_NO_CHECK))) {
dc8c34
+	    /* clear all of the "keep" flags unless it's from schema-reload */
dc8c34
+		attr_syntax_all_clear_flag( SLAPI_ATTR_FLAG_KEEP );
dc8c34
+	}
dc8c34
 
dc8c34
 	for ( i = 0; mod->mod_bvalues[i] != NULL; ++i ) {
dc8c34
 		if ( LDAP_SUCCESS != ( rc = read_at_ldif( mod->mod_bvalues[i]->bv_val,
dc8c34
@@ -2477,12 +2481,14 @@ schema_replace_attributes ( Slapi_PBlock *pb, LDAPMod *mod, char *errorbuf,
dc8c34
 	 * XXXmcs: we should consider reporting an error if any read only types
dc8c34
 	 * remain....
dc8c34
 	 */
dc8c34
-	attr_syntax_delete_all_not_flagged( SLAPI_ATTR_FLAG_KEEP
dc8c34
-			| SLAPI_ATTR_FLAG_STD_ATTR );
dc8c34
+	attr_syntax_delete_all_not_flagged( SLAPI_ATTR_FLAG_KEEP | 
dc8c34
+	                                    SLAPI_ATTR_FLAG_STD_ATTR );
dc8c34
 
dc8c34
 clean_up_and_return:
dc8c34
-	/* clear all of the "keep" flags */
dc8c34
-	attr_syntax_all_clear_flag( SLAPI_ATTR_FLAG_KEEP );
dc8c34
+	if (!(schema_flags & (DSE_SCHEMA_NO_LOAD|DSE_SCHEMA_NO_CHECK))) {
dc8c34
+	    /* clear all of the "keep" flags unless it's from schema-reload */
dc8c34
+		attr_syntax_all_clear_flag( SLAPI_ATTR_FLAG_KEEP );
dc8c34
+	}
dc8c34
 
dc8c34
 	return rc;
dc8c34
 }
dc8c34
@@ -3898,14 +3904,12 @@ load_schema_dse(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *ignored,
dc8c34
     int primary_file = 0;    /* this is the primary (writeable) schema file */
dc8c34
     int schema_ds4x_compat = config_get_ds4_compatible_schema();
dc8c34
     PRUint32 flags = *(PRUint32 *)arg;
dc8c34
-    flags |= DSE_SCHEMA_NO_GLOCK; /* don't lock global resources
dc8c34
-                                     during initialization */
dc8c34
 
dc8c34
     *returncode = 0;
dc8c34
 
dc8c34
     /*
dc8c34
      * Note: there is no need to call schema_lock_write() here because this
dc8c34
-        * function is only called during server startup.
dc8c34
+     * function is only called during server startup.
dc8c34
      */
dc8c34
 
dc8c34
     slapi_pblock_get( pb, SLAPI_DSE_IS_PRIMARY_FILE, &primary_file );
dc8c34
@@ -3947,6 +3951,8 @@ load_schema_dse(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *ignored,
dc8c34
     if (*returncode)
dc8c34
         return SLAPI_DSE_CALLBACK_ERROR;
dc8c34
 
dc8c34
+    flags |= DSE_SCHEMA_NO_GLOCK; /* don't lock global resources
dc8c34
+                                     during initialization */
dc8c34
     if (!slapi_entry_attr_find(e, "objectclasses", &attr) && attr)
dc8c34
     {
dc8c34
         /* enumerate the values in attr */
dc8c34
@@ -4017,7 +4023,6 @@ load_schema_dse(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *ignored,
dc8c34
  * DSE_SCHEMA_NO_CHECK     -- schema won't be checked
dc8c34
  * DSE_SCHEMA_NO_BACKEND   -- don't add as backend
dc8c34
  * DSE_SCHEMA_LOCKED       -- already locked; no further lock needed
dc8c34
-
dc8c34
  */
dc8c34
 static int
dc8c34
 init_schema_dse_ext(char *schemadir, Slapi_Backend *be,
dc8c34
@@ -4123,7 +4128,7 @@ init_schema_dse_ext(char *schemadir, Slapi_Backend *be,
dc8c34
 						  "DESC 'Standard schema for LDAP' SYNTAX "
dc8c34
 						  "1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2252' )",
dc8c34
 						  NULL, errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
dc8c34
-						  DSE_SCHEMA_NO_GLOCK|schema_flags, 0, 0, 0);
dc8c34
+						  schema_flags, 0, 0, 0);
dc8c34
 		}
dc8c34
 		if (rc)
dc8c34
 		{
dc8c34
@@ -4196,7 +4201,7 @@ init_schema_dse(const char *configdir)
dc8c34
 	{
dc8c34
 		schemadir = slapi_ch_smprintf("%s/%s", configdir, SCHEMA_SUBDIR_NAME);
dc8c34
 	}
dc8c34
-	rc = init_schema_dse_ext(schemadir, NULL, &pschemadse, 0);
dc8c34
+	rc = init_schema_dse_ext(schemadir, NULL, &pschemadse, DSE_SCHEMA_NO_GLOCK);
dc8c34
 	slapi_ch_free_string(&schemadir);
dc8c34
 	return rc;
dc8c34
 }
dc8c34
@@ -4860,14 +4865,14 @@ slapi_validate_schema_files(char *schemadir)
dc8c34
 {
dc8c34
 	struct dse *my_pschemadse = NULL;
dc8c34
 	int rc = init_schema_dse_ext(schemadir, NULL, &my_pschemadse,
dc8c34
-			DSE_SCHEMA_NO_LOAD | DSE_SCHEMA_NO_BACKEND);
dc8c34
+	                             DSE_SCHEMA_NO_LOAD | DSE_SCHEMA_NO_BACKEND);
dc8c34
 	dse_destroy(my_pschemadse); /* my_pschemadse was created just to 
dc8c34
-								   validate the schema */
dc8c34
+	                               validate the schema */
dc8c34
 	if (rc) {
dc8c34
 		return LDAP_SUCCESS;
dc8c34
 	} else {
dc8c34
 		slapi_log_error( SLAPI_LOG_FATAL, "schema_reload",
dc8c34
-				"schema file validation failed\n" );
dc8c34
+		                 "schema file validation failed\n" );
dc8c34
 		return LDAP_OBJECT_CLASS_VIOLATION;
dc8c34
 	}
dc8c34
 }
dc8c34
@@ -4893,10 +4898,13 @@ slapi_reload_schema_files(char *schemadir)
dc8c34
 	}
dc8c34
 	slapi_be_Wlock(be);	/* be lock must be outer of schemafile lock */
dc8c34
 	reload_schemafile_lock();
dc8c34
-	attr_syntax_delete_all();
dc8c34
+	/* Exclude attr_syntax not to grab from the hash table while cleaning up  */
dc8c34
+	attr_syntax_write_lock();
dc8c34
+	attr_syntax_delete_all_for_schemareload(SLAPI_ATTR_FLAG_KEEP);
dc8c34
 	oc_delete_all_nolock();
dc8c34
+	attr_syntax_unlock_write();
dc8c34
 	rc = init_schema_dse_ext(schemadir, be, &my_pschemadse,
dc8c34
-			   DSE_SCHEMA_NO_CHECK | DSE_SCHEMA_LOCKED);
dc8c34
+	                         DSE_SCHEMA_NO_CHECK | DSE_SCHEMA_LOCKED);
dc8c34
 	if (rc) {
dc8c34
 		dse_destroy(pschemadse);
dc8c34
 		pschemadse = my_pschemadse;
dc8c34
-- 
dc8c34
1.8.1.4
dc8c34