From 96f4c723a916cf20850679e1cce8bb2ceb601041 Mon Sep 17 00:00:00 2001 From: Hallvard Furuseth Date: Thu, 4 Jun 2009 21:16:38 +0000 Subject: [PATCH] For ITS#6157: Catch most invalid cancels/abandons, and honor them before waits --- servers/slapd/abandon.c | 11 +++++++++++ servers/slapd/bconfig.c | 18 ++++++++++++++++-- servers/slapd/cancel.c | 37 ++++++++++++++++++++++++++++++------- 3 files changed, 57 insertions(+), 9 deletions(-) diff --git a/servers/slapd/abandon.c b/servers/slapd/abandon.c index 8e08707756..8b0156902c 100644 --- a/servers/slapd/abandon.c +++ b/servers/slapd/abandon.c @@ -96,6 +96,17 @@ do_abandon( Operation *op, SlapReply *rs ) break; } } + + } else if ( o->o_tag == LDAP_REQ_BIND + || o->o_tag == LDAP_REQ_UNBIND + || o->o_tag == LDAP_REQ_ABANDON ) { + msg = "cannot be abandoned"; + +#if 0 /* Would break o_abandon used as "suppress response" flag, ITS#6138 */ + } else if ( o->o_abandon ) { + msg = "already being abandoned"; +#endif + } else { msg = "found"; /* Set the o_abandon flag in the to-be-abandoned operation. diff --git a/servers/slapd/bconfig.c b/servers/slapd/bconfig.c index b259178efe..a3fd9aa19f 100644 --- a/servers/slapd/bconfig.c +++ b/servers/slapd/bconfig.c @@ -4783,6 +4783,10 @@ config_back_add( Operation *op, SlapReply *rs ) } } + if ( op->o_abandon ) { + rs->sr_err = SLAPD_ABANDON; + goto out; + } ldap_pvt_thread_pool_pause( &connection_pool ); /* Strategy: @@ -5223,8 +5227,13 @@ config_back_modify( Operation *op, SlapReply *rs ) slap_mods_opattrs( op, &op->orm_modlist, 1 ); - if ( do_pause ) + if ( do_pause ) { + if ( op->o_abandon ) { + rs->sr_err = SLAPD_ABANDON; + goto out; + } ldap_pvt_thread_pool_pause( &connection_pool ); + } /* Strategy: * 1) perform the Modify on the cached Entry. @@ -5388,6 +5397,10 @@ config_back_modrdn( Operation *op, SlapReply *rs ) goto out; } + if ( op->o_abandon ) { + rs->sr_err = SLAPD_ABANDON; + goto out; + } ldap_pvt_thread_pool_pause( &connection_pool ); if ( ce->ce_type == Cft_Schema ) { @@ -5477,6 +5490,8 @@ config_back_delete( Operation *op, SlapReply *rs ) rs->sr_err = LDAP_NO_SUCH_OBJECT; } else if ( ce->ce_kids ) { rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + } else if ( op->o_abandon ) { + rs->sr_err = SLAPD_ABANDON; } else if ( ce->ce_type == Cft_Overlay || ce->ce_type == Cft_Database ){ char *iptr; int count, ixold; @@ -6655,4 +6670,3 @@ config_back_initialize( BackendInfo *bi ) return 0; } - diff --git a/servers/slapd/cancel.c b/servers/slapd/cancel.c index 5e65e090db..6d27d1756a 100644 --- a/servers/slapd/cancel.c +++ b/servers/slapd/cancel.c @@ -66,16 +66,25 @@ int cancel_extop( Operation *op, SlapReply *rs ) ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); + if ( op->o_abandon ) { + /* FIXME: Should instead reject the cancel/abandon of this op, but + * it seems unsafe to reset op->o_abandon once it is set. ITS#6138. + */ + rc = LDAP_OPERATIONS_ERROR; + rs->sr_text = "tried to abandon or cancel this operation"; + goto out; + } + LDAP_STAILQ_FOREACH( o, &op->o_conn->c_pending_ops, o_next ) { if ( o->o_msgid == opid ) { - ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); /* TODO: We could instead remove the cancelled operation * from c_pending_ops like Abandon does, and send its * response here. Not if it is pending because of a * congested connection though. */ + rc = LDAP_CANNOT_CANCEL; rs->sr_text = "too busy for Cancel, try Abandon instead"; - return LDAP_CANNOT_CANCEL; + goto out; } } @@ -88,15 +97,31 @@ int cancel_extop( Operation *op, SlapReply *rs ) if ( o == NULL ) { rc = LDAP_NO_SUCH_OPERATION; rs->sr_text = "message ID not found"; + + } else if ( o->o_tag == LDAP_REQ_BIND + || o->o_tag == LDAP_REQ_UNBIND + || o->o_tag == LDAP_REQ_ABANDON ) { + rc = LDAP_CANNOT_CANCEL; + } else if ( o->o_cancel != SLAP_CANCEL_NONE ) { - rc = LDAP_PROTOCOL_ERROR; + rc = LDAP_OPERATIONS_ERROR; rs->sr_text = "message ID already being cancelled"; + +#if 0 + } else if ( o->o_abandon ) { + /* TODO: Would this break something when + * o_abandon="suppress response"? (ITS#6138) + */ + rc = LDAP_TOO_LATE; +#endif + } else { rc = LDAP_SUCCESS; o->o_cancel = SLAP_CANCEL_REQ; o->o_abandon = 1; } + out: ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); if ( rc == LDAP_SUCCESS ) { @@ -109,14 +134,12 @@ int cancel_extop( Operation *op, SlapReply *rs ) } } - while ( o->o_cancel == SLAP_CANCEL_REQ ) { + while ( (rc = o->o_cancel) == SLAP_CANCEL_REQ ) { ldap_pvt_thread_yield(); } - if ( o->o_cancel == SLAP_CANCEL_ACK ) { + if ( rc == SLAP_CANCEL_ACK ) { rc = LDAP_SUCCESS; - } else { - rc = o->o_cancel; } o->o_cancel = SLAP_CANCEL_DONE; -- 2.39.5