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/nfsd | |
parent | 039a87ca536a85bc169ce092e44bd57adfa1f563 (diff) |
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/nfsd')
-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; | |||
204 | static int nfsd_startup(unsigned short port, int nrservs) | 204 | static int nfsd_startup(unsigned short port, int nrservs) |
205 | { | 205 | { |
206 | int ret; | 206 | int ret; |
207 | |||
208 | if (nfsd_up) | ||
209 | return 0; | ||
207 | /* | 210 | /* |
208 | * Readahead param cache - will no-op if it already exists. | 211 | * Readahead param cache - will no-op if it already exists. |
209 | * (Note therefore results will be suboptimal if number of | 212 | * (Note therefore results will be suboptimal if number of |
@@ -217,7 +220,7 @@ static int nfsd_startup(unsigned short port, int nrservs) | |||
217 | goto out_racache; | 220 | goto out_racache; |
218 | ret = lockd_up(); | 221 | ret = lockd_up(); |
219 | if (ret) | 222 | if (ret) |
220 | return ret; | 223 | goto out_racache; |
221 | ret = nfs4_state_start(); | 224 | ret = nfs4_state_start(); |
222 | if (ret) | 225 | if (ret) |
223 | goto out_lockd; | 226 | goto out_lockd; |
@@ -420,7 +423,7 @@ int | |||
420 | nfsd_svc(unsigned short port, int nrservs) | 423 | nfsd_svc(unsigned short port, int nrservs) |
421 | { | 424 | { |
422 | int error; | 425 | int error; |
423 | bool first_thread; | 426 | bool nfsd_up_before; |
424 | 427 | ||
425 | mutex_lock(&nfsd_mutex); | 428 | mutex_lock(&nfsd_mutex); |
426 | dprintk("nfsd: creating service\n"); | 429 | dprintk("nfsd: creating service\n"); |
@@ -432,29 +435,28 @@ nfsd_svc(unsigned short port, int nrservs) | |||
432 | if (nrservs == 0 && nfsd_serv == NULL) | 435 | if (nrservs == 0 && nfsd_serv == NULL) |
433 | goto out; | 436 | goto out; |
434 | 437 | ||
435 | first_thread = (nfsd_serv->sv_nrthreads == 0) && (nrservs != 0); | ||
436 | |||
437 | if (first_thread) { | ||
438 | error = nfsd_startup(port, nrservs); | ||
439 | if (error) | ||
440 | goto out; | ||
441 | } | ||
442 | error = nfsd_create_serv(); | 438 | error = nfsd_create_serv(); |
443 | if (error) | 439 | if (error) |
444 | goto out_shutdown; | 440 | goto out; |
445 | error = svc_set_num_threads(nfsd_serv, NULL, nrservs); | 441 | |
442 | nfsd_up_before = nfsd_up; | ||
443 | |||
444 | error = nfsd_startup(port, nrservs); | ||
446 | if (error) | 445 | if (error) |
447 | goto out_destroy; | 446 | goto out_destroy; |
447 | error = svc_set_num_threads(nfsd_serv, NULL, nrservs); | ||
448 | if (error) | ||
449 | goto out_shutdown; | ||
448 | /* We are holding a reference to nfsd_serv which | 450 | /* We are holding a reference to nfsd_serv which |
449 | * we don't want to count in the return value, | 451 | * we don't want to count in the return value, |
450 | * so subtract 1 | 452 | * so subtract 1 |
451 | */ | 453 | */ |
452 | error = nfsd_serv->sv_nrthreads - 1; | 454 | error = nfsd_serv->sv_nrthreads - 1; |
453 | out_destroy: | ||
454 | svc_destroy(nfsd_serv); /* Release server */ | ||
455 | out_shutdown: | 455 | out_shutdown: |
456 | if (error < 0 && first_thread) | 456 | if (error < 0 && !nfsd_up_before) |
457 | nfsd_shutdown(); | 457 | nfsd_shutdown(); |
458 | out_destroy: | ||
459 | svc_destroy(nfsd_serv); /* Release server */ | ||
458 | out: | 460 | out: |
459 | mutex_unlock(&nfsd_mutex); | 461 | mutex_unlock(&nfsd_mutex); |
460 | return error; | 462 | return error; |