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