summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/kernel-parameters.txt6
-rw-r--r--include/linux/sunrpc/svc.h1
-rw-r--r--include/linux/sunrpc/svc_xprt.h1
-rw-r--r--net/sunrpc/svc_xprt.c39
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.
3832 using these two parameters to set the minimum and 3832 using these two parameters to set the minimum and
3833 maximum port values. 3833 maximum port values.
3834 3834
3835 sunrpc.svc_rpc_per_connection_limit=
3836 [NFS,SUNRPC]
3837 Limit the number of requests that the server will
3838 process in parallel from a single connection.
3839 The default value is 0 (no limit).
3840
3835 sunrpc.pool_mode= 3841 sunrpc.pool_mode=
3836 [NFS] 3842 [NFS]
3837 Control how the NFS server code allocates CPUs to 3843 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 {
268 * cache pages */ 268 * cache pages */
269#define RQ_VICTIM (5) /* about to be shut down */ 269#define RQ_VICTIM (5) /* about to be shut down */
270#define RQ_BUSY (6) /* request is busy */ 270#define RQ_BUSY (6) /* request is busy */
271#define RQ_DATA (7) /* request has data */
271 unsigned long rq_flags; /* flags field */ 272 unsigned long rq_flags; /* flags field */
272 273
273 void * rq_argp; /* decoded arguments */ 274 void * rq_argp; /* decoded arguments */
diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h
index 79ba50856707..ad899ffed3be 100644
--- a/include/linux/sunrpc/svc_xprt.h
+++ b/include/linux/sunrpc/svc_xprt.h
@@ -69,6 +69,7 @@ struct svc_xprt {
69 69
70 struct svc_serv *xpt_server; /* service for transport */ 70 struct svc_serv *xpt_server; /* service for transport */
71 atomic_t xpt_reserved; /* space on outq that is rsvd */ 71 atomic_t xpt_reserved; /* space on outq that is rsvd */
72 atomic_t xpt_nr_rqsts; /* Number of requests */
72 struct mutex xpt_mutex; /* to serialize sending data */ 73 struct mutex xpt_mutex; /* to serialize sending data */
73 spinlock_t xpt_lock; /* protects sk_deferred 74 spinlock_t xpt_lock; /* protects sk_deferred
74 * and xpt_auth_cache */ 75 * and xpt_auth_cache */
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index e7082a4aeb56..2adc8db6aaf5 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -21,6 +21,10 @@
21 21
22#define RPCDBG_FACILITY RPCDBG_SVCXPRT 22#define RPCDBG_FACILITY RPCDBG_SVCXPRT
23 23
24static unsigned int svc_rpc_per_connection_limit __read_mostly;
25module_param(svc_rpc_per_connection_limit, uint, 0644);
26
27
24static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt); 28static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt);
25static int svc_deferred_recv(struct svc_rqst *rqstp); 29static int svc_deferred_recv(struct svc_rqst *rqstp);
26static struct cache_deferred_req *svc_defer(struct cache_req *req); 30static struct cache_deferred_req *svc_defer(struct cache_req *req);
@@ -329,12 +333,41 @@ char *svc_print_addr(struct svc_rqst *rqstp, char *buf, size_t len)
329} 333}
330EXPORT_SYMBOL_GPL(svc_print_addr); 334EXPORT_SYMBOL_GPL(svc_print_addr);
331 335
336static bool svc_xprt_slots_in_range(struct svc_xprt *xprt)
337{
338 unsigned int limit = svc_rpc_per_connection_limit;
339 int nrqsts = atomic_read(&xprt->xpt_nr_rqsts);
340
341 return limit == 0 || (nrqsts >= 0 && nrqsts < limit);
342}
343
344static bool svc_xprt_reserve_slot(struct svc_rqst *rqstp, struct svc_xprt *xprt)
345{
346 if (!test_bit(RQ_DATA, &rqstp->rq_flags)) {
347 if (!svc_xprt_slots_in_range(xprt))
348 return false;
349 atomic_inc(&xprt->xpt_nr_rqsts);
350 set_bit(RQ_DATA, &rqstp->rq_flags);
351 }
352 return true;
353}
354
355static void svc_xprt_release_slot(struct svc_rqst *rqstp)
356{
357 struct svc_xprt *xprt = rqstp->rq_xprt;
358 if (test_and_clear_bit(RQ_DATA, &rqstp->rq_flags)) {
359 atomic_dec(&xprt->xpt_nr_rqsts);
360 svc_xprt_enqueue(xprt);
361 }
362}
363
332static bool svc_xprt_has_something_to_do(struct svc_xprt *xprt) 364static bool svc_xprt_has_something_to_do(struct svc_xprt *xprt)
333{ 365{
334 if (xprt->xpt_flags & ((1<<XPT_CONN)|(1<<XPT_CLOSE))) 366 if (xprt->xpt_flags & ((1<<XPT_CONN)|(1<<XPT_CLOSE)))
335 return true; 367 return true;
336 if (xprt->xpt_flags & ((1<<XPT_DATA)|(1<<XPT_DEFERRED))) { 368 if (xprt->xpt_flags & ((1<<XPT_DATA)|(1<<XPT_DEFERRED))) {
337 if (xprt->xpt_ops->xpo_has_wspace(xprt)) 369 if (xprt->xpt_ops->xpo_has_wspace(xprt) &&
370 svc_xprt_slots_in_range(xprt))
338 return true; 371 return true;
339 trace_svc_xprt_no_write_space(xprt); 372 trace_svc_xprt_no_write_space(xprt);
340 return false; 373 return false;
@@ -516,8 +549,8 @@ static void svc_xprt_release(struct svc_rqst *rqstp)
516 549
517 rqstp->rq_res.head[0].iov_len = 0; 550 rqstp->rq_res.head[0].iov_len = 0;
518 svc_reserve(rqstp, 0); 551 svc_reserve(rqstp, 0);
552 svc_xprt_release_slot(rqstp);
519 rqstp->rq_xprt = NULL; 553 rqstp->rq_xprt = NULL;
520
521 svc_xprt_put(xprt); 554 svc_xprt_put(xprt);
522} 555}
523 556
@@ -785,7 +818,7 @@ static int svc_handle_xprt(struct svc_rqst *rqstp, struct svc_xprt *xprt)
785 svc_add_new_temp_xprt(serv, newxpt); 818 svc_add_new_temp_xprt(serv, newxpt);
786 else 819 else
787 module_put(xprt->xpt_class->xcl_owner); 820 module_put(xprt->xpt_class->xcl_owner);
788 } else { 821 } else if (svc_xprt_reserve_slot(rqstp, xprt)) {
789 /* XPT_DATA|XPT_DEFERRED case: */ 822 /* XPT_DATA|XPT_DEFERRED case: */
790 dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n", 823 dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n",
791 rqstp, rqstp->rq_pool->sp_id, xprt, 824 rqstp, rqstp->rq_pool->sp_id, xprt,