aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2006-10-02 05:17:44 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-02 10:57:17 -0400
commitbc591ccff27e6a85d3a0d6fcb16cfadcc45267a8 (patch)
tree20692a805b32ce5541f7175192f8ab81975434ec
parent40f10522173c34e56cb9bf2fd37c62f69a427f1b (diff)
[PATCH] knfsd: add a callback for when last rpc thread finishes
nfsd has some cleanup that it wants to do when the last thread exits, and there will shortly be some more. So collect this all into one place and define a callback for an rpc service to call when the service is about to be destroyed. [akpm@osdl.org: cleanups, build fix] 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--fs/lockd/svc.c2
-rw-r--r--fs/nfs/callback.c2
-rw-r--r--fs/nfsd/nfssvc.c40
-rw-r--r--include/linux/sunrpc/svc.h8
-rw-r--r--net/sunrpc/svc.c7
5 files changed, 33 insertions, 26 deletions
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 9a991b52c647..13feba45030e 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -236,7 +236,7 @@ lockd_up(void)
236 "lockd_up: no pid, %d users??\n", nlmsvc_users); 236 "lockd_up: no pid, %d users??\n", nlmsvc_users);
237 237
238 error = -ENOMEM; 238 error = -ENOMEM;
239 serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE); 239 serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, NULL);
240 if (!serv) { 240 if (!serv) {
241 printk(KERN_WARNING "lockd_up: create service failed\n"); 241 printk(KERN_WARNING "lockd_up: create service failed\n");
242 goto out; 242 goto out;
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index a3ee11364db0..e244cdc7afab 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -116,7 +116,7 @@ int nfs_callback_up(void)
116 goto out; 116 goto out;
117 init_completion(&nfs_callback_info.started); 117 init_completion(&nfs_callback_info.started);
118 init_completion(&nfs_callback_info.stopped); 118 init_completion(&nfs_callback_info.stopped);
119 serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE); 119 serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL);
120 ret = -ENOMEM; 120 ret = -ENOMEM;
121 if (!serv) 121 if (!serv)
122 goto out_err; 122 goto out_err;
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index ec1decf29bab..c52c99964a4c 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -130,11 +130,25 @@ int nfsd_nrthreads(void)
130 return nfsd_serv->sv_nrthreads; 130 return nfsd_serv->sv_nrthreads;
131} 131}
132 132
133static int killsig; /* signal that was used to kill last nfsd */
134static void nfsd_last_thread(struct svc_serv *serv)
135{
136 /* When last nfsd thread exits we need to do some clean-up */
137 nfsd_serv = NULL;
138 nfsd_racache_shutdown();
139 nfs4_state_shutdown();
140
141 printk(KERN_WARNING "nfsd: last server has exited\n");
142 if (killsig != SIG_NOCLEAN) {
143 printk(KERN_WARNING "nfsd: unexporting all filesystems\n");
144 nfsd_export_flush();
145 }
146}
133int 147int
134nfsd_svc(unsigned short port, int nrservs) 148nfsd_svc(unsigned short port, int nrservs)
135{ 149{
136 int error; 150 int error;
137 int none_left, found_one, i; 151 int found_one, i;
138 struct list_head *victim; 152 struct list_head *victim;
139 153
140 lock_kernel(); 154 lock_kernel();
@@ -197,7 +211,8 @@ nfsd_svc(unsigned short port, int nrservs)
197 211
198 atomic_set(&nfsd_busy, 0); 212 atomic_set(&nfsd_busy, 0);
199 error = -ENOMEM; 213 error = -ENOMEM;
200 nfsd_serv = svc_create(&nfsd_program, NFSD_BUFSIZE); 214 nfsd_serv = svc_create(&nfsd_program, NFSD_BUFSIZE,
215 nfsd_last_thread);
201 if (nfsd_serv == NULL) 216 if (nfsd_serv == NULL)
202 goto out; 217 goto out;
203 error = svc_makesock(nfsd_serv, IPPROTO_UDP, port); 218 error = svc_makesock(nfsd_serv, IPPROTO_UDP, port);
@@ -231,13 +246,7 @@ nfsd_svc(unsigned short port, int nrservs)
231 nrservs++; 246 nrservs++;
232 } 247 }
233 failure: 248 failure:
234 none_left = (nfsd_serv->sv_nrthreads == 1);
235 svc_destroy(nfsd_serv); /* Release server */ 249 svc_destroy(nfsd_serv); /* Release server */
236 if (none_left) {
237 nfsd_serv = NULL;
238 nfsd_racache_shutdown();
239 nfs4_state_shutdown();
240 }
241 out: 250 out:
242 unlock_kernel(); 251 unlock_kernel();
243 return error; 252 return error;
@@ -353,7 +362,7 @@ nfsd(struct svc_rqst *rqstp)
353 if (sigismember(&current->pending.signal, signo) && 362 if (sigismember(&current->pending.signal, signo) &&
354 !sigismember(&current->blocked, signo)) 363 !sigismember(&current->blocked, signo))
355 break; 364 break;
356 err = signo; 365 killsig = signo;
357 } 366 }
358 /* Clear signals before calling lockd_down() and svc_exit_thread() */ 367 /* Clear signals before calling lockd_down() and svc_exit_thread() */
359 flush_signals(current); 368 flush_signals(current);
@@ -362,19 +371,6 @@ nfsd(struct svc_rqst *rqstp)
362 371
363 /* Release lockd */ 372 /* Release lockd */
364 lockd_down(); 373 lockd_down();
365
366 /* Check if this is last thread */
367 if (serv->sv_nrthreads==1) {
368
369 printk(KERN_WARNING "nfsd: last server has exited\n");
370 if (err != SIG_NOCLEAN) {
371 printk(KERN_WARNING "nfsd: unexporting all filesystems\n");
372 nfsd_export_flush();
373 }
374 nfsd_serv = NULL;
375 nfsd_racache_shutdown(); /* release read-ahead cache */
376 nfs4_state_shutdown();
377 }
378 list_del(&me.list); 374 list_del(&me.list);
379 nfsdstats.th_cnt --; 375 nfsdstats.th_cnt --;
380 376
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 73140ee5c638..bff5e9b486c2 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -42,6 +42,11 @@ struct svc_serv {
42 int sv_tmpcnt; /* count of temporary sockets */ 42 int sv_tmpcnt; /* count of temporary sockets */
43 43
44 char * sv_name; /* service name */ 44 char * sv_name; /* service name */
45
46 void (*sv_shutdown)(struct svc_serv *serv);
47 /* Callback to use when last thread
48 * exits.
49 */
45}; 50};
46 51
47/* 52/*
@@ -328,7 +333,8 @@ typedef void (*svc_thread_fn)(struct svc_rqst *);
328/* 333/*
329 * Function prototypes. 334 * Function prototypes.
330 */ 335 */
331struct svc_serv * svc_create(struct svc_program *, unsigned int); 336struct svc_serv * svc_create(struct svc_program *, unsigned int,
337 void (*shutdown)(struct svc_serv*));
332int svc_create_thread(svc_thread_fn, struct svc_serv *); 338int svc_create_thread(svc_thread_fn, struct svc_serv *);
333void svc_exit_thread(struct svc_rqst *); 339void svc_exit_thread(struct svc_rqst *);
334void svc_destroy(struct svc_serv *); 340void svc_destroy(struct svc_serv *);
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 44b8d9d4c18a..f5aee4c61676 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -26,7 +26,8 @@
26 * Create an RPC service 26 * Create an RPC service
27 */ 27 */
28struct svc_serv * 28struct svc_serv *
29svc_create(struct svc_program *prog, unsigned int bufsize) 29svc_create(struct svc_program *prog, unsigned int bufsize,
30 void (*shutdown)(struct svc_serv *serv))
30{ 31{
31 struct svc_serv *serv; 32 struct svc_serv *serv;
32 int vers; 33 int vers;
@@ -39,6 +40,7 @@ svc_create(struct svc_program *prog, unsigned int bufsize)
39 serv->sv_nrthreads = 1; 40 serv->sv_nrthreads = 1;
40 serv->sv_stats = prog->pg_stats; 41 serv->sv_stats = prog->pg_stats;
41 serv->sv_bufsz = bufsize? bufsize : 4096; 42 serv->sv_bufsz = bufsize? bufsize : 4096;
43 serv->sv_shutdown = shutdown;
42 xdrsize = 0; 44 xdrsize = 0;
43 while (prog) { 45 while (prog) {
44 prog->pg_lovers = prog->pg_nvers-1; 46 prog->pg_lovers = prog->pg_nvers-1;
@@ -91,6 +93,9 @@ svc_destroy(struct svc_serv *serv)
91 sk_list); 93 sk_list);
92 svc_delete_socket(svsk); 94 svc_delete_socket(svsk);
93 } 95 }
96 if (serv->sv_shutdown)
97 serv->sv_shutdown(serv);
98
94 while (!list_empty(&serv->sv_permsocks)) { 99 while (!list_empty(&serv->sv_permsocks)) {
95 svsk = list_entry(serv->sv_permsocks.next, 100 svsk = list_entry(serv->sv_permsocks.next,
96 struct svc_sock, 101 struct svc_sock,