diff options
author | David Howells <dhowells@redhat.com> | 2020-07-02 14:59:46 +0100 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2020-09-08 21:10:45 +0100 |
commit | b7a7d67408032843c14071711d6259aada9392f0 (patch) | |
tree | 9e7d3c9daf4566dc07cdbeda4ee20ade628b2543 /net/rxrpc/call_object.c | |
parent | 4349abdb409b04a5ed4ca4d2c1df7ef0cc16f6bd (diff) |
rxrpc: Impose a maximum number of client calls
Impose a maximum on the number of client rxrpc calls that are allowed
simultaneously. This will be in lieu of a maximum number of client
connections as this is easier to administed as, unlike connections, calls
aren't reusable (to be changed in a subsequent patch)..
This doesn't affect the limits on service calls and connections.
Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'net/rxrpc/call_object.c')
-rw-r--r-- | net/rxrpc/call_object.c | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c index a40fae013942..c8015c76a81c 100644 --- a/net/rxrpc/call_object.c +++ b/net/rxrpc/call_object.c @@ -41,6 +41,11 @@ const char *const rxrpc_call_completions[NR__RXRPC_CALL_COMPLETIONS] = { struct kmem_cache *rxrpc_call_jar; +static struct semaphore rxrpc_call_limiter = + __SEMAPHORE_INITIALIZER(rxrpc_call_limiter, 1000); +static struct semaphore rxrpc_kernel_call_limiter = + __SEMAPHORE_INITIALIZER(rxrpc_kernel_call_limiter, 1000); + static void rxrpc_call_timer_expired(struct timer_list *t) { struct rxrpc_call *call = from_timer(call, t, timer); @@ -210,6 +215,34 @@ static void rxrpc_start_call_timer(struct rxrpc_call *call) } /* + * Wait for a call slot to become available. + */ +static struct semaphore *rxrpc_get_call_slot(struct rxrpc_call_params *p, gfp_t gfp) +{ + struct semaphore *limiter = &rxrpc_call_limiter; + + if (p->kernel) + limiter = &rxrpc_kernel_call_limiter; + if (p->interruptibility == RXRPC_UNINTERRUPTIBLE) { + down(limiter); + return limiter; + } + return down_interruptible(limiter) < 0 ? NULL : limiter; +} + +/* + * Release a call slot. + */ +static void rxrpc_put_call_slot(struct rxrpc_call *call) +{ + struct semaphore *limiter = &rxrpc_call_limiter; + + if (test_bit(RXRPC_CALL_KERNEL, &call->flags)) + limiter = &rxrpc_kernel_call_limiter; + up(limiter); +} + +/* * Set up a call for the given parameters. * - Called with the socket lock held, which it must release. * - If it returns a call, the call's lock will need releasing by the caller. @@ -225,15 +258,21 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx, { struct rxrpc_call *call, *xcall; struct rxrpc_net *rxnet; + struct semaphore *limiter; struct rb_node *parent, **pp; const void *here = __builtin_return_address(0); int ret; _enter("%p,%lx", rx, p->user_call_ID); + limiter = rxrpc_get_call_slot(p, gfp); + if (!limiter) + return ERR_PTR(-ERESTARTSYS); + call = rxrpc_alloc_client_call(rx, srx, gfp, debug_id); if (IS_ERR(call)) { release_sock(&rx->sk); + up(limiter); _leave(" = %ld", PTR_ERR(call)); return call; } @@ -243,6 +282,8 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx, trace_rxrpc_call(call->debug_id, rxrpc_call_new_client, atomic_read(&call->usage), here, (const void *)p->user_call_ID); + if (p->kernel) + __set_bit(RXRPC_CALL_KERNEL, &call->flags); /* We need to protect a partially set up call against the user as we * will be acting outside the socket lock. @@ -471,6 +512,8 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call) BUG(); spin_unlock_bh(&call->lock); + rxrpc_put_call_slot(call); + del_timer_sync(&call->timer); /* Make sure we don't get any more notifications */ |