ldap/servers/slapd/back-ldbm/ldbm_modify.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
New commits:
commit f1e30b0fdc06f8e8916c195cc9ff2b3c81fb8ece
Author: Thierry Bordaz <tbordaz(a)redhat.com>
Date: Fri Oct 16 18:18:01 2015 +0200
Ticket 47978: Deadlock between two MODs on the same entry between entry cache and
backend lock
Bug Description:
During a modify, the modified entry gets into the entry cache and is locked.
If after the be_txn_postop/txn_commit and before the modify returns
the modified entry gets out of the entry cache, the entry is not unlocked.
It can lead to hang as soon as an other write operation hit that unlocked entry.
This is a side effect of fix:
#47834 - Tombstone_to_glue: if parents are also converted to glue, the target
entry's DN must be adjusted.
Fix Description:
When the entry is locked, set a flag so that can later be unlocked
independently of its presence in the entry cache
https://fedorahosted.org/389/ticket/47978
Reviewed by: Noriko Hosoi (Thanks Noriko)
Platforms tested: F22 (IPA CI test test_integration/test_vault.py, one failure out
2-4)
Flag Day: no
Doc impact: no
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modify.c
b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
index 2682bcf..83b7b55 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_modify.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
@@ -391,6 +391,7 @@ ldbm_back_modify( Slapi_PBlock *pb )
int mod_count = 0;
int not_an_error = 0;
int fixup_tombstone = 0;
+ int ec_locked = 0;
slapi_pblock_get( pb, SLAPI_BACKEND, &be);
slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
@@ -799,6 +800,7 @@ ldbm_back_modify( Slapi_PBlock *pb )
CACHE_RETURN( &inst->inst_cache, &e );
/* lock new entry in cache to prevent usage until we are complete */
cache_lock_entry( &inst->inst_cache, ec );
+ ec_locked = 1;
postentry = slapi_entry_dup( ec->ep_entry );
slapi_pblock_set( pb, SLAPI_ENTRY_POST_OP, postentry );
@@ -919,7 +921,7 @@ common_return:
slapi_mods_done(&smods);
if (inst) {
- if (cache_is_in_cache(&inst->inst_cache, ec)) {
+ if (ec_locked || cache_is_in_cache(&inst->inst_cache, ec)) {
cache_unlock_entry(&inst->inst_cache, ec);
} else if (e) {
/* if ec was not in cache, cache_replace was not done.