aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Banks <gnb@melbourne.sgi.com>2006-10-02 05:17:59 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-02 10:57:19 -0400
commita74554429eada89a7ddb47317e6a2968d03e41a2 (patch)
tree0ebf1550dd1fdafd2900af44ea85d75831172fa3
parent9a24ab5749a31aa10ee60d9310ad72f24d7c38ab (diff)
[PATCH] knfsd: add svc_set_num_threads
Currently knfsd keeps its own list of all nfsd threads in nfssvc.c; add a new way of managing the list of all threads in a svc_serv. Add svc_create_pooled() to allow creation of a svc_serv whose threads are managed by the sunrpc code. Add svc_set_num_threads() to manage the number of threads in a service, either per-pool or globally across the service. Signed-off-by: Greg Banks <gnb@melbourne.sgi.com> Signed-off-by: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--include/linux/sunrpc/svc.h21
-rw-r--r--net/sunrpc/sunrpc_syms.c2
-rw-r--r--net/sunrpc/svc.c139
3 files changed, 154 insertions, 8 deletions
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 54d8e7bc2341..f2eeb833e7d8 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -17,6 +17,10 @@
17#include <linux/wait.h> 17#include <linux/wait.h>
18#include <linux/mm.h> 18#include <linux/mm.h>
19 19
20/*
21 * This is the RPC server thread function prototype
22 */
23typedef void (*svc_thread_fn)(struct svc_rqst *);
20 24
21/* 25/*
22 * 26 *
@@ -34,6 +38,7 @@ struct svc_pool {
34 struct list_head sp_threads; /* idle server threads */ 38 struct list_head sp_threads; /* idle server threads */
35 struct list_head sp_sockets; /* pending sockets */ 39 struct list_head sp_sockets; /* pending sockets */
36 unsigned int sp_nrthreads; /* # of threads in pool */ 40 unsigned int sp_nrthreads; /* # of threads in pool */
41 struct list_head sp_all_threads; /* all server threads */
37} ____cacheline_aligned_in_smp; 42} ____cacheline_aligned_in_smp;
38 43
39/* 44/*
@@ -68,6 +73,11 @@ struct svc_serv {
68 /* Callback to use when last thread 73 /* Callback to use when last thread
69 * exits. 74 * exits.
70 */ 75 */
76
77 struct module * sv_module; /* optional module to count when
78 * adding threads */
79 svc_thread_fn sv_function; /* main function for threads */
80 int sv_kill_signal; /* signal to kill threads */
71}; 81};
72 82
73/* 83/*
@@ -164,6 +174,7 @@ static inline void svc_putu32(struct kvec *iov, __be32 val)
164 */ 174 */
165struct svc_rqst { 175struct svc_rqst {
166 struct list_head rq_list; /* idle list */ 176 struct list_head rq_list; /* idle list */
177 struct list_head rq_all; /* all threads list */
167 struct svc_sock * rq_sock; /* socket */ 178 struct svc_sock * rq_sock; /* socket */
168 struct sockaddr_in rq_addr; /* peer address */ 179 struct sockaddr_in rq_addr; /* peer address */
169 int rq_addrlen; 180 int rq_addrlen;
@@ -218,6 +229,7 @@ struct svc_rqst {
218 * to prevent encrypting page 229 * to prevent encrypting page
219 * cache pages */ 230 * cache pages */
220 wait_queue_head_t rq_wait; /* synchronization */ 231 wait_queue_head_t rq_wait; /* synchronization */
232 struct task_struct *rq_task; /* service thread */
221}; 233};
222 234
223/* 235/*
@@ -359,17 +371,16 @@ struct svc_procedure {
359}; 371};
360 372
361/* 373/*
362 * This is the RPC server thread function prototype
363 */
364typedef void (*svc_thread_fn)(struct svc_rqst *);
365
366/*
367 * Function prototypes. 374 * Function prototypes.
368 */ 375 */
369struct svc_serv * svc_create(struct svc_program *, unsigned int, 376struct svc_serv * svc_create(struct svc_program *, unsigned int,
370 void (*shutdown)(struct svc_serv*)); 377 void (*shutdown)(struct svc_serv*));
371int svc_create_thread(svc_thread_fn, struct svc_serv *); 378int svc_create_thread(svc_thread_fn, struct svc_serv *);
372void svc_exit_thread(struct svc_rqst *); 379void svc_exit_thread(struct svc_rqst *);
380struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int,
381 void (*shutdown)(struct svc_serv*),
382 svc_thread_fn, int sig, struct module *);
383int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
373void svc_destroy(struct svc_serv *); 384void svc_destroy(struct svc_serv *);
374int svc_process(struct svc_rqst *); 385int svc_process(struct svc_rqst *);
375int svc_register(struct svc_serv *, int, unsigned short); 386int svc_register(struct svc_serv *, int, unsigned short);
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index 26c0531d7e25..192dff5dabcb 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -70,6 +70,8 @@ EXPORT_SYMBOL(put_rpccred);
70/* RPC server stuff */ 70/* RPC server stuff */
71EXPORT_SYMBOL(svc_create); 71EXPORT_SYMBOL(svc_create);
72EXPORT_SYMBOL(svc_create_thread); 72EXPORT_SYMBOL(svc_create_thread);
73EXPORT_SYMBOL(svc_create_pooled);
74EXPORT_SYMBOL(svc_set_num_threads);
73EXPORT_SYMBOL(svc_exit_thread); 75EXPORT_SYMBOL(svc_exit_thread);
74EXPORT_SYMBOL(svc_destroy); 76EXPORT_SYMBOL(svc_destroy);
75EXPORT_SYMBOL(svc_drop); 77EXPORT_SYMBOL(svc_drop);
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 6750cd474f84..8c75eec4fd6a 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -12,6 +12,8 @@
12#include <linux/net.h> 12#include <linux/net.h>
13#include <linux/in.h> 13#include <linux/in.h>
14#include <linux/mm.h> 14#include <linux/mm.h>
15#include <linux/interrupt.h>
16#include <linux/module.h>
15 17
16#include <linux/sunrpc/types.h> 18#include <linux/sunrpc/types.h>
17#include <linux/sunrpc/xdr.h> 19#include <linux/sunrpc/xdr.h>
@@ -25,8 +27,8 @@
25/* 27/*
26 * Create an RPC service 28 * Create an RPC service
27 */ 29 */
28struct svc_serv * 30static struct svc_serv *
29svc_create(struct svc_program *prog, unsigned int bufsize, 31__svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
30 void (*shutdown)(struct svc_serv *serv)) 32 void (*shutdown)(struct svc_serv *serv))
31{ 33{
32 struct svc_serv *serv; 34 struct svc_serv *serv;
@@ -61,7 +63,7 @@ svc_create(struct svc_program *prog, unsigned int bufsize,
61 init_timer(&serv->sv_temptimer); 63 init_timer(&serv->sv_temptimer);
62 spin_lock_init(&serv->sv_lock); 64 spin_lock_init(&serv->sv_lock);
63 65
64 serv->sv_nrpools = 1; 66 serv->sv_nrpools = npools;
65 serv->sv_pools = 67 serv->sv_pools =
66 kcalloc(sizeof(struct svc_pool), serv->sv_nrpools, 68 kcalloc(sizeof(struct svc_pool), serv->sv_nrpools,
67 GFP_KERNEL); 69 GFP_KERNEL);
@@ -79,6 +81,7 @@ svc_create(struct svc_program *prog, unsigned int bufsize,
79 pool->sp_id = i; 81 pool->sp_id = i;
80 INIT_LIST_HEAD(&pool->sp_threads); 82 INIT_LIST_HEAD(&pool->sp_threads);
81 INIT_LIST_HEAD(&pool->sp_sockets); 83 INIT_LIST_HEAD(&pool->sp_sockets);
84 INIT_LIST_HEAD(&pool->sp_all_threads);
82 spin_lock_init(&pool->sp_lock); 85 spin_lock_init(&pool->sp_lock);
83 } 86 }
84 87
@@ -89,6 +92,31 @@ svc_create(struct svc_program *prog, unsigned int bufsize,
89 return serv; 92 return serv;
90} 93}
91 94
95struct svc_serv *
96svc_create(struct svc_program *prog, unsigned int bufsize,
97 void (*shutdown)(struct svc_serv *serv))
98{
99 return __svc_create(prog, bufsize, /*npools*/1, shutdown);
100}
101
102struct svc_serv *
103svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
104 void (*shutdown)(struct svc_serv *serv),
105 svc_thread_fn func, int sig, struct module *mod)
106{
107 struct svc_serv *serv;
108
109 serv = __svc_create(prog, bufsize, /*npools*/1, shutdown);
110
111 if (serv != NULL) {
112 serv->sv_function = func;
113 serv->sv_kill_signal = sig;
114 serv->sv_module = mod;
115 }
116
117 return serv;
118}
119
92/* 120/*
93 * Destroy an RPC service. Should be called with the BKL held 121 * Destroy an RPC service. Should be called with the BKL held
94 */ 122 */
@@ -203,6 +231,7 @@ __svc_create_thread(svc_thread_fn func, struct svc_serv *serv,
203 serv->sv_nrthreads++; 231 serv->sv_nrthreads++;
204 spin_lock_bh(&pool->sp_lock); 232 spin_lock_bh(&pool->sp_lock);
205 pool->sp_nrthreads++; 233 pool->sp_nrthreads++;
234 list_add(&rqstp->rq_all, &pool->sp_all_threads);
206 spin_unlock_bh(&pool->sp_lock); 235 spin_unlock_bh(&pool->sp_lock);
207 rqstp->rq_server = serv; 236 rqstp->rq_server = serv;
208 rqstp->rq_pool = pool; 237 rqstp->rq_pool = pool;
@@ -229,6 +258,109 @@ svc_create_thread(svc_thread_fn func, struct svc_serv *serv)
229} 258}
230 259
231/* 260/*
261 * Choose a pool in which to create a new thread, for svc_set_num_threads
262 */
263static inline struct svc_pool *
264choose_pool(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state)
265{
266 if (pool != NULL)
267 return pool;
268
269 return &serv->sv_pools[(*state)++ % serv->sv_nrpools];
270}
271
272/*
273 * Choose a thread to kill, for svc_set_num_threads
274 */
275static inline struct task_struct *
276choose_victim(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state)
277{
278 unsigned int i;
279 struct task_struct *task = NULL;
280
281 if (pool != NULL) {
282 spin_lock_bh(&pool->sp_lock);
283 } else {
284 /* choose a pool in round-robin fashion */
285 for (i = 0; i < serv->sv_nrpools; i++) {
286 pool = &serv->sv_pools[--(*state) % serv->sv_nrpools];
287 spin_lock_bh(&pool->sp_lock);
288 if (!list_empty(&pool->sp_all_threads))
289 goto found_pool;
290 spin_unlock_bh(&pool->sp_lock);
291 }
292 return NULL;
293 }
294
295found_pool:
296 if (!list_empty(&pool->sp_all_threads)) {
297 struct svc_rqst *rqstp;
298
299 /*
300 * Remove from the pool->sp_all_threads list
301 * so we don't try to kill it again.
302 */
303 rqstp = list_entry(pool->sp_all_threads.next, struct svc_rqst, rq_all);
304 list_del_init(&rqstp->rq_all);
305 task = rqstp->rq_task;
306 }
307 spin_unlock_bh(&pool->sp_lock);
308
309 return task;
310}
311
312/*
313 * Create or destroy enough new threads to make the number
314 * of threads the given number. If `pool' is non-NULL, applies
315 * only to threads in that pool, otherwise round-robins between
316 * all pools. Must be called with a svc_get() reference and
317 * the BKL held.
318 *
319 * Destroying threads relies on the service threads filling in
320 * rqstp->rq_task, which only the nfs ones do. Assumes the serv
321 * has been created using svc_create_pooled().
322 *
323 * Based on code that used to be in nfsd_svc() but tweaked
324 * to be pool-aware.
325 */
326int
327svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
328{
329 struct task_struct *victim;
330 int error = 0;
331 unsigned int state = serv->sv_nrthreads-1;
332
333 if (pool == NULL) {
334 /* The -1 assumes caller has done a svc_get() */
335 nrservs -= (serv->sv_nrthreads-1);
336 } else {
337 spin_lock_bh(&pool->sp_lock);
338 nrservs -= pool->sp_nrthreads;
339 spin_unlock_bh(&pool->sp_lock);
340 }
341
342 /* create new threads */
343 while (nrservs > 0) {
344 nrservs--;
345 __module_get(serv->sv_module);
346 error = __svc_create_thread(serv->sv_function, serv,
347 choose_pool(serv, pool, &state));
348 if (error < 0) {
349 module_put(serv->sv_module);
350 break;
351 }
352 }
353 /* destroy old threads */
354 while (nrservs < 0 &&
355 (victim = choose_victim(serv, pool, &state)) != NULL) {
356 send_sig(serv->sv_kill_signal, victim, 1);
357 nrservs++;
358 }
359
360 return error;
361}
362
363/*
232 * Called from a server thread as it's exiting. Caller must hold BKL. 364 * Called from a server thread as it's exiting. Caller must hold BKL.
233 */ 365 */
234void 366void
@@ -244,6 +376,7 @@ svc_exit_thread(struct svc_rqst *rqstp)
244 376
245 spin_lock_bh(&pool->sp_lock); 377 spin_lock_bh(&pool->sp_lock);
246 pool->sp_nrthreads--; 378 pool->sp_nrthreads--;
379 list_del(&rqstp->rq_all);
247 spin_unlock_bh(&pool->sp_lock); 380 spin_unlock_bh(&pool->sp_lock);
248 381
249 kfree(rqstp); 382 kfree(rqstp);