diff options
author | J. Bruce Fields <bfields@redhat.com> | 2010-08-02 14:12:44 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2010-08-06 17:05:30 -0400 |
commit | 774f8bbd9ef2e71d4ef4b89933d292091d31ca98 (patch) | |
tree | bbc4afb785f31727b61279b1a026768d5953d60f /fs | |
parent | 039a87ca536a85bc169ce092e44bd57adfa1f563 (diff) | |
download | linux-774f8bbd9ef2e71d4ef4b89933d292091d31ca98.tar.bz2 |
nfsd: fix startup/shutdown order bug
We must create the server before we can call init_socks or check the
number of threads.
Symptoms were a NULL pointer dereference in nfsd_svc(). Problem
identified by Jeff Layton.
Also fix a minor cleanup-on-error case in nfsd_startup().
Reported-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfsd/nfssvc.c | 30 |
1 files changed, 16 insertions, 14 deletions
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 92173bde32d2..39ced4a52c5f 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -204,6 +204,9 @@ static bool nfsd_up = false; static int nfsd_startup(unsigned short port, int nrservs) { int ret; + + if (nfsd_up) + return 0; /* * Readahead param cache - will no-op if it already exists. * (Note therefore results will be suboptimal if number of @@ -217,7 +220,7 @@ static int nfsd_startup(unsigned short port, int nrservs) goto out_racache; ret = lockd_up(); if (ret) - return ret; + goto out_racache; ret = nfs4_state_start(); if (ret) goto out_lockd; @@ -420,7 +423,7 @@ int nfsd_svc(unsigned short port, int nrservs) { int error; - bool first_thread; + bool nfsd_up_before; mutex_lock(&nfsd_mutex); dprintk("nfsd: creating service\n"); @@ -432,29 +435,28 @@ nfsd_svc(unsigned short port, int nrservs) if (nrservs == 0 && nfsd_serv == NULL) goto out; - first_thread = (nfsd_serv->sv_nrthreads == 0) && (nrservs != 0); - - if (first_thread) { - error = nfsd_startup(port, nrservs); - if (error) - goto out; - } error = nfsd_create_serv(); if (error) - goto out_shutdown; - error = svc_set_num_threads(nfsd_serv, NULL, nrservs); + goto out; + + nfsd_up_before = nfsd_up; + + error = nfsd_startup(port, nrservs); if (error) goto out_destroy; + error = svc_set_num_threads(nfsd_serv, NULL, nrservs); + if (error) + goto out_shutdown; /* We are holding a reference to nfsd_serv which * we don't want to count in the return value, * so subtract 1 */ error = nfsd_serv->sv_nrthreads - 1; -out_destroy: - svc_destroy(nfsd_serv); /* Release server */ out_shutdown: - if (error < 0 && first_thread) + if (error < 0 && !nfsd_up_before) nfsd_shutdown(); +out_destroy: + svc_destroy(nfsd_serv); /* Release server */ out: mutex_unlock(&nfsd_mutex); return error; |