[PATCH] knfsd: add a callback for when last rpc thread finishes
NeilBrown [Mon, 2 Oct 2006 09:17:44 +0000 (02:17 -0700)]
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>

fs/lockd/svc.c
fs/nfs/callback.c
fs/nfsd/nfssvc.c
include/linux/sunrpc/svc.h
net/sunrpc/svc.c

index 9a991b5..13feba4 100644 (file)
@@ -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;
index a3ee113..e244cdc 100644 (file)
@@ -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;
index ec1decf..c52c999 100644 (file)
@@ -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 --;
 
index 73140ee..bff5e9b 100644 (file)
@@ -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 *);
index 44b8d9d..f5aee4c 100644 (file)
@@ -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,