Skip to content

Commit

Permalink
[PATCH] knfsd: split svc_serv into pools
Browse files Browse the repository at this point in the history
Split out the list of idle threads and pending sockets from svc_serv into a
new svc_pool structure, and allocate a fixed number (in this patch, 1) of
pools per svc_serv.  The new structure contains a lock which takes over
several of the duties of svc_serv->sv_lock, which is now relegated to
protecting only sv_tempsocks, sv_permsocks, and sv_tmpcnt in svc_serv.

The point is to move the hottest fields out of svc_serv and into svc_pool,
allowing a following patch to arrange for a svc_pool per NUMA node or per CPU.
 This is a major step towards making the NFS server NUMA-friendly.

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>
  • Loading branch information
Greg Banks authored and Linus Torvalds committed Oct 2, 2006
1 parent c081a0c commit 3262c81
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 54 deletions.
25 changes: 23 additions & 2 deletions include/linux/sunrpc/svc.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,25 @@
#include <linux/wait.h>
#include <linux/mm.h>


/*
*
* RPC service thread pool.
*
* Pool of threads and temporary sockets. Generally there is only
* a single one of these per RPC service, but on NUMA machines those
* services that can benefit from it (i.e. nfs but not lockd) will
* have one pool per NUMA node. This optimisation reduces cross-
* node traffic on multi-node NUMA NFS servers.
*/
struct svc_pool {
unsigned int sp_id; /* pool id; also node id on NUMA */
spinlock_t sp_lock; /* protects all fields */
struct list_head sp_threads; /* idle server threads */
struct list_head sp_sockets; /* pending sockets */
unsigned int sp_nrthreads; /* # of threads in pool */
} ____cacheline_aligned_in_smp;

/*
* RPC service.
*
Expand All @@ -28,8 +47,6 @@
* We currently do not support more than one RPC program per daemon.
*/
struct svc_serv {
struct list_head sv_threads; /* idle server threads */
struct list_head sv_sockets; /* pending sockets */
struct svc_program * sv_program; /* RPC program */
struct svc_stat * sv_stats; /* RPC statistics */
spinlock_t sv_lock;
Expand All @@ -44,6 +61,9 @@ struct svc_serv {

char * sv_name; /* service name */

unsigned int sv_nrpools; /* number of thread pools */
struct svc_pool * sv_pools; /* array of thread pools */

void (*sv_shutdown)(struct svc_serv *serv);
/* Callback to use when last thread
* exits.
Expand Down Expand Up @@ -138,6 +158,7 @@ struct svc_rqst {
int rq_addrlen;

struct svc_serv * rq_server; /* RPC service definition */
struct svc_pool * rq_pool; /* thread pool */
struct svc_procedure * rq_procinfo; /* procedure info */
struct auth_ops * rq_authop; /* authentication flavour */
struct svc_cred rq_cred; /* auth info */
Expand Down
1 change: 1 addition & 0 deletions include/linux/sunrpc/svcsock.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ struct svc_sock {
struct socket * sk_sock; /* berkeley socket layer */
struct sock * sk_sk; /* INET layer */

struct svc_pool * sk_pool; /* current pool iff queued */
struct svc_serv * sk_server; /* service for this socket */
atomic_t sk_inuse; /* use count */
unsigned long sk_flags;
Expand Down
56 changes: 49 additions & 7 deletions net/sunrpc/svc.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ svc_create(struct svc_program *prog, unsigned int bufsize,
struct svc_serv *serv;
int vers;
unsigned int xdrsize;
unsigned int i;

if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL)))
return NULL;
Expand All @@ -55,21 +56,41 @@ svc_create(struct svc_program *prog, unsigned int bufsize,
prog = prog->pg_next;
}
serv->sv_xdrsize = xdrsize;
INIT_LIST_HEAD(&serv->sv_threads);
INIT_LIST_HEAD(&serv->sv_sockets);
INIT_LIST_HEAD(&serv->sv_tempsocks);
INIT_LIST_HEAD(&serv->sv_permsocks);
init_timer(&serv->sv_temptimer);
spin_lock_init(&serv->sv_lock);

serv->sv_nrpools = 1;
serv->sv_pools =
kcalloc(sizeof(struct svc_pool), serv->sv_nrpools,
GFP_KERNEL);
if (!serv->sv_pools) {
kfree(serv);
return NULL;
}

for (i = 0; i < serv->sv_nrpools; i++) {
struct svc_pool *pool = &serv->sv_pools[i];

dprintk("initialising pool %u for %s\n",
i, serv->sv_name);

pool->sp_id = i;
INIT_LIST_HEAD(&pool->sp_threads);
INIT_LIST_HEAD(&pool->sp_sockets);
spin_lock_init(&pool->sp_lock);
}


/* Remove any stale portmap registrations */
svc_register(serv, 0, 0);

return serv;
}

/*
* Destroy an RPC service
* Destroy an RPC service. Should be called with the BKL held
*/
void
svc_destroy(struct svc_serv *serv)
Expand Down Expand Up @@ -110,6 +131,7 @@ svc_destroy(struct svc_serv *serv)

/* Unregister service with the portmapper */
svc_register(serv, 0, 0);
kfree(serv->sv_pools);
kfree(serv);
}

Expand Down Expand Up @@ -158,10 +180,11 @@ svc_release_buffer(struct svc_rqst *rqstp)
}

/*
* Create a server thread
* Create a thread in the given pool. Caller must hold BKL.
*/
int
svc_create_thread(svc_thread_fn func, struct svc_serv *serv)
static int
__svc_create_thread(svc_thread_fn func, struct svc_serv *serv,
struct svc_pool *pool)
{
struct svc_rqst *rqstp;
int error = -ENOMEM;
Expand All @@ -178,7 +201,11 @@ svc_create_thread(svc_thread_fn func, struct svc_serv *serv)
goto out_thread;

serv->sv_nrthreads++;
spin_lock_bh(&pool->sp_lock);
pool->sp_nrthreads++;
spin_unlock_bh(&pool->sp_lock);
rqstp->rq_server = serv;
rqstp->rq_pool = pool;
error = kernel_thread((int (*)(void *)) func, rqstp, 0);
if (error < 0)
goto out_thread;
Expand All @@ -193,17 +220,32 @@ svc_create_thread(svc_thread_fn func, struct svc_serv *serv)
}

/*
* Destroy an RPC server thread
* Create a thread in the default pool. Caller must hold BKL.
*/
int
svc_create_thread(svc_thread_fn func, struct svc_serv *serv)
{
return __svc_create_thread(func, serv, &serv->sv_pools[0]);
}

/*
* Called from a server thread as it's exiting. Caller must hold BKL.
*/
void
svc_exit_thread(struct svc_rqst *rqstp)
{
struct svc_serv *serv = rqstp->rq_server;
struct svc_pool *pool = rqstp->rq_pool;

svc_release_buffer(rqstp);
kfree(rqstp->rq_resp);
kfree(rqstp->rq_argp);
kfree(rqstp->rq_auth_data);

spin_lock_bh(&pool->sp_lock);
pool->sp_nrthreads--;
spin_unlock_bh(&pool->sp_lock);

kfree(rqstp);

/* Release the server */
Expand Down
Loading

0 comments on commit 3262c81

Please sign in to comment.