|
|
26b369 |
From 3b589a2bfc33f407cf2c23dc6896566bb8e2acdf Mon Sep 17 00:00:00 2001
|
|
|
26b369 |
From: Thierry Bordaz <tbordaz@redhat.com>
|
|
|
26b369 |
Date: Tue, 5 May 2020 17:44:01 +0200
|
|
|
26b369 |
Subject: [PATCH] Ticket 51068 - deadlock when updating the schema
|
|
|
26b369 |
|
|
|
26b369 |
Bug Description:
|
|
|
26b369 |
It exists a 3 threads deadlock scenario. It involves state change plugins when it
|
|
|
26b369 |
calls schema_changed_callback. So the trigger is a change of schema (direct or via
|
|
|
26b369 |
replication). The scenario is
|
|
|
26b369 |
MOD(cn=schema) hold StateChange lock wait for vattr lock
|
|
|
26b369 |
SRCH hold vattr lock wait for DB page
|
|
|
26b369 |
MOD hold DB page wait for StateChange lock
|
|
|
26b369 |
|
|
|
26b369 |
Fix Description:
|
|
|
26b369 |
Statechange lock protects the list of registered callbacks.
|
|
|
26b369 |
lock is a mutex where actually registration of callback is only done
|
|
|
26b369 |
at startup. Later the list is only lookup.
|
|
|
26b369 |
Making statechange lock a rwlock suppresses the deadlock scenario
|
|
|
26b369 |
as MODs will only acquire in read StateChange lock.
|
|
|
26b369 |
It should also improve performance as at the moment all MODs are serialized
|
|
|
26b369 |
on that lock
|
|
|
26b369 |
In order to prevent writer starvation a new slapi_new_rwlock_prio
|
|
|
26b369 |
create rwlock with priority to writers.
|
|
|
26b369 |
|
|
|
26b369 |
https://pagure.io/389-ds-base/issue/51068
|
|
|
26b369 |
|
|
|
26b369 |
Reviewed by: Mark Reynolds, William Brown
|
|
|
26b369 |
|
|
|
26b369 |
Platforms tested: 30
|
|
|
26b369 |
|
|
|
26b369 |
Flag Day: no
|
|
|
26b369 |
|
|
|
26b369 |
Doc impact: no
|
|
|
26b369 |
---
|
|
|
26b369 |
.../servers/plugins/statechange/statechange.c | 24 ++++++++++--------
|
|
|
26b369 |
ldap/servers/slapd/slapi-plugin.h | 16 ++++++++++++
|
|
|
26b369 |
ldap/servers/slapd/slapi2nspr.c | 25 +++++++++++++++++++
|
|
|
26b369 |
ldap/servers/slapd/vattr.c | 2 +-
|
|
|
26b369 |
4 files changed, 55 insertions(+), 12 deletions(-)
|
|
|
26b369 |
|
|
|
26b369 |
diff --git a/ldap/servers/plugins/statechange/statechange.c b/ldap/servers/plugins/statechange/statechange.c
|
|
|
26b369 |
index f89b394c6..0a3838b5e 100644
|
|
|
26b369 |
--- a/ldap/servers/plugins/statechange/statechange.c
|
|
|
26b369 |
+++ b/ldap/servers/plugins/statechange/statechange.c
|
|
|
26b369 |
@@ -40,7 +40,7 @@ static SCNotify *head; /* a place to start in the list */
|
|
|
26b369 |
#define SCN_PLUGIN_SUBSYSTEM "statechange-plugin" /* used for logging */
|
|
|
26b369 |
|
|
|
26b369 |
static void *api[5];
|
|
|
26b369 |
-static Slapi_Mutex *buffer_lock = 0;
|
|
|
26b369 |
+static Slapi_RWLock *buffer_lock = 0;
|
|
|
26b369 |
static PRUint64 g_plugin_started = 0;
|
|
|
26b369 |
|
|
|
26b369 |
/*
|
|
|
26b369 |
@@ -140,7 +140,7 @@ statechange_start(Slapi_PBlock *pb __attribute__((unused)))
|
|
|
26b369 |
api[3] = (void *)_statechange_unregister_all;
|
|
|
26b369 |
api[4] = (void *)_statechange_vattr_cache_invalidator_callback;
|
|
|
26b369 |
|
|
|
26b369 |
- if (0 == (buffer_lock = slapi_new_mutex())) /* we never free this mutex */
|
|
|
26b369 |
+ if (0 == (buffer_lock = slapi_new_rwlock()))
|
|
|
26b369 |
{
|
|
|
26b369 |
/* badness */
|
|
|
26b369 |
slapi_log_err(SLAPI_LOG_ERR, SCN_PLUGIN_SUBSYSTEM, "statechange_start - Failed to create lock\n");
|
|
|
26b369 |
@@ -180,7 +180,9 @@ statechange_close(Slapi_PBlock *pb __attribute__((unused)))
|
|
|
26b369 |
slapi_counter_destroy(&op_counter);
|
|
|
26b369 |
|
|
|
26b369 |
slapi_apib_unregister(StateChange_v1_0_GUID);
|
|
|
26b369 |
- slapi_destroy_mutex(buffer_lock);
|
|
|
26b369 |
+ if (buffer_lock) {
|
|
|
26b369 |
+ slapi_destroy_rwlock(buffer_lock);
|
|
|
26b369 |
+ }
|
|
|
26b369 |
buffer_lock = NULL;
|
|
|
26b369 |
|
|
|
26b369 |
slapi_log_err(SLAPI_LOG_TRACE, SCN_PLUGIN_SUBSYSTEM, "<-- statechange_close\n");
|
|
|
26b369 |
@@ -240,7 +242,7 @@ statechange_post_op(Slapi_PBlock *pb, int modtype)
|
|
|
26b369 |
slapi_log_err(SLAPI_LOG_TRACE, SCN_PLUGIN_SUBSYSTEM, "--> statechange_post_op\n");
|
|
|
26b369 |
|
|
|
26b369 |
/* evaluate this operation against the notification entries */
|
|
|
26b369 |
- slapi_lock_mutex(buffer_lock);
|
|
|
26b369 |
+ slapi_rwlock_rdlock(buffer_lock);
|
|
|
26b369 |
if (head) {
|
|
|
26b369 |
slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn;;
|
|
|
26b369 |
if (NULL == sdn) {
|
|
|
26b369 |
@@ -290,7 +292,7 @@ statechange_post_op(Slapi_PBlock *pb, int modtype)
|
|
|
26b369 |
} while (notify && notify != head);
|
|
|
26b369 |
}
|
|
|
26b369 |
bail:
|
|
|
26b369 |
- slapi_unlock_mutex(buffer_lock);
|
|
|
26b369 |
+ slapi_rwlock_unlock(buffer_lock);
|
|
|
26b369 |
slapi_log_err(SLAPI_LOG_TRACE, SCN_PLUGIN_SUBSYSTEM, "<-- statechange_post_op\n");
|
|
|
26b369 |
|
|
|
26b369 |
return SLAPI_PLUGIN_SUCCESS; /* always succeed */
|
|
|
26b369 |
@@ -338,7 +340,7 @@ _statechange_register(char *caller_id, char *dn, char *filter, void *caller_data
|
|
|
26b369 |
}
|
|
|
26b369 |
item->func = func;
|
|
|
26b369 |
|
|
|
26b369 |
- slapi_lock_mutex(buffer_lock);
|
|
|
26b369 |
+ slapi_rwlock_wrlock(buffer_lock);
|
|
|
26b369 |
if (head == NULL) {
|
|
|
26b369 |
head = item;
|
|
|
26b369 |
head->next = head;
|
|
|
26b369 |
@@ -349,7 +351,7 @@ _statechange_register(char *caller_id, char *dn, char *filter, void *caller_data
|
|
|
26b369 |
head->prev = item;
|
|
|
26b369 |
item->prev->next = item;
|
|
|
26b369 |
}
|
|
|
26b369 |
- slapi_unlock_mutex(buffer_lock);
|
|
|
26b369 |
+ slapi_rwlock_unlock(buffer_lock);
|
|
|
26b369 |
slapi_ch_free_string(&writable_filter);
|
|
|
26b369 |
|
|
|
26b369 |
ret = SLAPI_PLUGIN_SUCCESS;
|
|
|
26b369 |
@@ -371,7 +373,7 @@ _statechange_unregister(char *dn, char *filter, notify_callback thefunc)
|
|
|
26b369 |
return ret;
|
|
|
26b369 |
}
|
|
|
26b369 |
|
|
|
26b369 |
- slapi_lock_mutex(buffer_lock);
|
|
|
26b369 |
+ slapi_rwlock_wrlock(buffer_lock);
|
|
|
26b369 |
|
|
|
26b369 |
if ((func = statechange_find_notify(dn, filter, thefunc))) {
|
|
|
26b369 |
func->prev->next = func->next;
|
|
|
26b369 |
@@ -392,7 +394,7 @@ _statechange_unregister(char *dn, char *filter, notify_callback thefunc)
|
|
|
26b369 |
slapi_ch_free((void **)&func);
|
|
|
26b369 |
}
|
|
|
26b369 |
|
|
|
26b369 |
- slapi_unlock_mutex(buffer_lock);
|
|
|
26b369 |
+ slapi_rwlock_unlock(buffer_lock);
|
|
|
26b369 |
slapi_counter_decrement(op_counter);
|
|
|
26b369 |
|
|
|
26b369 |
return ret;
|
|
|
26b369 |
@@ -410,7 +412,7 @@ _statechange_unregister_all(char *caller_id, caller_data_free_callback callback)
|
|
|
26b369 |
return;
|
|
|
26b369 |
}
|
|
|
26b369 |
|
|
|
26b369 |
- slapi_lock_mutex(buffer_lock);
|
|
|
26b369 |
+ slapi_rwlock_wrlock(buffer_lock);
|
|
|
26b369 |
|
|
|
26b369 |
if (notify) {
|
|
|
26b369 |
do {
|
|
|
26b369 |
@@ -441,7 +443,7 @@ _statechange_unregister_all(char *caller_id, caller_data_free_callback callback)
|
|
|
26b369 |
} while (notify != start_notify && notify != NULL);
|
|
|
26b369 |
}
|
|
|
26b369 |
|
|
|
26b369 |
- slapi_unlock_mutex(buffer_lock);
|
|
|
26b369 |
+ slapi_rwlock_unlock(buffer_lock);
|
|
|
26b369 |
slapi_counter_decrement(op_counter);
|
|
|
26b369 |
}
|
|
|
26b369 |
|
|
|
26b369 |
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
|
|
|
26b369 |
index 679bdbb5c..865d83b9b 100644
|
|
|
26b369 |
--- a/ldap/servers/slapd/slapi-plugin.h
|
|
|
26b369 |
+++ b/ldap/servers/slapd/slapi-plugin.h
|
|
|
26b369 |
@@ -6126,6 +6126,22 @@ void slapi_destroy_condvar(Slapi_CondVar *cvar);
|
|
|
26b369 |
int slapi_wait_condvar(Slapi_CondVar *cvar, struct timeval *timeout);
|
|
|
26b369 |
int slapi_notify_condvar(Slapi_CondVar *cvar, int notify_all);
|
|
|
26b369 |
|
|
|
26b369 |
+/**
|
|
|
26b369 |
+ * Creates a new read/write lock
|
|
|
26b369 |
+ * If prio_writer the rwlock gives priority on writers
|
|
|
26b369 |
+ * else it give priority on readers (default)
|
|
|
26b369 |
+ *
|
|
|
26b369 |
+ * \return A pointer to a \c Slapi_RWLock
|
|
|
26b369 |
+ *
|
|
|
26b369 |
+ * \note Free the returned lock by calling slapi_destroy_rwlock() when finished
|
|
|
26b369 |
+ *
|
|
|
26b369 |
+ * \see slapi_destroy_rwlock()
|
|
|
26b369 |
+ * \see slapi_rwlock_rdlock()
|
|
|
26b369 |
+ * \see slapi_rwlock_wrlock()
|
|
|
26b369 |
+ * \see slapi_rwlock_unlock()
|
|
|
26b369 |
+ */
|
|
|
26b369 |
+Slapi_RWLock *slapi_new_rwlock_prio(int32_t prio_writer);
|
|
|
26b369 |
+
|
|
|
26b369 |
/**
|
|
|
26b369 |
* Creates a new read/write lock.
|
|
|
26b369 |
*
|
|
|
26b369 |
diff --git a/ldap/servers/slapd/slapi2nspr.c b/ldap/servers/slapd/slapi2nspr.c
|
|
|
26b369 |
index b3e6d94c2..232d1599e 100644
|
|
|
26b369 |
--- a/ldap/servers/slapd/slapi2nspr.c
|
|
|
26b369 |
+++ b/ldap/servers/slapd/slapi2nspr.c
|
|
|
26b369 |
@@ -181,6 +181,31 @@ slapi_notify_condvar(Slapi_CondVar *cvar, int notify_all)
|
|
|
26b369 |
return (prrc == PR_SUCCESS ? 1 : 0);
|
|
|
26b369 |
}
|
|
|
26b369 |
|
|
|
26b369 |
+Slapi_RWLock *
|
|
|
26b369 |
+slapi_new_rwlock_prio(int32_t prio_writer)
|
|
|
26b369 |
+{
|
|
|
26b369 |
+#ifdef USE_POSIX_RWLOCKS
|
|
|
26b369 |
+ pthread_rwlock_t *rwlock = NULL;
|
|
|
26b369 |
+ pthread_rwlockattr_t attr;
|
|
|
26b369 |
+
|
|
|
26b369 |
+ pthread_rwlockattr_init(&attr);
|
|
|
26b369 |
+ if (prio_writer) {
|
|
|
26b369 |
+ pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
|
|
|
26b369 |
+ } else {
|
|
|
26b369 |
+ pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_READER_NP);
|
|
|
26b369 |
+ }
|
|
|
26b369 |
+
|
|
|
26b369 |
+ rwlock = (pthread_rwlock_t *)slapi_ch_malloc(sizeof(pthread_rwlock_t));
|
|
|
26b369 |
+ if (rwlock) {
|
|
|
26b369 |
+ pthread_rwlock_init(rwlock, &attr);
|
|
|
26b369 |
+ }
|
|
|
26b369 |
+
|
|
|
26b369 |
+ return ((Slapi_RWLock *)rwlock);
|
|
|
26b369 |
+#else
|
|
|
26b369 |
+ return ((Slapi_RWLock *)PR_NewRWLock(PR_RWLOCK_RANK_NONE, "slapi_rwlock"));
|
|
|
26b369 |
+#endif
|
|
|
26b369 |
+}
|
|
|
26b369 |
+
|
|
|
26b369 |
Slapi_RWLock *
|
|
|
26b369 |
slapi_new_rwlock(void)
|
|
|
26b369 |
{
|
|
|
26b369 |
diff --git a/ldap/servers/slapd/vattr.c b/ldap/servers/slapd/vattr.c
|
|
|
26b369 |
index 852a887ce..eef444270 100644
|
|
|
26b369 |
--- a/ldap/servers/slapd/vattr.c
|
|
|
26b369 |
+++ b/ldap/servers/slapd/vattr.c
|
|
|
26b369 |
@@ -1996,7 +1996,7 @@ vattr_map_create(void)
|
|
|
26b369 |
return ENOMEM;
|
|
|
26b369 |
}
|
|
|
26b369 |
|
|
|
26b369 |
- the_map->lock = slapi_new_rwlock();
|
|
|
26b369 |
+ the_map->lock = slapi_new_rwlock_prio(1 /* priority on writers */);
|
|
|
26b369 |
if (NULL == the_map) {
|
|
|
26b369 |
slapd_nasty(sourcefile, 3, 0);
|
|
|
26b369 |
return ENOMEM;
|
|
|
26b369 |
--
|
|
|
26b369 |
2.26.2
|
|
|
26b369 |
|