128 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			128 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From 7943443bb92fca6676922349fb12503a527cb6b1 Mon Sep 17 00:00:00 2001
 | |
| From: Mark Reynolds <mreynolds@redhat.com>
 | |
| 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
 | |
| 
 |