aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfssvc.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/nfssvc.c')
-rw-r--r--fs/nfsd/nfssvc.c148
1 files changed, 76 insertions, 72 deletions
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 941041f4b136..80292ff5e924 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -21,6 +21,7 @@
21#include <linux/smp_lock.h> 21#include <linux/smp_lock.h>
22#include <linux/freezer.h> 22#include <linux/freezer.h>
23#include <linux/fs_struct.h> 23#include <linux/fs_struct.h>
24#include <linux/kthread.h>
24 25
25#include <linux/sunrpc/types.h> 26#include <linux/sunrpc/types.h>
26#include <linux/sunrpc/stats.h> 27#include <linux/sunrpc/stats.h>
@@ -36,28 +37,38 @@
36 37
37#define NFSDDBG_FACILITY NFSDDBG_SVC 38#define NFSDDBG_FACILITY NFSDDBG_SVC
38 39
39/* these signals will be delivered to an nfsd thread
40 * when handling a request
41 */
42#define ALLOWED_SIGS (sigmask(SIGKILL))
43/* these signals will be delivered to an nfsd thread
44 * when not handling a request. i.e. when waiting
45 */
46#define SHUTDOWN_SIGS (sigmask(SIGKILL) | sigmask(SIGHUP) | sigmask(SIGINT) | sigmask(SIGQUIT))
47/* if the last thread dies with SIGHUP, then the exports table is
48 * left unchanged ( like 2.4-{0-9} ). Any other signal will clear
49 * the exports table (like 2.2).
50 */
51#define SIG_NOCLEAN SIGHUP
52
53extern struct svc_program nfsd_program; 40extern struct svc_program nfsd_program;
54static void nfsd(struct svc_rqst *rqstp); 41static int nfsd(void *vrqstp);
55struct timeval nfssvc_boot; 42struct timeval nfssvc_boot;
56 struct svc_serv *nfsd_serv;
57static atomic_t nfsd_busy; 43static atomic_t nfsd_busy;
58static unsigned long nfsd_last_call; 44static unsigned long nfsd_last_call;
59static DEFINE_SPINLOCK(nfsd_call_lock); 45static DEFINE_SPINLOCK(nfsd_call_lock);
60 46
47/*
48 * nfsd_mutex protects nfsd_serv -- both the pointer itself and the members
49 * of the svc_serv struct. In particular, ->sv_nrthreads but also to some
50 * extent ->sv_temp_socks and ->sv_permsocks. It also protects nfsdstats.th_cnt
51 *
52 * If (out side the lock) nfsd_serv is non-NULL, then it must point to a
53 * properly initialised 'struct svc_serv' with ->sv_nrthreads > 0. That number
54 * of nfsd threads must exist and each must listed in ->sp_all_threads in each
55 * entry of ->sv_pools[].
56 *
57 * Transitions of the thread count between zero and non-zero are of particular
58 * interest since the svc_serv needs to be created and initialized at that
59 * point, or freed.
60 *
61 * Finally, the nfsd_mutex also protects some of the global variables that are
62 * accessed when nfsd starts and that are settable via the write_* routines in
63 * nfsctl.c. In particular:
64 *
65 * user_recovery_dirname
66 * user_lease_time
67 * nfsd_versions
68 */
69DEFINE_MUTEX(nfsd_mutex);
70struct svc_serv *nfsd_serv;
71
61#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) 72#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
62static struct svc_stat nfsd_acl_svcstats; 73static struct svc_stat nfsd_acl_svcstats;
63static struct svc_version * nfsd_acl_version[] = { 74static struct svc_version * nfsd_acl_version[] = {
@@ -145,13 +156,14 @@ int nfsd_vers(int vers, enum vers_op change)
145 156
146int nfsd_nrthreads(void) 157int nfsd_nrthreads(void)
147{ 158{
148 if (nfsd_serv == NULL) 159 int rv = 0;
149 return 0; 160 mutex_lock(&nfsd_mutex);
150 else 161 if (nfsd_serv)
151 return nfsd_serv->sv_nrthreads; 162 rv = nfsd_serv->sv_nrthreads;
163 mutex_unlock(&nfsd_mutex);
164 return rv;
152} 165}
153 166
154static int killsig; /* signal that was used to kill last nfsd */
155static void nfsd_last_thread(struct svc_serv *serv) 167static void nfsd_last_thread(struct svc_serv *serv)
156{ 168{
157 /* When last nfsd thread exits we need to do some clean-up */ 169 /* When last nfsd thread exits we need to do some clean-up */
@@ -162,11 +174,9 @@ static void nfsd_last_thread(struct svc_serv *serv)
162 nfsd_racache_shutdown(); 174 nfsd_racache_shutdown();
163 nfs4_state_shutdown(); 175 nfs4_state_shutdown();
164 176
165 printk(KERN_WARNING "nfsd: last server has exited\n"); 177 printk(KERN_WARNING "nfsd: last server has exited, flushing export "
166 if (killsig != SIG_NOCLEAN) { 178 "cache\n");
167 printk(KERN_WARNING "nfsd: unexporting all filesystems\n"); 179 nfsd_export_flush();
168 nfsd_export_flush();
169 }
170} 180}
171 181
172void nfsd_reset_versions(void) 182void nfsd_reset_versions(void)
@@ -190,13 +200,14 @@ void nfsd_reset_versions(void)
190 } 200 }
191} 201}
192 202
203
193int nfsd_create_serv(void) 204int nfsd_create_serv(void)
194{ 205{
195 int err = 0; 206 int err = 0;
196 lock_kernel(); 207
208 WARN_ON(!mutex_is_locked(&nfsd_mutex));
197 if (nfsd_serv) { 209 if (nfsd_serv) {
198 svc_get(nfsd_serv); 210 svc_get(nfsd_serv);
199 unlock_kernel();
200 return 0; 211 return 0;
201 } 212 }
202 if (nfsd_max_blksize == 0) { 213 if (nfsd_max_blksize == 0) {
@@ -217,13 +228,11 @@ int nfsd_create_serv(void)
217 } 228 }
218 229
219 atomic_set(&nfsd_busy, 0); 230 atomic_set(&nfsd_busy, 0);
220 nfsd_serv = svc_create_pooled(&nfsd_program, 231 nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
221 nfsd_max_blksize, 232 nfsd_last_thread, nfsd, THIS_MODULE);
222 nfsd_last_thread,
223 nfsd, SIG_NOCLEAN, THIS_MODULE);
224 if (nfsd_serv == NULL) 233 if (nfsd_serv == NULL)
225 err = -ENOMEM; 234 err = -ENOMEM;
226 unlock_kernel(); 235
227 do_gettimeofday(&nfssvc_boot); /* record boot time */ 236 do_gettimeofday(&nfssvc_boot); /* record boot time */
228 return err; 237 return err;
229} 238}
@@ -282,6 +291,8 @@ int nfsd_set_nrthreads(int n, int *nthreads)
282 int tot = 0; 291 int tot = 0;
283 int err = 0; 292 int err = 0;
284 293
294 WARN_ON(!mutex_is_locked(&nfsd_mutex));
295
285 if (nfsd_serv == NULL || n <= 0) 296 if (nfsd_serv == NULL || n <= 0)
286 return 0; 297 return 0;
287 298
@@ -316,7 +327,6 @@ int nfsd_set_nrthreads(int n, int *nthreads)
316 nthreads[0] = 1; 327 nthreads[0] = 1;
317 328
318 /* apply the new numbers */ 329 /* apply the new numbers */
319 lock_kernel();
320 svc_get(nfsd_serv); 330 svc_get(nfsd_serv);
321 for (i = 0; i < n; i++) { 331 for (i = 0; i < n; i++) {
322 err = svc_set_num_threads(nfsd_serv, &nfsd_serv->sv_pools[i], 332 err = svc_set_num_threads(nfsd_serv, &nfsd_serv->sv_pools[i],
@@ -325,7 +335,6 @@ int nfsd_set_nrthreads(int n, int *nthreads)
325 break; 335 break;
326 } 336 }
327 svc_destroy(nfsd_serv); 337 svc_destroy(nfsd_serv);
328 unlock_kernel();
329 338
330 return err; 339 return err;
331} 340}
@@ -334,8 +343,8 @@ int
334nfsd_svc(unsigned short port, int nrservs) 343nfsd_svc(unsigned short port, int nrservs)
335{ 344{
336 int error; 345 int error;
337 346
338 lock_kernel(); 347 mutex_lock(&nfsd_mutex);
339 dprintk("nfsd: creating service\n"); 348 dprintk("nfsd: creating service\n");
340 error = -EINVAL; 349 error = -EINVAL;
341 if (nrservs <= 0) 350 if (nrservs <= 0)
@@ -363,7 +372,7 @@ nfsd_svc(unsigned short port, int nrservs)
363 failure: 372 failure:
364 svc_destroy(nfsd_serv); /* Release server */ 373 svc_destroy(nfsd_serv); /* Release server */
365 out: 374 out:
366 unlock_kernel(); 375 mutex_unlock(&nfsd_mutex);
367 return error; 376 return error;
368} 377}
369 378
@@ -391,18 +400,17 @@ update_thread_usage(int busy_threads)
391/* 400/*
392 * This is the NFS server kernel thread 401 * This is the NFS server kernel thread
393 */ 402 */
394static void 403static int
395nfsd(struct svc_rqst *rqstp) 404nfsd(void *vrqstp)
396{ 405{
406 struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp;
397 struct fs_struct *fsp; 407 struct fs_struct *fsp;
398 int err; 408 int err, preverr = 0;
399 sigset_t shutdown_mask, allowed_mask;
400 409
401 /* Lock module and set up kernel thread */ 410 /* Lock module and set up kernel thread */
402 lock_kernel(); 411 mutex_lock(&nfsd_mutex);
403 daemonize("nfsd");
404 412
405 /* After daemonize() this kernel thread shares current->fs 413 /* At this point, the thread shares current->fs
406 * with the init process. We need to create files with a 414 * with the init process. We need to create files with a
407 * umask of 0 instead of init's umask. */ 415 * umask of 0 instead of init's umask. */
408 fsp = copy_fs_struct(current->fs); 416 fsp = copy_fs_struct(current->fs);
@@ -414,14 +422,17 @@ nfsd(struct svc_rqst *rqstp)
414 current->fs = fsp; 422 current->fs = fsp;
415 current->fs->umask = 0; 423 current->fs->umask = 0;
416 424
417 siginitsetinv(&shutdown_mask, SHUTDOWN_SIGS); 425 /*
418 siginitsetinv(&allowed_mask, ALLOWED_SIGS); 426 * thread is spawned with all signals set to SIG_IGN, re-enable
427 * the ones that will bring down the thread
428 */
429 allow_signal(SIGKILL);
430 allow_signal(SIGHUP);
431 allow_signal(SIGINT);
432 allow_signal(SIGQUIT);
419 433
420 nfsdstats.th_cnt++; 434 nfsdstats.th_cnt++;
421 435 mutex_unlock(&nfsd_mutex);
422 rqstp->rq_task = current;
423
424 unlock_kernel();
425 436
426 /* 437 /*
427 * We want less throttling in balance_dirty_pages() so that nfs to 438 * We want less throttling in balance_dirty_pages() so that nfs to
@@ -435,26 +446,30 @@ nfsd(struct svc_rqst *rqstp)
435 * The main request loop 446 * The main request loop
436 */ 447 */
437 for (;;) { 448 for (;;) {
438 /* Block all but the shutdown signals */
439 sigprocmask(SIG_SETMASK, &shutdown_mask, NULL);
440
441 /* 449 /*
442 * Find a socket with data available and call its 450 * Find a socket with data available and call its
443 * recvfrom routine. 451 * recvfrom routine.
444 */ 452 */
445 while ((err = svc_recv(rqstp, 60*60*HZ)) == -EAGAIN) 453 while ((err = svc_recv(rqstp, 60*60*HZ)) == -EAGAIN)
446 ; 454 ;
447 if (err < 0) 455 if (err == -EINTR)
448 break; 456 break;
457 else if (err < 0) {
458 if (err != preverr) {
459 printk(KERN_WARNING "%s: unexpected error "
460 "from svc_recv (%d)\n", __func__, -err);
461 preverr = err;
462 }
463 schedule_timeout_uninterruptible(HZ);
464 continue;
465 }
466
449 update_thread_usage(atomic_read(&nfsd_busy)); 467 update_thread_usage(atomic_read(&nfsd_busy));
450 atomic_inc(&nfsd_busy); 468 atomic_inc(&nfsd_busy);
451 469
452 /* Lock the export hash tables for reading. */ 470 /* Lock the export hash tables for reading. */
453 exp_readlock(); 471 exp_readlock();
454 472
455 /* Process request with signals blocked. */
456 sigprocmask(SIG_SETMASK, &allowed_mask, NULL);
457
458 svc_process(rqstp); 473 svc_process(rqstp);
459 474
460 /* Unlock export hash tables */ 475 /* Unlock export hash tables */
@@ -463,22 +478,10 @@ nfsd(struct svc_rqst *rqstp)
463 atomic_dec(&nfsd_busy); 478 atomic_dec(&nfsd_busy);
464 } 479 }
465 480
466 if (err != -EINTR) {
467 printk(KERN_WARNING "nfsd: terminating on error %d\n", -err);
468 } else {
469 unsigned int signo;
470
471 for (signo = 1; signo <= _NSIG; signo++)
472 if (sigismember(&current->pending.signal, signo) &&
473 !sigismember(&current->blocked, signo))
474 break;
475 killsig = signo;
476 }
477 /* Clear signals before calling svc_exit_thread() */ 481 /* Clear signals before calling svc_exit_thread() */
478 flush_signals(current); 482 flush_signals(current);
479 483
480 lock_kernel(); 484 mutex_lock(&nfsd_mutex);
481
482 nfsdstats.th_cnt --; 485 nfsdstats.th_cnt --;
483 486
484out: 487out:
@@ -486,8 +489,9 @@ out:
486 svc_exit_thread(rqstp); 489 svc_exit_thread(rqstp);
487 490
488 /* Release module */ 491 /* Release module */
489 unlock_kernel(); 492 mutex_unlock(&nfsd_mutex);
490 module_put_and_exit(0); 493 module_put_and_exit(0);
494 return 0;
491} 495}
492 496
493static __be32 map_new_errors(u32 vers, __be32 nfserr) 497static __be32 map_new_errors(u32 vers, __be32 nfserr)