From 61c5aca30532dfde05e3b2d9ed941dccaa6837ad Mon Sep 17 00:00:00 2001 From: Thierry Bordaz Date: Mar 13 2020 16:36:34 +0000 Subject: Bug 1751295: (2) When sync-repl is enabled, slapi-nis can deadlock during retrochanglog trimming Bug Description: Note: same description as original fix for 1751295 When sync-repl is enabled, it enables retroCL that can lead to the following deadlock scenario. Since 1435663, slapi-nis lock is acquired from be_preop to be_postop. So during a write operation on domain, retroCL is updated and being a BE_TXN_POST it holds slapi-nis lock when it tries to acquire retroCL backend lock. If at the same time an operation on the retroCL (like retroCL trimming) acquire retroCL backend lock then during its BE_TXN_POST it tries to acquire slapi-nis lock. This is a common scenario, when there are updates on several backends, there is a chance that two updates are acquiring the backends lock in the opposite order. Here the backends are slapi-nis and retroCL. Fix Description: All slapi-nis plugin callbacks (be_pre/post and betxn_pre/post) should ignore updates on suffixes like cn=changelog, cn=config and cn=schema. Up to now, only be_pre/post checked if the update can be ignored. https://bugzilla.redhat.com/show_bug.cgi?id=1751295 --- diff --git a/src/back-sch.c b/src/back-sch.c index ae8f96b..03abbeb 100644 --- a/src/back-sch.c +++ b/src/back-sch.c @@ -2342,36 +2342,16 @@ backend_betxn_pre_write_cb(Slapi_PBlock *pb) { struct plugin_state *state; + if (backend_shr_write_ignore(pb)) { +#if DEBUG_MAP_LOCK + slapi_log_error(SLAPI_LOG_FATAL, "schemacompat", + "backend_betxn_pre_write_cb: (%p) operation is not impacting schema compat\n", PR_MyThreadId(), 1); +#endif + return 0; + } slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state); return state->use_be_txns ? backend_write_cb(pb, state) : 0; } -static PRBool -backend_be_write_ignore(Slapi_PBlock *pb) -{ - char *dn = NULL; - Slapi_DN *target_sdn = NULL; - int check; - int i = 0; - PRBool ignore = PR_FALSE; - - /* Check if the target DN is a subordinates of - * on of the ignored containers - */ - slapi_pblock_get(pb, SLAPI_ORIGINAL_TARGET, &dn); - target_sdn = slapi_sdn_new_dn_byval(dn); - - for (i = 0; ignored_containers_sdn[i]; i++) { - check = slapi_sdn_issuffix(target_sdn, ignored_containers_sdn[i]); - if (check != 0) { - /* This entry is an ignored container */ - ignore = PR_TRUE; - break; - } - } - slapi_sdn_free(&target_sdn); - return ignore; -} - static int backend_be_pre_write_cb(Slapi_PBlock *pb) { @@ -2392,7 +2372,7 @@ backend_be_pre_write_cb(Slapi_PBlock *pb) { if (rw_monitor_enabled() == MAP_MONITOR_DISABLED) { return 0; } - if (backend_be_write_ignore(pb)) { + if (backend_shr_write_ignore(pb)) { #if DEBUG_MAP_LOCK slapi_log_error(SLAPI_LOG_FATAL, "schemacompat", "backend_be_pre_write_cb: (%p) operation is not impacting schema compat\n", PR_MyThreadId(), 1); @@ -2484,7 +2464,7 @@ backend_be_post_write_cb(Slapi_PBlock *pb) if (rw_monitor_enabled() == MAP_MONITOR_DISABLED) { return 0; } - if (backend_be_write_ignore(pb)) { + if (backend_shr_write_ignore(pb)) { #if DEBUG_MAP_LOCK slapi_log_error(SLAPI_LOG_FATAL, "schemacompat", "backend_be_post_write_cb: (%p) operation was not impacting schema compat\n", PR_MyThreadId(), 1); diff --git a/src/back-shr.c b/src/back-shr.c index 4292e18..e2b5dd3 100644 --- a/src/back-shr.c +++ b/src/back-shr.c @@ -1894,6 +1894,13 @@ backend_shr_add_cb(Slapi_PBlock *pb) if (wrap_get_call_level() > 0) { return 0; } + if (backend_shr_write_ignore(pb)) { +#if DEBUG_MAP_LOCK + slapi_log_error(SLAPI_LOG_FATAL, "schema-compat", + "backend_shr_add_cb: (%p) operation is not impacting schema compat\n", PR_MyThreadId(), 1); +#endif + return 0; + } /* Read parameters from the pblock. */ slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &cbdata.state); @@ -2944,6 +2951,33 @@ init_map_lock(void) #endif } +PRBool +backend_shr_write_ignore(Slapi_PBlock *pb) +{ + char *dn = NULL; + Slapi_DN *target_sdn = NULL; + int check; + int i = 0; + PRBool ignore = PR_FALSE; + + /* Check if the target DN is a subordinates of + * on of the ignored containers + */ + slapi_pblock_get(pb, SLAPI_ORIGINAL_TARGET, &dn); + target_sdn = slapi_sdn_new_dn_byval(dn); + + for (i = 0; ignored_containers_sdn[i]; i++) { + check = slapi_sdn_issuffix(target_sdn, ignored_containers_sdn[i]); + if (check != 0) { + /* This entry is an ignored container */ + ignore = PR_TRUE; + break; + } + } + slapi_sdn_free(&target_sdn); + return ignore; +} + int rw_monitor_enabled(void) { diff --git a/src/back-shr.h b/src/back-shr.h index e9b88c5..e0d154b 100644 --- a/src/back-shr.h +++ b/src/back-shr.h @@ -38,6 +38,7 @@ int get_plugin_monitor_count(void); void set_plugin_monitor_count(int lock_count); void init_map_lock(void); extern Slapi_DN **ignored_containers_sdn; +PRBool backend_shr_write_ignore(Slapi_PBlock *pb); struct plugin_state;