diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-04-06 16:25:56 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-04-06 16:25:56 -0400 |
commit | a63856252d2112e7c452696037a86ceb12f47f80 (patch) | |
tree | b1ad03fe441349069f80e58de425b3f72af9e5b7 /fs/nfsd/nfssvc.c | |
parent | b24241a09208874d5d770bee30791daae41ad762 (diff) | |
parent | 04826f43d4f0a4d56423eb8abb9f2ec9987df5b5 (diff) |
Merge branch 'for-2.6.30' of git://linux-nfs.org/~bfields/linux
* 'for-2.6.30' of git://linux-nfs.org/~bfields/linux: (81 commits)
nfsd41: define nfsd4_set_statp as noop for !CONFIG_NFSD_V4
nfsd41: define NFSD_DRC_SIZE_SHIFT in set_max_drc
nfsd41: Documentation/filesystems/nfs41-server.txt
nfsd41: CREATE_EXCLUSIVE4_1
nfsd41: SUPPATTR_EXCLCREAT attribute
nfsd41: support for 3-word long attribute bitmask
nfsd: dynamically skip encoded fattr bitmap in _nfsd4_verify
nfsd41: pass writable attrs mask to nfsd4_decode_fattr
nfsd41: provide support for minor version 1 at rpc level
nfsd41: control nfsv4.1 svc via /proc/fs/nfsd/versions
nfsd41: add OPEN4_SHARE_ACCESS_WANT nfs4_stateid bmap
nfsd41: access_valid
nfsd41: clientid handling
nfsd41: check encode size for sessions maxresponse cached
nfsd41: stateid handling
nfsd: pass nfsd4_compound_state* to nfs4_preprocess_{state,seq}id_op
nfsd41: destroy_session operation
nfsd41: non-page DRC for solo sequence responses
nfsd41: Add a create session replay cache
nfsd41: create_session operation
...
Diffstat (limited to 'fs/nfsd/nfssvc.c')
-rw-r--r-- | fs/nfsd/nfssvc.c | 88 |
1 files changed, 60 insertions, 28 deletions
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 7c09852be713..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 @@ | |||
40 | extern struct svc_program nfsd_program; | 41 | extern struct svc_program nfsd_program; |
41 | static int nfsd(void *vrqstp); | 42 | static int nfsd(void *vrqstp); |
42 | struct timeval nfssvc_boot; | 43 | struct timeval nfssvc_boot; |
43 | static atomic_t nfsd_busy; | ||
44 | static unsigned long nfsd_last_call; | ||
45 | static 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 | ||
124 | u32 nfsd_supported_minorversion; | ||
125 | |||
126 | int nfsd_vers(int vers, enum vers_op change) | 126 | int 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 | |||
153 | int 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 | */ | ||
237 | static 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 | ||
204 | int nfsd_create_serv(void) | 248 | int nfsd_create_serv(void) |
205 | { | 249 | { |
@@ -227,11 +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 | nfsd_last_thread, nfsd, THIS_MODULE); | 275 | nfsd_last_thread, nfsd, THIS_MODULE); |
233 | if (nfsd_serv == NULL) | 276 | if (nfsd_serv == NULL) |
234 | err = -ENOMEM; | 277 | err = -ENOMEM; |
278 | else | ||
279 | set_max_drc(); | ||
235 | 280 | ||
236 | do_gettimeofday(&nfssvc_boot); /* record boot time */ | 281 | do_gettimeofday(&nfssvc_boot); /* record boot time */ |
237 | return err; | 282 | return err; |
@@ -375,26 +420,6 @@ nfsd_svc(unsigned short port, int nrservs) | |||
375 | return error; | 420 | return error; |
376 | } | 421 | } |
377 | 422 | ||
378 | static inline void | ||
379 | update_thread_usage(int busy_threads) | ||
380 | { | ||
381 | unsigned long prev_call; | ||
382 | unsigned long diff; | ||
383 | int decile; | ||
384 | |||
385 | spin_lock(&nfsd_call_lock); | ||
386 | prev_call = nfsd_last_call; | ||
387 | nfsd_last_call = jiffies; | ||
388 | decile = busy_threads*10/nfsdstats.th_cnt; | ||
389 | if (decile>0 && decile <= 10) { | ||
390 | diff = nfsd_last_call - prev_call; | ||
391 | if ( (nfsdstats.th_usage[decile-1] += diff) >= NFSD_USAGE_WRAP) | ||
392 | nfsdstats.th_usage[decile-1] -= NFSD_USAGE_WRAP; | ||
393 | if (decile == 10) | ||
394 | nfsdstats.th_fullcnt++; | ||
395 | } | ||
396 | spin_unlock(&nfsd_call_lock); | ||
397 | } | ||
398 | 423 | ||
399 | /* | 424 | /* |
400 | * This is the NFS server kernel thread | 425 | * This is the NFS server kernel thread |
@@ -460,8 +485,6 @@ nfsd(void *vrqstp) | |||
460 | continue; | 485 | continue; |
461 | } | 486 | } |
462 | 487 | ||
463 | update_thread_usage(atomic_read(&nfsd_busy)); | ||
464 | atomic_inc(&nfsd_busy); | ||
465 | 488 | ||
466 | /* Lock the export hash tables for reading. */ | 489 | /* Lock the export hash tables for reading. */ |
467 | exp_readlock(); | 490 | exp_readlock(); |
@@ -470,8 +493,6 @@ nfsd(void *vrqstp) | |||
470 | 493 | ||
471 | /* Unlock export hash tables */ | 494 | /* Unlock export hash tables */ |
472 | exp_readunlock(); | 495 | exp_readunlock(); |
473 | update_thread_usage(atomic_read(&nfsd_busy)); | ||
474 | atomic_dec(&nfsd_busy); | ||
475 | } | 496 | } |
476 | 497 | ||
477 | /* Clear signals before calling svc_exit_thread() */ | 498 | /* Clear signals before calling svc_exit_thread() */ |
@@ -539,6 +560,10 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) | |||
539 | + rqstp->rq_res.head[0].iov_len; | 560 | + rqstp->rq_res.head[0].iov_len; |
540 | rqstp->rq_res.head[0].iov_len += sizeof(__be32); | 561 | rqstp->rq_res.head[0].iov_len += sizeof(__be32); |
541 | 562 | ||
563 | /* NFSv4.1 DRC requires statp */ | ||
564 | if (rqstp->rq_vers == 4) | ||
565 | nfsd4_set_statp(rqstp, statp); | ||
566 | |||
542 | /* Now call the procedure handler, and encode NFS status. */ | 567 | /* Now call the procedure handler, and encode NFS status. */ |
543 | nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); | 568 | nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); |
544 | nfserr = map_new_errors(rqstp->rq_vers, nfserr); | 569 | nfserr = map_new_errors(rqstp->rq_vers, nfserr); |
@@ -570,3 +595,10 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) | |||
570 | nfsd_cache_update(rqstp, proc->pc_cachetype, statp + 1); | 595 | nfsd_cache_update(rqstp, proc->pc_cachetype, statp + 1); |
571 | return 1; | 596 | return 1; |
572 | } | 597 | } |
598 | |||
599 | int 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 | } | ||