diff options
| author | Greg Banks <gnb@melbourne.sgi.com> | 2006-10-02 05:17:59 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-02 10:57:19 -0400 |
| commit | a74554429eada89a7ddb47317e6a2968d03e41a2 (patch) | |
| tree | 0ebf1550dd1fdafd2900af44ea85d75831172fa3 /net | |
| parent | 9a24ab5749a31aa10ee60d9310ad72f24d7c38ab (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>
Diffstat (limited to 'net')
| -rw-r--r-- | net/sunrpc/sunrpc_syms.c | 2 | ||||
| -rw-r--r-- | net/sunrpc/svc.c | 139 |
2 files changed, 138 insertions, 3 deletions
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 */ |
| 71 | EXPORT_SYMBOL(svc_create); | 71 | EXPORT_SYMBOL(svc_create); |
| 72 | EXPORT_SYMBOL(svc_create_thread); | 72 | EXPORT_SYMBOL(svc_create_thread); |
| 73 | EXPORT_SYMBOL(svc_create_pooled); | ||
| 74 | EXPORT_SYMBOL(svc_set_num_threads); | ||
| 73 | EXPORT_SYMBOL(svc_exit_thread); | 75 | EXPORT_SYMBOL(svc_exit_thread); |
| 74 | EXPORT_SYMBOL(svc_destroy); | 76 | EXPORT_SYMBOL(svc_destroy); |
| 75 | EXPORT_SYMBOL(svc_drop); | 77 | EXPORT_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 | */ |
| 28 | struct svc_serv * | 30 | static struct svc_serv * |
| 29 | svc_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 | ||
| 95 | struct svc_serv * | ||
| 96 | svc_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 | |||
| 102 | struct svc_serv * | ||
| 103 | svc_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 | */ | ||
| 263 | static inline struct svc_pool * | ||
| 264 | choose_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 | */ | ||
| 275 | static inline struct task_struct * | ||
| 276 | choose_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 | |||
| 295 | found_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 | */ | ||
| 326 | int | ||
| 327 | svc_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 | */ |
| 234 | void | 366 | void |
| @@ -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); |
