Return-Path: Received: from us-smtp-delivery-194.mimecast.com ([63.128.21.194]:30910 "EHLO us-smtp-delivery-194.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751175AbcFXVYv convert rfc822-to-8bit (ORCPT ); Fri, 24 Jun 2016 17:24:51 -0400 From: Trond Myklebust To: Fields Bruce CC: "linux-nfs@vger.kernel.org" Subject: Re: [PATCH 08/10] SUNRPC: Add a server side per-connection limit Date: Fri, 24 Jun 2016 21:24:44 +0000 Message-ID: <1ABE553D-2310-4638-9352-AFB62C9E0121@primarydata.com> References: <1466780152-7154-1-git-send-email-trond.myklebust@primarydata.com> <1466780152-7154-2-git-send-email-trond.myklebust@primarydata.com> <1466780152-7154-3-git-send-email-trond.myklebust@primarydata.com> <1466780152-7154-4-git-send-email-trond.myklebust@primarydata.com> <1466780152-7154-5-git-send-email-trond.myklebust@primarydata.com> <1466780152-7154-6-git-send-email-trond.myklebust@primarydata.com> <1466780152-7154-7-git-send-email-trond.myklebust@primarydata.com> <1466780152-7154-8-git-send-email-trond.myklebust@primarydata.com> <20160624211516.GK3287@fieldses.org> In-Reply-To: <20160624211516.GK3287@fieldses.org> MIME-Version: 1.0 Content-Type: text/plain; charset=WINDOWS-1252 Sender: linux-nfs-owner@vger.kernel.org List-ID: > On Jun 24, 2016, at 17:15, J. Bruce Fields wrote: > > On Fri, Jun 24, 2016 at 10:55:50AM -0400, Trond Myklebust wrote: >> Allow the user to limit the number of requests serviced through a single >> connection. > > Could you give a little detail about the problem you encountered and how > this solved it? If you have a large number of clients, some of which are faster than others, then you can end up with a starvation problem, with the fast clients hogging all the threads by virtue of being able to pump out lots more requests. Limiting the number of threads each client (or at least each connection) may use helps to mitigate the problem. > > --b. > >> >> Signed-off-by: Trond Myklebust >> --- >> Documentation/kernel-parameters.txt | 6 ++++++ >> include/linux/sunrpc/svc.h | 1 + >> include/linux/sunrpc/svc_xprt.h | 1 + >> net/sunrpc/svc_xprt.c | 39 ++++++++++++++++++++++++++++++++++--- >> 4 files changed, 44 insertions(+), 3 deletions(-) >> >> diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt >> index 82b42c958d1c..48ba6d2e670a 100644 >> --- a/Documentation/kernel-parameters.txt >> +++ b/Documentation/kernel-parameters.txt >> @@ -3832,6 +3832,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted. >> using these two parameters to set the minimum and >> maximum port values. >> >> + sunrpc.svc_rpc_per_connection_limit= >> + [NFS,SUNRPC] >> + Limit the number of requests that the server will >> + process in parallel from a single connection. >> + The default value is 0 (no limit). >> + >> sunrpc.pool_mode= >> [NFS] >> Control how the NFS server code allocates CPUs to >> diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h >> index 7ca44fb5b675..7321ae933867 100644 >> --- a/include/linux/sunrpc/svc.h >> +++ b/include/linux/sunrpc/svc.h >> @@ -268,6 +268,7 @@ struct svc_rqst { >> * cache pages */ >> #define RQ_VICTIM (5) /* about to be shut down */ >> #define RQ_BUSY (6) /* request is busy */ >> +#define RQ_DATA (7) /* request has data */ >> unsigned long rq_flags; /* flags field */ >> >> void * rq_argp; /* decoded arguments */ >> diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h >> index b7dabc4baafd..555c004de51e 100644 >> --- a/include/linux/sunrpc/svc_xprt.h >> +++ b/include/linux/sunrpc/svc_xprt.h >> @@ -69,6 +69,7 @@ struct svc_xprt { >> >> struct svc_serv *xpt_server; /* service for transport */ >> atomic_t xpt_reserved; /* space on outq that is rsvd */ >> + atomic_t xpt_nr_rqsts; /* Number of requests */ >> struct mutex xpt_mutex; /* to serialize sending data */ >> spinlock_t xpt_lock; /* protects sk_deferred >> * and xpt_auth_cache */ >> diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c >> index eccc61237ca9..cd26d0d9e41f 100644 >> --- a/net/sunrpc/svc_xprt.c >> +++ b/net/sunrpc/svc_xprt.c >> @@ -21,6 +21,10 @@ >> >> #define RPCDBG_FACILITY RPCDBG_SVCXPRT >> >> +static unsigned int svc_rpc_per_connection_limit __read_mostly; >> +module_param(svc_rpc_per_connection_limit, uint, 0644); >> + >> + >> static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt); >> static int svc_deferred_recv(struct svc_rqst *rqstp); >> static struct cache_deferred_req *svc_defer(struct cache_req *req); >> @@ -327,12 +331,41 @@ char *svc_print_addr(struct svc_rqst *rqstp, char *buf, size_t len) >> } >> EXPORT_SYMBOL_GPL(svc_print_addr); >> >> +static bool svc_xprt_slots_in_range(struct svc_xprt *xprt) >> +{ >> + unsigned int limit = svc_rpc_per_connection_limit; >> + int nrqsts = atomic_read(&xprt->xpt_nr_rqsts); >> + >> + return limit == 0 || (nrqsts >= 0 && nrqsts < limit); >> +} >> + >> +static bool svc_xprt_reserve_slot(struct svc_rqst *rqstp, struct svc_xprt *xprt) >> +{ >> + if (!test_bit(RQ_DATA, &rqstp->rq_flags)) { >> + if (!svc_xprt_slots_in_range(xprt)) >> + return false; >> + atomic_inc(&xprt->xpt_nr_rqsts); >> + set_bit(RQ_DATA, &rqstp->rq_flags); >> + } >> + return true; >> +} >> + >> +static void svc_xprt_release_slot(struct svc_rqst *rqstp) >> +{ >> + struct svc_xprt *xprt = rqstp->rq_xprt; >> + if (test_and_clear_bit(RQ_DATA, &rqstp->rq_flags)) { >> + atomic_dec(&xprt->xpt_nr_rqsts); >> + svc_xprt_enqueue(xprt); >> + } >> +} >> + >> static bool svc_xprt_has_something_to_do(struct svc_xprt *xprt) >> { >> if (xprt->xpt_flags & ((1<> return true; >> if (xprt->xpt_flags & ((1<> - if (xprt->xpt_ops->xpo_has_wspace(xprt)) >> + if (xprt->xpt_ops->xpo_has_wspace(xprt) && >> + svc_xprt_slots_in_range(xprt)) >> return true; >> trace_svc_xprt_no_write_space(xprt); >> return false; >> @@ -514,8 +547,8 @@ static void svc_xprt_release(struct svc_rqst *rqstp) >> >> rqstp->rq_res.head[0].iov_len = 0; >> svc_reserve(rqstp, 0); >> + svc_xprt_release_slot(rqstp); >> rqstp->rq_xprt = NULL; >> - >> svc_xprt_put(xprt); >> } >> >> @@ -783,7 +816,7 @@ static int svc_handle_xprt(struct svc_rqst *rqstp, struct svc_xprt *xprt) >> svc_add_new_temp_xprt(serv, newxpt); >> else >> module_put(xprt->xpt_class->xcl_owner); >> - } else { >> + } else if (svc_xprt_reserve_slot(rqstp, xprt)) { >> /* XPT_DATA|XPT_DEFERRED case: */ >> dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n", >> rqstp, rqstp->rq_pool->sp_id, xprt, >> -- >> 2.7.4 >