From: Howard Chu Date: Mon, 27 Feb 2023 15:01:23 +0000 (+0000) Subject: ITS#10016: slapo-syncprov: fix Abandon with active qtask X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5f934c8c457ffe906c844ab2313943ae9b66bc46;p=thirdparty%2Fopenldap.git ITS#10016: slapo-syncprov: fix Abandon with active qtask --- diff --git a/servers/slapd/overlays/syncprov.c b/servers/slapd/overlays/syncprov.c index f62d6c63ea..44a6181410 100644 --- a/servers/slapd/overlays/syncprov.c +++ b/servers/slapd/overlays/syncprov.c @@ -871,6 +871,11 @@ static void free_resinfo( syncres *sr ) #define FS_UNLINK 1 #define FS_LOCK 2 +#define FS_DEFER 4 + +#define FSR_NOTFREE 0 +#define FSR_DIDFREE 1 +#define FSR_CANFREE 2 static int syncprov_free_syncop( syncops *so, int flags ) @@ -881,12 +886,19 @@ syncprov_free_syncop( syncops *so, int flags ) if ( flags & FS_LOCK ) ldap_pvt_thread_mutex_lock( &so->s_mutex ); /* already being freed, or still in use */ - if ( !so->s_inuse || --so->s_inuse > 0 ) { + if ( !so->s_inuse || so->s_inuse > 1 ) { if ( flags & FS_LOCK ) ldap_pvt_thread_mutex_unlock( &so->s_mutex ); - return 0; + if ( !( flags & FS_DEFER ) && so->s_inuse ) + so->s_inuse--; + return FSR_NOTFREE; } ldap_pvt_thread_mutex_unlock( &so->s_mutex ); + + /* caller wants to cleanup other stuff before actual free */ + if ( flags & FS_DEFER ) + return FSR_CANFREE; + if (( flags & FS_UNLINK ) && so->s_si ) { syncops **sop; ldap_pvt_thread_mutex_lock( &so->s_si->si_ops_mutex ); @@ -914,7 +926,7 @@ syncprov_free_syncop( syncops *so, int flags ) } ldap_pvt_thread_mutex_destroy( &so->s_mutex ); ch_free( so ); - return 1; + return FSR_DIDFREE; } /* Send a persistent search response */ @@ -1029,6 +1041,9 @@ syncprov_qplay( Operation *op, syncops *so ) } else { rc = syncprov_sendresp( op, sr->s_info, so, sr->s_mode ); } + } else { + /* set rc so we don't do a new qstart */ + rc = 1; } free_resinfo( sr ); @@ -1055,6 +1070,9 @@ syncprov_qplay( Operation *op, syncops *so ) return rc; } +static int +syncprov_drop_psearch( syncops *so, int lock ); + /* task for playing back queued responses */ static void * syncprov_qtask( void *ctx, void *arg ) @@ -1063,7 +1081,7 @@ syncprov_qtask( void *ctx, void *arg ) OperationBuffer opbuf; Operation *op; BackendDB be; - int rc; + int rc, flag, frc; op = &opbuf.ob_op; *op = *so->s_op; @@ -1092,14 +1110,24 @@ syncprov_qtask( void *ctx, void *arg ) if ( !rc && !so->s_res ) rc = 1; + flag = FS_UNLINK; + if ( rc && op->o_abandon ) + flag = FS_DEFER; + /* decrement use count... */ - if ( !syncprov_free_syncop( so, FS_UNLINK )) { + frc = syncprov_free_syncop( so, flag ); + if ( frc == FSR_NOTFREE ) { if ( rc ) /* if we didn't unlink, and task is no longer queued, clear flag */ so->s_flags ^= PS_TASK_QUEUED; ldap_pvt_thread_mutex_unlock( &so->s_mutex ); } + /* if we got abandoned while processing, cleanup now */ + if ( frc == FSR_CANFREE ) { + syncprov_drop_psearch( so, 1 ); + } + return NULL; } @@ -1274,7 +1302,9 @@ syncprov_op_abandon( Operation *op, SlapReply *rs ) return SLAP_CB_CONTINUE; } } - syncprov_drop_psearch( so, 0 ); + /* if task is active, it must drop itself */ + if ( !( so->s_flags & PS_TASK_QUEUED )) + syncprov_drop_psearch( so, 0 ); } return SLAP_CB_CONTINUE; }