ldap/servers/slapd/back-ldbm/ldbm_search.c | 8 ++++-
ldap/servers/slapd/opshared.c | 10 +++++++
ldap/servers/slapd/pagedresults.c | 40 +++++++++++++++++++++++++++++
ldap/servers/slapd/proto-slap.h | 2 +
ldap/servers/slapd/slap.h | 3 ++
5 files changed, 61 insertions(+), 2 deletions(-)
New commits:
commit 77717b89e1497f4bfe0fca66129eed4299dcc07e
Author: Rich Megginson <rmeggins(a)redhat.com>
Date: Thu Jan 13 13:44:15 2011 -0700
Bug 666076 - dirsrv crash (1.2.7.5) with multiple simple paged result searches
https://bugzilla.redhat.com/show_bug.cgi?id=666076
Resolves: bug 666076
Bug Description: dirsrv crash (1.2.7.5) with multiple simple paged result searches
Reviewed by: nkinder, nhosoi (Thanks!)
Branch: master
Fix Description: Only allow one simple paged results search per-connection
at a time. The new function pagedresults_check_or_set_processing() will
check the flag in the connection to see if pagedresults processing is in
progress. If so, the function will return True and the search will terminate
with LDAP_UNWILLING_TO_PERFORM (as per section 3 in RFC 2696, a server is
allowed to return unwillingToPerform if there is a limit to the number of
outstanding paged search requests from a given client). The processing
flag will be reset once the search result has been sent to the client.
Since the problem is multiple threads in the same connection accessing
the pagedresults data, the workaround is to just set
nsslapd-maxthreadsperconn: 1
in cn=config in dse.ldif.
Platforms tested: RHEL6 x86_64
Flag Day: no
Doc impact: no
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_search.c
b/ldap/servers/slapd/back-ldbm/ldbm_search.c
index 568d32c..19a6bac 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_search.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_search.c
@@ -1169,6 +1169,7 @@ ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int use_extension
)
if ( !use_extension )
{
CACHE_RETURN( &inst->inst_cache, &(sr->sr_entry) );
+ sr->sr_entry = NULL;
}
if(sr->sr_vlventry != NULL && !use_extension )
@@ -1207,7 +1208,6 @@ ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int use_extension
)
curtime = current_time();
if ( tlimit != -1 && curtime > stoptime )
{
- slapi_send_ldap_result( pb, LDAP_TIMELIMIT_EXCEEDED, NULL, NULL, nentries,
urls );
/* in case paged results, clean up the conn */
pagedresults_set_search_result(pb->pb_conn, NULL);
slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET, NULL );
@@ -1218,13 +1218,13 @@ ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int
use_extension )
slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY, NULL );
delete_search_result_set( &sr );
rc = SLAPI_FAIL_GENERAL;
+ slapi_send_ldap_result( pb, LDAP_TIMELIMIT_EXCEEDED, NULL, NULL, nentries,
urls );
goto bail;
}
/* check lookthrough limit */
if ( llimit != -1 && sr->sr_lookthroughcount >= llimit )
{
- slapi_send_ldap_result( pb, LDAP_ADMINLIMIT_EXCEEDED, NULL, NULL, nentries,
urls );
/* in case paged results, clean up the conn */
pagedresults_set_search_result(pb->pb_conn, NULL);
slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET, NULL );
@@ -1235,6 +1235,7 @@ ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int use_extension
)
slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY, NULL );
delete_search_result_set( &sr );
rc = SLAPI_FAIL_GENERAL;
+ slapi_send_ldap_result( pb, LDAP_ADMINLIMIT_EXCEEDED, NULL, NULL, nentries,
urls );
goto bail;
}
@@ -1424,12 +1425,14 @@ ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int
use_extension )
else
{
CACHE_RETURN ( &inst->inst_cache, &(sr->sr_entry) );
+ sr->sr_entry = NULL;
}
}
else
{
/* Failed the filter test, and this isn't a VLV Search */
CACHE_RETURN( &inst->inst_cache, &(sr->sr_entry) );
+ sr->sr_entry = NULL;
if (LDAP_UNWILLING_TO_PERFORM == filter_test) {
/* Need to catch this error to detect the vattr loop */
slapi_send_ldap_result( pb, filter_test, NULL,
@@ -1489,6 +1492,7 @@ delete_search_result_set( back_search_result_set **sr )
{
idl_free( (*sr)->sr_candidates );
}
+ memset( *sr, 0, sizeof( back_search_result_set ) );
slapi_ch_free( (void**)sr );
}
diff --git a/ldap/servers/slapd/opshared.c b/ldap/servers/slapd/opshared.c
index a2684f9..a12ad04 100644
--- a/ldap/servers/slapd/opshared.c
+++ b/ldap/servers/slapd/opshared.c
@@ -225,6 +225,7 @@ op_shared_search (Slapi_PBlock *pb, int send_result)
Slapi_Backend *pr_be = NULL;
void *pr_search_result = NULL;
int pr_search_result_count = 0;
+ int pr_reset_processing = 0;
be_list[0] = NULL;
referral_list[0] = NULL;
@@ -395,6 +396,12 @@ op_shared_search (Slapi_PBlock *pb, int send_result)
&pagesize, &curr_search_count);
if (LDAP_SUCCESS == rc) {
unsigned int opnote = SLAPI_OP_NOTE_SIMPLEPAGED;
+ if (pagedresults_check_or_set_processing(pb->pb_conn)) {
+ send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM,
+ NULL, "Simple Paged Results Search already in
progress on this connection", 0, NULL);
+ goto free_and_return_nolock;
+ }
+ pr_reset_processing = 1; /* need to reset after we are done with this op
*/
operation->o_flags |= OP_FLAG_PAGED_RESULTS;
pr_be = pagedresults_get_current_be(pb->pb_conn);
pr_search_result = pagedresults_get_search_result(pb->pb_conn);
@@ -879,6 +886,9 @@ free_and_return:
slapi_sdn_done(&sdn);
slapi_ch_free_string(&proxydn);
slapi_ch_free_string(&proxystr);
+ if (pr_reset_processing) {
+ pagedresults_reset_processing(pb->pb_conn);
+ }
}
/* Returns 1 if this processing on this entry is finished
diff --git a/ldap/servers/slapd/pagedresults.c b/ldap/servers/slapd/pagedresults.c
index 47b3490..172e3a9 100644
--- a/ldap/servers/slapd/pagedresults.c
+++ b/ldap/servers/slapd/pagedresults.c
@@ -364,6 +364,7 @@ pagedresults_set_timelimit(Connection *conn, time_t timelimit)
}
/*
+ * must be called with conn->c_mutex held
* return values
* 0: not a simple paged result connection
* 1: simple paged result and successfully abandoned
@@ -383,7 +384,46 @@ pagedresults_cleanup(Connection *conn)
conn->c_current_be = 0;
conn->c_search_result_count = 0;
conn->c_timelimit = 0;
+ conn->c_flags &= ~CONN_FLAG_PAGEDRESULTS_PROCESSING;
rc = 1;
}
return rc;
}
+
+/*
+ * check to see if this connection is currently processing
+ * a pagedresults search - if it is, return True - if not,
+ * mark that it is processing, and return False
+ */
+int
+pagedresults_check_or_set_processing(Connection *conn)
+{
+ int ret = 0;
+ if (conn) {
+ PR_Lock(conn->c_mutex);
+ ret = conn->c_flags&CONN_FLAG_PAGEDRESULTS_PROCESSING;
+ /* if ret is true, the following doesn't do anything */
+ conn->c_flags |= CONN_FLAG_PAGEDRESULTS_PROCESSING;
+ PR_Unlock(conn->c_mutex);
+ }
+ return ret;
+}
+
+/*
+ * mark the connection as being done with pagedresults
+ * processing - returns True if it was processing,
+ * False otherwise
+ */
+int
+pagedresults_reset_processing(Connection *conn)
+{
+ int ret = 0;
+ if (conn) {
+ PR_Lock(conn->c_mutex);
+ ret = conn->c_flags&CONN_FLAG_PAGEDRESULTS_PROCESSING;
+ /* if ret is false, the following doesn't do anything */
+ conn->c_flags &= ~CONN_FLAG_PAGEDRESULTS_PROCESSING;
+ PR_Unlock(conn->c_mutex);
+ }
+ return ret;
+}
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
index 1a8c6e5..c46b623 100644
--- a/ldap/servers/slapd/proto-slap.h
+++ b/ldap/servers/slapd/proto-slap.h
@@ -1380,6 +1380,8 @@ int pagedresults_get_sort_result_code(Connection *conn);
int pagedresults_set_sort_result_code(Connection *conn, int code);
int pagedresults_set_timelimit(Connection *conn, time_t timelimit);
int pagedresults_cleanup(Connection *conn);
+int pagedresults_check_or_set_processing(Connection *conn);
+int pagedresults_reset_processing(Connection *conn);
/*
* sort.c
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
index d71367f..f02eb3b 100644
--- a/ldap/servers/slapd/slap.h
+++ b/ldap/servers/slapd/slap.h
@@ -1395,6 +1395,9 @@ typedef struct conn {
#define CONN_FLAG_PAGEDRESULTS_UNINDEXED 128 /* If the search is unindexed,
* store the info in c_flags
*/
+#define CONN_FLAG_PAGEDRESULTS_PROCESSING 256 /* there is an operation
+ * processing a pagedresults search
+ */
#define CONN_GET_SORT_RESULT_CODE (-1)
#define START_TLS_OID "1.3.6.1.4.1.1466.20037"