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.c100
1 files changed, 64 insertions, 36 deletions
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 07e4f5d7baa8..cbba4a935786 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -22,6 +22,7 @@
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#include <linux/kthread.h>
25#include <linux/swap.h>
25 26
26#include <linux/sunrpc/types.h> 27#include <linux/sunrpc/types.h>
27#include <linux/sunrpc/stats.h> 28#include <linux/sunrpc/stats.h>
@@ -40,9 +41,6 @@
40extern struct svc_program nfsd_program; 41extern struct svc_program nfsd_program;
41static int nfsd(void *vrqstp); 42static int nfsd(void *vrqstp);
42struct timeval nfssvc_boot; 43struct timeval nfssvc_boot;
43static atomic_t nfsd_busy;
44static unsigned long nfsd_last_call;
45static DEFINE_SPINLOCK(nfsd_call_lock);
46 44
47/* 45/*
48 * nfsd_mutex protects nfsd_serv -- both the pointer itself and the members 46 * nfsd_mutex protects nfsd_serv -- both the pointer itself and the members
@@ -123,6 +121,8 @@ struct svc_program nfsd_program = {
123 121
124}; 122};
125 123
124u32 nfsd_supported_minorversion;
125
126int nfsd_vers(int vers, enum vers_op change) 126int nfsd_vers(int vers, enum vers_op change)
127{ 127{
128 if (vers < NFSD_MINVERS || vers >= NFSD_NRVERS) 128 if (vers < NFSD_MINVERS || vers >= NFSD_NRVERS)
@@ -149,6 +149,28 @@ int nfsd_vers(int vers, enum vers_op change)
149 } 149 }
150 return 0; 150 return 0;
151} 151}
152
153int nfsd_minorversion(u32 minorversion, enum vers_op change)
154{
155 if (minorversion > NFSD_SUPPORTED_MINOR_VERSION)
156 return -1;
157 switch(change) {
158 case NFSD_SET:
159 nfsd_supported_minorversion = minorversion;
160 break;
161 case NFSD_CLEAR:
162 if (minorversion == 0)
163 return -1;
164 nfsd_supported_minorversion = minorversion - 1;
165 break;
166 case NFSD_TEST:
167 return minorversion <= nfsd_supported_minorversion;
168 case NFSD_AVAIL:
169 return minorversion <= NFSD_SUPPORTED_MINOR_VERSION;
170 }
171 return 0;
172}
173
152/* 174/*
153 * Maximum number of nfsd processes 175 * Maximum number of nfsd processes
154 */ 176 */
@@ -200,6 +222,28 @@ void nfsd_reset_versions(void)
200 } 222 }
201} 223}
202 224
225/*
226 * Each session guarantees a negotiated per slot memory cache for replies
227 * which in turn consumes memory beyond the v2/v3/v4.0 server. A dedicated
228 * NFSv4.1 server might want to use more memory for a DRC than a machine
229 * with mutiple services.
230 *
231 * Impose a hard limit on the number of pages for the DRC which varies
232 * according to the machines free pages. This is of course only a default.
233 *
234 * For now this is a #defined shift which could be under admin control
235 * in the future.
236 */
237static void set_max_drc(void)
238{
239 /* The percent of nr_free_buffer_pages used by the V4.1 server DRC */
240 #define NFSD_DRC_SIZE_SHIFT 7
241 nfsd_serv->sv_drc_max_pages = nr_free_buffer_pages()
242 >> NFSD_DRC_SIZE_SHIFT;
243 nfsd_serv->sv_drc_pages_used = 0;
244 dprintk("%s svc_drc_max_pages %u\n", __func__,
245 nfsd_serv->sv_drc_max_pages);
246}
203 247
204int nfsd_create_serv(void) 248int nfsd_create_serv(void)
205{ 249{
@@ -227,12 +271,12 @@ int nfsd_create_serv(void)
227 nfsd_max_blksize /= 2; 271 nfsd_max_blksize /= 2;
228 } 272 }
229 273
230 atomic_set(&nfsd_busy, 0);
231 nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize, 274 nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
232 AF_INET,
233 nfsd_last_thread, nfsd, THIS_MODULE); 275 nfsd_last_thread, nfsd, THIS_MODULE);
234 if (nfsd_serv == NULL) 276 if (nfsd_serv == NULL)
235 err = -ENOMEM; 277 err = -ENOMEM;
278 else
279 set_max_drc();
236 280
237 do_gettimeofday(&nfssvc_boot); /* record boot time */ 281 do_gettimeofday(&nfssvc_boot); /* record boot time */
238 return err; 282 return err;
@@ -244,7 +288,7 @@ static int nfsd_init_socks(int port)
244 if (!list_empty(&nfsd_serv->sv_permsocks)) 288 if (!list_empty(&nfsd_serv->sv_permsocks))
245 return 0; 289 return 0;
246 290
247 error = svc_create_xprt(nfsd_serv, "udp", port, 291 error = svc_create_xprt(nfsd_serv, "udp", PF_INET, port,
248 SVC_SOCK_DEFAULTS); 292 SVC_SOCK_DEFAULTS);
249 if (error < 0) 293 if (error < 0)
250 return error; 294 return error;
@@ -253,7 +297,7 @@ static int nfsd_init_socks(int port)
253 if (error < 0) 297 if (error < 0)
254 return error; 298 return error;
255 299
256 error = svc_create_xprt(nfsd_serv, "tcp", port, 300 error = svc_create_xprt(nfsd_serv, "tcp", PF_INET, port,
257 SVC_SOCK_DEFAULTS); 301 SVC_SOCK_DEFAULTS);
258 if (error < 0) 302 if (error < 0)
259 return error; 303 return error;
@@ -376,26 +420,6 @@ nfsd_svc(unsigned short port, int nrservs)
376 return error; 420 return error;
377} 421}
378 422
379static inline void
380update_thread_usage(int busy_threads)
381{
382 unsigned long prev_call;
383 unsigned long diff;
384 int decile;
385
386 spin_lock(&nfsd_call_lock);
387 prev_call = nfsd_last_call;
388 nfsd_last_call = jiffies;
389 decile = busy_threads*10/nfsdstats.th_cnt;
390 if (decile>0 && decile <= 10) {
391 diff = nfsd_last_call - prev_call;
392 if ( (nfsdstats.th_usage[decile-1] += diff) >= NFSD_USAGE_WRAP)
393 nfsdstats.th_usage[decile-1] -= NFSD_USAGE_WRAP;
394 if (decile == 10)
395 nfsdstats.th_fullcnt++;
396 }
397 spin_unlock(&nfsd_call_lock);
398}
399 423
400/* 424/*
401 * This is the NFS server kernel thread 425 * This is the NFS server kernel thread
@@ -404,7 +428,6 @@ static int
404nfsd(void *vrqstp) 428nfsd(void *vrqstp)
405{ 429{
406 struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp; 430 struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp;
407 struct fs_struct *fsp;
408 int err, preverr = 0; 431 int err, preverr = 0;
409 432
410 /* Lock module and set up kernel thread */ 433 /* Lock module and set up kernel thread */
@@ -413,13 +436,11 @@ nfsd(void *vrqstp)
413 /* At this point, the thread shares current->fs 436 /* At this point, the thread shares current->fs
414 * with the init process. We need to create files with a 437 * with the init process. We need to create files with a
415 * umask of 0 instead of init's umask. */ 438 * umask of 0 instead of init's umask. */
416 fsp = copy_fs_struct(current->fs); 439 if (unshare_fs_struct() < 0) {
417 if (!fsp) {
418 printk("Unable to start nfsd thread: out of memory\n"); 440 printk("Unable to start nfsd thread: out of memory\n");
419 goto out; 441 goto out;
420 } 442 }
421 exit_fs(current); 443
422 current->fs = fsp;
423 current->fs->umask = 0; 444 current->fs->umask = 0;
424 445
425 /* 446 /*
@@ -464,8 +485,6 @@ nfsd(void *vrqstp)
464 continue; 485 continue;
465 } 486 }
466 487
467 update_thread_usage(atomic_read(&nfsd_busy));
468 atomic_inc(&nfsd_busy);
469 488
470 /* Lock the export hash tables for reading. */ 489 /* Lock the export hash tables for reading. */
471 exp_readlock(); 490 exp_readlock();
@@ -474,8 +493,6 @@ nfsd(void *vrqstp)
474 493
475 /* Unlock export hash tables */ 494 /* Unlock export hash tables */
476 exp_readunlock(); 495 exp_readunlock();
477 update_thread_usage(atomic_read(&nfsd_busy));
478 atomic_dec(&nfsd_busy);
479 } 496 }
480 497
481 /* Clear signals before calling svc_exit_thread() */ 498 /* Clear signals before calling svc_exit_thread() */
@@ -543,6 +560,10 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
543 + rqstp->rq_res.head[0].iov_len; 560 + rqstp->rq_res.head[0].iov_len;
544 rqstp->rq_res.head[0].iov_len += sizeof(__be32); 561 rqstp->rq_res.head[0].iov_len += sizeof(__be32);
545 562
563 /* NFSv4.1 DRC requires statp */
564 if (rqstp->rq_vers == 4)
565 nfsd4_set_statp(rqstp, statp);
566
546 /* Now call the procedure handler, and encode NFS status. */ 567 /* Now call the procedure handler, and encode NFS status. */
547 nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); 568 nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
548 nfserr = map_new_errors(rqstp->rq_vers, nfserr); 569 nfserr = map_new_errors(rqstp->rq_vers, nfserr);
@@ -574,3 +595,10 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
574 nfsd_cache_update(rqstp, proc->pc_cachetype, statp + 1); 595 nfsd_cache_update(rqstp, proc->pc_cachetype, statp + 1);
575 return 1; 596 return 1;
576} 597}
598
599int nfsd_pool_stats_open(struct inode *inode, struct file *file)
600{
601 if (nfsd_serv == NULL)
602 return -ENODEV;
603 return svc_pool_stats_open(nfsd_serv, file);
604}