|
|
fcc543 |
From 6a1af7917a86c0b7218d876852cd9c0d5027edeb Mon Sep 17 00:00:00 2001
|
|
|
fcc543 |
From: tbordaz <tbordaz@redhat.com>
|
|
|
fcc543 |
Date: Thu, 29 Apr 2021 09:29:44 +0200
|
|
|
fcc543 |
Subject: [PATCH 2/2] Issue 4667 - incorrect accounting of readers in vattr
|
|
|
fcc543 |
rwlock (#4732)
|
|
|
fcc543 |
|
|
|
fcc543 |
Bug description:
|
|
|
fcc543 |
The fix #2932 (Contention on virtual attribute lookup) reduced
|
|
|
fcc543 |
contention on vattr acquiring vattr lock at the operation
|
|
|
fcc543 |
level rather than at the attribute level (filter and
|
|
|
fcc543 |
returned attr).
|
|
|
fcc543 |
The fix #2932 is invalid. it can lead to deadlock scenario
|
|
|
fcc543 |
(3 threads). A vattr writer (new cos/schema) blocks
|
|
|
fcc543 |
an update thread that hold DB pages and later needs vattr.
|
|
|
fcc543 |
Then if a reader (holding vattr) blocks vattr writer and later
|
|
|
fcc543 |
needs the same DB pages, there is a deadlock.
|
|
|
fcc543 |
The decisions are:
|
|
|
fcc543 |
- revert #2932 (this issue)
|
|
|
fcc543 |
- Skip contention if deployement has no vattr #4678
|
|
|
fcc543 |
- reduce contention with new approaches
|
|
|
fcc543 |
(COW and/or cache vattr struct in each thread)
|
|
|
fcc543 |
no issue opened
|
|
|
fcc543 |
|
|
|
fcc543 |
Fix description:
|
|
|
fcc543 |
The fix reverts #2932
|
|
|
fcc543 |
|
|
|
fcc543 |
relates: https://github.com/389ds/389-ds-base/issues/4667
|
|
|
fcc543 |
|
|
|
fcc543 |
Reviewed by: William Brown, Simon Pichugin
|
|
|
fcc543 |
|
|
|
fcc543 |
Platforms tested: F33
|
|
|
fcc543 |
---
|
|
|
fcc543 |
ldap/servers/slapd/detach.c | 8 --
|
|
|
fcc543 |
ldap/servers/slapd/opshared.c | 6 --
|
|
|
fcc543 |
ldap/servers/slapd/proto-slap.h | 5 --
|
|
|
fcc543 |
ldap/servers/slapd/vattr.c | 147 ++------------------------------
|
|
|
fcc543 |
4 files changed, 8 insertions(+), 158 deletions(-)
|
|
|
fcc543 |
|
|
|
fcc543 |
diff --git a/ldap/servers/slapd/detach.c b/ldap/servers/slapd/detach.c
|
|
|
fcc543 |
index d5c95a04f..8270b83c5 100644
|
|
|
fcc543 |
--- a/ldap/servers/slapd/detach.c
|
|
|
fcc543 |
+++ b/ldap/servers/slapd/detach.c
|
|
|
fcc543 |
@@ -144,10 +144,6 @@ detach(int slapd_exemode, int importexport_encrypt, int s_port, daemon_ports_t *
|
|
|
fcc543 |
}
|
|
|
fcc543 |
break;
|
|
|
fcc543 |
}
|
|
|
fcc543 |
- /* The thread private counter needs to be allocated after the fork
|
|
|
fcc543 |
- * it is not inherited from parent process
|
|
|
fcc543 |
- */
|
|
|
fcc543 |
- vattr_global_lock_create();
|
|
|
fcc543 |
|
|
|
fcc543 |
/* call this right after the fork, but before closing stdin */
|
|
|
fcc543 |
if (slapd_do_all_nss_ssl_init(slapd_exemode, importexport_encrypt, s_port, ports_info)) {
|
|
|
fcc543 |
@@ -178,10 +174,6 @@ detach(int slapd_exemode, int importexport_encrypt, int s_port, daemon_ports_t *
|
|
|
fcc543 |
|
|
|
fcc543 |
g_set_detached(1);
|
|
|
fcc543 |
} else { /* not detaching - call nss/ssl init */
|
|
|
fcc543 |
- /* The thread private counter needs to be allocated after the fork
|
|
|
fcc543 |
- * it is not inherited from parent process
|
|
|
fcc543 |
- */
|
|
|
fcc543 |
- vattr_global_lock_create();
|
|
|
fcc543 |
|
|
|
fcc543 |
if (slapd_do_all_nss_ssl_init(slapd_exemode, importexport_encrypt, s_port, ports_info)) {
|
|
|
fcc543 |
return 1;
|
|
|
fcc543 |
diff --git a/ldap/servers/slapd/opshared.c b/ldap/servers/slapd/opshared.c
|
|
|
fcc543 |
index 05b9a1553..a1630e134 100644
|
|
|
fcc543 |
--- a/ldap/servers/slapd/opshared.c
|
|
|
fcc543 |
+++ b/ldap/servers/slapd/opshared.c
|
|
|
fcc543 |
@@ -266,7 +266,6 @@ op_shared_search(Slapi_PBlock *pb, int send_result)
|
|
|
fcc543 |
int pr_idx = -1;
|
|
|
fcc543 |
Slapi_DN *orig_sdn = NULL;
|
|
|
fcc543 |
int free_sdn = 0;
|
|
|
fcc543 |
- PRBool vattr_lock_acquired = PR_FALSE;
|
|
|
fcc543 |
|
|
|
fcc543 |
be_list[0] = NULL;
|
|
|
fcc543 |
referral_list[0] = NULL;
|
|
|
fcc543 |
@@ -538,8 +537,6 @@ op_shared_search(Slapi_PBlock *pb, int send_result)
|
|
|
fcc543 |
}
|
|
|
fcc543 |
|
|
|
fcc543 |
slapi_pblock_set(pb, SLAPI_BACKEND_COUNT, &index);
|
|
|
fcc543 |
- vattr_rdlock();
|
|
|
fcc543 |
- vattr_lock_acquired = PR_TRUE;
|
|
|
fcc543 |
|
|
|
fcc543 |
if (be) {
|
|
|
fcc543 |
slapi_pblock_set(pb, SLAPI_BACKEND, be);
|
|
|
fcc543 |
@@ -1007,9 +1004,6 @@ free_and_return:
|
|
|
fcc543 |
} else if (be_single) {
|
|
|
fcc543 |
slapi_be_Unlock(be_single);
|
|
|
fcc543 |
}
|
|
|
fcc543 |
- if (vattr_lock_acquired) {
|
|
|
fcc543 |
- vattr_rd_unlock();
|
|
|
fcc543 |
- }
|
|
|
fcc543 |
|
|
|
fcc543 |
free_and_return_nolock:
|
|
|
fcc543 |
slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, &rc);
|
|
|
fcc543 |
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
|
|
|
fcc543 |
index 13b41ffa4..50f1ff75a 100644
|
|
|
fcc543 |
--- a/ldap/servers/slapd/proto-slap.h
|
|
|
fcc543 |
+++ b/ldap/servers/slapd/proto-slap.h
|
|
|
fcc543 |
@@ -1415,11 +1415,6 @@ void subentry_create_filter(Slapi_Filter **filter);
|
|
|
fcc543 |
* vattr.c
|
|
|
fcc543 |
*/
|
|
|
fcc543 |
void vattr_init(void);
|
|
|
fcc543 |
-void vattr_global_lock_create(void);
|
|
|
fcc543 |
-void vattr_rdlock();
|
|
|
fcc543 |
-void vattr_rd_unlock();
|
|
|
fcc543 |
-void vattr_wrlock();
|
|
|
fcc543 |
-void vattr_wr_unlock();
|
|
|
fcc543 |
void vattr_cleanup(void);
|
|
|
fcc543 |
|
|
|
fcc543 |
/*
|
|
|
fcc543 |
diff --git a/ldap/servers/slapd/vattr.c b/ldap/servers/slapd/vattr.c
|
|
|
fcc543 |
index eef444270..b9a4ee965 100644
|
|
|
fcc543 |
--- a/ldap/servers/slapd/vattr.c
|
|
|
fcc543 |
+++ b/ldap/servers/slapd/vattr.c
|
|
|
fcc543 |
@@ -110,7 +110,6 @@ struct _vattr_map
|
|
|
fcc543 |
typedef struct _vattr_map vattr_map;
|
|
|
fcc543 |
|
|
|
fcc543 |
static vattr_map *the_map = NULL;
|
|
|
fcc543 |
-static PRUintn thread_private_global_vattr_lock;
|
|
|
fcc543 |
|
|
|
fcc543 |
/* Housekeeping Functions, called by server startup/shutdown code */
|
|
|
fcc543 |
|
|
|
fcc543 |
@@ -125,136 +124,6 @@ vattr_init()
|
|
|
fcc543 |
vattr_basic_sp_init();
|
|
|
fcc543 |
#endif
|
|
|
fcc543 |
}
|
|
|
fcc543 |
-/*
|
|
|
fcc543 |
- * https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSPR/Reference/PR_NewThreadPrivateIndex
|
|
|
fcc543 |
- * It is called each time:
|
|
|
fcc543 |
- * - PR_SetThreadPrivate is call with a not NULL private value
|
|
|
fcc543 |
- * - on thread exit
|
|
|
fcc543 |
- */
|
|
|
fcc543 |
-static void
|
|
|
fcc543 |
-vattr_global_lock_free(void *ptr)
|
|
|
fcc543 |
-{
|
|
|
fcc543 |
- int *nb_acquired = ptr;
|
|
|
fcc543 |
- if (nb_acquired) {
|
|
|
fcc543 |
- slapi_ch_free((void **)&nb_acquired);
|
|
|
fcc543 |
- }
|
|
|
fcc543 |
-}
|
|
|
fcc543 |
-/* Create a private variable for each individual thread of the current process */
|
|
|
fcc543 |
-void
|
|
|
fcc543 |
-vattr_global_lock_create()
|
|
|
fcc543 |
-{
|
|
|
fcc543 |
- if (PR_NewThreadPrivateIndex(&thread_private_global_vattr_lock, vattr_global_lock_free) != PR_SUCCESS) {
|
|
|
fcc543 |
- slapi_log_err(SLAPI_LOG_ALERT,
|
|
|
fcc543 |
- "vattr_global_lock_create", "Failure to create global lock for virtual attribute !\n");
|
|
|
fcc543 |
- PR_ASSERT(0);
|
|
|
fcc543 |
- }
|
|
|
fcc543 |
-}
|
|
|
fcc543 |
-static int
|
|
|
fcc543 |
-global_vattr_lock_get_acquired_count()
|
|
|
fcc543 |
-{
|
|
|
fcc543 |
- int *nb_acquired;
|
|
|
fcc543 |
- nb_acquired = (int *) PR_GetThreadPrivate(thread_private_global_vattr_lock);
|
|
|
fcc543 |
- if (nb_acquired == NULL) {
|
|
|
fcc543 |
- /* if it was not initialized set it to zero */
|
|
|
fcc543 |
- nb_acquired = (int *) slapi_ch_calloc(1, sizeof(int));
|
|
|
fcc543 |
- PR_SetThreadPrivate(thread_private_global_vattr_lock, (void *) nb_acquired);
|
|
|
fcc543 |
- }
|
|
|
fcc543 |
- return *nb_acquired;
|
|
|
fcc543 |
-}
|
|
|
fcc543 |
-static void
|
|
|
fcc543 |
-global_vattr_lock_set_acquired_count(int nb_acquired)
|
|
|
fcc543 |
-{
|
|
|
fcc543 |
- int *val;
|
|
|
fcc543 |
- val = (int *) PR_GetThreadPrivate(thread_private_global_vattr_lock);
|
|
|
fcc543 |
- if (val == NULL) {
|
|
|
fcc543 |
- /* if it was not initialized set it to zero */
|
|
|
fcc543 |
- val = (int *) slapi_ch_calloc(1, sizeof(int));
|
|
|
fcc543 |
- PR_SetThreadPrivate(thread_private_global_vattr_lock, (void *) val);
|
|
|
fcc543 |
- }
|
|
|
fcc543 |
- *val = nb_acquired;
|
|
|
fcc543 |
-}
|
|
|
fcc543 |
-/* The map lock can be acquired recursively. So only the first rdlock
|
|
|
fcc543 |
- * will acquire the lock.
|
|
|
fcc543 |
- * A optimization acquires it at high level (op_shared_search), so that
|
|
|
fcc543 |
- * later calls during the operation processing will just increase/decrease a counter.
|
|
|
fcc543 |
- */
|
|
|
fcc543 |
-void
|
|
|
fcc543 |
-vattr_rdlock()
|
|
|
fcc543 |
-{
|
|
|
fcc543 |
- int nb_acquire = global_vattr_lock_get_acquired_count();
|
|
|
fcc543 |
-
|
|
|
fcc543 |
- if (nb_acquire == 0) {
|
|
|
fcc543 |
- /* The lock was not held just acquire it */
|
|
|
fcc543 |
- slapi_rwlock_rdlock(the_map->lock);
|
|
|
fcc543 |
- }
|
|
|
fcc543 |
- nb_acquire++;
|
|
|
fcc543 |
- global_vattr_lock_set_acquired_count(nb_acquire);
|
|
|
fcc543 |
-
|
|
|
fcc543 |
-}
|
|
|
fcc543 |
-/* The map lock can be acquired recursively. So only the last unlock
|
|
|
fcc543 |
- * will release the lock.
|
|
|
fcc543 |
- * A optimization acquires it at high level (op_shared_search), so that
|
|
|
fcc543 |
- * later calls during the operation processing will just increase/decrease a counter.
|
|
|
fcc543 |
- */
|
|
|
fcc543 |
-void
|
|
|
fcc543 |
-vattr_rd_unlock()
|
|
|
fcc543 |
-{
|
|
|
fcc543 |
- int nb_acquire = global_vattr_lock_get_acquired_count();
|
|
|
fcc543 |
-
|
|
|
fcc543 |
- if (nb_acquire >= 1) {
|
|
|
fcc543 |
- nb_acquire--;
|
|
|
fcc543 |
- if (nb_acquire == 0) {
|
|
|
fcc543 |
- slapi_rwlock_unlock(the_map->lock);
|
|
|
fcc543 |
- }
|
|
|
fcc543 |
- global_vattr_lock_set_acquired_count(nb_acquire);
|
|
|
fcc543 |
- } else {
|
|
|
fcc543 |
- /* this is likely the consequence of lock acquire in read during an internal search
|
|
|
fcc543 |
- * but the search callback updated the map and release the readlock and acquired
|
|
|
fcc543 |
- * it in write.
|
|
|
fcc543 |
- * So after the update the lock was no longer held but when completing the internal
|
|
|
fcc543 |
- * search we release the global read lock, that now has nothing to do
|
|
|
fcc543 |
- */
|
|
|
fcc543 |
- slapi_log_err(SLAPI_LOG_DEBUG,
|
|
|
fcc543 |
- "vattr_rd_unlock", "vattr lock no longer acquired in read.\n");
|
|
|
fcc543 |
- }
|
|
|
fcc543 |
-}
|
|
|
fcc543 |
-
|
|
|
fcc543 |
-/* The map lock is acquired in write (updating the map)
|
|
|
fcc543 |
- * It exists a possibility that lock is acquired in write while it is already
|
|
|
fcc543 |
- * hold in read by this thread (internal search with updating callback)
|
|
|
fcc543 |
- * In such situation, the we must abandon the read global lock and acquire in write
|
|
|
fcc543 |
- */
|
|
|
fcc543 |
-void
|
|
|
fcc543 |
-vattr_wrlock()
|
|
|
fcc543 |
-{
|
|
|
fcc543 |
- int nb_read_acquire = global_vattr_lock_get_acquired_count();
|
|
|
fcc543 |
-
|
|
|
fcc543 |
- if (nb_read_acquire) {
|
|
|
fcc543 |
- /* The lock was acquired in read but we need it in write
|
|
|
fcc543 |
- * release it and set the global vattr_lock counter to 0
|
|
|
fcc543 |
- */
|
|
|
fcc543 |
- slapi_rwlock_unlock(the_map->lock);
|
|
|
fcc543 |
- global_vattr_lock_set_acquired_count(0);
|
|
|
fcc543 |
- }
|
|
|
fcc543 |
- slapi_rwlock_wrlock(the_map->lock);
|
|
|
fcc543 |
-}
|
|
|
fcc543 |
-/* The map lock is release from a write write (updating the map)
|
|
|
fcc543 |
- */
|
|
|
fcc543 |
-void
|
|
|
fcc543 |
-vattr_wr_unlock()
|
|
|
fcc543 |
-{
|
|
|
fcc543 |
- int nb_read_acquire = global_vattr_lock_get_acquired_count();
|
|
|
fcc543 |
-
|
|
|
fcc543 |
- if (nb_read_acquire) {
|
|
|
fcc543 |
- /* The lock being acquired in write, the private thread counter
|
|
|
fcc543 |
- * (that count the number of time it was acquired in read) should be 0
|
|
|
fcc543 |
- */
|
|
|
fcc543 |
- slapi_log_err(SLAPI_LOG_INFO,
|
|
|
fcc543 |
- "vattr_unlock", "The lock was acquired in write. We should not be here\n");
|
|
|
fcc543 |
- PR_ASSERT(nb_read_acquire == 0);
|
|
|
fcc543 |
- }
|
|
|
fcc543 |
- slapi_rwlock_unlock(the_map->lock);
|
|
|
fcc543 |
-}
|
|
|
fcc543 |
/* Called on server shutdown, free all structures, inform service providers that we're going down etc */
|
|
|
fcc543 |
void
|
|
|
fcc543 |
vattr_cleanup()
|
|
|
fcc543 |
@@ -2069,11 +1938,11 @@ vattr_map_lookup(const char *type_to_find, vattr_map_entry **result)
|
|
|
fcc543 |
}
|
|
|
fcc543 |
|
|
|
fcc543 |
/* Get the reader lock */
|
|
|
fcc543 |
- vattr_rdlock();
|
|
|
fcc543 |
+ slapi_rwlock_rdlock(the_map->lock);
|
|
|
fcc543 |
*result = (vattr_map_entry *)PL_HashTableLookupConst(the_map->hashtable,
|
|
|
fcc543 |
(void *)basetype);
|
|
|
fcc543 |
/* Release ze lock */
|
|
|
fcc543 |
- vattr_rd_unlock();
|
|
|
fcc543 |
+ slapi_rwlock_unlock(the_map->lock);
|
|
|
fcc543 |
|
|
|
fcc543 |
if (tmp) {
|
|
|
fcc543 |
slapi_ch_free_string(&tmp);
|
|
|
fcc543 |
@@ -2092,13 +1961,13 @@ vattr_map_insert(vattr_map_entry *vae)
|
|
|
fcc543 |
{
|
|
|
fcc543 |
PR_ASSERT(the_map);
|
|
|
fcc543 |
/* Get the writer lock */
|
|
|
fcc543 |
- vattr_wrlock();
|
|
|
fcc543 |
+ slapi_rwlock_wrlock(the_map->lock);
|
|
|
fcc543 |
/* Insert the thing */
|
|
|
fcc543 |
/* It's illegal to call this function if the entry is already there */
|
|
|
fcc543 |
PR_ASSERT(NULL == PL_HashTableLookupConst(the_map->hashtable, (void *)vae->type_name));
|
|
|
fcc543 |
PL_HashTableAdd(the_map->hashtable, (void *)vae->type_name, (void *)vae);
|
|
|
fcc543 |
/* Unlock and we're done */
|
|
|
fcc543 |
- vattr_wr_unlock();
|
|
|
fcc543 |
+ slapi_rwlock_unlock(the_map->lock);
|
|
|
fcc543 |
return 0;
|
|
|
fcc543 |
}
|
|
|
fcc543 |
|
|
|
fcc543 |
@@ -2235,13 +2104,13 @@ schema_changed_callback(Slapi_Entry *e __attribute__((unused)),
|
|
|
fcc543 |
void *caller_data __attribute__((unused)))
|
|
|
fcc543 |
{
|
|
|
fcc543 |
/* Get the writer lock */
|
|
|
fcc543 |
- vattr_wrlock();
|
|
|
fcc543 |
+ slapi_rwlock_wrlock(the_map->lock);
|
|
|
fcc543 |
|
|
|
fcc543 |
/* go through the list */
|
|
|
fcc543 |
PL_HashTableEnumerateEntries(the_map->hashtable, vattr_map_entry_rebuild_schema, 0);
|
|
|
fcc543 |
|
|
|
fcc543 |
/* Unlock and we're done */
|
|
|
fcc543 |
- vattr_wr_unlock();
|
|
|
fcc543 |
+ slapi_rwlock_unlock(the_map->lock);
|
|
|
fcc543 |
}
|
|
|
fcc543 |
|
|
|
fcc543 |
|
|
|
fcc543 |
@@ -2261,7 +2130,7 @@ slapi_vattr_schema_check_type(Slapi_Entry *e, char *type)
|
|
|
fcc543 |
objAttrValue *obj;
|
|
|
fcc543 |
|
|
|
fcc543 |
if (0 == vattr_map_lookup(type, &map_entry)) {
|
|
|
fcc543 |
- vattr_rdlock();
|
|
|
fcc543 |
+ slapi_rwlock_rdlock(the_map->lock);
|
|
|
fcc543 |
|
|
|
fcc543 |
obj = map_entry->objectclasses;
|
|
|
fcc543 |
|
|
|
fcc543 |
@@ -2278,7 +2147,7 @@ slapi_vattr_schema_check_type(Slapi_Entry *e, char *type)
|
|
|
fcc543 |
obj = obj->pNext;
|
|
|
fcc543 |
}
|
|
|
fcc543 |
|
|
|
fcc543 |
- vattr_rd_unlock();
|
|
|
fcc543 |
+ slapi_rwlock_unlock(the_map->lock);
|
|
|
fcc543 |
}
|
|
|
fcc543 |
|
|
|
fcc543 |
slapi_valueset_free(vs);
|
|
|
fcc543 |
--
|
|
|
fcc543 |
2.31.1
|
|
|
fcc543 |
|