diff options
author | Jeff Layton <jlayton@redhat.com> | 2010-07-19 16:50:04 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2010-07-23 08:51:22 -0400 |
commit | 4ad9a344be2291b1e594a4a5aee25c5a5df34a97 (patch) | |
tree | f2e8780a1461194231fbb124cffc964517424c1e /fs/nfsd/nfssvc.c | |
parent | 55b13354d789dcf0b85db6d86fc3a9e57dca02c1 (diff) |
nfsd4: fix v4 state shutdown error paths
If someone tries to shut down the laundry_wq while it isn't up it'll
cause an oops.
This can happen because write_ports can create a nfsd_svc before we
really start the nfs server, and we may fail before the server is ever
started.
Also make sure state is shutdown on error paths in nfsd_svc().
Use a common global nfsd_up flag instead of nfs4_init, and create common
helper functions for nfsd start/shutdown, as there will be other work
that we want done only when we the number of nfsd threads transitions
between zero and nonzero.
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd/nfssvc.c')
-rw-r--r-- | fs/nfsd/nfssvc.c | 51 |
1 files changed, 42 insertions, 9 deletions
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 06b2a26edfe0..d7a4d7b37448 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -180,6 +180,31 @@ int nfsd_nrthreads(void) | |||
180 | return rv; | 180 | return rv; |
181 | } | 181 | } |
182 | 182 | ||
183 | static bool nfsd_up = false; | ||
184 | |||
185 | static int nfsd_startup(unsigned short port, int nrservs) | ||
186 | { | ||
187 | int ret; | ||
188 | |||
189 | ret = nfs4_state_start(); | ||
190 | nfsd_up = true; | ||
191 | return ret; | ||
192 | } | ||
193 | |||
194 | static void nfsd_shutdown(void) | ||
195 | { | ||
196 | /* | ||
197 | * write_ports can create the server without actually starting | ||
198 | * any threads--if we get shut down before any threads are | ||
199 | * started, then nfsd_last_thread will be run before any of this | ||
200 | * other initialization has been done. | ||
201 | */ | ||
202 | if (!nfsd_up) | ||
203 | return; | ||
204 | nfs4_state_shutdown(); | ||
205 | nfsd_up = false; | ||
206 | } | ||
207 | |||
183 | static void nfsd_last_thread(struct svc_serv *serv) | 208 | static void nfsd_last_thread(struct svc_serv *serv) |
184 | { | 209 | { |
185 | /* When last nfsd thread exits we need to do some clean-up */ | 210 | /* When last nfsd thread exits we need to do some clean-up */ |
@@ -188,7 +213,7 @@ static void nfsd_last_thread(struct svc_serv *serv) | |||
188 | lockd_down(); | 213 | lockd_down(); |
189 | nfsd_serv = NULL; | 214 | nfsd_serv = NULL; |
190 | nfsd_racache_shutdown(); | 215 | nfsd_racache_shutdown(); |
191 | nfs4_state_shutdown(); | 216 | nfsd_shutdown(); |
192 | 217 | ||
193 | printk(KERN_WARNING "nfsd: last server has exited, flushing export " | 218 | printk(KERN_WARNING "nfsd: last server has exited, flushing export " |
194 | "cache\n"); | 219 | "cache\n"); |
@@ -380,6 +405,7 @@ int | |||
380 | nfsd_svc(unsigned short port, int nrservs) | 405 | nfsd_svc(unsigned short port, int nrservs) |
381 | { | 406 | { |
382 | int error; | 407 | int error; |
408 | bool first_thread; | ||
383 | 409 | ||
384 | mutex_lock(&nfsd_mutex); | 410 | mutex_lock(&nfsd_mutex); |
385 | dprintk("nfsd: creating service\n"); | 411 | dprintk("nfsd: creating service\n"); |
@@ -395,19 +421,23 @@ nfsd_svc(unsigned short port, int nrservs) | |||
395 | error = nfsd_racache_init(2*nrservs); | 421 | error = nfsd_racache_init(2*nrservs); |
396 | if (error<0) | 422 | if (error<0) |
397 | goto out; | 423 | goto out; |
398 | error = nfs4_state_start(); | 424 | |
399 | if (error) | 425 | first_thread = (nfsd_serv->sv_nrthreads == 0) && (nrservs != 0); |
400 | goto out; | 426 | |
427 | if (first_thread) { | ||
428 | error = nfsd_startup(port, nrservs); | ||
429 | if (error) | ||
430 | goto out; | ||
431 | } | ||
401 | 432 | ||
402 | nfsd_reset_versions(); | 433 | nfsd_reset_versions(); |
403 | 434 | ||
404 | error = nfsd_create_serv(); | 435 | error = nfsd_create_serv(); |
405 | |||
406 | if (error) | 436 | if (error) |
407 | goto out; | 437 | goto out_shutdown; |
408 | error = nfsd_init_socks(port); | 438 | error = nfsd_init_socks(port); |
409 | if (error) | 439 | if (error) |
410 | goto failure; | 440 | goto out_destroy; |
411 | 441 | ||
412 | error = svc_set_num_threads(nfsd_serv, NULL, nrservs); | 442 | error = svc_set_num_threads(nfsd_serv, NULL, nrservs); |
413 | if (error == 0) | 443 | if (error == 0) |
@@ -416,9 +446,12 @@ nfsd_svc(unsigned short port, int nrservs) | |||
416 | * so subtract 1 | 446 | * so subtract 1 |
417 | */ | 447 | */ |
418 | error = nfsd_serv->sv_nrthreads - 1; | 448 | error = nfsd_serv->sv_nrthreads - 1; |
419 | failure: | 449 | out_destroy: |
420 | svc_destroy(nfsd_serv); /* Release server */ | 450 | svc_destroy(nfsd_serv); /* Release server */ |
421 | out: | 451 | out_shutdown: |
452 | if (error < 0 && first_thread) | ||
453 | nfsd_shutdown(); | ||
454 | out: | ||
422 | mutex_unlock(&nfsd_mutex); | 455 | mutex_unlock(&nfsd_mutex); |
423 | return error; | 456 | return error; |
424 | } | 457 | } |