]> git.ipfire.org Git - thirdparty/openldap.git/commitdiff
ITS#10016: slapo-syncprov: fix Abandon with active qtask
authorHoward Chu <hyc@openldap.org>
Mon, 27 Feb 2023 15:01:23 +0000 (15:01 +0000)
committerQuanah Gibson-Mount <quanah@openldap.org>
Thu, 27 Apr 2023 15:10:27 +0000 (15:10 +0000)
servers/slapd/overlays/syncprov.c

index 1ff507c864360fc865ef713d2d80a617c51eba83..5504c9743d56d0d2389bf2fc9bb8c8216a1b9916 100644 (file)
@@ -869,6 +869,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 )
@@ -879,12 +884,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 );
@@ -912,7 +924,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 */
@@ -1027,6 +1039,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 );
@@ -1053,6 +1068,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 )
@@ -1061,7 +1079,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;
@@ -1090,14 +1108,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;
 }
 
@@ -1272,7 +1300,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;
 }