diff options
Diffstat (limited to 'net/rxrpc/conn_client.c')
| -rw-r--r-- | net/rxrpc/conn_client.c | 38 | 
1 files changed, 23 insertions, 15 deletions
diff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c index 3c9eeb5b750c..bdb335cb2d05 100644 --- a/net/rxrpc/conn_client.c +++ b/net/rxrpc/conn_client.c @@ -40,6 +40,8 @@ __read_mostly unsigned long rxrpc_conn_idle_client_fast_expiry = 2 * HZ;  DEFINE_IDR(rxrpc_client_conn_ids);  static DEFINE_SPINLOCK(rxrpc_conn_id_lock); +static void rxrpc_deactivate_bundle(struct rxrpc_bundle *bundle); +  /*   * Get a connection ID and epoch for a client connection from the global pool.   * The connection struct pointer is then recorded in the idr radix tree.  The @@ -123,6 +125,7 @@ static struct rxrpc_bundle *rxrpc_alloc_bundle(struct rxrpc_conn_parameters *cp,  		bundle->params = *cp;  		rxrpc_get_peer(bundle->params.peer);  		refcount_set(&bundle->ref, 1); +		atomic_set(&bundle->active, 1);  		spin_lock_init(&bundle->channel_lock);  		INIT_LIST_HEAD(&bundle->waiting_calls);  	} @@ -149,7 +152,7 @@ void rxrpc_put_bundle(struct rxrpc_bundle *bundle)  	dead = __refcount_dec_and_test(&bundle->ref, &r); -	_debug("PUT B=%x %d", d, r); +	_debug("PUT B=%x %d", d, r - 1);  	if (dead)  		rxrpc_free_bundle(bundle);  } @@ -338,6 +341,7 @@ found_bundle_free:  	rxrpc_free_bundle(candidate);  found_bundle:  	rxrpc_get_bundle(bundle); +	atomic_inc(&bundle->active);  	spin_unlock(&local->client_bundles_lock);  	_leave(" = %u [found]", bundle->debug_id);  	return bundle; @@ -435,6 +439,7 @@ static void rxrpc_add_conn_to_bundle(struct rxrpc_bundle *bundle, gfp_t gfp)  			if (old)  				trace_rxrpc_client(old, -1, rxrpc_client_replace);  			candidate->bundle_shift = shift; +			atomic_inc(&bundle->active);  			bundle->conns[i] = candidate;  			for (j = 0; j < RXRPC_MAXCALLS; j++)  				set_bit(shift + j, &bundle->avail_chans); @@ -725,6 +730,7 @@ granted_channel:  	smp_rmb();  out_put_bundle: +	rxrpc_deactivate_bundle(bundle);  	rxrpc_put_bundle(bundle);  out:  	_leave(" = %d", ret); @@ -900,9 +906,8 @@ out:  static void rxrpc_unbundle_conn(struct rxrpc_connection *conn)  {  	struct rxrpc_bundle *bundle = conn->bundle; -	struct rxrpc_local *local = bundle->params.local;  	unsigned int bindex; -	bool need_drop = false, need_put = false; +	bool need_drop = false;  	int i;  	_enter("C=%x", conn->debug_id); @@ -921,15 +926,22 @@ static void rxrpc_unbundle_conn(struct rxrpc_connection *conn)  	}  	spin_unlock(&bundle->channel_lock); -	/* If there are no more connections, remove the bundle */ -	if (!bundle->avail_chans) { -		_debug("maybe unbundle"); -		spin_lock(&local->client_bundles_lock); +	if (need_drop) { +		rxrpc_deactivate_bundle(bundle); +		rxrpc_put_connection(conn); +	} +} -		for (i = 0; i < ARRAY_SIZE(bundle->conns); i++) -			if (bundle->conns[i]) -				break; -		if (i == ARRAY_SIZE(bundle->conns) && !bundle->params.exclusive) { +/* + * Drop the active count on a bundle. + */ +static void rxrpc_deactivate_bundle(struct rxrpc_bundle *bundle) +{ +	struct rxrpc_local *local = bundle->params.local; +	bool need_put = false; + +	if (atomic_dec_and_lock(&bundle->active, &local->client_bundles_lock)) { +		if (!bundle->params.exclusive) {  			_debug("erase bundle");  			rb_erase(&bundle->local_node, &local->client_bundles);  			need_put = true; @@ -939,10 +951,6 @@ static void rxrpc_unbundle_conn(struct rxrpc_connection *conn)  		if (need_put)  			rxrpc_put_bundle(bundle);  	} - -	if (need_drop) -		rxrpc_put_connection(conn); -	_leave("");  }  /*  | 
