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 a123b5466aae3eac4193451ac587d90ef1b61815 Author: Rich Megginson rmeggins@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 88af80f..2ca416f 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_search.c +++ b/ldap/servers/slapd/back-ldbm/ldbm_search.c @@ -1201,6 +1201,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 ) @@ -1239,7 +1240,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 ); @@ -1250,13 +1250,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 ); @@ -1267,6 +1267,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; }
@@ -1456,12 +1457,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, @@ -1544,6 +1547,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 1f14341..b3e2c45 100644 --- a/ldap/servers/slapd/opshared.c +++ b/ldap/servers/slapd/opshared.c @@ -226,6 +226,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; @@ -396,6 +397,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); @@ -880,6 +887,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 a1b0333..652d4e1 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 @@ -385,5 +386,44 @@ pagedresults_cleanup(Connection *conn) } conn->c_search_result_count = 0; conn->c_timelimit = 0; + conn->c_flags &= ~CONN_FLAG_PAGEDRESULTS_PROCESSING; 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 3d22da5..7bd94d4 100644 --- a/ldap/servers/slapd/proto-slap.h +++ b/ldap/servers/slapd/proto-slap.h @@ -1387,6 +1387,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 65ee8ce..ee02a26 100644 --- a/ldap/servers/slapd/slap.h +++ b/ldap/servers/slapd/slap.h @@ -1409,6 +1409,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"