aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/Kconfig2
-rw-r--r--fs/lockd/svclock.c2
-rw-r--r--fs/locks.c3
-rw-r--r--fs/nfs/Kconfig2
-rw-r--r--fs/nfsd/export.c13
-rw-r--r--fs/nfsd/nfs3xdr.c1
-rw-r--r--fs/nfsd/nfs4callback.c222
-rw-r--r--fs/nfsd/nfs4proc.c129
-rw-r--r--fs/nfsd/nfs4state.c119
-rw-r--r--fs/nfsd/nfs4xdr.c294
-rw-r--r--fs/nfsd/nfscache.c33
-rw-r--r--fs/nfsd/nfsctl.c284
-rw-r--r--fs/nfsd/nfsfh.c6
13 files changed, 651 insertions, 459 deletions
diff --git a/fs/Kconfig b/fs/Kconfig
index 9f7270f36b2a..44ab328ceb2a 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -226,10 +226,12 @@ source "fs/nfsd/Kconfig"
226 226
227config LOCKD 227config LOCKD
228 tristate 228 tristate
229 depends on FILE_LOCKING
229 230
230config LOCKD_V4 231config LOCKD_V4
231 bool 232 bool
232 depends on NFSD_V3 || NFS_V3 233 depends on NFSD_V3 || NFS_V3
234 depends on FILE_LOCKING
233 default y 235 default y
234 236
235config EXPORTFS 237config EXPORTFS
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 83ee34203bd7..e577a78d7bac 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -326,6 +326,8 @@ static void nlmsvc_freegrantargs(struct nlm_rqst *call)
326{ 326{
327 if (call->a_args.lock.oh.data != call->a_owner) 327 if (call->a_args.lock.oh.data != call->a_owner)
328 kfree(call->a_args.lock.oh.data); 328 kfree(call->a_args.lock.oh.data);
329
330 locks_release_private(&call->a_args.lock.fl);
329} 331}
330 332
331/* 333/*
diff --git a/fs/locks.c b/fs/locks.c
index ec3deea29e37..b6440f52178f 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -151,7 +151,7 @@ static struct file_lock *locks_alloc_lock(void)
151 return kmem_cache_alloc(filelock_cache, GFP_KERNEL); 151 return kmem_cache_alloc(filelock_cache, GFP_KERNEL);
152} 152}
153 153
154static void locks_release_private(struct file_lock *fl) 154void locks_release_private(struct file_lock *fl)
155{ 155{
156 if (fl->fl_ops) { 156 if (fl->fl_ops) {
157 if (fl->fl_ops->fl_release_private) 157 if (fl->fl_ops->fl_release_private)
@@ -165,6 +165,7 @@ static void locks_release_private(struct file_lock *fl)
165 } 165 }
166 166
167} 167}
168EXPORT_SYMBOL_GPL(locks_release_private);
168 169
169/* Free a lock which is not in use. */ 170/* Free a lock which is not in use. */
170static void locks_free_lock(struct file_lock *fl) 171static void locks_free_lock(struct file_lock *fl)
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
index e67f3ec07736..7dbb8f27b9d6 100644
--- a/fs/nfs/Kconfig
+++ b/fs/nfs/Kconfig
@@ -1,6 +1,6 @@
1config NFS_FS 1config NFS_FS
2 tristate "NFS client support" 2 tristate "NFS client support"
3 depends on INET 3 depends on INET && FILE_LOCKING
4 select LOCKD 4 select LOCKD
5 select SUNRPC 5 select SUNRPC
6 select NFS_ACL_SUPPORT if NFS_V3_ACL 6 select NFS_ACL_SUPPORT if NFS_V3_ACL
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 5839b229cd0e..6eb918153fd4 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -464,16 +464,11 @@ static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp)
464 if (err) 464 if (err)
465 return err; 465 return err;
466 /* 466 /*
467 * Just a quick sanity check; we could also try to check 467 * XXX: It would be nice to also check whether this
468 * whether this pseudoflavor is supported, but at worst 468 * pseudoflavor is supported, so we can discover the
469 * an unsupported pseudoflavor on the export would just 469 * problem at export time instead of when a client fails
470 * be a pseudoflavor that won't match the flavor of any 470 * to authenticate.
471 * authenticated request. The administrator will
472 * probably discover the problem when someone fails to
473 * authenticate.
474 */ 471 */
475 if (f->pseudoflavor < 0)
476 return -EINVAL;
477 err = get_int(mesg, &f->flags); 472 err = get_int(mesg, &f->flags);
478 if (err) 473 if (err)
479 return err; 474 return err;
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 17d0dd997204..01d4ec1c88e0 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -272,6 +272,7 @@ void fill_post_wcc(struct svc_fh *fhp)
272 272
273 err = vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry, 273 err = vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry,
274 &fhp->fh_post_attr); 274 &fhp->fh_post_attr);
275 fhp->fh_post_change = fhp->fh_dentry->d_inode->i_version;
275 if (err) 276 if (err)
276 fhp->fh_post_saved = 0; 277 fhp->fh_post_saved = 0;
277 else 278 else
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 290289bd44f7..f4fab69a8c30 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -215,18 +215,18 @@ encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr)
215} 215}
216 216
217static int 217static int
218encode_cb_recall(struct xdr_stream *xdr, struct nfs4_cb_recall *cb_rec) 218encode_cb_recall(struct xdr_stream *xdr, struct nfs4_delegation *dp)
219{ 219{
220 __be32 *p; 220 __be32 *p;
221 int len = cb_rec->cbr_fh.fh_size; 221 int len = dp->dl_fh.fh_size;
222 222
223 RESERVE_SPACE(12+sizeof(cb_rec->cbr_stateid) + len); 223 RESERVE_SPACE(12+sizeof(dp->dl_stateid) + len);
224 WRITE32(OP_CB_RECALL); 224 WRITE32(OP_CB_RECALL);
225 WRITE32(cb_rec->cbr_stateid.si_generation); 225 WRITE32(dp->dl_stateid.si_generation);
226 WRITEMEM(&cb_rec->cbr_stateid.si_opaque, sizeof(stateid_opaque_t)); 226 WRITEMEM(&dp->dl_stateid.si_opaque, sizeof(stateid_opaque_t));
227 WRITE32(cb_rec->cbr_trunc); 227 WRITE32(0); /* truncate optimization not implemented */
228 WRITE32(len); 228 WRITE32(len);
229 WRITEMEM(&cb_rec->cbr_fh.fh_base, len); 229 WRITEMEM(&dp->dl_fh.fh_base, len);
230 return 0; 230 return 0;
231} 231}
232 232
@@ -241,11 +241,11 @@ nfs4_xdr_enc_cb_null(struct rpc_rqst *req, __be32 *p)
241} 241}
242 242
243static int 243static int
244nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p, struct nfs4_cb_recall *args) 244nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p, struct nfs4_delegation *args)
245{ 245{
246 struct xdr_stream xdr; 246 struct xdr_stream xdr;
247 struct nfs4_cb_compound_hdr hdr = { 247 struct nfs4_cb_compound_hdr hdr = {
248 .ident = args->cbr_ident, 248 .ident = args->dl_ident,
249 .nops = 1, 249 .nops = 1,
250 }; 250 };
251 251
@@ -358,18 +358,21 @@ static struct rpc_program cb_program = {
358 .pipe_dir_name = "/nfsd4_cb", 358 .pipe_dir_name = "/nfsd4_cb",
359}; 359};
360 360
361static int max_cb_time(void)
362{
363 return max(NFSD_LEASE_TIME/10, (time_t)1) * HZ;
364}
365
361/* Reference counting, callback cleanup, etc., all look racy as heck. 366/* Reference counting, callback cleanup, etc., all look racy as heck.
362 * And why is cb_set an atomic? */ 367 * And why is cb_set an atomic? */
363 368
364static struct rpc_clnt *setup_callback_client(struct nfs4_client *clp) 369int setup_callback_client(struct nfs4_client *clp)
365{ 370{
366 struct sockaddr_in addr; 371 struct sockaddr_in addr;
367 struct nfs4_callback *cb = &clp->cl_callback; 372 struct nfs4_cb_conn *cb = &clp->cl_cb_conn;
368 struct rpc_timeout timeparms = { 373 struct rpc_timeout timeparms = {
369 .to_initval = (NFSD_LEASE_TIME/4) * HZ, 374 .to_initval = max_cb_time(),
370 .to_retries = 5, 375 .to_retries = 0,
371 .to_maxval = (NFSD_LEASE_TIME/2) * HZ,
372 .to_exponential = 1,
373 }; 376 };
374 struct rpc_create_args args = { 377 struct rpc_create_args args = {
375 .protocol = IPPROTO_TCP, 378 .protocol = IPPROTO_TCP,
@@ -386,7 +389,7 @@ static struct rpc_clnt *setup_callback_client(struct nfs4_client *clp)
386 struct rpc_clnt *client; 389 struct rpc_clnt *client;
387 390
388 if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) 391 if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5))
389 return ERR_PTR(-EINVAL); 392 return -EINVAL;
390 393
391 /* Initialize address */ 394 /* Initialize address */
392 memset(&addr, 0, sizeof(addr)); 395 memset(&addr, 0, sizeof(addr));
@@ -396,48 +399,77 @@ static struct rpc_clnt *setup_callback_client(struct nfs4_client *clp)
396 399
397 /* Create RPC client */ 400 /* Create RPC client */
398 client = rpc_create(&args); 401 client = rpc_create(&args);
399 if (IS_ERR(client)) 402 if (IS_ERR(client)) {
400 dprintk("NFSD: couldn't create callback client: %ld\n", 403 dprintk("NFSD: couldn't create callback client: %ld\n",
401 PTR_ERR(client)); 404 PTR_ERR(client));
402 return client; 405 return PTR_ERR(client);
406 }
407 cb->cb_client = client;
408 return 0;
409
410}
411
412static void warn_no_callback_path(struct nfs4_client *clp, int reason)
413{
414 dprintk("NFSD: warning: no callback path to client %.*s: error %d\n",
415 (int)clp->cl_name.len, clp->cl_name.data, reason);
416}
417
418static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata)
419{
420 struct nfs4_client *clp = calldata;
421
422 if (task->tk_status)
423 warn_no_callback_path(clp, task->tk_status);
424 else
425 atomic_set(&clp->cl_cb_conn.cb_set, 1);
426 put_nfs4_client(clp);
427}
428
429static const struct rpc_call_ops nfsd4_cb_probe_ops = {
430 .rpc_call_done = nfsd4_cb_probe_done,
431};
403 432
433static struct rpc_cred *lookup_cb_cred(struct nfs4_cb_conn *cb)
434{
435 struct auth_cred acred = {
436 .machine_cred = 1
437 };
438
439 /*
440 * Note in the gss case this doesn't actually have to wait for a
441 * gss upcall (or any calls to the client); this just creates a
442 * non-uptodate cred which the rpc state machine will fill in with
443 * a refresh_upcall later.
444 */
445 return rpcauth_lookup_credcache(cb->cb_client->cl_auth, &acred,
446 RPCAUTH_LOOKUP_NEW);
404} 447}
405 448
406static int do_probe_callback(void *data) 449void do_probe_callback(struct nfs4_client *clp)
407{ 450{
408 struct nfs4_client *clp = data; 451 struct nfs4_cb_conn *cb = &clp->cl_cb_conn;
409 struct nfs4_callback *cb = &clp->cl_callback;
410 struct rpc_message msg = { 452 struct rpc_message msg = {
411 .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], 453 .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
412 .rpc_argp = clp, 454 .rpc_argp = clp,
413 }; 455 };
414 struct rpc_clnt *client; 456 struct rpc_cred *cred;
415 int status; 457 int status;
416 458
417 client = setup_callback_client(clp); 459 cred = lookup_cb_cred(cb);
418 if (IS_ERR(client)) { 460 if (IS_ERR(cred)) {
419 status = PTR_ERR(client); 461 status = PTR_ERR(cred);
420 dprintk("NFSD: couldn't create callback client: %d\n", 462 goto out;
421 status); 463 }
422 goto out_err; 464 cb->cb_cred = cred;
465 msg.rpc_cred = cb->cb_cred;
466 status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_SOFT,
467 &nfsd4_cb_probe_ops, (void *)clp);
468out:
469 if (status) {
470 warn_no_callback_path(clp, status);
471 put_nfs4_client(clp);
423 } 472 }
424
425 status = rpc_call_sync(client, &msg, RPC_TASK_SOFT);
426
427 if (status)
428 goto out_release_client;
429
430 cb->cb_client = client;
431 atomic_set(&cb->cb_set, 1);
432 put_nfs4_client(clp);
433 return 0;
434out_release_client:
435 rpc_shutdown_client(client);
436out_err:
437 dprintk("NFSD: warning: no callback path to client %.*s: error %d\n",
438 (int)clp->cl_name.len, clp->cl_name.data, status);
439 put_nfs4_client(clp);
440 return 0;
441} 473}
442 474
443/* 475/*
@@ -446,21 +478,65 @@ out_err:
446void 478void
447nfsd4_probe_callback(struct nfs4_client *clp) 479nfsd4_probe_callback(struct nfs4_client *clp)
448{ 480{
449 struct task_struct *t; 481 int status;
482
483 BUG_ON(atomic_read(&clp->cl_cb_conn.cb_set));
450 484
451 BUG_ON(atomic_read(&clp->cl_callback.cb_set)); 485 status = setup_callback_client(clp);
486 if (status) {
487 warn_no_callback_path(clp, status);
488 return;
489 }
452 490
453 /* the task holds a reference to the nfs4_client struct */ 491 /* the task holds a reference to the nfs4_client struct */
454 atomic_inc(&clp->cl_count); 492 atomic_inc(&clp->cl_count);
455 493
456 t = kthread_run(do_probe_callback, clp, "nfs4_cb_probe"); 494 do_probe_callback(clp);
495}
457 496
458 if (IS_ERR(t)) 497static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
459 atomic_dec(&clp->cl_count); 498{
499 struct nfs4_delegation *dp = calldata;
500 struct nfs4_client *clp = dp->dl_client;
460 501
461 return; 502 switch (task->tk_status) {
503 case -EIO:
504 /* Network partition? */
505 atomic_set(&clp->cl_cb_conn.cb_set, 0);
506 warn_no_callback_path(clp, task->tk_status);
507 case -EBADHANDLE:
508 case -NFS4ERR_BAD_STATEID:
509 /* Race: client probably got cb_recall
510 * before open reply granting delegation */
511 break;
512 default:
513 /* success, or error we can't handle */
514 return;
515 }
516 if (dp->dl_retries--) {
517 rpc_delay(task, 2*HZ);
518 task->tk_status = 0;
519 rpc_restart_call(task);
520 } else {
521 atomic_set(&clp->cl_cb_conn.cb_set, 0);
522 warn_no_callback_path(clp, task->tk_status);
523 }
462} 524}
463 525
526static void nfsd4_cb_recall_release(void *calldata)
527{
528 struct nfs4_delegation *dp = calldata;
529 struct nfs4_client *clp = dp->dl_client;
530
531 nfs4_put_delegation(dp);
532 put_nfs4_client(clp);
533}
534
535static const struct rpc_call_ops nfsd4_cb_recall_ops = {
536 .rpc_call_done = nfsd4_cb_recall_done,
537 .rpc_release = nfsd4_cb_recall_release,
538};
539
464/* 540/*
465 * called with dp->dl_count inc'ed. 541 * called with dp->dl_count inc'ed.
466 */ 542 */
@@ -468,41 +544,19 @@ void
468nfsd4_cb_recall(struct nfs4_delegation *dp) 544nfsd4_cb_recall(struct nfs4_delegation *dp)
469{ 545{
470 struct nfs4_client *clp = dp->dl_client; 546 struct nfs4_client *clp = dp->dl_client;
471 struct rpc_clnt *clnt = clp->cl_callback.cb_client; 547 struct rpc_clnt *clnt = clp->cl_cb_conn.cb_client;
472 struct nfs4_cb_recall *cbr = &dp->dl_recall;
473 struct rpc_message msg = { 548 struct rpc_message msg = {
474 .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL], 549 .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL],
475 .rpc_argp = cbr, 550 .rpc_argp = dp,
551 .rpc_cred = clp->cl_cb_conn.cb_cred
476 }; 552 };
477 int retries = 1; 553 int status;
478 int status = 0; 554
479 555 dp->dl_retries = 1;
480 cbr->cbr_trunc = 0; /* XXX need to implement truncate optimization */ 556 status = rpc_call_async(clnt, &msg, RPC_TASK_SOFT,
481 cbr->cbr_dp = dp; 557 &nfsd4_cb_recall_ops, dp);
482 558 if (status) {
483 status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT); 559 put_nfs4_client(clp);
484 while (retries--) { 560 nfs4_put_delegation(dp);
485 switch (status) {
486 case -EIO:
487 /* Network partition? */
488 atomic_set(&clp->cl_callback.cb_set, 0);
489 case -EBADHANDLE:
490 case -NFS4ERR_BAD_STATEID:
491 /* Race: client probably got cb_recall
492 * before open reply granting delegation */
493 break;
494 default:
495 goto out_put_cred;
496 }
497 ssleep(2);
498 status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT);
499 } 561 }
500out_put_cred:
501 /*
502 * Success or failure, now we're either waiting for lease expiration
503 * or deleg_return.
504 */
505 put_nfs4_client(clp);
506 nfs4_put_delegation(dp);
507 return;
508} 562}
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index b2883e9c6381..7c8801769a3c 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -51,6 +51,78 @@
51 51
52#define NFSDDBG_FACILITY NFSDDBG_PROC 52#define NFSDDBG_FACILITY NFSDDBG_PROC
53 53
54static u32 nfsd_attrmask[] = {
55 NFSD_WRITEABLE_ATTRS_WORD0,
56 NFSD_WRITEABLE_ATTRS_WORD1,
57 NFSD_WRITEABLE_ATTRS_WORD2
58};
59
60static u32 nfsd41_ex_attrmask[] = {
61 NFSD_SUPPATTR_EXCLCREAT_WORD0,
62 NFSD_SUPPATTR_EXCLCREAT_WORD1,
63 NFSD_SUPPATTR_EXCLCREAT_WORD2
64};
65
66static __be32
67check_attr_support(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
68 u32 *bmval, u32 *writable)
69{
70 struct dentry *dentry = cstate->current_fh.fh_dentry;
71 struct svc_export *exp = cstate->current_fh.fh_export;
72
73 /*
74 * Check about attributes are supported by the NFSv4 server or not.
75 * According to spec, unsupported attributes return ERR_ATTRNOTSUPP.
76 */
77 if ((bmval[0] & ~nfsd_suppattrs0(cstate->minorversion)) ||
78 (bmval[1] & ~nfsd_suppattrs1(cstate->minorversion)) ||
79 (bmval[2] & ~nfsd_suppattrs2(cstate->minorversion)))
80 return nfserr_attrnotsupp;
81
82 /*
83 * Check FATTR4_WORD0_ACL & FATTR4_WORD0_FS_LOCATIONS can be supported
84 * in current environment or not.
85 */
86 if (bmval[0] & FATTR4_WORD0_ACL) {
87 if (!IS_POSIXACL(dentry->d_inode))
88 return nfserr_attrnotsupp;
89 }
90 if (bmval[0] & FATTR4_WORD0_FS_LOCATIONS) {
91 if (exp->ex_fslocs.locations == NULL)
92 return nfserr_attrnotsupp;
93 }
94
95 /*
96 * According to spec, read-only attributes return ERR_INVAL.
97 */
98 if (writable) {
99 if ((bmval[0] & ~writable[0]) || (bmval[1] & ~writable[1]) ||
100 (bmval[2] & ~writable[2]))
101 return nfserr_inval;
102 }
103
104 return nfs_ok;
105}
106
107static __be32
108nfsd4_check_open_attributes(struct svc_rqst *rqstp,
109 struct nfsd4_compound_state *cstate, struct nfsd4_open *open)
110{
111 __be32 status = nfs_ok;
112
113 if (open->op_create == NFS4_OPEN_CREATE) {
114 if (open->op_createmode == NFS4_CREATE_UNCHECKED
115 || open->op_createmode == NFS4_CREATE_GUARDED)
116 status = check_attr_support(rqstp, cstate,
117 open->op_bmval, nfsd_attrmask);
118 else if (open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1)
119 status = check_attr_support(rqstp, cstate,
120 open->op_bmval, nfsd41_ex_attrmask);
121 }
122
123 return status;
124}
125
54static inline void 126static inline void
55fh_dup2(struct svc_fh *dst, struct svc_fh *src) 127fh_dup2(struct svc_fh *dst, struct svc_fh *src)
56{ 128{
@@ -225,6 +297,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
225 if (status) 297 if (status)
226 goto out; 298 goto out;
227 299
300 status = nfsd4_check_open_attributes(rqstp, cstate, open);
301 if (status)
302 goto out;
303
228 /* Openowner is now set, so sequence id will get bumped. Now we need 304 /* Openowner is now set, so sequence id will get bumped. Now we need
229 * these checks before we do any creates: */ 305 * these checks before we do any creates: */
230 status = nfserr_grace; 306 status = nfserr_grace;
@@ -395,6 +471,11 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
395 if (status) 471 if (status)
396 return status; 472 return status;
397 473
474 status = check_attr_support(rqstp, cstate, create->cr_bmval,
475 nfsd_attrmask);
476 if (status)
477 return status;
478
398 switch (create->cr_type) { 479 switch (create->cr_type) {
399 case NF4LNK: 480 case NF4LNK:
400 /* ugh! we have to null-terminate the linktext, or 481 /* ugh! we have to null-terminate the linktext, or
@@ -689,6 +770,12 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
689 if (status) 770 if (status)
690 return status; 771 return status;
691 status = nfs_ok; 772 status = nfs_ok;
773
774 status = check_attr_support(rqstp, cstate, setattr->sa_bmval,
775 nfsd_attrmask);
776 if (status)
777 goto out;
778
692 if (setattr->sa_acl != NULL) 779 if (setattr->sa_acl != NULL)
693 status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh, 780 status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh,
694 setattr->sa_acl); 781 setattr->sa_acl);
@@ -763,10 +850,10 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
763 if (status) 850 if (status)
764 return status; 851 return status;
765 852
766 if ((verify->ve_bmval[0] & ~nfsd_suppattrs0(cstate->minorversion)) 853 status = check_attr_support(rqstp, cstate, verify->ve_bmval, NULL);
767 || (verify->ve_bmval[1] & ~nfsd_suppattrs1(cstate->minorversion)) 854 if (status)
768 || (verify->ve_bmval[2] & ~nfsd_suppattrs2(cstate->minorversion))) 855 return status;
769 return nfserr_attrnotsupp; 856
770 if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR) 857 if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR)
771 || (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)) 858 || (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1))
772 return nfserr_inval; 859 return nfserr_inval;
@@ -1226,24 +1313,9 @@ static const char *nfsd4_op_name(unsigned opnum)
1226 return "unknown_operation"; 1313 return "unknown_operation";
1227} 1314}
1228 1315
1229#define nfs4svc_decode_voidargs NULL
1230#define nfs4svc_release_void NULL
1231#define nfsd4_voidres nfsd4_voidargs 1316#define nfsd4_voidres nfsd4_voidargs
1232#define nfs4svc_release_compound NULL
1233struct nfsd4_voidargs { int dummy; }; 1317struct nfsd4_voidargs { int dummy; };
1234 1318
1235#define PROC(name, argt, rest, relt, cache, respsize) \
1236 { (svc_procfunc) nfsd4_proc_##name, \
1237 (kxdrproc_t) nfs4svc_decode_##argt##args, \
1238 (kxdrproc_t) nfs4svc_encode_##rest##res, \
1239 (kxdrproc_t) nfs4svc_release_##relt, \
1240 sizeof(struct nfsd4_##argt##args), \
1241 sizeof(struct nfsd4_##rest##res), \
1242 0, \
1243 cache, \
1244 respsize, \
1245 }
1246
1247/* 1319/*
1248 * TODO: At the present time, the NFSv4 server does not do XID caching 1320 * TODO: At the present time, the NFSv4 server does not do XID caching
1249 * of requests. Implementing XID caching would not be a serious problem, 1321 * of requests. Implementing XID caching would not be a serious problem,
@@ -1255,8 +1327,23 @@ struct nfsd4_voidargs { int dummy; };
1255 * better XID's. 1327 * better XID's.
1256 */ 1328 */
1257static struct svc_procedure nfsd_procedures4[2] = { 1329static struct svc_procedure nfsd_procedures4[2] = {
1258 PROC(null, void, void, void, RC_NOCACHE, 1), 1330 [NFSPROC4_NULL] = {
1259 PROC(compound, compound, compound, compound, RC_NOCACHE, NFSD_BUFSIZE/4) 1331 .pc_func = (svc_procfunc) nfsd4_proc_null,
1332 .pc_encode = (kxdrproc_t) nfs4svc_encode_voidres,
1333 .pc_argsize = sizeof(struct nfsd4_voidargs),
1334 .pc_ressize = sizeof(struct nfsd4_voidres),
1335 .pc_cachetype = RC_NOCACHE,
1336 .pc_xdrressize = 1,
1337 },
1338 [NFSPROC4_COMPOUND] = {
1339 .pc_func = (svc_procfunc) nfsd4_proc_compound,
1340 .pc_decode = (kxdrproc_t) nfs4svc_decode_compoundargs,
1341 .pc_encode = (kxdrproc_t) nfs4svc_encode_compoundres,
1342 .pc_argsize = sizeof(struct nfsd4_compoundargs),
1343 .pc_ressize = sizeof(struct nfsd4_compoundres),
1344 .pc_cachetype = RC_NOCACHE,
1345 .pc_xdrressize = NFSD_BUFSIZE/4,
1346 },
1260}; 1347};
1261 1348
1262struct svc_version nfsd_version4 = { 1349struct svc_version nfsd_version4 = {
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 3b711f5147a7..89d9ac55c034 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -182,7 +182,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
182{ 182{
183 struct nfs4_delegation *dp; 183 struct nfs4_delegation *dp;
184 struct nfs4_file *fp = stp->st_file; 184 struct nfs4_file *fp = stp->st_file;
185 struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback; 185 struct nfs4_cb_conn *cb = &stp->st_stateowner->so_client->cl_cb_conn;
186 186
187 dprintk("NFSD alloc_init_deleg\n"); 187 dprintk("NFSD alloc_init_deleg\n");
188 if (fp->fi_had_conflict) 188 if (fp->fi_had_conflict)
@@ -203,10 +203,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
203 get_file(stp->st_vfs_file); 203 get_file(stp->st_vfs_file);
204 dp->dl_vfs_file = stp->st_vfs_file; 204 dp->dl_vfs_file = stp->st_vfs_file;
205 dp->dl_type = type; 205 dp->dl_type = type;
206 dp->dl_recall.cbr_dp = NULL; 206 dp->dl_ident = cb->cb_ident;
207 dp->dl_recall.cbr_ident = cb->cb_ident; 207 dp->dl_stateid.si_boot = get_seconds();
208 dp->dl_recall.cbr_trunc = 0;
209 dp->dl_stateid.si_boot = boot_time;
210 dp->dl_stateid.si_stateownerid = current_delegid++; 208 dp->dl_stateid.si_stateownerid = current_delegid++;
211 dp->dl_stateid.si_fileid = 0; 209 dp->dl_stateid.si_fileid = 0;
212 dp->dl_stateid.si_generation = 0; 210 dp->dl_stateid.si_generation = 0;
@@ -632,16 +630,20 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name)
632static void 630static void
633shutdown_callback_client(struct nfs4_client *clp) 631shutdown_callback_client(struct nfs4_client *clp)
634{ 632{
635 struct rpc_clnt *clnt = clp->cl_callback.cb_client; 633 struct rpc_clnt *clnt = clp->cl_cb_conn.cb_client;
636 634
637 if (clnt) { 635 if (clnt) {
638 /* 636 /*
639 * Callback threads take a reference on the client, so there 637 * Callback threads take a reference on the client, so there
640 * should be no outstanding callbacks at this point. 638 * should be no outstanding callbacks at this point.
641 */ 639 */
642 clp->cl_callback.cb_client = NULL; 640 clp->cl_cb_conn.cb_client = NULL;
643 rpc_shutdown_client(clnt); 641 rpc_shutdown_client(clnt);
644 } 642 }
643 if (clp->cl_cb_conn.cb_cred) {
644 put_rpccred(clp->cl_cb_conn.cb_cred);
645 clp->cl_cb_conn.cb_cred = NULL;
646 }
645} 647}
646 648
647static inline void 649static inline void
@@ -714,7 +716,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir)
714 return NULL; 716 return NULL;
715 memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); 717 memcpy(clp->cl_recdir, recdir, HEXDIR_LEN);
716 atomic_set(&clp->cl_count, 1); 718 atomic_set(&clp->cl_count, 1);
717 atomic_set(&clp->cl_callback.cb_set, 0); 719 atomic_set(&clp->cl_cb_conn.cb_set, 0);
718 INIT_LIST_HEAD(&clp->cl_idhash); 720 INIT_LIST_HEAD(&clp->cl_idhash);
719 INIT_LIST_HEAD(&clp->cl_strhash); 721 INIT_LIST_HEAD(&clp->cl_strhash);
720 INIT_LIST_HEAD(&clp->cl_openowners); 722 INIT_LIST_HEAD(&clp->cl_openowners);
@@ -966,7 +968,7 @@ parse_ipv4(unsigned int addr_len, char *addr_val, unsigned int *cbaddrp, unsigne
966static void 968static void
967gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se) 969gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se)
968{ 970{
969 struct nfs4_callback *cb = &clp->cl_callback; 971 struct nfs4_cb_conn *cb = &clp->cl_cb_conn;
970 972
971 /* Currently, we only support tcp for the callback channel */ 973 /* Currently, we only support tcp for the callback channel */
972 if ((se->se_callback_netid_len != 3) || memcmp((char *)se->se_callback_netid_val, "tcp", 3)) 974 if ((se->se_callback_netid_len != 3) || memcmp((char *)se->se_callback_netid_val, "tcp", 3))
@@ -1686,9 +1688,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
1686 else { 1688 else {
1687 /* XXX: We just turn off callbacks until we can handle 1689 /* XXX: We just turn off callbacks until we can handle
1688 * change request correctly. */ 1690 * change request correctly. */
1689 atomic_set(&conf->cl_callback.cb_set, 0); 1691 atomic_set(&conf->cl_cb_conn.cb_set, 0);
1690 gen_confirm(conf);
1691 nfsd4_remove_clid_dir(unconf);
1692 expire_client(unconf); 1692 expire_client(unconf);
1693 status = nfs_ok; 1693 status = nfs_ok;
1694 1694
@@ -1882,7 +1882,7 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *
1882 stp->st_stateowner = sop; 1882 stp->st_stateowner = sop;
1883 get_nfs4_file(fp); 1883 get_nfs4_file(fp);
1884 stp->st_file = fp; 1884 stp->st_file = fp;
1885 stp->st_stateid.si_boot = boot_time; 1885 stp->st_stateid.si_boot = get_seconds();
1886 stp->st_stateid.si_stateownerid = sop->so_id; 1886 stp->st_stateid.si_stateownerid = sop->so_id;
1887 stp->st_stateid.si_fileid = fp->fi_id; 1887 stp->st_stateid.si_fileid = fp->fi_id;
1888 stp->st_stateid.si_generation = 0; 1888 stp->st_stateid.si_generation = 0;
@@ -2059,19 +2059,6 @@ nfs4_file_downgrade(struct file *filp, unsigned int share_access)
2059} 2059}
2060 2060
2061/* 2061/*
2062 * Recall a delegation
2063 */
2064static int
2065do_recall(void *__dp)
2066{
2067 struct nfs4_delegation *dp = __dp;
2068
2069 dp->dl_file->fi_had_conflict = true;
2070 nfsd4_cb_recall(dp);
2071 return 0;
2072}
2073
2074/*
2075 * Spawn a thread to perform a recall on the delegation represented 2062 * Spawn a thread to perform a recall on the delegation represented
2076 * by the lease (file_lock) 2063 * by the lease (file_lock)
2077 * 2064 *
@@ -2082,8 +2069,7 @@ do_recall(void *__dp)
2082static 2069static
2083void nfsd_break_deleg_cb(struct file_lock *fl) 2070void nfsd_break_deleg_cb(struct file_lock *fl)
2084{ 2071{
2085 struct nfs4_delegation *dp= (struct nfs4_delegation *)fl->fl_owner; 2072 struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner;
2086 struct task_struct *t;
2087 2073
2088 dprintk("NFSD nfsd_break_deleg_cb: dp %p fl %p\n",dp,fl); 2074 dprintk("NFSD nfsd_break_deleg_cb: dp %p fl %p\n",dp,fl);
2089 if (!dp) 2075 if (!dp)
@@ -2111,16 +2097,8 @@ void nfsd_break_deleg_cb(struct file_lock *fl)
2111 */ 2097 */
2112 fl->fl_break_time = 0; 2098 fl->fl_break_time = 0;
2113 2099
2114 t = kthread_run(do_recall, dp, "%s", "nfs4_cb_recall"); 2100 dp->dl_file->fi_had_conflict = true;
2115 if (IS_ERR(t)) { 2101 nfsd4_cb_recall(dp);
2116 struct nfs4_client *clp = dp->dl_client;
2117
2118 printk(KERN_INFO "NFSD: Callback thread failed for "
2119 "for client (clientid %08x/%08x)\n",
2120 clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
2121 put_nfs4_client(dp->dl_client);
2122 nfs4_put_delegation(dp);
2123 }
2124} 2102}
2125 2103
2126/* 2104/*
@@ -2422,7 +2400,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
2422{ 2400{
2423 struct nfs4_delegation *dp; 2401 struct nfs4_delegation *dp;
2424 struct nfs4_stateowner *sop = stp->st_stateowner; 2402 struct nfs4_stateowner *sop = stp->st_stateowner;
2425 struct nfs4_callback *cb = &sop->so_client->cl_callback; 2403 struct nfs4_cb_conn *cb = &sop->so_client->cl_cb_conn;
2426 struct file_lock fl, *flp = &fl; 2404 struct file_lock fl, *flp = &fl;
2427 int status, flag = 0; 2405 int status, flag = 0;
2428 2406
@@ -2614,7 +2592,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2614 renew_client(clp); 2592 renew_client(clp);
2615 status = nfserr_cb_path_down; 2593 status = nfserr_cb_path_down;
2616 if (!list_empty(&clp->cl_delegations) 2594 if (!list_empty(&clp->cl_delegations)
2617 && !atomic_read(&clp->cl_callback.cb_set)) 2595 && !atomic_read(&clp->cl_cb_conn.cb_set))
2618 goto out; 2596 goto out;
2619 status = nfs_ok; 2597 status = nfs_ok;
2620out: 2598out:
@@ -2738,12 +2716,42 @@ nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp)
2738static int 2716static int
2739STALE_STATEID(stateid_t *stateid) 2717STALE_STATEID(stateid_t *stateid)
2740{ 2718{
2741 if (stateid->si_boot == boot_time) 2719 if (time_after((unsigned long)boot_time,
2742 return 0; 2720 (unsigned long)stateid->si_boot)) {
2743 dprintk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n", 2721 dprintk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n",
2744 stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid, 2722 stateid->si_boot, stateid->si_stateownerid,
2745 stateid->si_generation); 2723 stateid->si_fileid, stateid->si_generation);
2746 return 1; 2724 return 1;
2725 }
2726 return 0;
2727}
2728
2729static int
2730EXPIRED_STATEID(stateid_t *stateid)
2731{
2732 if (time_before((unsigned long)boot_time,
2733 ((unsigned long)stateid->si_boot)) &&
2734 time_before((unsigned long)(stateid->si_boot + lease_time), get_seconds())) {
2735 dprintk("NFSD: expired stateid (%08x/%08x/%08x/%08x)!\n",
2736 stateid->si_boot, stateid->si_stateownerid,
2737 stateid->si_fileid, stateid->si_generation);
2738 return 1;
2739 }
2740 return 0;
2741}
2742
2743static __be32
2744stateid_error_map(stateid_t *stateid)
2745{
2746 if (STALE_STATEID(stateid))
2747 return nfserr_stale_stateid;
2748 if (EXPIRED_STATEID(stateid))
2749 return nfserr_expired;
2750
2751 dprintk("NFSD: bad stateid (%08x/%08x/%08x/%08x)!\n",
2752 stateid->si_boot, stateid->si_stateownerid,
2753 stateid->si_fileid, stateid->si_generation);
2754 return nfserr_bad_stateid;
2747} 2755}
2748 2756
2749static inline int 2757static inline int
@@ -2867,8 +2875,10 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
2867 status = nfserr_bad_stateid; 2875 status = nfserr_bad_stateid;
2868 if (is_delegation_stateid(stateid)) { 2876 if (is_delegation_stateid(stateid)) {
2869 dp = find_delegation_stateid(ino, stateid); 2877 dp = find_delegation_stateid(ino, stateid);
2870 if (!dp) 2878 if (!dp) {
2879 status = stateid_error_map(stateid);
2871 goto out; 2880 goto out;
2881 }
2872 status = check_stateid_generation(stateid, &dp->dl_stateid, 2882 status = check_stateid_generation(stateid, &dp->dl_stateid,
2873 flags); 2883 flags);
2874 if (status) 2884 if (status)
@@ -2881,8 +2891,10 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
2881 *filpp = dp->dl_vfs_file; 2891 *filpp = dp->dl_vfs_file;
2882 } else { /* open or lock stateid */ 2892 } else { /* open or lock stateid */
2883 stp = find_stateid(stateid, flags); 2893 stp = find_stateid(stateid, flags);
2884 if (!stp) 2894 if (!stp) {
2895 status = stateid_error_map(stateid);
2885 goto out; 2896 goto out;
2897 }
2886 if (nfs4_check_fh(current_fh, stp)) 2898 if (nfs4_check_fh(current_fh, stp))
2887 goto out; 2899 goto out;
2888 if (!stp->st_stateowner->so_confirmed) 2900 if (!stp->st_stateowner->so_confirmed)
@@ -2956,7 +2968,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
2956 */ 2968 */
2957 sop = search_close_lru(stateid->si_stateownerid, flags); 2969 sop = search_close_lru(stateid->si_stateownerid, flags);
2958 if (sop == NULL) 2970 if (sop == NULL)
2959 return nfserr_bad_stateid; 2971 return stateid_error_map(stateid);
2960 *sopp = sop; 2972 *sopp = sop;
2961 goto check_replay; 2973 goto check_replay;
2962 } 2974 }
@@ -3227,8 +3239,10 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3227 if (!is_delegation_stateid(stateid)) 3239 if (!is_delegation_stateid(stateid))
3228 goto out; 3240 goto out;
3229 dp = find_delegation_stateid(inode, stateid); 3241 dp = find_delegation_stateid(inode, stateid);
3230 if (!dp) 3242 if (!dp) {
3243 status = stateid_error_map(stateid);
3231 goto out; 3244 goto out;
3245 }
3232 status = check_stateid_generation(stateid, &dp->dl_stateid, flags); 3246 status = check_stateid_generation(stateid, &dp->dl_stateid, flags);
3233 if (status) 3247 if (status)
3234 goto out; 3248 goto out;
@@ -3455,7 +3469,7 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc
3455 stp->st_stateowner = sop; 3469 stp->st_stateowner = sop;
3456 get_nfs4_file(fp); 3470 get_nfs4_file(fp);
3457 stp->st_file = fp; 3471 stp->st_file = fp;
3458 stp->st_stateid.si_boot = boot_time; 3472 stp->st_stateid.si_boot = get_seconds();
3459 stp->st_stateid.si_stateownerid = sop->so_id; 3473 stp->st_stateid.si_stateownerid = sop->so_id;
3460 stp->st_stateid.si_fileid = fp->fi_id; 3474 stp->st_stateid.si_fileid = fp->fi_id;
3461 stp->st_stateid.si_generation = 0; 3475 stp->st_stateid.si_generation = 0;
@@ -3987,6 +4001,7 @@ nfs4_state_init(void)
3987 INIT_LIST_HEAD(&conf_str_hashtbl[i]); 4001 INIT_LIST_HEAD(&conf_str_hashtbl[i]);
3988 INIT_LIST_HEAD(&unconf_str_hashtbl[i]); 4002 INIT_LIST_HEAD(&unconf_str_hashtbl[i]);
3989 INIT_LIST_HEAD(&unconf_id_hashtbl[i]); 4003 INIT_LIST_HEAD(&unconf_id_hashtbl[i]);
4004 INIT_LIST_HEAD(&reclaim_str_hashtbl[i]);
3990 } 4005 }
3991 for (i = 0; i < SESSION_HASH_SIZE; i++) 4006 for (i = 0; i < SESSION_HASH_SIZE; i++)
3992 INIT_LIST_HEAD(&sessionid_hashtbl[i]); 4007 INIT_LIST_HEAD(&sessionid_hashtbl[i]);
@@ -4009,8 +4024,6 @@ nfs4_state_init(void)
4009 INIT_LIST_HEAD(&close_lru); 4024 INIT_LIST_HEAD(&close_lru);
4010 INIT_LIST_HEAD(&client_lru); 4025 INIT_LIST_HEAD(&client_lru);
4011 INIT_LIST_HEAD(&del_recall_lru); 4026 INIT_LIST_HEAD(&del_recall_lru);
4012 for (i = 0; i < CLIENT_HASH_SIZE; i++)
4013 INIT_LIST_HEAD(&reclaim_str_hashtbl[i]);
4014 reclaim_str_hashtbl_size = 0; 4027 reclaim_str_hashtbl_size = 0;
4015 return 0; 4028 return 0;
4016} 4029}
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index b73549d293be..d07f704a2ac9 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -83,16 +83,6 @@ check_filename(char *str, int len, __be32 err)
83 return 0; 83 return 0;
84} 84}
85 85
86/*
87 * START OF "GENERIC" DECODE ROUTINES.
88 * These may look a little ugly since they are imported from a "generic"
89 * set of XDR encode/decode routines which are intended to be shared by
90 * all of our NFSv4 implementations (OpenBSD, MacOS X...).
91 *
92 * If the pain of reading these is too great, it should be a straightforward
93 * task to translate them into Linux-specific versions which are more
94 * consistent with the style used in NFSv2/v3...
95 */
96#define DECODE_HEAD \ 86#define DECODE_HEAD \
97 __be32 *p; \ 87 __be32 *p; \
98 __be32 status 88 __be32 status
@@ -254,20 +244,8 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval)
254 DECODE_TAIL; 244 DECODE_TAIL;
255} 245}
256 246
257static u32 nfsd_attrmask[] = {
258 NFSD_WRITEABLE_ATTRS_WORD0,
259 NFSD_WRITEABLE_ATTRS_WORD1,
260 NFSD_WRITEABLE_ATTRS_WORD2
261};
262
263static u32 nfsd41_ex_attrmask[] = {
264 NFSD_SUPPATTR_EXCLCREAT_WORD0,
265 NFSD_SUPPATTR_EXCLCREAT_WORD1,
266 NFSD_SUPPATTR_EXCLCREAT_WORD2
267};
268
269static __be32 247static __be32
270nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, u32 *writable, 248nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
271 struct iattr *iattr, struct nfs4_acl **acl) 249 struct iattr *iattr, struct nfs4_acl **acl)
272{ 250{
273 int expected_len, len = 0; 251 int expected_len, len = 0;
@@ -280,18 +258,6 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, u32 *writable,
280 if ((status = nfsd4_decode_bitmap(argp, bmval))) 258 if ((status = nfsd4_decode_bitmap(argp, bmval)))
281 return status; 259 return status;
282 260
283 /*
284 * According to spec, unsupported attributes return ERR_ATTRNOTSUPP;
285 * read-only attributes return ERR_INVAL.
286 */
287 if ((bmval[0] & ~nfsd_suppattrs0(argp->minorversion)) ||
288 (bmval[1] & ~nfsd_suppattrs1(argp->minorversion)) ||
289 (bmval[2] & ~nfsd_suppattrs2(argp->minorversion)))
290 return nfserr_attrnotsupp;
291 if ((bmval[0] & ~writable[0]) || (bmval[1] & ~writable[1]) ||
292 (bmval[2] & ~writable[2]))
293 return nfserr_inval;
294
295 READ_BUF(4); 261 READ_BUF(4);
296 READ32(expected_len); 262 READ32(expected_len);
297 263
@@ -424,8 +390,11 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, u32 *writable,
424 goto xdr_error; 390 goto xdr_error;
425 } 391 }
426 } 392 }
427 BUG_ON(bmval[2]); /* no such writeable attr supported yet */ 393 if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0
428 if (len != expected_len) 394 || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1
395 || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2)
396 READ_BUF(expected_len - len);
397 else if (len != expected_len)
429 goto xdr_error; 398 goto xdr_error;
430 399
431 DECODE_TAIL; 400 DECODE_TAIL;
@@ -518,8 +487,8 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create
518 if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval))) 487 if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval)))
519 return status; 488 return status;
520 489
521 status = nfsd4_decode_fattr(argp, create->cr_bmval, nfsd_attrmask, 490 status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr,
522 &create->cr_iattr, &create->cr_acl); 491 &create->cr_acl);
523 if (status) 492 if (status)
524 goto out; 493 goto out;
525 494
@@ -682,7 +651,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
682 case NFS4_CREATE_UNCHECKED: 651 case NFS4_CREATE_UNCHECKED:
683 case NFS4_CREATE_GUARDED: 652 case NFS4_CREATE_GUARDED:
684 status = nfsd4_decode_fattr(argp, open->op_bmval, 653 status = nfsd4_decode_fattr(argp, open->op_bmval,
685 nfsd_attrmask, &open->op_iattr, &open->op_acl); 654 &open->op_iattr, &open->op_acl);
686 if (status) 655 if (status)
687 goto out; 656 goto out;
688 break; 657 break;
@@ -696,8 +665,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
696 READ_BUF(8); 665 READ_BUF(8);
697 COPYMEM(open->op_verf.data, 8); 666 COPYMEM(open->op_verf.data, 8);
698 status = nfsd4_decode_fattr(argp, open->op_bmval, 667 status = nfsd4_decode_fattr(argp, open->op_bmval,
699 nfsd41_ex_attrmask, &open->op_iattr, 668 &open->op_iattr, &open->op_acl);
700 &open->op_acl);
701 if (status) 669 if (status)
702 goto out; 670 goto out;
703 break; 671 break;
@@ -893,8 +861,8 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta
893 status = nfsd4_decode_stateid(argp, &setattr->sa_stateid); 861 status = nfsd4_decode_stateid(argp, &setattr->sa_stateid);
894 if (status) 862 if (status)
895 return status; 863 return status;
896 return nfsd4_decode_fattr(argp, setattr->sa_bmval, nfsd_attrmask, 864 return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr,
897 &setattr->sa_iattr, &setattr->sa_acl); 865 &setattr->sa_acl);
898} 866}
899 867
900static __be32 868static __be32
@@ -1328,64 +1296,64 @@ static nfsd4_dec nfsd4_dec_ops[] = {
1328}; 1296};
1329 1297
1330static nfsd4_dec nfsd41_dec_ops[] = { 1298static nfsd4_dec nfsd41_dec_ops[] = {
1331 [OP_ACCESS] (nfsd4_dec)nfsd4_decode_access, 1299 [OP_ACCESS] = (nfsd4_dec)nfsd4_decode_access,
1332 [OP_CLOSE] (nfsd4_dec)nfsd4_decode_close, 1300 [OP_CLOSE] = (nfsd4_dec)nfsd4_decode_close,
1333 [OP_COMMIT] (nfsd4_dec)nfsd4_decode_commit, 1301 [OP_COMMIT] = (nfsd4_dec)nfsd4_decode_commit,
1334 [OP_CREATE] (nfsd4_dec)nfsd4_decode_create, 1302 [OP_CREATE] = (nfsd4_dec)nfsd4_decode_create,
1335 [OP_DELEGPURGE] (nfsd4_dec)nfsd4_decode_notsupp, 1303 [OP_DELEGPURGE] = (nfsd4_dec)nfsd4_decode_notsupp,
1336 [OP_DELEGRETURN] (nfsd4_dec)nfsd4_decode_delegreturn, 1304 [OP_DELEGRETURN] = (nfsd4_dec)nfsd4_decode_delegreturn,
1337 [OP_GETATTR] (nfsd4_dec)nfsd4_decode_getattr, 1305 [OP_GETATTR] = (nfsd4_dec)nfsd4_decode_getattr,
1338 [OP_GETFH] (nfsd4_dec)nfsd4_decode_noop, 1306 [OP_GETFH] = (nfsd4_dec)nfsd4_decode_noop,
1339 [OP_LINK] (nfsd4_dec)nfsd4_decode_link, 1307 [OP_LINK] = (nfsd4_dec)nfsd4_decode_link,
1340 [OP_LOCK] (nfsd4_dec)nfsd4_decode_lock, 1308 [OP_LOCK] = (nfsd4_dec)nfsd4_decode_lock,
1341 [OP_LOCKT] (nfsd4_dec)nfsd4_decode_lockt, 1309 [OP_LOCKT] = (nfsd4_dec)nfsd4_decode_lockt,
1342 [OP_LOCKU] (nfsd4_dec)nfsd4_decode_locku, 1310 [OP_LOCKU] = (nfsd4_dec)nfsd4_decode_locku,
1343 [OP_LOOKUP] (nfsd4_dec)nfsd4_decode_lookup, 1311 [OP_LOOKUP] = (nfsd4_dec)nfsd4_decode_lookup,
1344 [OP_LOOKUPP] (nfsd4_dec)nfsd4_decode_noop, 1312 [OP_LOOKUPP] = (nfsd4_dec)nfsd4_decode_noop,
1345 [OP_NVERIFY] (nfsd4_dec)nfsd4_decode_verify, 1313 [OP_NVERIFY] = (nfsd4_dec)nfsd4_decode_verify,
1346 [OP_OPEN] (nfsd4_dec)nfsd4_decode_open, 1314 [OP_OPEN] = (nfsd4_dec)nfsd4_decode_open,
1347 [OP_OPENATTR] (nfsd4_dec)nfsd4_decode_notsupp, 1315 [OP_OPENATTR] = (nfsd4_dec)nfsd4_decode_notsupp,
1348 [OP_OPEN_CONFIRM] (nfsd4_dec)nfsd4_decode_notsupp, 1316 [OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_notsupp,
1349 [OP_OPEN_DOWNGRADE] (nfsd4_dec)nfsd4_decode_open_downgrade, 1317 [OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade,
1350 [OP_PUTFH] (nfsd4_dec)nfsd4_decode_putfh, 1318 [OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh,
1351 [OP_PUTPUBFH] (nfsd4_dec)nfsd4_decode_notsupp, 1319 [OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_notsupp,
1352 [OP_PUTROOTFH] (nfsd4_dec)nfsd4_decode_noop, 1320 [OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop,
1353 [OP_READ] (nfsd4_dec)nfsd4_decode_read, 1321 [OP_READ] = (nfsd4_dec)nfsd4_decode_read,
1354 [OP_READDIR] (nfsd4_dec)nfsd4_decode_readdir, 1322 [OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir,
1355 [OP_READLINK] (nfsd4_dec)nfsd4_decode_noop, 1323 [OP_READLINK] = (nfsd4_dec)nfsd4_decode_noop,
1356 [OP_REMOVE] (nfsd4_dec)nfsd4_decode_remove, 1324 [OP_REMOVE] = (nfsd4_dec)nfsd4_decode_remove,
1357 [OP_RENAME] (nfsd4_dec)nfsd4_decode_rename, 1325 [OP_RENAME] = (nfsd4_dec)nfsd4_decode_rename,
1358 [OP_RENEW] (nfsd4_dec)nfsd4_decode_notsupp, 1326 [OP_RENEW] = (nfsd4_dec)nfsd4_decode_notsupp,
1359 [OP_RESTOREFH] (nfsd4_dec)nfsd4_decode_noop, 1327 [OP_RESTOREFH] = (nfsd4_dec)nfsd4_decode_noop,
1360 [OP_SAVEFH] (nfsd4_dec)nfsd4_decode_noop, 1328 [OP_SAVEFH] = (nfsd4_dec)nfsd4_decode_noop,
1361 [OP_SECINFO] (nfsd4_dec)nfsd4_decode_secinfo, 1329 [OP_SECINFO] = (nfsd4_dec)nfsd4_decode_secinfo,
1362 [OP_SETATTR] (nfsd4_dec)nfsd4_decode_setattr, 1330 [OP_SETATTR] = (nfsd4_dec)nfsd4_decode_setattr,
1363 [OP_SETCLIENTID] (nfsd4_dec)nfsd4_decode_notsupp, 1331 [OP_SETCLIENTID] = (nfsd4_dec)nfsd4_decode_notsupp,
1364 [OP_SETCLIENTID_CONFIRM](nfsd4_dec)nfsd4_decode_notsupp, 1332 [OP_SETCLIENTID_CONFIRM]= (nfsd4_dec)nfsd4_decode_notsupp,
1365 [OP_VERIFY] (nfsd4_dec)nfsd4_decode_verify, 1333 [OP_VERIFY] = (nfsd4_dec)nfsd4_decode_verify,
1366 [OP_WRITE] (nfsd4_dec)nfsd4_decode_write, 1334 [OP_WRITE] = (nfsd4_dec)nfsd4_decode_write,
1367 [OP_RELEASE_LOCKOWNER] (nfsd4_dec)nfsd4_decode_notsupp, 1335 [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_notsupp,
1368 1336
1369 /* new operations for NFSv4.1 */ 1337 /* new operations for NFSv4.1 */
1370 [OP_BACKCHANNEL_CTL] (nfsd4_dec)nfsd4_decode_notsupp, 1338 [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_notsupp,
1371 [OP_BIND_CONN_TO_SESSION](nfsd4_dec)nfsd4_decode_notsupp, 1339 [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_notsupp,
1372 [OP_EXCHANGE_ID] (nfsd4_dec)nfsd4_decode_exchange_id, 1340 [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id,
1373 [OP_CREATE_SESSION] (nfsd4_dec)nfsd4_decode_create_session, 1341 [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session,
1374 [OP_DESTROY_SESSION] (nfsd4_dec)nfsd4_decode_destroy_session, 1342 [OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session,
1375 [OP_FREE_STATEID] (nfsd4_dec)nfsd4_decode_notsupp, 1343 [OP_FREE_STATEID] = (nfsd4_dec)nfsd4_decode_notsupp,
1376 [OP_GET_DIR_DELEGATION] (nfsd4_dec)nfsd4_decode_notsupp, 1344 [OP_GET_DIR_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp,
1377 [OP_GETDEVICEINFO] (nfsd4_dec)nfsd4_decode_notsupp, 1345 [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_notsupp,
1378 [OP_GETDEVICELIST] (nfsd4_dec)nfsd4_decode_notsupp, 1346 [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp,
1379 [OP_LAYOUTCOMMIT] (nfsd4_dec)nfsd4_decode_notsupp, 1347 [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_notsupp,
1380 [OP_LAYOUTGET] (nfsd4_dec)nfsd4_decode_notsupp, 1348 [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_notsupp,
1381 [OP_LAYOUTRETURN] (nfsd4_dec)nfsd4_decode_notsupp, 1349 [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_notsupp,
1382 [OP_SECINFO_NO_NAME] (nfsd4_dec)nfsd4_decode_notsupp, 1350 [OP_SECINFO_NO_NAME] = (nfsd4_dec)nfsd4_decode_notsupp,
1383 [OP_SEQUENCE] (nfsd4_dec)nfsd4_decode_sequence, 1351 [OP_SEQUENCE] = (nfsd4_dec)nfsd4_decode_sequence,
1384 [OP_SET_SSV] (nfsd4_dec)nfsd4_decode_notsupp, 1352 [OP_SET_SSV] = (nfsd4_dec)nfsd4_decode_notsupp,
1385 [OP_TEST_STATEID] (nfsd4_dec)nfsd4_decode_notsupp, 1353 [OP_TEST_STATEID] = (nfsd4_dec)nfsd4_decode_notsupp,
1386 [OP_WANT_DELEGATION] (nfsd4_dec)nfsd4_decode_notsupp, 1354 [OP_WANT_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp,
1387 [OP_DESTROY_CLIENTID] (nfsd4_dec)nfsd4_decode_notsupp, 1355 [OP_DESTROY_CLIENTID] = (nfsd4_dec)nfsd4_decode_notsupp,
1388 [OP_RECLAIM_COMPLETE] (nfsd4_dec)nfsd4_decode_notsupp, 1356 [OP_RECLAIM_COMPLETE] = (nfsd4_dec)nfsd4_decode_notsupp,
1389}; 1357};
1390 1358
1391struct nfsd4_minorversion_ops { 1359struct nfsd4_minorversion_ops {
@@ -1489,21 +1457,6 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
1489 1457
1490 DECODE_TAIL; 1458 DECODE_TAIL;
1491} 1459}
1492/*
1493 * END OF "GENERIC" DECODE ROUTINES.
1494 */
1495
1496/*
1497 * START OF "GENERIC" ENCODE ROUTINES.
1498 * These may look a little ugly since they are imported from a "generic"
1499 * set of XDR encode/decode routines which are intended to be shared by
1500 * all of our NFSv4 implementations (OpenBSD, MacOS X...).
1501 *
1502 * If the pain of reading these is too great, it should be a straightforward
1503 * task to translate them into Linux-specific versions which are more
1504 * consistent with the style used in NFSv2/v3...
1505 */
1506#define ENCODE_HEAD __be32 *p
1507 1460
1508#define WRITE32(n) *p++ = htonl(n) 1461#define WRITE32(n) *p++ = htonl(n)
1509#define WRITE64(n) do { \ 1462#define WRITE64(n) do { \
@@ -1515,13 +1468,41 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
1515 memcpy(p, ptr, nbytes); \ 1468 memcpy(p, ptr, nbytes); \
1516 p += XDR_QUADLEN(nbytes); \ 1469 p += XDR_QUADLEN(nbytes); \
1517}} while (0) 1470}} while (0)
1518#define WRITECINFO(c) do { \ 1471
1519 *p++ = htonl(c.atomic); \ 1472static void write32(__be32 **p, u32 n)
1520 *p++ = htonl(c.before_ctime_sec); \ 1473{
1521 *p++ = htonl(c.before_ctime_nsec); \ 1474 *(*p)++ = n;
1522 *p++ = htonl(c.after_ctime_sec); \ 1475}
1523 *p++ = htonl(c.after_ctime_nsec); \ 1476
1524} while (0) 1477static void write64(__be32 **p, u64 n)
1478{
1479 write32(p, (u32)(n >> 32));
1480 write32(p, (u32)n);
1481}
1482
1483static void write_change(__be32 **p, struct kstat *stat, struct inode *inode)
1484{
1485 if (IS_I_VERSION(inode)) {
1486 write64(p, inode->i_version);
1487 } else {
1488 write32(p, stat->ctime.tv_sec);
1489 write32(p, stat->ctime.tv_nsec);
1490 }
1491}
1492
1493static void write_cinfo(__be32 **p, struct nfsd4_change_info *c)
1494{
1495 write32(p, c->atomic);
1496 if (c->change_supported) {
1497 write64(p, c->before_change);
1498 write64(p, c->after_change);
1499 } else {
1500 write32(p, c->before_ctime_sec);
1501 write32(p, c->before_ctime_nsec);
1502 write32(p, c->after_ctime_sec);
1503 write32(p, c->after_ctime_nsec);
1504 }
1505}
1525 1506
1526#define RESERVE_SPACE(nbytes) do { \ 1507#define RESERVE_SPACE(nbytes) do { \
1527 p = resp->p; \ 1508 p = resp->p; \
@@ -1874,16 +1855,9 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
1874 WRITE32(NFS4_FH_PERSISTENT|NFS4_FH_VOL_RENAME); 1855 WRITE32(NFS4_FH_PERSISTENT|NFS4_FH_VOL_RENAME);
1875 } 1856 }
1876 if (bmval0 & FATTR4_WORD0_CHANGE) { 1857 if (bmval0 & FATTR4_WORD0_CHANGE) {
1877 /*
1878 * Note: This _must_ be consistent with the scheme for writing
1879 * change_info, so any changes made here must be reflected there
1880 * as well. (See xdr4.h:set_change_info() and the WRITECINFO()
1881 * macro above.)
1882 */
1883 if ((buflen -= 8) < 0) 1858 if ((buflen -= 8) < 0)
1884 goto out_resource; 1859 goto out_resource;
1885 WRITE32(stat.ctime.tv_sec); 1860 write_change(&p, &stat, dentry->d_inode);
1886 WRITE32(stat.ctime.tv_nsec);
1887 } 1861 }
1888 if (bmval0 & FATTR4_WORD0_SIZE) { 1862 if (bmval0 & FATTR4_WORD0_SIZE) {
1889 if ((buflen -= 8) < 0) 1863 if ((buflen -= 8) < 0)
@@ -2348,7 +2322,7 @@ fail:
2348static void 2322static void
2349nfsd4_encode_stateid(struct nfsd4_compoundres *resp, stateid_t *sid) 2323nfsd4_encode_stateid(struct nfsd4_compoundres *resp, stateid_t *sid)
2350{ 2324{
2351 ENCODE_HEAD; 2325 __be32 *p;
2352 2326
2353 RESERVE_SPACE(sizeof(stateid_t)); 2327 RESERVE_SPACE(sizeof(stateid_t));
2354 WRITE32(sid->si_generation); 2328 WRITE32(sid->si_generation);
@@ -2359,7 +2333,7 @@ nfsd4_encode_stateid(struct nfsd4_compoundres *resp, stateid_t *sid)
2359static __be32 2333static __be32
2360nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access) 2334nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access)
2361{ 2335{
2362 ENCODE_HEAD; 2336 __be32 *p;
2363 2337
2364 if (!nfserr) { 2338 if (!nfserr) {
2365 RESERVE_SPACE(8); 2339 RESERVE_SPACE(8);
@@ -2386,7 +2360,7 @@ nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_c
2386static __be32 2360static __be32
2387nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit) 2361nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit)
2388{ 2362{
2389 ENCODE_HEAD; 2363 __be32 *p;
2390 2364
2391 if (!nfserr) { 2365 if (!nfserr) {
2392 RESERVE_SPACE(8); 2366 RESERVE_SPACE(8);
@@ -2399,11 +2373,11 @@ nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
2399static __be32 2373static __be32
2400nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create) 2374nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create)
2401{ 2375{
2402 ENCODE_HEAD; 2376 __be32 *p;
2403 2377
2404 if (!nfserr) { 2378 if (!nfserr) {
2405 RESERVE_SPACE(32); 2379 RESERVE_SPACE(32);
2406 WRITECINFO(create->cr_cinfo); 2380 write_cinfo(&p, &create->cr_cinfo);
2407 WRITE32(2); 2381 WRITE32(2);
2408 WRITE32(create->cr_bmval[0]); 2382 WRITE32(create->cr_bmval[0]);
2409 WRITE32(create->cr_bmval[1]); 2383 WRITE32(create->cr_bmval[1]);
@@ -2435,7 +2409,7 @@ nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh
2435{ 2409{
2436 struct svc_fh *fhp = *fhpp; 2410 struct svc_fh *fhp = *fhpp;
2437 unsigned int len; 2411 unsigned int len;
2438 ENCODE_HEAD; 2412 __be32 *p;
2439 2413
2440 if (!nfserr) { 2414 if (!nfserr) {
2441 len = fhp->fh_handle.fh_size; 2415 len = fhp->fh_handle.fh_size;
@@ -2454,7 +2428,7 @@ nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh
2454static void 2428static void
2455nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denied *ld) 2429nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denied *ld)
2456{ 2430{
2457 ENCODE_HEAD; 2431 __be32 *p;
2458 2432
2459 RESERVE_SPACE(32 + XDR_LEN(ld->ld_sop ? ld->ld_sop->so_owner.len : 0)); 2433 RESERVE_SPACE(32 + XDR_LEN(ld->ld_sop ? ld->ld_sop->so_owner.len : 0));
2460 WRITE64(ld->ld_start); 2434 WRITE64(ld->ld_start);
@@ -2510,11 +2484,11 @@ nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l
2510static __be32 2484static __be32
2511nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link) 2485nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link)
2512{ 2486{
2513 ENCODE_HEAD; 2487 __be32 *p;
2514 2488
2515 if (!nfserr) { 2489 if (!nfserr) {
2516 RESERVE_SPACE(20); 2490 RESERVE_SPACE(20);
2517 WRITECINFO(link->li_cinfo); 2491 write_cinfo(&p, &link->li_cinfo);
2518 ADJUST_ARGS(); 2492 ADJUST_ARGS();
2519 } 2493 }
2520 return nfserr; 2494 return nfserr;
@@ -2524,7 +2498,7 @@ nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_li
2524static __be32 2498static __be32
2525nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open) 2499nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open)
2526{ 2500{
2527 ENCODE_HEAD; 2501 __be32 *p;
2528 ENCODE_SEQID_OP_HEAD; 2502 ENCODE_SEQID_OP_HEAD;
2529 2503
2530 if (nfserr) 2504 if (nfserr)
@@ -2532,7 +2506,7 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op
2532 2506
2533 nfsd4_encode_stateid(resp, &open->op_stateid); 2507 nfsd4_encode_stateid(resp, &open->op_stateid);
2534 RESERVE_SPACE(40); 2508 RESERVE_SPACE(40);
2535 WRITECINFO(open->op_cinfo); 2509 write_cinfo(&p, &open->op_cinfo);
2536 WRITE32(open->op_rflags); 2510 WRITE32(open->op_rflags);
2537 WRITE32(2); 2511 WRITE32(2);
2538 WRITE32(open->op_bmval[0]); 2512 WRITE32(open->op_bmval[0]);
@@ -2619,7 +2593,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
2619 int v, pn; 2593 int v, pn;
2620 unsigned long maxcount; 2594 unsigned long maxcount;
2621 long len; 2595 long len;
2622 ENCODE_HEAD; 2596 __be32 *p;
2623 2597
2624 if (nfserr) 2598 if (nfserr)
2625 return nfserr; 2599 return nfserr;
@@ -2681,7 +2655,7 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd
2681{ 2655{
2682 int maxcount; 2656 int maxcount;
2683 char *page; 2657 char *page;
2684 ENCODE_HEAD; 2658 __be32 *p;
2685 2659
2686 if (nfserr) 2660 if (nfserr)
2687 return nfserr; 2661 return nfserr;
@@ -2730,7 +2704,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
2730 int maxcount; 2704 int maxcount;
2731 loff_t offset; 2705 loff_t offset;
2732 __be32 *page, *savep, *tailbase; 2706 __be32 *page, *savep, *tailbase;
2733 ENCODE_HEAD; 2707 __be32 *p;
2734 2708
2735 if (nfserr) 2709 if (nfserr)
2736 return nfserr; 2710 return nfserr;
@@ -2806,11 +2780,11 @@ err_no_verf:
2806static __be32 2780static __be32
2807nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove) 2781nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove)
2808{ 2782{
2809 ENCODE_HEAD; 2783 __be32 *p;
2810 2784
2811 if (!nfserr) { 2785 if (!nfserr) {
2812 RESERVE_SPACE(20); 2786 RESERVE_SPACE(20);
2813 WRITECINFO(remove->rm_cinfo); 2787 write_cinfo(&p, &remove->rm_cinfo);
2814 ADJUST_ARGS(); 2788 ADJUST_ARGS();
2815 } 2789 }
2816 return nfserr; 2790 return nfserr;
@@ -2819,12 +2793,12 @@ nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
2819static __be32 2793static __be32
2820nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename) 2794nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename)
2821{ 2795{
2822 ENCODE_HEAD; 2796 __be32 *p;
2823 2797
2824 if (!nfserr) { 2798 if (!nfserr) {
2825 RESERVE_SPACE(40); 2799 RESERVE_SPACE(40);
2826 WRITECINFO(rename->rn_sinfo); 2800 write_cinfo(&p, &rename->rn_sinfo);
2827 WRITECINFO(rename->rn_tinfo); 2801 write_cinfo(&p, &rename->rn_tinfo);
2828 ADJUST_ARGS(); 2802 ADJUST_ARGS();
2829 } 2803 }
2830 return nfserr; 2804 return nfserr;
@@ -2839,7 +2813,7 @@ nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
2839 u32 nflavs; 2813 u32 nflavs;
2840 struct exp_flavor_info *flavs; 2814 struct exp_flavor_info *flavs;
2841 struct exp_flavor_info def_flavs[2]; 2815 struct exp_flavor_info def_flavs[2];
2842 ENCODE_HEAD; 2816 __be32 *p;
2843 2817
2844 if (nfserr) 2818 if (nfserr)
2845 goto out; 2819 goto out;
@@ -2904,7 +2878,7 @@ out:
2904static __be32 2878static __be32
2905nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr) 2879nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr)
2906{ 2880{
2907 ENCODE_HEAD; 2881 __be32 *p;
2908 2882
2909 RESERVE_SPACE(12); 2883 RESERVE_SPACE(12);
2910 if (nfserr) { 2884 if (nfserr) {
@@ -2924,7 +2898,7 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
2924static __be32 2898static __be32
2925nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd) 2899nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd)
2926{ 2900{
2927 ENCODE_HEAD; 2901 __be32 *p;
2928 2902
2929 if (!nfserr) { 2903 if (!nfserr) {
2930 RESERVE_SPACE(8 + sizeof(nfs4_verifier)); 2904 RESERVE_SPACE(8 + sizeof(nfs4_verifier));
@@ -2944,7 +2918,7 @@ nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct n
2944static __be32 2918static __be32
2945nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write) 2919nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write)
2946{ 2920{
2947 ENCODE_HEAD; 2921 __be32 *p;
2948 2922
2949 if (!nfserr) { 2923 if (!nfserr) {
2950 RESERVE_SPACE(16); 2924 RESERVE_SPACE(16);
@@ -2960,7 +2934,7 @@ static __be32
2960nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, int nfserr, 2934nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, int nfserr,
2961 struct nfsd4_exchange_id *exid) 2935 struct nfsd4_exchange_id *exid)
2962{ 2936{
2963 ENCODE_HEAD; 2937 __be32 *p;
2964 char *major_id; 2938 char *major_id;
2965 char *server_scope; 2939 char *server_scope;
2966 int major_id_sz; 2940 int major_id_sz;
@@ -3015,7 +2989,7 @@ static __be32
3015nfsd4_encode_create_session(struct nfsd4_compoundres *resp, int nfserr, 2989nfsd4_encode_create_session(struct nfsd4_compoundres *resp, int nfserr,
3016 struct nfsd4_create_session *sess) 2990 struct nfsd4_create_session *sess)
3017{ 2991{
3018 ENCODE_HEAD; 2992 __be32 *p;
3019 2993
3020 if (nfserr) 2994 if (nfserr)
3021 return nfserr; 2995 return nfserr;
@@ -3071,7 +3045,7 @@ __be32
3071nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, 3045nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr,
3072 struct nfsd4_sequence *seq) 3046 struct nfsd4_sequence *seq)
3073{ 3047{
3074 ENCODE_HEAD; 3048 __be32 *p;
3075 3049
3076 if (nfserr) 3050 if (nfserr)
3077 return nfserr; 3051 return nfserr;
@@ -3219,7 +3193,7 @@ void
3219nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) 3193nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
3220{ 3194{
3221 __be32 *statp; 3195 __be32 *statp;
3222 ENCODE_HEAD; 3196 __be32 *p;
3223 3197
3224 RESERVE_SPACE(8); 3198 RESERVE_SPACE(8);
3225 WRITE32(op->opnum); 3199 WRITE32(op->opnum);
@@ -3253,7 +3227,7 @@ status:
3253void 3227void
3254nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op) 3228nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
3255{ 3229{
3256 ENCODE_HEAD; 3230 __be32 *p;
3257 struct nfs4_replay *rp = op->replay; 3231 struct nfs4_replay *rp = op->replay;
3258 3232
3259 BUG_ON(!rp); 3233 BUG_ON(!rp);
@@ -3268,10 +3242,6 @@ nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
3268 ADJUST_ARGS(); 3242 ADJUST_ARGS();
3269} 3243}
3270 3244
3271/*
3272 * END OF "GENERIC" ENCODE ROUTINES.
3273 */
3274
3275int 3245int
3276nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy) 3246nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy)
3277{ 3247{
diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c
index 5bfc2ac60d54..4638635c5d87 100644
--- a/fs/nfsd/nfscache.c
+++ b/fs/nfsd/nfscache.c
@@ -29,15 +29,24 @@
29 */ 29 */
30#define CACHESIZE 1024 30#define CACHESIZE 1024
31#define HASHSIZE 64 31#define HASHSIZE 64
32#define REQHASH(xid) (((((__force __u32)xid) >> 24) ^ ((__force __u32)xid)) & (HASHSIZE-1))
33 32
34static struct hlist_head * hash_list; 33static struct hlist_head * cache_hash;
35static struct list_head lru_head; 34static struct list_head lru_head;
36static int cache_disabled = 1; 35static int cache_disabled = 1;
37 36
37/*
38 * Calculate the hash index from an XID.
39 */
40static inline u32 request_hash(u32 xid)
41{
42 u32 h = xid;
43 h ^= (xid >> 24);
44 return h & (HASHSIZE-1);
45}
46
38static int nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec); 47static int nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec);
39 48
40/* 49/*
41 * locking for the reply cache: 50 * locking for the reply cache:
42 * A cache entry is "single use" if c_state == RC_INPROG 51 * A cache entry is "single use" if c_state == RC_INPROG
43 * Otherwise, it when accessing _prev or _next, the lock must be held. 52 * Otherwise, it when accessing _prev or _next, the lock must be held.
@@ -62,8 +71,8 @@ int nfsd_reply_cache_init(void)
62 i--; 71 i--;
63 } 72 }
64 73
65 hash_list = kcalloc (HASHSIZE, sizeof(struct hlist_head), GFP_KERNEL); 74 cache_hash = kcalloc (HASHSIZE, sizeof(struct hlist_head), GFP_KERNEL);
66 if (!hash_list) 75 if (!cache_hash)
67 goto out_nomem; 76 goto out_nomem;
68 77
69 cache_disabled = 0; 78 cache_disabled = 0;
@@ -88,8 +97,8 @@ void nfsd_reply_cache_shutdown(void)
88 97
89 cache_disabled = 1; 98 cache_disabled = 1;
90 99
91 kfree (hash_list); 100 kfree (cache_hash);
92 hash_list = NULL; 101 cache_hash = NULL;
93} 102}
94 103
95/* 104/*
@@ -108,7 +117,7 @@ static void
108hash_refile(struct svc_cacherep *rp) 117hash_refile(struct svc_cacherep *rp)
109{ 118{
110 hlist_del_init(&rp->c_hash); 119 hlist_del_init(&rp->c_hash);
111 hlist_add_head(&rp->c_hash, hash_list + REQHASH(rp->c_xid)); 120 hlist_add_head(&rp->c_hash, cache_hash + request_hash(rp->c_xid));
112} 121}
113 122
114/* 123/*
@@ -138,7 +147,7 @@ nfsd_cache_lookup(struct svc_rqst *rqstp, int type)
138 spin_lock(&cache_lock); 147 spin_lock(&cache_lock);
139 rtn = RC_DOIT; 148 rtn = RC_DOIT;
140 149
141 rh = &hash_list[REQHASH(xid)]; 150 rh = &cache_hash[request_hash(xid)];
142 hlist_for_each_entry(rp, hn, rh, c_hash) { 151 hlist_for_each_entry(rp, hn, rh, c_hash) {
143 if (rp->c_state != RC_UNUSED && 152 if (rp->c_state != RC_UNUSED &&
144 xid == rp->c_xid && proc == rp->c_proc && 153 xid == rp->c_xid && proc == rp->c_proc &&
@@ -165,8 +174,8 @@ nfsd_cache_lookup(struct svc_rqst *rqstp, int type)
165 } 174 }
166 } 175 }
167 176
168 /* This should not happen */ 177 /* All entries on the LRU are in-progress. This should not happen */
169 if (rp == NULL) { 178 if (&rp->c_lru == &lru_head) {
170 static int complaints; 179 static int complaints;
171 180
172 printk(KERN_WARNING "nfsd: all repcache entries locked!\n"); 181 printk(KERN_WARNING "nfsd: all repcache entries locked!\n");
@@ -264,7 +273,7 @@ nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, __be32 *statp)
264 273
265 len = resv->iov_len - ((char*)statp - (char*)resv->iov_base); 274 len = resv->iov_len - ((char*)statp - (char*)resv->iov_base);
266 len >>= 2; 275 len >>= 2;
267 276
268 /* Don't cache excessive amounts of data and XDR failures */ 277 /* Don't cache excessive amounts of data and XDR failures */
269 if (!statp || len > (256 >> 2)) { 278 if (!statp || len > (256 >> 2)) {
270 rp->c_state = RC_UNUSED; 279 rp->c_state = RC_UNUSED;
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index af16849d243a..877e713a0fd6 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -695,8 +695,9 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
695 if (rv) 695 if (rv)
696 return rv; 696 return rv;
697 } 697 }
698 sprintf(buf, "%d\n", nfsd_nrthreads()); 698
699 return strlen(buf); 699 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n",
700 nfsd_nrthreads());
700} 701}
701 702
702/** 703/**
@@ -793,7 +794,7 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
793{ 794{
794 char *mesg = buf; 795 char *mesg = buf;
795 char *vers, *minorp, sign; 796 char *vers, *minorp, sign;
796 int len, num; 797 int len, num, remaining;
797 unsigned minor; 798 unsigned minor;
798 ssize_t tlen = 0; 799 ssize_t tlen = 0;
799 char *sep; 800 char *sep;
@@ -840,32 +841,50 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
840 } 841 }
841 next: 842 next:
842 vers += len + 1; 843 vers += len + 1;
843 tlen += len;
844 } while ((len = qword_get(&mesg, vers, size)) > 0); 844 } while ((len = qword_get(&mesg, vers, size)) > 0);
845 /* If all get turned off, turn them back on, as 845 /* If all get turned off, turn them back on, as
846 * having no versions is BAD 846 * having no versions is BAD
847 */ 847 */
848 nfsd_reset_versions(); 848 nfsd_reset_versions();
849 } 849 }
850
850 /* Now write current state into reply buffer */ 851 /* Now write current state into reply buffer */
851 len = 0; 852 len = 0;
852 sep = ""; 853 sep = "";
854 remaining = SIMPLE_TRANSACTION_LIMIT;
853 for (num=2 ; num <= 4 ; num++) 855 for (num=2 ; num <= 4 ; num++)
854 if (nfsd_vers(num, NFSD_AVAIL)) { 856 if (nfsd_vers(num, NFSD_AVAIL)) {
855 len += sprintf(buf+len, "%s%c%d", sep, 857 len = snprintf(buf, remaining, "%s%c%d", sep,
856 nfsd_vers(num, NFSD_TEST)?'+':'-', 858 nfsd_vers(num, NFSD_TEST)?'+':'-',
857 num); 859 num);
858 sep = " "; 860 sep = " ";
861
862 if (len > remaining)
863 break;
864 remaining -= len;
865 buf += len;
866 tlen += len;
859 } 867 }
860 if (nfsd_vers(4, NFSD_AVAIL)) 868 if (nfsd_vers(4, NFSD_AVAIL))
861 for (minor = 1; minor <= NFSD_SUPPORTED_MINOR_VERSION; minor++) 869 for (minor = 1; minor <= NFSD_SUPPORTED_MINOR_VERSION;
862 len += sprintf(buf+len, " %c4.%u", 870 minor++) {
871 len = snprintf(buf, remaining, " %c4.%u",
863 (nfsd_vers(4, NFSD_TEST) && 872 (nfsd_vers(4, NFSD_TEST) &&
864 nfsd_minorversion(minor, NFSD_TEST)) ? 873 nfsd_minorversion(minor, NFSD_TEST)) ?
865 '+' : '-', 874 '+' : '-',
866 minor); 875 minor);
867 len += sprintf(buf+len, "\n"); 876
868 return len; 877 if (len > remaining)
878 break;
879 remaining -= len;
880 buf += len;
881 tlen += len;
882 }
883
884 len = snprintf(buf, remaining, "\n");
885 if (len > remaining)
886 return -EINVAL;
887 return tlen + len;
869} 888}
870 889
871/** 890/**
@@ -910,104 +929,143 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size)
910 return rv; 929 return rv;
911} 930}
912 931
913static ssize_t __write_ports(struct file *file, char *buf, size_t size) 932/*
933 * Zero-length write. Return a list of NFSD's current listener
934 * transports.
935 */
936static ssize_t __write_ports_names(char *buf)
914{ 937{
915 if (size == 0) { 938 if (nfsd_serv == NULL)
916 int len = 0; 939 return 0;
940 return svc_xprt_names(nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT);
941}
917 942
918 if (nfsd_serv) 943/*
919 len = svc_xprt_names(nfsd_serv, buf, 0); 944 * A single 'fd' number was written, in which case it must be for
920 return len; 945 * a socket of a supported family/protocol, and we use it as an
921 } 946 * nfsd listener.
922 /* Either a single 'fd' number is written, in which 947 */
923 * case it must be for a socket of a supported family/protocol, 948static ssize_t __write_ports_addfd(char *buf)
924 * and we use it as an nfsd socket, or 949{
925 * A '-' followed by the 'name' of a socket in which case 950 char *mesg = buf;
926 * we close the socket. 951 int fd, err;
927 */ 952
928 if (isdigit(buf[0])) { 953 err = get_int(&mesg, &fd);
929 char *mesg = buf; 954 if (err != 0 || fd < 0)
930 int fd; 955 return -EINVAL;
931 int err; 956
932 err = get_int(&mesg, &fd); 957 err = nfsd_create_serv();
933 if (err) 958 if (err != 0)
934 return -EINVAL; 959 return err;
935 if (fd < 0) 960
936 return -EINVAL; 961 err = lockd_up();
937 err = nfsd_create_serv(); 962 if (err != 0)
938 if (!err) { 963 goto out;
939 err = svc_addsock(nfsd_serv, fd, buf); 964
940 if (err >= 0) { 965 err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT);
941 err = lockd_up(); 966 if (err < 0)
942 if (err < 0) 967 lockd_down();
943 svc_sock_names(buf+strlen(buf)+1, nfsd_serv, buf); 968
944 } 969out:
945 /* Decrease the count, but don't shutdown the 970 /* Decrease the count, but don't shut down the service */
946 * the service 971 nfsd_serv->sv_nrthreads--;
947 */ 972 return err;
948 nfsd_serv->sv_nrthreads--; 973}
949 } 974
950 return err < 0 ? err : 0; 975/*
951 } 976 * A '-' followed by the 'name' of a socket means we close the socket.
952 if (buf[0] == '-' && isdigit(buf[1])) { 977 */
953 char *toclose = kstrdup(buf+1, GFP_KERNEL); 978static ssize_t __write_ports_delfd(char *buf)
954 int len = 0; 979{
955 if (!toclose) 980 char *toclose;
956 return -ENOMEM; 981 int len = 0;
957 if (nfsd_serv) 982
958 len = svc_sock_names(buf, nfsd_serv, toclose); 983 toclose = kstrdup(buf + 1, GFP_KERNEL);
959 if (len >= 0) 984 if (toclose == NULL)
960 lockd_down(); 985 return -ENOMEM;
961 kfree(toclose); 986
962 return len; 987 if (nfsd_serv != NULL)
963 } 988 len = svc_sock_names(nfsd_serv, buf,
964 /* 989 SIMPLE_TRANSACTION_LIMIT, toclose);
965 * Add a transport listener by writing it's transport name 990 if (len >= 0)
966 */ 991 lockd_down();
967 if (isalpha(buf[0])) { 992
968 int err; 993 kfree(toclose);
969 char transport[16]; 994 return len;
970 int port; 995}
971 if (sscanf(buf, "%15s %4d", transport, &port) == 2) { 996
972 if (port < 1 || port > 65535) 997/*
973 return -EINVAL; 998 * A transport listener is added by writing it's transport name and
974 err = nfsd_create_serv(); 999 * a port number.
975 if (!err) { 1000 */
976 err = svc_create_xprt(nfsd_serv, 1001static ssize_t __write_ports_addxprt(char *buf)
977 transport, PF_INET, port, 1002{
978 SVC_SOCK_ANONYMOUS); 1003 char transport[16];
979 if (err == -ENOENT) 1004 int port, err;
980 /* Give a reasonable perror msg for 1005
981 * bad transport string */ 1006 if (sscanf(buf, "%15s %4u", transport, &port) != 2)
982 err = -EPROTONOSUPPORT; 1007 return -EINVAL;
983 } 1008
984 return err < 0 ? err : 0; 1009 if (port < 1 || port > USHORT_MAX)
985 } 1010 return -EINVAL;
986 } 1011
987 /* 1012 err = nfsd_create_serv();
988 * Remove a transport by writing it's transport name and port number 1013 if (err != 0)
989 */ 1014 return err;
990 if (buf[0] == '-' && isalpha(buf[1])) { 1015
991 struct svc_xprt *xprt; 1016 err = svc_create_xprt(nfsd_serv, transport,
992 int err = -EINVAL; 1017 PF_INET, port, SVC_SOCK_ANONYMOUS);
993 char transport[16]; 1018 if (err < 0) {
994 int port; 1019 /* Give a reasonable perror msg for bad transport string */
995 if (sscanf(&buf[1], "%15s %4d", transport, &port) == 2) { 1020 if (err == -ENOENT)
996 if (port < 1 || port > 65535) 1021 err = -EPROTONOSUPPORT;
997 return -EINVAL; 1022 return err;
998 if (nfsd_serv) {
999 xprt = svc_find_xprt(nfsd_serv, transport,
1000 AF_UNSPEC, port);
1001 if (xprt) {
1002 svc_close_xprt(xprt);
1003 svc_xprt_put(xprt);
1004 err = 0;
1005 } else
1006 err = -ENOTCONN;
1007 }
1008 return err < 0 ? err : 0;
1009 }
1010 } 1023 }
1024 return 0;
1025}
1026
1027/*
1028 * A transport listener is removed by writing a "-", it's transport
1029 * name, and it's port number.
1030 */
1031static ssize_t __write_ports_delxprt(char *buf)
1032{
1033 struct svc_xprt *xprt;
1034 char transport[16];
1035 int port;
1036
1037 if (sscanf(&buf[1], "%15s %4u", transport, &port) != 2)
1038 return -EINVAL;
1039
1040 if (port < 1 || port > USHORT_MAX || nfsd_serv == NULL)
1041 return -EINVAL;
1042
1043 xprt = svc_find_xprt(nfsd_serv, transport, AF_UNSPEC, port);
1044 if (xprt == NULL)
1045 return -ENOTCONN;
1046
1047 svc_close_xprt(xprt);
1048 svc_xprt_put(xprt);
1049 return 0;
1050}
1051
1052static ssize_t __write_ports(struct file *file, char *buf, size_t size)
1053{
1054 if (size == 0)
1055 return __write_ports_names(buf);
1056
1057 if (isdigit(buf[0]))
1058 return __write_ports_addfd(buf);
1059
1060 if (buf[0] == '-' && isdigit(buf[1]))
1061 return __write_ports_delfd(buf);
1062
1063 if (isalpha(buf[0]))
1064 return __write_ports_addxprt(buf);
1065
1066 if (buf[0] == '-' && isalpha(buf[1]))
1067 return __write_ports_delxprt(buf);
1068
1011 return -EINVAL; 1069 return -EINVAL;
1012} 1070}
1013 1071
@@ -1030,7 +1088,9 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size)
1030 * buf: C string containing an unsigned 1088 * buf: C string containing an unsigned
1031 * integer value representing a bound 1089 * integer value representing a bound
1032 * but unconnected socket that is to be 1090 * but unconnected socket that is to be
1033 * used as an NFSD listener 1091 * used as an NFSD listener; listen(3)
1092 * must be called for a SOCK_STREAM
1093 * socket, otherwise it is ignored
1034 * size: non-zero length of C string in @buf 1094 * size: non-zero length of C string in @buf
1035 * Output: 1095 * Output:
1036 * On success: NFS service is started; 1096 * On success: NFS service is started;
@@ -1138,7 +1198,9 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
1138 nfsd_max_blksize = bsize; 1198 nfsd_max_blksize = bsize;
1139 mutex_unlock(&nfsd_mutex); 1199 mutex_unlock(&nfsd_mutex);
1140 } 1200 }
1141 return sprintf(buf, "%d\n", nfsd_max_blksize); 1201
1202 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n",
1203 nfsd_max_blksize);
1142} 1204}
1143 1205
1144#ifdef CONFIG_NFSD_V4 1206#ifdef CONFIG_NFSD_V4
@@ -1162,8 +1224,9 @@ static ssize_t __write_leasetime(struct file *file, char *buf, size_t size)
1162 return -EINVAL; 1224 return -EINVAL;
1163 nfs4_reset_lease(lease); 1225 nfs4_reset_lease(lease);
1164 } 1226 }
1165 sprintf(buf, "%ld\n", nfs4_lease_time()); 1227
1166 return strlen(buf); 1228 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%ld\n",
1229 nfs4_lease_time());
1167} 1230}
1168 1231
1169/** 1232/**
@@ -1219,8 +1282,9 @@ static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size)
1219 1282
1220 status = nfs4_reset_recoverydir(recdir); 1283 status = nfs4_reset_recoverydir(recdir);
1221 } 1284 }
1222 sprintf(buf, "%s\n", nfs4_recoverydir()); 1285
1223 return strlen(buf); 1286 return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n",
1287 nfs4_recoverydir());
1224} 1288}
1225 1289
1226/** 1290/**
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 9f1ca17293d3..8847f3fbfc1e 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -27,9 +27,6 @@
27#define NFSDDBG_FACILITY NFSDDBG_FH 27#define NFSDDBG_FACILITY NFSDDBG_FH
28 28
29 29
30static int nfsd_nr_verified;
31static int nfsd_nr_put;
32
33/* 30/*
34 * our acceptability function. 31 * our acceptability function.
35 * if NOSUBTREECHECK, accept anything 32 * if NOSUBTREECHECK, accept anything
@@ -251,7 +248,6 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
251 248
252 fhp->fh_dentry = dentry; 249 fhp->fh_dentry = dentry;
253 fhp->fh_export = exp; 250 fhp->fh_export = exp;
254 nfsd_nr_verified++;
255 return 0; 251 return 0;
256out: 252out:
257 exp_put(exp); 253 exp_put(exp);
@@ -552,7 +548,6 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
552 return nfserr_opnotsupp; 548 return nfserr_opnotsupp;
553 } 549 }
554 550
555 nfsd_nr_verified++;
556 return 0; 551 return 0;
557} 552}
558 553
@@ -609,7 +604,6 @@ fh_put(struct svc_fh *fhp)
609 fhp->fh_pre_saved = 0; 604 fhp->fh_pre_saved = 0;
610 fhp->fh_post_saved = 0; 605 fhp->fh_post_saved = 0;
611#endif 606#endif
612 nfsd_nr_put++;
613 } 607 }
614 if (exp) { 608 if (exp) {
615 cache_put(&exp->h, &svc_export_cache); 609 cache_put(&exp->h, &svc_export_cache);