summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 9a991b52c64..13feba45030 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -236,7 +236,7 @@ lockd_up(void)
"lockd_up: no pid, %d users??\n", nlmsvc_users);
error = -ENOMEM;
- serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE);
+ serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, NULL);
if (!serv) {
printk(KERN_WARNING "lockd_up: create service failed\n");
goto out;
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index a3ee11364db..e244cdc7afa 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -116,7 +116,7 @@ int nfs_callback_up(void)
goto out;
init_completion(&nfs_callback_info.started);
init_completion(&nfs_callback_info.stopped);
- serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE);
+ serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL);
ret = -ENOMEM;
if (!serv)
goto out_err;
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index ec1decf29ba..c52c99964a4 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -130,11 +130,25 @@ int nfsd_nrthreads(void)
return nfsd_serv->sv_nrthreads;
}
+static int killsig; /* signal that was used to kill last nfsd */
+static void nfsd_last_thread(struct svc_serv *serv)
+{
+ /* When last nfsd thread exits we need to do some clean-up */
+ nfsd_serv = NULL;
+ nfsd_racache_shutdown();
+ nfs4_state_shutdown();
+
+ printk(KERN_WARNING "nfsd: last server has exited\n");
+ if (killsig != SIG_NOCLEAN) {
+ printk(KERN_WARNING "nfsd: unexporting all filesystems\n");
+ nfsd_export_flush();
+ }
+}
int
nfsd_svc(unsigned short port, int nrservs)
{
int error;
- int none_left, found_one, i;
+ int found_one, i;
struct list_head *victim;
lock_kernel();
@@ -197,7 +211,8 @@ nfsd_svc(unsigned short port, int nrservs)
atomic_set(&nfsd_busy, 0);
error = -ENOMEM;
- nfsd_serv = svc_create(&nfsd_program, NFSD_BUFSIZE);
+ nfsd_serv = svc_create(&nfsd_program, NFSD_BUFSIZE,
+ nfsd_last_thread);
if (nfsd_serv == NULL)
goto out;
error = svc_makesock(nfsd_serv, IPPROTO_UDP, port);
@@ -231,13 +246,7 @@ nfsd_svc(unsigned short port, int nrservs)
nrservs++;
}
failure:
- none_left = (nfsd_serv->sv_nrthreads == 1);
svc_destroy(nfsd_serv); /* Release server */
- if (none_left) {
- nfsd_serv = NULL;
- nfsd_racache_shutdown();
- nfs4_state_shutdown();
- }
out:
unlock_kernel();
return error;
@@ -353,7 +362,7 @@ nfsd(struct svc_rqst *rqstp)
if (sigismember(&current->pending.signal, signo) &&
!sigismember(&current->blocked, signo))
break;
- err = signo;
+ killsig = signo;
}
/* Clear signals before calling lockd_down() and svc_exit_thread() */
flush_signals(current);
@@ -362,19 +371,6 @@ nfsd(struct svc_rqst *rqstp)
/* Release lockd */
lockd_down();
-
- /* Check if this is last thread */
- if (serv->sv_nrthreads==1) {
-
- printk(KERN_WARNING "nfsd: last server has exited\n");
- if (err != SIG_NOCLEAN) {
- printk(KERN_WARNING "nfsd: unexporting all filesystems\n");
- nfsd_export_flush();
- }
- nfsd_serv = NULL;
- nfsd_racache_shutdown(); /* release read-ahead cache */
- nfs4_state_shutdown();
- }
list_del(&me.list);
nfsdstats.th_cnt --;
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 73140ee5c63..bff5e9b486c 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -42,6 +42,11 @@ struct svc_serv {
int sv_tmpcnt; /* count of temporary sockets */
char * sv_name; /* service name */
+
+ void (*sv_shutdown)(struct svc_serv *serv);
+ /* Callback to use when last thread
+ * exits.
+ */
};
/*
@@ -328,7 +333,8 @@ typedef void (*svc_thread_fn)(struct svc_rqst *);
/*
* Function prototypes.
*/
-struct svc_serv * svc_create(struct svc_program *, unsigned int);
+struct svc_serv * svc_create(struct svc_program *, unsigned int,
+ void (*shutdown)(struct svc_serv*));
int svc_create_thread(svc_thread_fn, struct svc_serv *);
void svc_exit_thread(struct svc_rqst *);
void svc_destroy(struct svc_serv *);
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 44b8d9d4c18..f5aee4c6167 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -26,7 +26,8 @@
* Create an RPC service
*/
struct svc_serv *
-svc_create(struct svc_program *prog, unsigned int bufsize)
+svc_create(struct svc_program *prog, unsigned int bufsize,
+ void (*shutdown)(struct svc_serv *serv))
{
struct svc_serv *serv;
int vers;
@@ -39,6 +40,7 @@ svc_create(struct svc_program *prog, unsigned int bufsize)
serv->sv_nrthreads = 1;
serv->sv_stats = prog->pg_stats;
serv->sv_bufsz = bufsize? bufsize : 4096;
+ serv->sv_shutdown = shutdown;
xdrsize = 0;
while (prog) {
prog->pg_lovers = prog->pg_nvers-1;
@@ -91,6 +93,9 @@ svc_destroy(struct svc_serv *serv)
sk_list);
svc_delete_socket(svsk);
}
+ if (serv->sv_shutdown)
+ serv->sv_shutdown(serv);
+
while (!list_empty(&serv->sv_permsocks)) {
svsk = list_entry(serv->sv_permsocks.next,
struct svc_sock,