diff options
author | Rich Megginson <rmeggins@redhat.com> | 2010-03-23 19:08:13 -0600 |
---|---|---|
committer | Rich Megginson <rmeggins@redhat.com> | 2010-03-24 10:16:03 -0600 |
commit | eac3f15f2209719e05640e1576b4273d03bef079 (patch) | |
tree | 976ce426d57db852468344402c4461d6d983c003 /ldap/servers/slapd/back-ldbm/ldbm_modrdn.c | |
parent | 682529e7f8391744615b40a14852efd317936109 (diff) | |
download | ds-eac3f15f2209719e05640e1576b4273d03bef079.tar.gz ds-eac3f15f2209719e05640e1576b4273d03bef079.tar.xz ds-eac3f15f2209719e05640e1576b4273d03bef079.zip |
Bug 571677 - Busy replica on consumers when directly deleting a replication conflict
https://bugzilla.redhat.com/show_bug.cgi?id=571677
Resolves: bug 571677
Bug Description: Busy replica on consumers when directly deleting a replication conflict
Reviewed by: nhosoi (Thanks!)
Branch: HEAD
Fix Description: In some cases, urp fixup operations can be called from
the bepreop stage of other operations. The ldbm_back_delete() and
ldbm_back_modify() code lock the target entry in the cache. If a bepreop
then attempts to operate on the same entry and acquire the lock on the
entry, deadlock will occur.
The modrdn code does not acquire the cache lock on the target entries
before calling the bepreops. The modify and delete code does not acquire
the cache lock on the target entries before calling the bepostops.
I tried unlocking the target entry before calling the bepreops, then locking
the entry just after. This causes the problem to disappear, but I do not
know if this will lead to race conditions. The modrdn has been working this
way forever, and there are no known race conditions with that code.
I think the most robust fix for this issue would be to introduce some sort
of semaphore instead of a simple mutex on the cached entry. Then
cache_lock_entry would look something like this:
if entry->sem == 0
entry->sem++ /* acquire entry */
entry->locking_thread = this_thread
else if entry->locking_thread == this_thread
entry->sem++ /* increment count on this entry */
else
wait_for_sem(entry->sem) /* wait until released */
and cache_unlock_entry would look something like this:
entry->sem--;
if entry->sem == 0
entry->locking_thread = 0
Platforms tested: RHEL5 x86_64
Flag Day: no
Doc impact: no
Diffstat (limited to 'ldap/servers/slapd/back-ldbm/ldbm_modrdn.c')
-rw-r--r-- | ldap/servers/slapd/back-ldbm/ldbm_modrdn.c | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c index a3f19297..6d0a440b 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c +++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c @@ -1008,6 +1008,7 @@ common_return: CACHE_RETURN( &inst->inst_cache, &ec ); } + moddn_unlock_and_return_entries(be,&e,&existingentry); /* * The bepostop is called even if the operation fails. */ @@ -1021,7 +1022,6 @@ common_return: slapi_mods_done(&smods_operation_wsi); slapi_mods_done(&smods_generated); slapi_mods_done(&smods_generated_wsi); - moddn_unlock_and_return_entries(be,&e,&existingentry); slapi_ch_free((void**)&child_entries); slapi_ch_free((void**)&child_dns); if (ldap_result_matcheddn && 0 != strcmp(ldap_result_matcheddn, "NULL")) |