From 7943443bb92fca6676922349fb12503a527cb6b1 Mon Sep 17 00:00:00 2001 From: Mark Reynolds Date: Thu, 15 May 2025 10:35:27 -0400 Subject: [PATCH] Issue 6782 - Improve paged result locking Description: When cleaning a slot, instead of mem setting everything to Zero and restoring the mutex, manually reset all the values leaving the mutex pointer intact. There is also a deadlock possibility when checking for abandoned PR search in opshared.c, and we were checking a flag value outside of the per_conn lock. Relates: https://github.com/389ds/389-ds-base/issues/6782 Reviewed by: progier & spichugi(Thanks!!) --- ldap/servers/slapd/opshared.c | 10 +++++++++- ldap/servers/slapd/pagedresults.c | 27 +++++++++++++++++---------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/ldap/servers/slapd/opshared.c b/ldap/servers/slapd/opshared.c index 7dc2d5983..14a7dcdfb 100644 --- a/ldap/servers/slapd/opshared.c +++ b/ldap/servers/slapd/opshared.c @@ -592,6 +592,14 @@ op_shared_search(Slapi_PBlock *pb, int send_result) int32_t tlimit; slapi_pblock_get(pb, SLAPI_SEARCH_TIMELIMIT, &tlimit); pagedresults_set_timelimit(pb_conn, operation, (time_t)tlimit, pr_idx); + /* When using this mutex in conjunction with the main paged + * result lock, you must do so in this order: + * + * --> pagedresults_lock() + * --> pagedresults_mutex + * <-- pagedresults_mutex + * <-- pagedresults_unlock() + */ pagedresults_mutex = pageresult_lock_get_addr(pb_conn); } @@ -717,11 +725,11 @@ op_shared_search(Slapi_PBlock *pb, int send_result) pr_search_result = pagedresults_get_search_result(pb_conn, operation, 1 /*locked*/, pr_idx); if (pr_search_result) { if (pagedresults_is_abandoned_or_notavailable(pb_conn, 1 /*locked*/, pr_idx)) { + pthread_mutex_unlock(pagedresults_mutex); pagedresults_unlock(pb_conn, pr_idx); /* Previous operation was abandoned and the simplepaged object is not in use. */ send_ldap_result(pb, 0, NULL, "Simple Paged Results Search abandoned", 0, NULL); rc = LDAP_SUCCESS; - pthread_mutex_unlock(pagedresults_mutex); goto free_and_return; } else { slapi_pblock_set(pb, SLAPI_SEARCH_RESULT_SET, pr_search_result); diff --git a/ldap/servers/slapd/pagedresults.c b/ldap/servers/slapd/pagedresults.c index 642aefb3d..c3f3aae01 100644 --- a/ldap/servers/slapd/pagedresults.c +++ b/ldap/servers/slapd/pagedresults.c @@ -48,7 +48,6 @@ pageresult_lock_get_addr(Connection *conn) static void _pr_cleanup_one_slot(PagedResults *prp) { - PRLock *prmutex = NULL; if (!prp) { return; } @@ -56,13 +55,17 @@ _pr_cleanup_one_slot(PagedResults *prp) /* sr is left; release it. */ prp->pr_current_be->be_search_results_release(&(prp->pr_search_result_set)); } - /* clean up the slot */ - if (prp->pr_mutex) { - /* pr_mutex is reused; back it up and reset it. */ - prmutex = prp->pr_mutex; - } - memset(prp, '\0', sizeof(PagedResults)); - prp->pr_mutex = prmutex; + + /* clean up the slot except the mutex */ + prp->pr_current_be = NULL; + prp->pr_search_result_set = NULL; + prp->pr_search_result_count = 0; + prp->pr_search_result_set_size_estimate = 0; + prp->pr_sort_result_code = 0; + prp->pr_timelimit_hr.tv_sec = 0; + prp->pr_timelimit_hr.tv_nsec = 0; + prp->pr_flags = 0; + prp->pr_msgid = 0; } /* @@ -1007,7 +1010,8 @@ op_set_pagedresults(Operation *op) /* * pagedresults_lock/unlock -- introduced to protect search results for the - * asynchronous searches. + * asynchronous searches. Do not call these functions while the PR conn lock + * is held (e.g. pageresult_lock_get_addr(conn)) */ void pagedresults_lock(Connection *conn, int index) @@ -1045,6 +1049,8 @@ int pagedresults_is_abandoned_or_notavailable(Connection *conn, int locked, int index) { PagedResults *prp; + int32_t result; + if (!conn || (index < 0) || (index >= conn->c_pagedresults.prl_maxlen)) { return 1; /* not abandoned, but do not want to proceed paged results op. */ } @@ -1052,10 +1058,11 @@ pagedresults_is_abandoned_or_notavailable(Connection *conn, int locked, int inde pthread_mutex_lock(pageresult_lock_get_addr(conn)); } prp = conn->c_pagedresults.prl_list + index; + result = prp->pr_flags & CONN_FLAG_PAGEDRESULTS_ABANDONED; if (!locked) { pthread_mutex_unlock(pageresult_lock_get_addr(conn)); } - return prp->pr_flags & CONN_FLAG_PAGEDRESULTS_ABANDONED; + return result; } int -- 2.49.0