diff --git a/servers/lloadd/bind.c b/servers/lloadd/bind.c index 393989f76c..d19aa782a7 100644 --- a/servers/lloadd/bind.c +++ b/servers/lloadd/bind.c @@ -263,7 +263,6 @@ void client_reset( Connection *c ) { TAvlnode *root; - int freed; root = c->c_ops; c->c_ops = NULL; @@ -292,19 +291,8 @@ client_reset( Connection *c ) CONNECTION_UNLOCK_INCREF(c); if ( root ) { - TAvlnode *node = tavl_end( root, TAVL_DIR_LEFT ); - do { - Operation *op = node->avl_data; - - operation_abandon( op ); - - CONNECTION_LOCK(c); - op->o_client_refcnt--; - operation_destroy_from_client( op ); - CONNECTION_UNLOCK(c); - } while ( (node = tavl_next( node, TAVL_DIR_RIGHT )) ); - - freed = tavl_free( root, NULL ); + int freed; + freed = tavl_free( root, (AVL_FREE)operation_abandon ); Debug( LDAP_DEBUG_TRACE, "client_reset: " "dropped %d operations\n", freed ); diff --git a/servers/lloadd/operation.c b/servers/lloadd/operation.c index 37abe89b64..f5a9b6a015 100644 --- a/servers/lloadd/operation.c +++ b/servers/lloadd/operation.c @@ -513,6 +513,13 @@ fail: return NULL; } +/* + * Will remove the operation from its upstream and if it was still there, + * sends an abandon request. + * + * Being called from client_reset or request_abandon, the following hold: + * - op->o_client_refcnt > 0 (and it follows that op->o_client != NULL) + */ void operation_abandon( Operation *op ) { @@ -524,22 +531,15 @@ operation_abandon( Operation *op ) ldap_pvt_thread_mutex_lock( &operation_mutex ); c = op->o_upstream; if ( !c ) { - c = op->o_client; - assert( c ); - - /* Caller should hold a reference on client */ - CONNECTION_LOCK(c); ldap_pvt_thread_mutex_unlock( &operation_mutex ); - operation_destroy_from_client( op ); - CLIENT_UNLOCK_OR_DESTROY(c); - return; + goto done; } CONNECTION_LOCK(c); ldap_pvt_thread_mutex_unlock( &operation_mutex ); if ( tavl_delete( &c->c_ops, op, operation_upstream_cmp ) == NULL ) { /* The operation has already been abandoned or finished */ - goto done; + goto unlock; } c->c_n_ops_executing--; b = (Backend *)c->c_private; @@ -557,7 +557,7 @@ operation_abandon( Operation *op ) "ber_alloc failed\n" ); ldap_pvt_thread_mutex_unlock( &c->c_io_mutex ); CONNECTION_LOCK_DECREF(c); - goto done; + goto unlock; } c->c_pendingber = ber; @@ -577,9 +577,18 @@ operation_abandon( Operation *op ) } CONNECTION_LOCK_DECREF(c); -done: - operation_destroy_from_upstream( op ); +unlock: UPSTREAM_UNLOCK_OR_DESTROY(c); + +done: + c = op->o_client; + assert( c ); + + /* Caller should hold a reference on client */ + CONNECTION_LOCK(c); + op->o_client_refcnt--; + operation_destroy_from_client( op ); + CONNECTION_UNLOCK(c); } int diff --git a/servers/lloadd/upstream.c b/servers/lloadd/upstream.c index 40b125276b..c6d8bc2c7a 100644 --- a/servers/lloadd/upstream.c +++ b/servers/lloadd/upstream.c @@ -418,8 +418,13 @@ handle_one_response( Connection *c ) client = op->o_client; if ( client ) { CONNECTION_LOCK(client); - op->o_client_refcnt++; - CONNECTION_UNLOCK_INCREF(client); + if ( client->c_live ) { + op->o_client_refcnt++; + CONNECTION_UNLOCK_INCREF(client); + } else { + CONNECTION_UNLOCK(client); + client = NULL; + } } ldap_pvt_thread_mutex_unlock( &operation_mutex );