aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2010-07-19 16:50:04 -0400
committerJ. Bruce Fields <bfields@redhat.com>2010-07-23 08:51:22 -0400
commit4ad9a344be2291b1e594a4a5aee25c5a5df34a97 (patch)
treef2e8780a1461194231fbb124cffc964517424c1e /fs
parent55b13354d789dcf0b85db6d86fc3a9e57dca02c1 (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')
-rw-r--r--fs/nfsd/nfs4state.c12
-rw-r--r--fs/nfsd/nfssvc.c51
2 files changed, 43 insertions, 20 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 182448f7112a..9cc3b786d56c 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -51,7 +51,6 @@ static time_t boot_time;
51static u32 current_ownerid = 1; 51static u32 current_ownerid = 1;
52static u32 current_fileid = 1; 52static u32 current_fileid = 1;
53static u32 current_delegid = 1; 53static u32 current_delegid = 1;
54static u32 nfs4_init;
55static stateid_t zerostateid; /* bits all 0 */ 54static stateid_t zerostateid; /* bits all 0 */
56static stateid_t onestateid; /* bits all 1 */ 55static stateid_t onestateid; /* bits all 1 */
57static u64 current_sessionid = 1; 56static u64 current_sessionid = 1;
@@ -4071,16 +4070,8 @@ out_free_laundry:
4071int 4070int
4072nfs4_state_start(void) 4071nfs4_state_start(void)
4073{ 4072{
4074 int ret;
4075
4076 if (nfs4_init)
4077 return 0;
4078 nfsd4_load_reboot_recovery_data(); 4073 nfsd4_load_reboot_recovery_data();
4079 ret = __nfs4_state_start(); 4074 return __nfs4_state_start();
4080 if (ret)
4081 return ret;
4082 nfs4_init = 1;
4083 return 0;
4084} 4075}
4085 4076
4086static void 4077static void
@@ -4115,7 +4106,6 @@ __nfs4_state_shutdown(void)
4115 } 4106 }
4116 4107
4117 nfsd4_shutdown_recdir(); 4108 nfsd4_shutdown_recdir();
4118 nfs4_init = 0;
4119} 4109}
4120 4110
4121void 4111void
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
183static bool nfsd_up = false;
184
185static 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
194static 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
183static void nfsd_last_thread(struct svc_serv *serv) 208static 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
380nfsd_svc(unsigned short port, int nrservs) 405nfsd_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: 449out_destroy:
420 svc_destroy(nfsd_serv); /* Release server */ 450 svc_destroy(nfsd_serv); /* Release server */
421 out: 451out_shutdown:
452 if (error < 0 && first_thread)
453 nfsd_shutdown();
454out:
422 mutex_unlock(&nfsd_mutex); 455 mutex_unlock(&nfsd_mutex);
423 return error; 456 return error;
424} 457}