diff options
author | Jeff Layton <jlayton@redhat.com> | 2008-01-29 10:30:54 -0500 |
---|---|---|
committer | J. Bruce Fields <bfields@citi.umich.edu> | 2008-02-01 16:42:15 -0500 |
commit | 0113ab34644649aceaac37ef4b7e5c7d5c183be3 (patch) | |
tree | b0b1cde6e10b550bf4b9fcc523d855a6a1fade9d | |
parent | 87d26ea7771ad637035e6bd5a2700d81ee9162da (diff) |
SUNRPC: spin svc_rqst initialization to its own function
Move the initialzation in __svc_create_thread that happens prior to
thread creation to a new function. Export the function to allow
services to have better control over the svc_rqst structs.
Also rearrange the rqstp initialization to prevent NULL pointer
dereferences in svc_exit_thread in case allocations fail.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Reviewed-by: NeilBrown <neilb@suse.de>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
-rw-r--r-- | include/linux/sunrpc/svc.h | 2 | ||||
-rw-r--r-- | net/sunrpc/svc.c | 59 |
2 files changed, 44 insertions, 17 deletions
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 742ab461d842..64c771056187 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h | |||
@@ -384,6 +384,8 @@ struct svc_procedure { | |||
384 | */ | 384 | */ |
385 | struct svc_serv * svc_create(struct svc_program *, unsigned int, | 385 | struct svc_serv * svc_create(struct svc_program *, unsigned int, |
386 | void (*shutdown)(struct svc_serv*)); | 386 | void (*shutdown)(struct svc_serv*)); |
387 | struct svc_rqst *svc_prepare_thread(struct svc_serv *serv, | ||
388 | struct svc_pool *pool); | ||
387 | int svc_create_thread(svc_thread_fn, struct svc_serv *); | 389 | int svc_create_thread(svc_thread_fn, struct svc_serv *); |
388 | void svc_exit_thread(struct svc_rqst *); | 390 | void svc_exit_thread(struct svc_rqst *); |
389 | struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int, | 391 | struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int, |
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index a5eb2d6b14ae..b76963d52657 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c | |||
@@ -531,31 +531,17 @@ svc_release_buffer(struct svc_rqst *rqstp) | |||
531 | put_page(rqstp->rq_pages[i]); | 531 | put_page(rqstp->rq_pages[i]); |
532 | } | 532 | } |
533 | 533 | ||
534 | /* | 534 | struct svc_rqst * |
535 | * Create a thread in the given pool. Caller must hold BKL. | 535 | svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool) |
536 | * On a NUMA or SMP machine, with a multi-pool serv, the thread | ||
537 | * will be restricted to run on the cpus belonging to the pool. | ||
538 | */ | ||
539 | static int | ||
540 | __svc_create_thread(svc_thread_fn func, struct svc_serv *serv, | ||
541 | struct svc_pool *pool) | ||
542 | { | 536 | { |
543 | struct svc_rqst *rqstp; | 537 | struct svc_rqst *rqstp; |
544 | int error = -ENOMEM; | ||
545 | int have_oldmask = 0; | ||
546 | cpumask_t oldmask; | ||
547 | 538 | ||
548 | rqstp = kzalloc(sizeof(*rqstp), GFP_KERNEL); | 539 | rqstp = kzalloc(sizeof(*rqstp), GFP_KERNEL); |
549 | if (!rqstp) | 540 | if (!rqstp) |
550 | goto out; | 541 | goto out_enomem; |
551 | 542 | ||
552 | init_waitqueue_head(&rqstp->rq_wait); | 543 | init_waitqueue_head(&rqstp->rq_wait); |
553 | 544 | ||
554 | if (!(rqstp->rq_argp = kmalloc(serv->sv_xdrsize, GFP_KERNEL)) | ||
555 | || !(rqstp->rq_resp = kmalloc(serv->sv_xdrsize, GFP_KERNEL)) | ||
556 | || !svc_init_buffer(rqstp, serv->sv_max_mesg)) | ||
557 | goto out_thread; | ||
558 | |||
559 | serv->sv_nrthreads++; | 545 | serv->sv_nrthreads++; |
560 | spin_lock_bh(&pool->sp_lock); | 546 | spin_lock_bh(&pool->sp_lock); |
561 | pool->sp_nrthreads++; | 547 | pool->sp_nrthreads++; |
@@ -564,6 +550,45 @@ __svc_create_thread(svc_thread_fn func, struct svc_serv *serv, | |||
564 | rqstp->rq_server = serv; | 550 | rqstp->rq_server = serv; |
565 | rqstp->rq_pool = pool; | 551 | rqstp->rq_pool = pool; |
566 | 552 | ||
553 | rqstp->rq_argp = kmalloc(serv->sv_xdrsize, GFP_KERNEL); | ||
554 | if (!rqstp->rq_argp) | ||
555 | goto out_thread; | ||
556 | |||
557 | rqstp->rq_resp = kmalloc(serv->sv_xdrsize, GFP_KERNEL); | ||
558 | if (!rqstp->rq_resp) | ||
559 | goto out_thread; | ||
560 | |||
561 | if (!svc_init_buffer(rqstp, serv->sv_max_mesg)) | ||
562 | goto out_thread; | ||
563 | |||
564 | return rqstp; | ||
565 | out_thread: | ||
566 | svc_exit_thread(rqstp); | ||
567 | out_enomem: | ||
568 | return ERR_PTR(-ENOMEM); | ||
569 | } | ||
570 | EXPORT_SYMBOL(svc_prepare_thread); | ||
571 | |||
572 | /* | ||
573 | * Create a thread in the given pool. Caller must hold BKL. | ||
574 | * On a NUMA or SMP machine, with a multi-pool serv, the thread | ||
575 | * will be restricted to run on the cpus belonging to the pool. | ||
576 | */ | ||
577 | static int | ||
578 | __svc_create_thread(svc_thread_fn func, struct svc_serv *serv, | ||
579 | struct svc_pool *pool) | ||
580 | { | ||
581 | struct svc_rqst *rqstp; | ||
582 | int error = -ENOMEM; | ||
583 | int have_oldmask = 0; | ||
584 | cpumask_t oldmask; | ||
585 | |||
586 | rqstp = svc_prepare_thread(serv, pool); | ||
587 | if (IS_ERR(rqstp)) { | ||
588 | error = PTR_ERR(rqstp); | ||
589 | goto out; | ||
590 | } | ||
591 | |||
567 | if (serv->sv_nrpools > 1) | 592 | if (serv->sv_nrpools > 1) |
568 | have_oldmask = svc_pool_map_set_cpumask(pool->sp_id, &oldmask); | 593 | have_oldmask = svc_pool_map_set_cpumask(pool->sp_id, &oldmask); |
569 | 594 | ||