diff options
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/export.c | 13 | ||||
-rw-r--r-- | fs/nfsd/nfs3xdr.c | 1 | ||||
-rw-r--r-- | fs/nfsd/nfs4callback.c | 222 | ||||
-rw-r--r-- | fs/nfsd/nfs4proc.c | 129 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 119 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 294 | ||||
-rw-r--r-- | fs/nfsd/nfscache.c | 33 | ||||
-rw-r--r-- | fs/nfsd/nfsctl.c | 284 | ||||
-rw-r--r-- | fs/nfsd/nfsfh.c | 6 |
9 files changed, 644 insertions, 457 deletions
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 | ||
217 | static int | 217 | static int |
218 | encode_cb_recall(struct xdr_stream *xdr, struct nfs4_cb_recall *cb_rec) | 218 | encode_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 | ||
243 | static int | 243 | static int |
244 | nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p, struct nfs4_cb_recall *args) | 244 | nfs4_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 | ||
361 | static 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 | ||
364 | static struct rpc_clnt *setup_callback_client(struct nfs4_client *clp) | 369 | int 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 | |||
412 | static 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 | |||
418 | static 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 | |||
429 | static const struct rpc_call_ops nfsd4_cb_probe_ops = { | ||
430 | .rpc_call_done = nfsd4_cb_probe_done, | ||
431 | }; | ||
403 | 432 | ||
433 | static 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 | ||
406 | static int do_probe_callback(void *data) | 449 | void 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); | ||
468 | out: | ||
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; | ||
434 | out_release_client: | ||
435 | rpc_shutdown_client(client); | ||
436 | out_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: | |||
446 | void | 478 | void |
447 | nfsd4_probe_callback(struct nfs4_client *clp) | 479 | nfsd4_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)) | 497 | static 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 | ||
526 | static 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 | |||
535 | static 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 | |||
468 | nfsd4_cb_recall(struct nfs4_delegation *dp) | 544 | nfsd4_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 | } |
500 | out_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 | ||
54 | static u32 nfsd_attrmask[] = { | ||
55 | NFSD_WRITEABLE_ATTRS_WORD0, | ||
56 | NFSD_WRITEABLE_ATTRS_WORD1, | ||
57 | NFSD_WRITEABLE_ATTRS_WORD2 | ||
58 | }; | ||
59 | |||
60 | static u32 nfsd41_ex_attrmask[] = { | ||
61 | NFSD_SUPPATTR_EXCLCREAT_WORD0, | ||
62 | NFSD_SUPPATTR_EXCLCREAT_WORD1, | ||
63 | NFSD_SUPPATTR_EXCLCREAT_WORD2 | ||
64 | }; | ||
65 | |||
66 | static __be32 | ||
67 | check_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 | |||
107 | static __be32 | ||
108 | nfsd4_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 | |||
54 | static inline void | 126 | static inline void |
55 | fh_dup2(struct svc_fh *dst, struct svc_fh *src) | 127 | fh_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 | ||
1233 | struct nfsd4_voidargs { int dummy; }; | 1317 | struct 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 | */ |
1257 | static struct svc_procedure nfsd_procedures4[2] = { | 1329 | static 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 | ||
1262 | struct svc_version nfsd_version4 = { | 1349 | struct 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) | |||
632 | static void | 630 | static void |
633 | shutdown_callback_client(struct nfs4_client *clp) | 631 | shutdown_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 | ||
647 | static inline void | 649 | static 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 | |||
966 | static void | 968 | static void |
967 | gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se) | 969 | gen_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 | */ | ||
2064 | static int | ||
2065 | do_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) | |||
2082 | static | 2069 | static |
2083 | void nfsd_break_deleg_cb(struct file_lock *fl) | 2070 | void 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; |
2620 | out: | 2598 | out: |
@@ -2738,12 +2716,42 @@ nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp) | |||
2738 | static int | 2716 | static int |
2739 | STALE_STATEID(stateid_t *stateid) | 2717 | STALE_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 | |||
2729 | static int | ||
2730 | EXPIRED_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 | |||
2743 | static __be32 | ||
2744 | stateid_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 | ||
2749 | static inline int | 2757 | static 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 | ||
257 | static u32 nfsd_attrmask[] = { | ||
258 | NFSD_WRITEABLE_ATTRS_WORD0, | ||
259 | NFSD_WRITEABLE_ATTRS_WORD1, | ||
260 | NFSD_WRITEABLE_ATTRS_WORD2 | ||
261 | }; | ||
262 | |||
263 | static u32 nfsd41_ex_attrmask[] = { | ||
264 | NFSD_SUPPATTR_EXCLCREAT_WORD0, | ||
265 | NFSD_SUPPATTR_EXCLCREAT_WORD1, | ||
266 | NFSD_SUPPATTR_EXCLCREAT_WORD2 | ||
267 | }; | ||
268 | |||
269 | static __be32 | 247 | static __be32 |
270 | nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, u32 *writable, | 248 | nfsd4_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 | ||
900 | static __be32 | 868 | static __be32 |
@@ -1328,64 +1296,64 @@ static nfsd4_dec nfsd4_dec_ops[] = { | |||
1328 | }; | 1296 | }; |
1329 | 1297 | ||
1330 | static nfsd4_dec nfsd41_dec_ops[] = { | 1298 | static 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 | ||
1391 | struct nfsd4_minorversion_ops { | 1359 | struct 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); \ | 1472 | static 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) | 1477 | static void write64(__be32 **p, u64 n) |
1478 | { | ||
1479 | write32(p, (u32)(n >> 32)); | ||
1480 | write32(p, (u32)n); | ||
1481 | } | ||
1482 | |||
1483 | static 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 | |||
1493 | static 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: | |||
2348 | static void | 2322 | static void |
2349 | nfsd4_encode_stateid(struct nfsd4_compoundres *resp, stateid_t *sid) | 2323 | nfsd4_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) | |||
2359 | static __be32 | 2333 | static __be32 |
2360 | nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access) | 2334 | nfsd4_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 | |||
2386 | static __be32 | 2360 | static __be32 |
2387 | nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit) | 2361 | nfsd4_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_ | |||
2399 | static __be32 | 2373 | static __be32 |
2400 | nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create) | 2374 | nfsd4_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 | |||
2454 | static void | 2428 | static void |
2455 | nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denied *ld) | 2429 | nfsd4_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 | |||
2510 | static __be32 | 2484 | static __be32 |
2511 | nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link) | 2485 | nfsd4_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 | |||
2524 | static __be32 | 2498 | static __be32 |
2525 | nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open) | 2499 | nfsd4_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: | |||
2806 | static __be32 | 2780 | static __be32 |
2807 | nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove) | 2781 | nfsd4_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_ | |||
2819 | static __be32 | 2793 | static __be32 |
2820 | nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename) | 2794 | nfsd4_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: | |||
2904 | static __be32 | 2878 | static __be32 |
2905 | nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr) | 2879 | nfsd4_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 | |||
2924 | static __be32 | 2898 | static __be32 |
2925 | nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd) | 2899 | nfsd4_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 | |||
2944 | static __be32 | 2918 | static __be32 |
2945 | nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write) | 2919 | nfsd4_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 | |||
2960 | nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, int nfserr, | 2934 | nfsd4_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 | |||
3015 | nfsd4_encode_create_session(struct nfsd4_compoundres *resp, int nfserr, | 2989 | nfsd4_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 | |||
3071 | nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, | 3045 | nfsd4_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 | |||
3219 | nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) | 3193 | nfsd4_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: | |||
3253 | void | 3227 | void |
3254 | nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op) | 3228 | nfsd4_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 | |||
3275 | int | 3245 | int |
3276 | nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy) | 3246 | nfs4svc_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 | ||
34 | static struct hlist_head * hash_list; | 33 | static struct hlist_head * cache_hash; |
35 | static struct list_head lru_head; | 34 | static struct list_head lru_head; |
36 | static int cache_disabled = 1; | 35 | static int cache_disabled = 1; |
37 | 36 | ||
37 | /* | ||
38 | * Calculate the hash index from an XID. | ||
39 | */ | ||
40 | static inline u32 request_hash(u32 xid) | ||
41 | { | ||
42 | u32 h = xid; | ||
43 | h ^= (xid >> 24); | ||
44 | return h & (HASHSIZE-1); | ||
45 | } | ||
46 | |||
38 | static int nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec); | 47 | static 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 | |||
108 | hash_refile(struct svc_cacherep *rp) | 117 | hash_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 | ||
913 | static 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 | */ | ||
936 | static 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, | 948 | static 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 | } | 969 | out: |
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); | 978 | static 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, | 1001 | static 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 | */ | ||
1031 | static 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 | |||
1052 | static 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 | ||
30 | static int nfsd_nr_verified; | ||
31 | static 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; |
256 | out: | 252 | out: |
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); |