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>
This commit is contained in:
@@ -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);
|
||||
@@ -209,6 +214,34 @@ static void rxrpc_start_call_timer(struct rxrpc_call *call)
|
||||
call->timer.expires = now;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
@@ -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 */
|
||||
|
Reference in New Issue
Block a user