diff options
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/auth.h | 22 | ||||
-rw-r--r-- | fs/nfsd/export.c | 20 | ||||
-rw-r--r-- | fs/nfsd/nfs2acl.c | 7 | ||||
-rw-r--r-- | fs/nfsd/nfs3xdr.c | 21 | ||||
-rw-r--r-- | fs/nfsd/nfs4callback.c | 92 | ||||
-rw-r--r-- | fs/nfsd/nfs4idmap.c | 28 | ||||
-rw-r--r-- | fs/nfsd/nfs4proc.c | 2 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 257 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 36 | ||||
-rw-r--r-- | fs/nfsd/nfscache.c | 28 | ||||
-rw-r--r-- | fs/nfsd/nfsctl.c | 124 | ||||
-rw-r--r-- | fs/nfsd/nfsfh.c | 1 | ||||
-rw-r--r-- | fs/nfsd/nfssvc.c | 8 | ||||
-rw-r--r-- | fs/nfsd/nfsxdr.c | 9 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 51 |
15 files changed, 390 insertions, 316 deletions
diff --git a/fs/nfsd/auth.h b/fs/nfsd/auth.h new file mode 100644 index 000000000000..78b3c0e93822 --- /dev/null +++ b/fs/nfsd/auth.h | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * nfsd-specific authentication stuff. | ||
3 | * uid/gid mapping not yet implemented. | ||
4 | * | ||
5 | * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> | ||
6 | */ | ||
7 | |||
8 | #ifndef LINUX_NFSD_AUTH_H | ||
9 | #define LINUX_NFSD_AUTH_H | ||
10 | |||
11 | #define nfsd_luid(rq, uid) ((u32)(uid)) | ||
12 | #define nfsd_lgid(rq, gid) ((u32)(gid)) | ||
13 | #define nfsd_ruid(rq, uid) ((u32)(uid)) | ||
14 | #define nfsd_rgid(rq, gid) ((u32)(gid)) | ||
15 | |||
16 | /* | ||
17 | * Set the current process's fsuid/fsgid etc to those of the NFS | ||
18 | * client user | ||
19 | */ | ||
20 | int nfsd_setuser(struct svc_rqst *, struct svc_export *); | ||
21 | |||
22 | #endif /* LINUX_NFSD_AUTH_H */ | ||
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 66d0aeb32a47..79b4bf812960 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
@@ -1357,8 +1357,6 @@ exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp) | |||
1357 | mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL); | 1357 | mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL); |
1358 | 1358 | ||
1359 | exp = rqst_exp_find(rqstp, FSID_NUM, fsidv); | 1359 | exp = rqst_exp_find(rqstp, FSID_NUM, fsidv); |
1360 | if (PTR_ERR(exp) == -ENOENT) | ||
1361 | return nfserr_perm; | ||
1362 | if (IS_ERR(exp)) | 1360 | if (IS_ERR(exp)) |
1363 | return nfserrno(PTR_ERR(exp)); | 1361 | return nfserrno(PTR_ERR(exp)); |
1364 | rv = fh_compose(fhp, exp, exp->ex_dentry, NULL); | 1362 | rv = fh_compose(fhp, exp, exp->ex_dentry, NULL); |
@@ -1637,13 +1635,19 @@ exp_verify_string(char *cp, int max) | |||
1637 | /* | 1635 | /* |
1638 | * Initialize the exports module. | 1636 | * Initialize the exports module. |
1639 | */ | 1637 | */ |
1640 | void | 1638 | int |
1641 | nfsd_export_init(void) | 1639 | nfsd_export_init(void) |
1642 | { | 1640 | { |
1641 | int rv; | ||
1643 | dprintk("nfsd: initializing export module.\n"); | 1642 | dprintk("nfsd: initializing export module.\n"); |
1644 | 1643 | ||
1645 | cache_register(&svc_export_cache); | 1644 | rv = cache_register(&svc_export_cache); |
1646 | cache_register(&svc_expkey_cache); | 1645 | if (rv) |
1646 | return rv; | ||
1647 | rv = cache_register(&svc_expkey_cache); | ||
1648 | if (rv) | ||
1649 | cache_unregister(&svc_export_cache); | ||
1650 | return rv; | ||
1647 | 1651 | ||
1648 | } | 1652 | } |
1649 | 1653 | ||
@@ -1670,10 +1674,8 @@ nfsd_export_shutdown(void) | |||
1670 | 1674 | ||
1671 | exp_writelock(); | 1675 | exp_writelock(); |
1672 | 1676 | ||
1673 | if (cache_unregister(&svc_expkey_cache)) | 1677 | cache_unregister(&svc_expkey_cache); |
1674 | printk(KERN_ERR "nfsd: failed to unregister expkey cache\n"); | 1678 | cache_unregister(&svc_export_cache); |
1675 | if (cache_unregister(&svc_export_cache)) | ||
1676 | printk(KERN_ERR "nfsd: failed to unregister export cache\n"); | ||
1677 | svcauth_unix_purge(); | 1679 | svcauth_unix_purge(); |
1678 | 1680 | ||
1679 | exp_writeunlock(); | 1681 | exp_writeunlock(); |
diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index 0e5fa11e6b44..1c3b7654e966 100644 --- a/fs/nfsd/nfs2acl.c +++ b/fs/nfsd/nfs2acl.c | |||
@@ -221,12 +221,17 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p, | |||
221 | struct nfsd3_getaclres *resp) | 221 | struct nfsd3_getaclres *resp) |
222 | { | 222 | { |
223 | struct dentry *dentry = resp->fh.fh_dentry; | 223 | struct dentry *dentry = resp->fh.fh_dentry; |
224 | struct inode *inode = dentry->d_inode; | 224 | struct inode *inode; |
225 | struct kvec *head = rqstp->rq_res.head; | 225 | struct kvec *head = rqstp->rq_res.head; |
226 | unsigned int base; | 226 | unsigned int base; |
227 | int n; | 227 | int n; |
228 | int w; | 228 | int w; |
229 | 229 | ||
230 | /* | ||
231 | * Since this is version 2, the check for nfserr in | ||
232 | * nfsd_dispatch actually ensures the following cannot happen. | ||
233 | * However, it seems fragile to depend on that. | ||
234 | */ | ||
230 | if (dentry == NULL || dentry->d_inode == NULL) | 235 | if (dentry == NULL || dentry->d_inode == NULL) |
231 | return 0; | 236 | return 0; |
232 | inode = dentry->d_inode; | 237 | inode = dentry->d_inode; |
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index f917fd25858a..d7647f70e02b 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/sunrpc/svc.h> | 21 | #include <linux/sunrpc/svc.h> |
22 | #include <linux/nfsd/nfsd.h> | 22 | #include <linux/nfsd/nfsd.h> |
23 | #include <linux/nfsd/xdr3.h> | 23 | #include <linux/nfsd/xdr3.h> |
24 | #include "auth.h" | ||
24 | 25 | ||
25 | #define NFSDDBG_FACILITY NFSDDBG_XDR | 26 | #define NFSDDBG_FACILITY NFSDDBG_XDR |
26 | 27 | ||
@@ -88,10 +89,10 @@ encode_fh(__be32 *p, struct svc_fh *fhp) | |||
88 | * no slashes or null bytes. | 89 | * no slashes or null bytes. |
89 | */ | 90 | */ |
90 | static __be32 * | 91 | static __be32 * |
91 | decode_filename(__be32 *p, char **namp, int *lenp) | 92 | decode_filename(__be32 *p, char **namp, unsigned int *lenp) |
92 | { | 93 | { |
93 | char *name; | 94 | char *name; |
94 | int i; | 95 | unsigned int i; |
95 | 96 | ||
96 | if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) { | 97 | if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) { |
97 | for (i = 0, name = *namp; i < *lenp; i++, name++) { | 98 | for (i = 0, name = *namp; i < *lenp; i++, name++) { |
@@ -452,8 +453,7 @@ int | |||
452 | nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p, | 453 | nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p, |
453 | struct nfsd3_symlinkargs *args) | 454 | struct nfsd3_symlinkargs *args) |
454 | { | 455 | { |
455 | unsigned int len; | 456 | unsigned int len, avail; |
456 | int avail; | ||
457 | char *old, *new; | 457 | char *old, *new; |
458 | struct kvec *vec; | 458 | struct kvec *vec; |
459 | 459 | ||
@@ -486,7 +486,8 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p, | |||
486 | /* now copy next page if there is one */ | 486 | /* now copy next page if there is one */ |
487 | if (len && !avail && rqstp->rq_arg.page_len) { | 487 | if (len && !avail && rqstp->rq_arg.page_len) { |
488 | avail = rqstp->rq_arg.page_len; | 488 | avail = rqstp->rq_arg.page_len; |
489 | if (avail > PAGE_SIZE) avail = PAGE_SIZE; | 489 | if (avail > PAGE_SIZE) |
490 | avail = PAGE_SIZE; | ||
490 | old = page_address(rqstp->rq_arg.pages[0]); | 491 | old = page_address(rqstp->rq_arg.pages[0]); |
491 | } | 492 | } |
492 | while (len && avail && *old) { | 493 | while (len && avail && *old) { |
@@ -816,11 +817,11 @@ static __be32 * | |||
816 | encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, | 817 | encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, |
817 | struct svc_fh *fhp) | 818 | struct svc_fh *fhp) |
818 | { | 819 | { |
819 | p = encode_post_op_attr(cd->rqstp, p, fhp); | 820 | p = encode_post_op_attr(cd->rqstp, p, fhp); |
820 | *p++ = xdr_one; /* yes, a file handle follows */ | 821 | *p++ = xdr_one; /* yes, a file handle follows */ |
821 | p = encode_fh(p, fhp); | 822 | p = encode_fh(p, fhp); |
822 | fh_put(fhp); | 823 | fh_put(fhp); |
823 | return p; | 824 | return p; |
824 | } | 825 | } |
825 | 826 | ||
826 | static int | 827 | static int |
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 9d536a8cb379..aae2b29ae2c9 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -350,30 +350,6 @@ static struct rpc_version * nfs_cb_version[] = { | |||
350 | static int do_probe_callback(void *data) | 350 | static int do_probe_callback(void *data) |
351 | { | 351 | { |
352 | struct nfs4_client *clp = data; | 352 | struct nfs4_client *clp = data; |
353 | struct nfs4_callback *cb = &clp->cl_callback; | ||
354 | struct rpc_message msg = { | ||
355 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], | ||
356 | .rpc_argp = clp, | ||
357 | }; | ||
358 | int status; | ||
359 | |||
360 | status = rpc_call_sync(cb->cb_client, &msg, RPC_TASK_SOFT); | ||
361 | |||
362 | if (status) { | ||
363 | rpc_shutdown_client(cb->cb_client); | ||
364 | cb->cb_client = NULL; | ||
365 | } else | ||
366 | atomic_set(&cb->cb_set, 1); | ||
367 | put_nfs4_client(clp); | ||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | /* | ||
372 | * Set up the callback client and put a NFSPROC4_CB_NULL on the wire... | ||
373 | */ | ||
374 | void | ||
375 | nfsd4_probe_callback(struct nfs4_client *clp) | ||
376 | { | ||
377 | struct sockaddr_in addr; | 353 | struct sockaddr_in addr; |
378 | struct nfs4_callback *cb = &clp->cl_callback; | 354 | struct nfs4_callback *cb = &clp->cl_callback; |
379 | struct rpc_timeout timeparms = { | 355 | struct rpc_timeout timeparms = { |
@@ -390,13 +366,15 @@ nfsd4_probe_callback(struct nfs4_client *clp) | |||
390 | .timeout = &timeparms, | 366 | .timeout = &timeparms, |
391 | .program = program, | 367 | .program = program, |
392 | .version = nfs_cb_version[1]->number, | 368 | .version = nfs_cb_version[1]->number, |
393 | .authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */ | 369 | .authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */ |
394 | .flags = (RPC_CLNT_CREATE_NOPING), | 370 | .flags = (RPC_CLNT_CREATE_NOPING), |
395 | }; | 371 | }; |
396 | struct task_struct *t; | 372 | struct rpc_message msg = { |
397 | 373 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], | |
398 | if (atomic_read(&cb->cb_set)) | 374 | .rpc_argp = clp, |
399 | return; | 375 | }; |
376 | struct rpc_clnt *client; | ||
377 | int status; | ||
400 | 378 | ||
401 | /* Initialize address */ | 379 | /* Initialize address */ |
402 | memset(&addr, 0, sizeof(addr)); | 380 | memset(&addr, 0, sizeof(addr)); |
@@ -416,29 +394,50 @@ nfsd4_probe_callback(struct nfs4_client *clp) | |||
416 | program->stats->program = program; | 394 | program->stats->program = program; |
417 | 395 | ||
418 | /* Create RPC client */ | 396 | /* Create RPC client */ |
419 | cb->cb_client = rpc_create(&args); | 397 | client = rpc_create(&args); |
420 | if (IS_ERR(cb->cb_client)) { | 398 | if (IS_ERR(client)) { |
421 | dprintk("NFSD: couldn't create callback client\n"); | 399 | dprintk("NFSD: couldn't create callback client\n"); |
400 | status = PTR_ERR(client); | ||
422 | goto out_err; | 401 | goto out_err; |
423 | } | 402 | } |
424 | 403 | ||
404 | status = rpc_call_sync(client, &msg, RPC_TASK_SOFT); | ||
405 | |||
406 | if (status) | ||
407 | goto out_release_client; | ||
408 | |||
409 | cb->cb_client = client; | ||
410 | atomic_set(&cb->cb_set, 1); | ||
411 | put_nfs4_client(clp); | ||
412 | return 0; | ||
413 | out_release_client: | ||
414 | rpc_shutdown_client(client); | ||
415 | out_err: | ||
416 | put_nfs4_client(clp); | ||
417 | dprintk("NFSD: warning: no callback path to client %.*s\n", | ||
418 | (int)clp->cl_name.len, clp->cl_name.data); | ||
419 | return status; | ||
420 | } | ||
421 | |||
422 | /* | ||
423 | * Set up the callback client and put a NFSPROC4_CB_NULL on the wire... | ||
424 | */ | ||
425 | void | ||
426 | nfsd4_probe_callback(struct nfs4_client *clp) | ||
427 | { | ||
428 | struct task_struct *t; | ||
429 | |||
430 | BUG_ON(atomic_read(&clp->cl_callback.cb_set)); | ||
431 | |||
425 | /* the task holds a reference to the nfs4_client struct */ | 432 | /* the task holds a reference to the nfs4_client struct */ |
426 | atomic_inc(&clp->cl_count); | 433 | atomic_inc(&clp->cl_count); |
427 | 434 | ||
428 | t = kthread_run(do_probe_callback, clp, "nfs4_cb_probe"); | 435 | t = kthread_run(do_probe_callback, clp, "nfs4_cb_probe"); |
429 | 436 | ||
430 | if (IS_ERR(t)) | 437 | if (IS_ERR(t)) |
431 | goto out_release_clp; | 438 | atomic_dec(&clp->cl_count); |
432 | 439 | ||
433 | return; | 440 | return; |
434 | |||
435 | out_release_clp: | ||
436 | atomic_dec(&clp->cl_count); | ||
437 | rpc_shutdown_client(cb->cb_client); | ||
438 | out_err: | ||
439 | cb->cb_client = NULL; | ||
440 | dprintk("NFSD: warning: no callback path to client %.*s\n", | ||
441 | (int)clp->cl_name.len, clp->cl_name.data); | ||
442 | } | 441 | } |
443 | 442 | ||
444 | /* | 443 | /* |
@@ -458,9 +457,6 @@ nfsd4_cb_recall(struct nfs4_delegation *dp) | |||
458 | int retries = 1; | 457 | int retries = 1; |
459 | int status = 0; | 458 | int status = 0; |
460 | 459 | ||
461 | if ((!atomic_read(&clp->cl_callback.cb_set)) || !clnt) | ||
462 | return; | ||
463 | |||
464 | cbr->cbr_trunc = 0; /* XXX need to implement truncate optimization */ | 460 | cbr->cbr_trunc = 0; /* XXX need to implement truncate optimization */ |
465 | cbr->cbr_dp = dp; | 461 | cbr->cbr_dp = dp; |
466 | 462 | ||
@@ -469,6 +465,7 @@ nfsd4_cb_recall(struct nfs4_delegation *dp) | |||
469 | switch (status) { | 465 | switch (status) { |
470 | case -EIO: | 466 | case -EIO: |
471 | /* Network partition? */ | 467 | /* Network partition? */ |
468 | atomic_set(&clp->cl_callback.cb_set, 0); | ||
472 | case -EBADHANDLE: | 469 | case -EBADHANDLE: |
473 | case -NFS4ERR_BAD_STATEID: | 470 | case -NFS4ERR_BAD_STATEID: |
474 | /* Race: client probably got cb_recall | 471 | /* Race: client probably got cb_recall |
@@ -481,11 +478,10 @@ nfsd4_cb_recall(struct nfs4_delegation *dp) | |||
481 | status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT); | 478 | status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT); |
482 | } | 479 | } |
483 | out_put_cred: | 480 | out_put_cred: |
484 | if (status == -EIO) | 481 | /* |
485 | atomic_set(&clp->cl_callback.cb_set, 0); | 482 | * Success or failure, now we're either waiting for lease expiration |
486 | /* Success or failure, now we're either waiting for lease expiration | 483 | * or deleg_return. |
487 | * or deleg_return. */ | 484 | */ |
488 | dprintk("NFSD: nfs4_cb_recall: dp %p dl_flock %p dl_count %d\n",dp, dp->dl_flock, atomic_read(&dp->dl_count)); | ||
489 | put_nfs4_client(clp); | 485 | put_nfs4_client(clp); |
490 | nfs4_put_delegation(dp); | 486 | nfs4_put_delegation(dp); |
491 | return; | 487 | return; |
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index 4c0c683ce07a..996bd88b75ba 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c | |||
@@ -255,13 +255,10 @@ idtoname_parse(struct cache_detail *cd, char *buf, int buflen) | |||
255 | goto out; | 255 | goto out; |
256 | if (len == 0) | 256 | if (len == 0) |
257 | set_bit(CACHE_NEGATIVE, &ent.h.flags); | 257 | set_bit(CACHE_NEGATIVE, &ent.h.flags); |
258 | else { | 258 | else if (len >= IDMAP_NAMESZ) |
259 | if (error >= IDMAP_NAMESZ) { | 259 | goto out; |
260 | error = -EINVAL; | 260 | else |
261 | goto out; | ||
262 | } | ||
263 | memcpy(ent.name, buf1, sizeof(ent.name)); | 261 | memcpy(ent.name, buf1, sizeof(ent.name)); |
264 | } | ||
265 | error = -ENOMEM; | 262 | error = -ENOMEM; |
266 | res = idtoname_update(&ent, res); | 263 | res = idtoname_update(&ent, res); |
267 | if (res == NULL) | 264 | if (res == NULL) |
@@ -467,20 +464,25 @@ nametoid_update(struct ent *new, struct ent *old) | |||
467 | * Exported API | 464 | * Exported API |
468 | */ | 465 | */ |
469 | 466 | ||
470 | void | 467 | int |
471 | nfsd_idmap_init(void) | 468 | nfsd_idmap_init(void) |
472 | { | 469 | { |
473 | cache_register(&idtoname_cache); | 470 | int rv; |
474 | cache_register(&nametoid_cache); | 471 | |
472 | rv = cache_register(&idtoname_cache); | ||
473 | if (rv) | ||
474 | return rv; | ||
475 | rv = cache_register(&nametoid_cache); | ||
476 | if (rv) | ||
477 | cache_unregister(&idtoname_cache); | ||
478 | return rv; | ||
475 | } | 479 | } |
476 | 480 | ||
477 | void | 481 | void |
478 | nfsd_idmap_shutdown(void) | 482 | nfsd_idmap_shutdown(void) |
479 | { | 483 | { |
480 | if (cache_unregister(&idtoname_cache)) | 484 | cache_unregister(&idtoname_cache); |
481 | printk(KERN_ERR "nfsd: failed to unregister idtoname cache\n"); | 485 | cache_unregister(&nametoid_cache); |
482 | if (cache_unregister(&nametoid_cache)) | ||
483 | printk(KERN_ERR "nfsd: failed to unregister nametoid cache\n"); | ||
484 | } | 486 | } |
485 | 487 | ||
486 | /* | 488 | /* |
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 18ead1790bb3..c593db047d8b 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -750,7 +750,7 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
750 | cstate->current_fh.fh_export, | 750 | cstate->current_fh.fh_export, |
751 | cstate->current_fh.fh_dentry, buf, | 751 | cstate->current_fh.fh_dentry, buf, |
752 | &count, verify->ve_bmval, | 752 | &count, verify->ve_bmval, |
753 | rqstp); | 753 | rqstp, 0); |
754 | 754 | ||
755 | /* this means that nfsd4_encode_fattr() ran out of space */ | 755 | /* this means that nfsd4_encode_fattr() ran out of space */ |
756 | if (status == nfserr_resource && count == 0) | 756 | if (status == nfserr_resource && count == 0) |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 31673cd251c3..f6744bc03dae 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -61,7 +61,6 @@ static time_t lease_time = 90; /* default lease time */ | |||
61 | static time_t user_lease_time = 90; | 61 | static time_t user_lease_time = 90; |
62 | static time_t boot_time; | 62 | static time_t boot_time; |
63 | static int in_grace = 1; | 63 | static int in_grace = 1; |
64 | static u32 current_clientid = 1; | ||
65 | static u32 current_ownerid = 1; | 64 | static u32 current_ownerid = 1; |
66 | static u32 current_fileid = 1; | 65 | static u32 current_fileid = 1; |
67 | static u32 current_delegid = 1; | 66 | static u32 current_delegid = 1; |
@@ -340,21 +339,20 @@ STALE_CLIENTID(clientid_t *clid) | |||
340 | * This type of memory management is somewhat inefficient, but we use it | 339 | * This type of memory management is somewhat inefficient, but we use it |
341 | * anyway since SETCLIENTID is not a common operation. | 340 | * anyway since SETCLIENTID is not a common operation. |
342 | */ | 341 | */ |
343 | static inline struct nfs4_client * | 342 | static struct nfs4_client *alloc_client(struct xdr_netobj name) |
344 | alloc_client(struct xdr_netobj name) | ||
345 | { | 343 | { |
346 | struct nfs4_client *clp; | 344 | struct nfs4_client *clp; |
347 | 345 | ||
348 | if ((clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL))!= NULL) { | 346 | clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL); |
349 | if ((clp->cl_name.data = kmalloc(name.len, GFP_KERNEL)) != NULL) { | 347 | if (clp == NULL) |
350 | memcpy(clp->cl_name.data, name.data, name.len); | 348 | return NULL; |
351 | clp->cl_name.len = name.len; | 349 | clp->cl_name.data = kmalloc(name.len, GFP_KERNEL); |
352 | } | 350 | if (clp->cl_name.data == NULL) { |
353 | else { | 351 | kfree(clp); |
354 | kfree(clp); | 352 | return NULL; |
355 | clp = NULL; | ||
356 | } | ||
357 | } | 353 | } |
354 | memcpy(clp->cl_name.data, name.data, name.len); | ||
355 | clp->cl_name.len = name.len; | ||
358 | return clp; | 356 | return clp; |
359 | } | 357 | } |
360 | 358 | ||
@@ -363,8 +361,11 @@ shutdown_callback_client(struct nfs4_client *clp) | |||
363 | { | 361 | { |
364 | struct rpc_clnt *clnt = clp->cl_callback.cb_client; | 362 | struct rpc_clnt *clnt = clp->cl_callback.cb_client; |
365 | 363 | ||
366 | /* shutdown rpc client, ending any outstanding recall rpcs */ | ||
367 | if (clnt) { | 364 | if (clnt) { |
365 | /* | ||
366 | * Callback threads take a reference on the client, so there | ||
367 | * should be no outstanding callbacks at this point. | ||
368 | */ | ||
368 | clp->cl_callback.cb_client = NULL; | 369 | clp->cl_callback.cb_client = NULL; |
369 | rpc_shutdown_client(clnt); | 370 | rpc_shutdown_client(clnt); |
370 | } | 371 | } |
@@ -422,12 +423,13 @@ expire_client(struct nfs4_client *clp) | |||
422 | put_nfs4_client(clp); | 423 | put_nfs4_client(clp); |
423 | } | 424 | } |
424 | 425 | ||
425 | static struct nfs4_client * | 426 | static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir) |
426 | create_client(struct xdr_netobj name, char *recdir) { | 427 | { |
427 | struct nfs4_client *clp; | 428 | struct nfs4_client *clp; |
428 | 429 | ||
429 | if (!(clp = alloc_client(name))) | 430 | clp = alloc_client(name); |
430 | goto out; | 431 | if (clp == NULL) |
432 | return NULL; | ||
431 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); | 433 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); |
432 | atomic_set(&clp->cl_count, 1); | 434 | atomic_set(&clp->cl_count, 1); |
433 | atomic_set(&clp->cl_callback.cb_set, 0); | 435 | atomic_set(&clp->cl_callback.cb_set, 0); |
@@ -436,32 +438,30 @@ create_client(struct xdr_netobj name, char *recdir) { | |||
436 | INIT_LIST_HEAD(&clp->cl_openowners); | 438 | INIT_LIST_HEAD(&clp->cl_openowners); |
437 | INIT_LIST_HEAD(&clp->cl_delegations); | 439 | INIT_LIST_HEAD(&clp->cl_delegations); |
438 | INIT_LIST_HEAD(&clp->cl_lru); | 440 | INIT_LIST_HEAD(&clp->cl_lru); |
439 | out: | ||
440 | return clp; | 441 | return clp; |
441 | } | 442 | } |
442 | 443 | ||
443 | static void | 444 | static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) |
444 | copy_verf(struct nfs4_client *target, nfs4_verifier *source) { | 445 | { |
445 | memcpy(target->cl_verifier.data, source->data, sizeof(target->cl_verifier.data)); | 446 | memcpy(target->cl_verifier.data, source->data, |
447 | sizeof(target->cl_verifier.data)); | ||
446 | } | 448 | } |
447 | 449 | ||
448 | static void | 450 | static void copy_clid(struct nfs4_client *target, struct nfs4_client *source) |
449 | copy_clid(struct nfs4_client *target, struct nfs4_client *source) { | 451 | { |
450 | target->cl_clientid.cl_boot = source->cl_clientid.cl_boot; | 452 | target->cl_clientid.cl_boot = source->cl_clientid.cl_boot; |
451 | target->cl_clientid.cl_id = source->cl_clientid.cl_id; | 453 | target->cl_clientid.cl_id = source->cl_clientid.cl_id; |
452 | } | 454 | } |
453 | 455 | ||
454 | static void | 456 | static void copy_cred(struct svc_cred *target, struct svc_cred *source) |
455 | copy_cred(struct svc_cred *target, struct svc_cred *source) { | 457 | { |
456 | |||
457 | target->cr_uid = source->cr_uid; | 458 | target->cr_uid = source->cr_uid; |
458 | target->cr_gid = source->cr_gid; | 459 | target->cr_gid = source->cr_gid; |
459 | target->cr_group_info = source->cr_group_info; | 460 | target->cr_group_info = source->cr_group_info; |
460 | get_group_info(target->cr_group_info); | 461 | get_group_info(target->cr_group_info); |
461 | } | 462 | } |
462 | 463 | ||
463 | static inline int | 464 | static int same_name(const char *n1, const char *n2) |
464 | same_name(const char *n1, const char *n2) | ||
465 | { | 465 | { |
466 | return 0 == memcmp(n1, n2, HEXDIR_LEN); | 466 | return 0 == memcmp(n1, n2, HEXDIR_LEN); |
467 | } | 467 | } |
@@ -485,26 +485,26 @@ same_creds(struct svc_cred *cr1, struct svc_cred *cr2) | |||
485 | return cr1->cr_uid == cr2->cr_uid; | 485 | return cr1->cr_uid == cr2->cr_uid; |
486 | } | 486 | } |
487 | 487 | ||
488 | static void | 488 | static void gen_clid(struct nfs4_client *clp) |
489 | gen_clid(struct nfs4_client *clp) { | 489 | { |
490 | static u32 current_clientid = 1; | ||
491 | |||
490 | clp->cl_clientid.cl_boot = boot_time; | 492 | clp->cl_clientid.cl_boot = boot_time; |
491 | clp->cl_clientid.cl_id = current_clientid++; | 493 | clp->cl_clientid.cl_id = current_clientid++; |
492 | } | 494 | } |
493 | 495 | ||
494 | static void | 496 | static void gen_confirm(struct nfs4_client *clp) |
495 | gen_confirm(struct nfs4_client *clp) { | 497 | { |
496 | struct timespec tv; | 498 | static u32 i; |
497 | u32 * p; | 499 | u32 *p; |
498 | 500 | ||
499 | tv = CURRENT_TIME; | ||
500 | p = (u32 *)clp->cl_confirm.data; | 501 | p = (u32 *)clp->cl_confirm.data; |
501 | *p++ = tv.tv_sec; | 502 | *p++ = get_seconds(); |
502 | *p++ = tv.tv_nsec; | 503 | *p++ = i++; |
503 | } | 504 | } |
504 | 505 | ||
505 | static int | 506 | static int check_name(struct xdr_netobj name) |
506 | check_name(struct xdr_netobj name) { | 507 | { |
507 | |||
508 | if (name.len == 0) | 508 | if (name.len == 0) |
509 | return 0; | 509 | return 0; |
510 | if (name.len > NFS4_OPAQUE_LIMIT) { | 510 | if (name.len > NFS4_OPAQUE_LIMIT) { |
@@ -683,39 +683,6 @@ out_err: | |||
683 | return; | 683 | return; |
684 | } | 684 | } |
685 | 685 | ||
686 | /* | ||
687 | * RFC 3010 has a complex implmentation description of processing a | ||
688 | * SETCLIENTID request consisting of 5 bullets, labeled as | ||
689 | * CASE0 - CASE4 below. | ||
690 | * | ||
691 | * NOTES: | ||
692 | * callback information will be processed in a future patch | ||
693 | * | ||
694 | * an unconfirmed record is added when: | ||
695 | * NORMAL (part of CASE 4): there is no confirmed nor unconfirmed record. | ||
696 | * CASE 1: confirmed record found with matching name, principal, | ||
697 | * verifier, and clientid. | ||
698 | * CASE 2: confirmed record found with matching name, principal, | ||
699 | * and there is no unconfirmed record with matching | ||
700 | * name and principal | ||
701 | * | ||
702 | * an unconfirmed record is replaced when: | ||
703 | * CASE 3: confirmed record found with matching name, principal, | ||
704 | * and an unconfirmed record is found with matching | ||
705 | * name, principal, and with clientid and | ||
706 | * confirm that does not match the confirmed record. | ||
707 | * CASE 4: there is no confirmed record with matching name and | ||
708 | * principal. there is an unconfirmed record with | ||
709 | * matching name, principal. | ||
710 | * | ||
711 | * an unconfirmed record is deleted when: | ||
712 | * CASE 1: an unconfirmed record that matches input name, verifier, | ||
713 | * and confirmed clientid. | ||
714 | * CASE 4: any unconfirmed records with matching name and principal | ||
715 | * that exist after an unconfirmed record has been replaced | ||
716 | * as described above. | ||
717 | * | ||
718 | */ | ||
719 | __be32 | 686 | __be32 |
720 | nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 687 | nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
721 | struct nfsd4_setclientid *setclid) | 688 | struct nfsd4_setclientid *setclid) |
@@ -748,11 +715,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
748 | nfs4_lock_state(); | 715 | nfs4_lock_state(); |
749 | conf = find_confirmed_client_by_str(dname, strhashval); | 716 | conf = find_confirmed_client_by_str(dname, strhashval); |
750 | if (conf) { | 717 | if (conf) { |
751 | /* | 718 | /* RFC 3530 14.2.33 CASE 0: */ |
752 | * CASE 0: | ||
753 | * clname match, confirmed, different principal | ||
754 | * or different ip_address | ||
755 | */ | ||
756 | status = nfserr_clid_inuse; | 719 | status = nfserr_clid_inuse; |
757 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred) | 720 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred) |
758 | || conf->cl_addr != sin->sin_addr.s_addr) { | 721 | || conf->cl_addr != sin->sin_addr.s_addr) { |
@@ -761,12 +724,17 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
761 | goto out; | 724 | goto out; |
762 | } | 725 | } |
763 | } | 726 | } |
727 | /* | ||
728 | * section 14.2.33 of RFC 3530 (under the heading "IMPLEMENTATION") | ||
729 | * has a description of SETCLIENTID request processing consisting | ||
730 | * of 5 bullet points, labeled as CASE0 - CASE4 below. | ||
731 | */ | ||
764 | unconf = find_unconfirmed_client_by_str(dname, strhashval); | 732 | unconf = find_unconfirmed_client_by_str(dname, strhashval); |
765 | status = nfserr_resource; | 733 | status = nfserr_resource; |
766 | if (!conf) { | 734 | if (!conf) { |
767 | /* | 735 | /* |
768 | * CASE 4: | 736 | * RFC 3530 14.2.33 CASE 4: |
769 | * placed first, because it is the normal case. | 737 | * placed first, because it is the normal case |
770 | */ | 738 | */ |
771 | if (unconf) | 739 | if (unconf) |
772 | expire_client(unconf); | 740 | expire_client(unconf); |
@@ -776,17 +744,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
776 | gen_clid(new); | 744 | gen_clid(new); |
777 | } else if (same_verf(&conf->cl_verifier, &clverifier)) { | 745 | } else if (same_verf(&conf->cl_verifier, &clverifier)) { |
778 | /* | 746 | /* |
779 | * CASE 1: | 747 | * RFC 3530 14.2.33 CASE 1: |
780 | * cl_name match, confirmed, principal match | 748 | * probable callback update |
781 | * verifier match: probable callback update | ||
782 | * | ||
783 | * remove any unconfirmed nfs4_client with | ||
784 | * matching cl_name, cl_verifier, and cl_clientid | ||
785 | * | ||
786 | * create and insert an unconfirmed nfs4_client with same | ||
787 | * cl_name, cl_verifier, and cl_clientid as existing | ||
788 | * nfs4_client, but with the new callback info and a | ||
789 | * new cl_confirm | ||
790 | */ | 749 | */ |
791 | if (unconf) { | 750 | if (unconf) { |
792 | /* Note this is removing unconfirmed {*x***}, | 751 | /* Note this is removing unconfirmed {*x***}, |
@@ -802,43 +761,25 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
802 | copy_clid(new, conf); | 761 | copy_clid(new, conf); |
803 | } else if (!unconf) { | 762 | } else if (!unconf) { |
804 | /* | 763 | /* |
805 | * CASE 2: | 764 | * RFC 3530 14.2.33 CASE 2: |
806 | * clname match, confirmed, principal match | 765 | * probable client reboot; state will be removed if |
807 | * verfier does not match | 766 | * confirmed. |
808 | * no unconfirmed. create a new unconfirmed nfs4_client | ||
809 | * using input clverifier, clname, and callback info | ||
810 | * and generate a new cl_clientid and cl_confirm. | ||
811 | */ | 767 | */ |
812 | new = create_client(clname, dname); | 768 | new = create_client(clname, dname); |
813 | if (new == NULL) | 769 | if (new == NULL) |
814 | goto out; | 770 | goto out; |
815 | gen_clid(new); | 771 | gen_clid(new); |
816 | } else if (!same_verf(&conf->cl_confirm, &unconf->cl_confirm)) { | 772 | } else { |
817 | /* | 773 | /* |
818 | * CASE3: | 774 | * RFC 3530 14.2.33 CASE 3: |
819 | * confirmed found (name, principal match) | 775 | * probable client reboot; state will be removed if |
820 | * confirmed verifier does not match input clverifier | 776 | * confirmed. |
821 | * | ||
822 | * unconfirmed found (name match) | ||
823 | * confirmed->cl_confirm != unconfirmed->cl_confirm | ||
824 | * | ||
825 | * remove unconfirmed. | ||
826 | * | ||
827 | * create an unconfirmed nfs4_client | ||
828 | * with same cl_name as existing confirmed nfs4_client, | ||
829 | * but with new callback info, new cl_clientid, | ||
830 | * new cl_verifier and a new cl_confirm | ||
831 | */ | 777 | */ |
832 | expire_client(unconf); | 778 | expire_client(unconf); |
833 | new = create_client(clname, dname); | 779 | new = create_client(clname, dname); |
834 | if (new == NULL) | 780 | if (new == NULL) |
835 | goto out; | 781 | goto out; |
836 | gen_clid(new); | 782 | gen_clid(new); |
837 | } else { | ||
838 | /* No cases hit !!! */ | ||
839 | status = nfserr_inval; | ||
840 | goto out; | ||
841 | |||
842 | } | 783 | } |
843 | copy_verf(new, &clverifier); | 784 | copy_verf(new, &clverifier); |
844 | new->cl_addr = sin->sin_addr.s_addr; | 785 | new->cl_addr = sin->sin_addr.s_addr; |
@@ -857,11 +798,9 @@ out: | |||
857 | 798 | ||
858 | 799 | ||
859 | /* | 800 | /* |
860 | * RFC 3010 has a complex implmentation description of processing a | 801 | * Section 14.2.34 of RFC 3530 (under the heading "IMPLEMENTATION") has |
861 | * SETCLIENTID_CONFIRM request consisting of 4 bullets describing | 802 | * a description of SETCLIENTID_CONFIRM request processing consisting of 4 |
862 | * processing on a DRC miss, labeled as CASE1 - CASE4 below. | 803 | * bullets, labeled as CASE1 - CASE4 below. |
863 | * | ||
864 | * NOTE: callback information will be processed here in a future patch | ||
865 | */ | 804 | */ |
866 | __be32 | 805 | __be32 |
867 | nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | 806 | nfsd4_setclientid_confirm(struct svc_rqst *rqstp, |
@@ -892,16 +831,16 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
892 | if (unconf && unconf->cl_addr != sin->sin_addr.s_addr) | 831 | if (unconf && unconf->cl_addr != sin->sin_addr.s_addr) |
893 | goto out; | 832 | goto out; |
894 | 833 | ||
895 | if ((conf && unconf) && | 834 | /* |
896 | (same_verf(&unconf->cl_confirm, &confirm)) && | 835 | * section 14.2.34 of RFC 3530 has a description of |
897 | (same_verf(&conf->cl_verifier, &unconf->cl_verifier)) && | 836 | * SETCLIENTID_CONFIRM request processing consisting |
898 | (same_name(conf->cl_recdir,unconf->cl_recdir)) && | 837 | * of 4 bullet points, labeled as CASE1 - CASE4 below. |
899 | (!same_verf(&conf->cl_confirm, &unconf->cl_confirm))) { | 838 | */ |
900 | /* CASE 1: | 839 | if (conf && unconf && same_verf(&confirm, &unconf->cl_confirm)) { |
901 | * unconf record that matches input clientid and input confirm. | 840 | /* |
902 | * conf record that matches input clientid. | 841 | * RFC 3530 14.2.34 CASE 1: |
903 | * conf and unconf records match names, verifiers | 842 | * callback update |
904 | */ | 843 | */ |
905 | if (!same_creds(&conf->cl_cred, &unconf->cl_cred)) | 844 | if (!same_creds(&conf->cl_cred, &unconf->cl_cred)) |
906 | status = nfserr_clid_inuse; | 845 | status = nfserr_clid_inuse; |
907 | else { | 846 | else { |
@@ -914,15 +853,11 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
914 | status = nfs_ok; | 853 | status = nfs_ok; |
915 | 854 | ||
916 | } | 855 | } |
917 | } else if ((conf && !unconf) || | 856 | } else if (conf && !unconf) { |
918 | ((conf && unconf) && | 857 | /* |
919 | (!same_verf(&conf->cl_verifier, &unconf->cl_verifier) || | 858 | * RFC 3530 14.2.34 CASE 2: |
920 | !same_name(conf->cl_recdir, unconf->cl_recdir)))) { | 859 | * probable retransmitted request; play it safe and |
921 | /* CASE 2: | 860 | * do nothing. |
922 | * conf record that matches input clientid. | ||
923 | * if unconf record matches input clientid, then | ||
924 | * unconf->cl_name or unconf->cl_verifier don't match the | ||
925 | * conf record. | ||
926 | */ | 861 | */ |
927 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) | 862 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) |
928 | status = nfserr_clid_inuse; | 863 | status = nfserr_clid_inuse; |
@@ -930,10 +865,9 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
930 | status = nfs_ok; | 865 | status = nfs_ok; |
931 | } else if (!conf && unconf | 866 | } else if (!conf && unconf |
932 | && same_verf(&unconf->cl_confirm, &confirm)) { | 867 | && same_verf(&unconf->cl_confirm, &confirm)) { |
933 | /* CASE 3: | 868 | /* |
934 | * conf record not found. | 869 | * RFC 3530 14.2.34 CASE 3: |
935 | * unconf record found. | 870 | * Normal case; new or rebooted client: |
936 | * unconf->cl_confirm matches input confirm | ||
937 | */ | 871 | */ |
938 | if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred)) { | 872 | if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred)) { |
939 | status = nfserr_clid_inuse; | 873 | status = nfserr_clid_inuse; |
@@ -948,16 +882,15 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
948 | } | 882 | } |
949 | move_to_confirmed(unconf); | 883 | move_to_confirmed(unconf); |
950 | conf = unconf; | 884 | conf = unconf; |
885 | nfsd4_probe_callback(conf); | ||
951 | status = nfs_ok; | 886 | status = nfs_ok; |
952 | } | 887 | } |
953 | } else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm))) | 888 | } else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm))) |
954 | && (!unconf || (unconf && !same_verf(&unconf->cl_confirm, | 889 | && (!unconf || (unconf && !same_verf(&unconf->cl_confirm, |
955 | &confirm)))) { | 890 | &confirm)))) { |
956 | /* CASE 4: | 891 | /* |
957 | * conf record not found, or if conf, conf->cl_confirm does not | 892 | * RFC 3530 14.2.34 CASE 4: |
958 | * match input confirm. | 893 | * Client probably hasn't noticed that we rebooted yet. |
959 | * unconf record not found, or if unconf, unconf->cl_confirm | ||
960 | * does not match input confirm. | ||
961 | */ | 894 | */ |
962 | status = nfserr_stale_clientid; | 895 | status = nfserr_stale_clientid; |
963 | } else { | 896 | } else { |
@@ -965,8 +898,6 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
965 | status = nfserr_clid_inuse; | 898 | status = nfserr_clid_inuse; |
966 | } | 899 | } |
967 | out: | 900 | out: |
968 | if (!status) | ||
969 | nfsd4_probe_callback(conf); | ||
970 | nfs4_unlock_state(); | 901 | nfs4_unlock_state(); |
971 | return status; | 902 | return status; |
972 | } | 903 | } |
@@ -1226,14 +1157,19 @@ find_file(struct inode *ino) | |||
1226 | return NULL; | 1157 | return NULL; |
1227 | } | 1158 | } |
1228 | 1159 | ||
1229 | static int access_valid(u32 x) | 1160 | static inline int access_valid(u32 x) |
1230 | { | 1161 | { |
1231 | return (x > 0 && x < 4); | 1162 | if (x < NFS4_SHARE_ACCESS_READ) |
1163 | return 0; | ||
1164 | if (x > NFS4_SHARE_ACCESS_BOTH) | ||
1165 | return 0; | ||
1166 | return 1; | ||
1232 | } | 1167 | } |
1233 | 1168 | ||
1234 | static int deny_valid(u32 x) | 1169 | static inline int deny_valid(u32 x) |
1235 | { | 1170 | { |
1236 | return (x >= 0 && x < 5); | 1171 | /* Note: unlike access bits, deny bits may be zero. */ |
1172 | return x <= NFS4_SHARE_DENY_BOTH; | ||
1237 | } | 1173 | } |
1238 | 1174 | ||
1239 | static void | 1175 | static void |
@@ -2162,8 +2098,10 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei | |||
2162 | goto check_replay; | 2098 | goto check_replay; |
2163 | } | 2099 | } |
2164 | 2100 | ||
2101 | *stpp = stp; | ||
2102 | *sopp = sop = stp->st_stateowner; | ||
2103 | |||
2165 | if (lock) { | 2104 | if (lock) { |
2166 | struct nfs4_stateowner *sop = stp->st_stateowner; | ||
2167 | clientid_t *lockclid = &lock->v.new.clientid; | 2105 | clientid_t *lockclid = &lock->v.new.clientid; |
2168 | struct nfs4_client *clp = sop->so_client; | 2106 | struct nfs4_client *clp = sop->so_client; |
2169 | int lkflg = 0; | 2107 | int lkflg = 0; |
@@ -2193,9 +2131,6 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei | |||
2193 | return nfserr_bad_stateid; | 2131 | return nfserr_bad_stateid; |
2194 | } | 2132 | } |
2195 | 2133 | ||
2196 | *stpp = stp; | ||
2197 | *sopp = sop = stp->st_stateowner; | ||
2198 | |||
2199 | /* | 2134 | /* |
2200 | * We now validate the seqid and stateid generation numbers. | 2135 | * We now validate the seqid and stateid generation numbers. |
2201 | * For the moment, we ignore the possibility of | 2136 | * For the moment, we ignore the possibility of |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 57333944af7f..b0592e7c378d 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -148,12 +148,12 @@ xdr_error: \ | |||
148 | } \ | 148 | } \ |
149 | } while (0) | 149 | } while (0) |
150 | 150 | ||
151 | static __be32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes) | 151 | static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes) |
152 | { | 152 | { |
153 | /* We want more bytes than seem to be available. | 153 | /* We want more bytes than seem to be available. |
154 | * Maybe we need a new page, maybe we have just run out | 154 | * Maybe we need a new page, maybe we have just run out |
155 | */ | 155 | */ |
156 | int avail = (char*)argp->end - (char*)argp->p; | 156 | unsigned int avail = (char *)argp->end - (char *)argp->p; |
157 | __be32 *p; | 157 | __be32 *p; |
158 | if (avail + argp->pagelen < nbytes) | 158 | if (avail + argp->pagelen < nbytes) |
159 | return NULL; | 159 | return NULL; |
@@ -169,6 +169,11 @@ static __be32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes) | |||
169 | return NULL; | 169 | return NULL; |
170 | 170 | ||
171 | } | 171 | } |
172 | /* | ||
173 | * The following memcpy is safe because read_buf is always | ||
174 | * called with nbytes > avail, and the two cases above both | ||
175 | * guarantee p points to at least nbytes bytes. | ||
176 | */ | ||
172 | memcpy(p, argp->p, avail); | 177 | memcpy(p, argp->p, avail); |
173 | /* step to next page */ | 178 | /* step to next page */ |
174 | argp->p = page_address(argp->pagelist[0]); | 179 | argp->p = page_address(argp->pagelist[0]); |
@@ -1448,7 +1453,7 @@ static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) | |||
1448 | __be32 | 1453 | __be32 |
1449 | nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | 1454 | nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, |
1450 | struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval, | 1455 | struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval, |
1451 | struct svc_rqst *rqstp) | 1456 | struct svc_rqst *rqstp, int ignore_crossmnt) |
1452 | { | 1457 | { |
1453 | u32 bmval0 = bmval[0]; | 1458 | u32 bmval0 = bmval[0]; |
1454 | u32 bmval1 = bmval[1]; | 1459 | u32 bmval1 = bmval[1]; |
@@ -1828,7 +1833,12 @@ out_acl: | |||
1828 | if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) { | 1833 | if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) { |
1829 | if ((buflen -= 8) < 0) | 1834 | if ((buflen -= 8) < 0) |
1830 | goto out_resource; | 1835 | goto out_resource; |
1831 | if (exp->ex_mnt->mnt_root->d_inode == dentry->d_inode) { | 1836 | /* |
1837 | * Get parent's attributes if not ignoring crossmount | ||
1838 | * and this is the root of a cross-mounted filesystem. | ||
1839 | */ | ||
1840 | if (ignore_crossmnt == 0 && | ||
1841 | exp->ex_mnt->mnt_root->d_inode == dentry->d_inode) { | ||
1832 | err = vfs_getattr(exp->ex_mnt->mnt_parent, | 1842 | err = vfs_getattr(exp->ex_mnt->mnt_parent, |
1833 | exp->ex_mnt->mnt_mountpoint, &stat); | 1843 | exp->ex_mnt->mnt_mountpoint, &stat); |
1834 | if (err) | 1844 | if (err) |
@@ -1864,13 +1874,25 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd, | |||
1864 | struct svc_export *exp = cd->rd_fhp->fh_export; | 1874 | struct svc_export *exp = cd->rd_fhp->fh_export; |
1865 | struct dentry *dentry; | 1875 | struct dentry *dentry; |
1866 | __be32 nfserr; | 1876 | __be32 nfserr; |
1877 | int ignore_crossmnt = 0; | ||
1867 | 1878 | ||
1868 | dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen); | 1879 | dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen); |
1869 | if (IS_ERR(dentry)) | 1880 | if (IS_ERR(dentry)) |
1870 | return nfserrno(PTR_ERR(dentry)); | 1881 | return nfserrno(PTR_ERR(dentry)); |
1871 | 1882 | ||
1872 | exp_get(exp); | 1883 | exp_get(exp); |
1873 | if (d_mountpoint(dentry)) { | 1884 | /* |
1885 | * In the case of a mountpoint, the client may be asking for | ||
1886 | * attributes that are only properties of the underlying filesystem | ||
1887 | * as opposed to the cross-mounted file system. In such a case, | ||
1888 | * we will not follow the cross mount and will fill the attribtutes | ||
1889 | * directly from the mountpoint dentry. | ||
1890 | */ | ||
1891 | if (d_mountpoint(dentry) && | ||
1892 | (cd->rd_bmval[0] & ~FATTR4_WORD0_RDATTR_ERROR) == 0 && | ||
1893 | (cd->rd_bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID) == 0) | ||
1894 | ignore_crossmnt = 1; | ||
1895 | else if (d_mountpoint(dentry)) { | ||
1874 | int err; | 1896 | int err; |
1875 | 1897 | ||
1876 | /* | 1898 | /* |
@@ -1889,7 +1911,7 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd, | |||
1889 | 1911 | ||
1890 | } | 1912 | } |
1891 | nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval, | 1913 | nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval, |
1892 | cd->rd_rqstp); | 1914 | cd->rd_rqstp, ignore_crossmnt); |
1893 | out_put: | 1915 | out_put: |
1894 | dput(dentry); | 1916 | dput(dentry); |
1895 | exp_put(exp); | 1917 | exp_put(exp); |
@@ -2043,7 +2065,7 @@ nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 | |||
2043 | buflen = resp->end - resp->p - (COMPOUND_ERR_SLACK_SPACE >> 2); | 2065 | buflen = resp->end - resp->p - (COMPOUND_ERR_SLACK_SPACE >> 2); |
2044 | nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry, | 2066 | nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry, |
2045 | resp->p, &buflen, getattr->ga_bmval, | 2067 | resp->p, &buflen, getattr->ga_bmval, |
2046 | resp->rqstp); | 2068 | resp->rqstp, 0); |
2047 | if (!nfserr) | 2069 | if (!nfserr) |
2048 | resp->p += buflen; | 2070 | resp->p += buflen; |
2049 | return nfserr; | 2071 | return nfserr; |
diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c index 578f2c9d56be..5bfc2ac60d54 100644 --- a/fs/nfsd/nfscache.c +++ b/fs/nfsd/nfscache.c | |||
@@ -44,17 +44,17 @@ static int nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec); | |||
44 | */ | 44 | */ |
45 | static DEFINE_SPINLOCK(cache_lock); | 45 | static DEFINE_SPINLOCK(cache_lock); |
46 | 46 | ||
47 | void | 47 | int nfsd_reply_cache_init(void) |
48 | nfsd_cache_init(void) | ||
49 | { | 48 | { |
50 | struct svc_cacherep *rp; | 49 | struct svc_cacherep *rp; |
51 | int i; | 50 | int i; |
52 | 51 | ||
53 | INIT_LIST_HEAD(&lru_head); | 52 | INIT_LIST_HEAD(&lru_head); |
54 | i = CACHESIZE; | 53 | i = CACHESIZE; |
55 | while(i) { | 54 | while (i) { |
56 | rp = kmalloc(sizeof(*rp), GFP_KERNEL); | 55 | rp = kmalloc(sizeof(*rp), GFP_KERNEL); |
57 | if (!rp) break; | 56 | if (!rp) |
57 | goto out_nomem; | ||
58 | list_add(&rp->c_lru, &lru_head); | 58 | list_add(&rp->c_lru, &lru_head); |
59 | rp->c_state = RC_UNUSED; | 59 | rp->c_state = RC_UNUSED; |
60 | rp->c_type = RC_NOCACHE; | 60 | rp->c_type = RC_NOCACHE; |
@@ -62,23 +62,19 @@ nfsd_cache_init(void) | |||
62 | i--; | 62 | i--; |
63 | } | 63 | } |
64 | 64 | ||
65 | if (i) | ||
66 | printk (KERN_ERR "nfsd: cannot allocate all %d cache entries, only got %d\n", | ||
67 | CACHESIZE, CACHESIZE-i); | ||
68 | |||
69 | hash_list = kcalloc (HASHSIZE, sizeof(struct hlist_head), GFP_KERNEL); | 65 | hash_list = kcalloc (HASHSIZE, sizeof(struct hlist_head), GFP_KERNEL); |
70 | if (!hash_list) { | 66 | if (!hash_list) |
71 | nfsd_cache_shutdown(); | 67 | goto out_nomem; |
72 | printk (KERN_ERR "nfsd: cannot allocate %Zd bytes for hash list\n", | ||
73 | HASHSIZE * sizeof(struct hlist_head)); | ||
74 | return; | ||
75 | } | ||
76 | 68 | ||
77 | cache_disabled = 0; | 69 | cache_disabled = 0; |
70 | return 0; | ||
71 | out_nomem: | ||
72 | printk(KERN_ERR "nfsd: failed to allocate reply cache\n"); | ||
73 | nfsd_reply_cache_shutdown(); | ||
74 | return -ENOMEM; | ||
78 | } | 75 | } |
79 | 76 | ||
80 | void | 77 | void nfsd_reply_cache_shutdown(void) |
81 | nfsd_cache_shutdown(void) | ||
82 | { | 78 | { |
83 | struct svc_cacherep *rp; | 79 | struct svc_cacherep *rp; |
84 | 80 | ||
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 77dc9893b7ba..8516137cdbb0 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
@@ -304,6 +304,9 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size) | |||
304 | struct auth_domain *dom; | 304 | struct auth_domain *dom; |
305 | struct knfsd_fh fh; | 305 | struct knfsd_fh fh; |
306 | 306 | ||
307 | if (size == 0) | ||
308 | return -EINVAL; | ||
309 | |||
307 | if (buf[size-1] != '\n') | 310 | if (buf[size-1] != '\n') |
308 | return -EINVAL; | 311 | return -EINVAL; |
309 | buf[size-1] = 0; | 312 | buf[size-1] = 0; |
@@ -503,7 +506,7 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size) | |||
503 | int len = 0; | 506 | int len = 0; |
504 | lock_kernel(); | 507 | lock_kernel(); |
505 | if (nfsd_serv) | 508 | if (nfsd_serv) |
506 | len = svc_sock_names(buf, nfsd_serv, NULL); | 509 | len = svc_xprt_names(nfsd_serv, buf, 0); |
507 | unlock_kernel(); | 510 | unlock_kernel(); |
508 | return len; | 511 | return len; |
509 | } | 512 | } |
@@ -540,7 +543,7 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size) | |||
540 | } | 543 | } |
541 | return err < 0 ? err : 0; | 544 | return err < 0 ? err : 0; |
542 | } | 545 | } |
543 | if (buf[0] == '-') { | 546 | if (buf[0] == '-' && isdigit(buf[1])) { |
544 | char *toclose = kstrdup(buf+1, GFP_KERNEL); | 547 | char *toclose = kstrdup(buf+1, GFP_KERNEL); |
545 | int len = 0; | 548 | int len = 0; |
546 | if (!toclose) | 549 | if (!toclose) |
@@ -554,6 +557,53 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size) | |||
554 | kfree(toclose); | 557 | kfree(toclose); |
555 | return len; | 558 | return len; |
556 | } | 559 | } |
560 | /* | ||
561 | * Add a transport listener by writing it's transport name | ||
562 | */ | ||
563 | if (isalpha(buf[0])) { | ||
564 | int err; | ||
565 | char transport[16]; | ||
566 | int port; | ||
567 | if (sscanf(buf, "%15s %4d", transport, &port) == 2) { | ||
568 | err = nfsd_create_serv(); | ||
569 | if (!err) { | ||
570 | err = svc_create_xprt(nfsd_serv, | ||
571 | transport, port, | ||
572 | SVC_SOCK_ANONYMOUS); | ||
573 | if (err == -ENOENT) | ||
574 | /* Give a reasonable perror msg for | ||
575 | * bad transport string */ | ||
576 | err = -EPROTONOSUPPORT; | ||
577 | } | ||
578 | return err < 0 ? err : 0; | ||
579 | } | ||
580 | } | ||
581 | /* | ||
582 | * Remove a transport by writing it's transport name and port number | ||
583 | */ | ||
584 | if (buf[0] == '-' && isalpha(buf[1])) { | ||
585 | struct svc_xprt *xprt; | ||
586 | int err = -EINVAL; | ||
587 | char transport[16]; | ||
588 | int port; | ||
589 | if (sscanf(&buf[1], "%15s %4d", transport, &port) == 2) { | ||
590 | if (port == 0) | ||
591 | return -EINVAL; | ||
592 | lock_kernel(); | ||
593 | if (nfsd_serv) { | ||
594 | xprt = svc_find_xprt(nfsd_serv, transport, | ||
595 | AF_UNSPEC, port); | ||
596 | if (xprt) { | ||
597 | svc_close_xprt(xprt); | ||
598 | svc_xprt_put(xprt); | ||
599 | err = 0; | ||
600 | } else | ||
601 | err = -ENOTCONN; | ||
602 | } | ||
603 | unlock_kernel(); | ||
604 | return err < 0 ? err : 0; | ||
605 | } | ||
606 | } | ||
557 | return -EINVAL; | 607 | return -EINVAL; |
558 | } | 608 | } |
559 | 609 | ||
@@ -616,7 +666,7 @@ static ssize_t write_recoverydir(struct file *file, char *buf, size_t size) | |||
616 | char *recdir; | 666 | char *recdir; |
617 | int len, status; | 667 | int len, status; |
618 | 668 | ||
619 | if (size > PATH_MAX || buf[size-1] != '\n') | 669 | if (size == 0 || size > PATH_MAX || buf[size-1] != '\n') |
620 | return -EINVAL; | 670 | return -EINVAL; |
621 | buf[size-1] = 0; | 671 | buf[size-1] = 0; |
622 | 672 | ||
@@ -674,6 +724,27 @@ static struct file_system_type nfsd_fs_type = { | |||
674 | .kill_sb = kill_litter_super, | 724 | .kill_sb = kill_litter_super, |
675 | }; | 725 | }; |
676 | 726 | ||
727 | #ifdef CONFIG_PROC_FS | ||
728 | static int create_proc_exports_entry(void) | ||
729 | { | ||
730 | struct proc_dir_entry *entry; | ||
731 | |||
732 | entry = proc_mkdir("fs/nfs", NULL); | ||
733 | if (!entry) | ||
734 | return -ENOMEM; | ||
735 | entry = create_proc_entry("fs/nfs/exports", 0, NULL); | ||
736 | if (!entry) | ||
737 | return -ENOMEM; | ||
738 | entry->proc_fops = &exports_operations; | ||
739 | return 0; | ||
740 | } | ||
741 | #else /* CONFIG_PROC_FS */ | ||
742 | static int create_proc_exports_entry(void) | ||
743 | { | ||
744 | return 0; | ||
745 | } | ||
746 | #endif | ||
747 | |||
677 | static int __init init_nfsd(void) | 748 | static int __init init_nfsd(void) |
678 | { | 749 | { |
679 | int retval; | 750 | int retval; |
@@ -683,32 +754,43 @@ static int __init init_nfsd(void) | |||
683 | if (retval) | 754 | if (retval) |
684 | return retval; | 755 | return retval; |
685 | nfsd_stat_init(); /* Statistics */ | 756 | nfsd_stat_init(); /* Statistics */ |
686 | nfsd_cache_init(); /* RPC reply cache */ | 757 | retval = nfsd_reply_cache_init(); |
687 | nfsd_export_init(); /* Exports table */ | 758 | if (retval) |
759 | goto out_free_stat; | ||
760 | retval = nfsd_export_init(); | ||
761 | if (retval) | ||
762 | goto out_free_cache; | ||
688 | nfsd_lockd_init(); /* lockd->nfsd callbacks */ | 763 | nfsd_lockd_init(); /* lockd->nfsd callbacks */ |
689 | nfsd_idmap_init(); /* Name to ID mapping */ | 764 | retval = nfsd_idmap_init(); |
690 | if (proc_mkdir("fs/nfs", NULL)) { | 765 | if (retval) |
691 | struct proc_dir_entry *entry; | 766 | goto out_free_lockd; |
692 | entry = create_proc_entry("fs/nfs/exports", 0, NULL); | 767 | retval = create_proc_exports_entry(); |
693 | if (entry) | 768 | if (retval) |
694 | entry->proc_fops = &exports_operations; | 769 | goto out_free_idmap; |
695 | } | ||
696 | retval = register_filesystem(&nfsd_fs_type); | 770 | retval = register_filesystem(&nfsd_fs_type); |
697 | if (retval) { | 771 | if (retval) |
698 | nfsd_export_shutdown(); | 772 | goto out_free_all; |
699 | nfsd_cache_shutdown(); | 773 | return 0; |
700 | remove_proc_entry("fs/nfs/exports", NULL); | 774 | out_free_all: |
701 | remove_proc_entry("fs/nfs", NULL); | 775 | remove_proc_entry("fs/nfs/exports", NULL); |
702 | nfsd_stat_shutdown(); | 776 | remove_proc_entry("fs/nfs", NULL); |
703 | nfsd_lockd_shutdown(); | 777 | out_free_idmap: |
704 | } | 778 | nfsd_idmap_shutdown(); |
779 | out_free_lockd: | ||
780 | nfsd_lockd_shutdown(); | ||
781 | nfsd_export_shutdown(); | ||
782 | out_free_cache: | ||
783 | nfsd_reply_cache_shutdown(); | ||
784 | out_free_stat: | ||
785 | nfsd_stat_shutdown(); | ||
786 | nfsd4_free_slabs(); | ||
705 | return retval; | 787 | return retval; |
706 | } | 788 | } |
707 | 789 | ||
708 | static void __exit exit_nfsd(void) | 790 | static void __exit exit_nfsd(void) |
709 | { | 791 | { |
710 | nfsd_export_shutdown(); | 792 | nfsd_export_shutdown(); |
711 | nfsd_cache_shutdown(); | 793 | nfsd_reply_cache_shutdown(); |
712 | remove_proc_entry("fs/nfs/exports", NULL); | 794 | remove_proc_entry("fs/nfs/exports", NULL); |
713 | remove_proc_entry("fs/nfs", NULL); | 795 | remove_proc_entry("fs/nfs", NULL); |
714 | nfsd_stat_shutdown(); | 796 | nfsd_stat_shutdown(); |
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 468f17a78441..8fbd2dc08a92 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/sunrpc/svc.h> | 22 | #include <linux/sunrpc/svc.h> |
23 | #include <linux/sunrpc/svcauth_gss.h> | 23 | #include <linux/sunrpc/svcauth_gss.h> |
24 | #include <linux/nfsd/nfsd.h> | 24 | #include <linux/nfsd/nfsd.h> |
25 | #include "auth.h" | ||
25 | 26 | ||
26 | #define NFSDDBG_FACILITY NFSDDBG_FH | 27 | #define NFSDDBG_FACILITY NFSDDBG_FH |
27 | 28 | ||
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 1190aeaa92be..9647b0f7bc0c 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -155,8 +155,8 @@ static int killsig; /* signal that was used to kill last nfsd */ | |||
155 | static void nfsd_last_thread(struct svc_serv *serv) | 155 | static void nfsd_last_thread(struct svc_serv *serv) |
156 | { | 156 | { |
157 | /* When last nfsd thread exits we need to do some clean-up */ | 157 | /* When last nfsd thread exits we need to do some clean-up */ |
158 | struct svc_sock *svsk; | 158 | struct svc_xprt *xprt; |
159 | list_for_each_entry(svsk, &serv->sv_permsocks, sk_list) | 159 | list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) |
160 | lockd_down(); | 160 | lockd_down(); |
161 | nfsd_serv = NULL; | 161 | nfsd_serv = NULL; |
162 | nfsd_racache_shutdown(); | 162 | nfsd_racache_shutdown(); |
@@ -236,7 +236,7 @@ static int nfsd_init_socks(int port) | |||
236 | 236 | ||
237 | error = lockd_up(IPPROTO_UDP); | 237 | error = lockd_up(IPPROTO_UDP); |
238 | if (error >= 0) { | 238 | if (error >= 0) { |
239 | error = svc_makesock(nfsd_serv, IPPROTO_UDP, port, | 239 | error = svc_create_xprt(nfsd_serv, "udp", port, |
240 | SVC_SOCK_DEFAULTS); | 240 | SVC_SOCK_DEFAULTS); |
241 | if (error < 0) | 241 | if (error < 0) |
242 | lockd_down(); | 242 | lockd_down(); |
@@ -247,7 +247,7 @@ static int nfsd_init_socks(int port) | |||
247 | #ifdef CONFIG_NFSD_TCP | 247 | #ifdef CONFIG_NFSD_TCP |
248 | error = lockd_up(IPPROTO_TCP); | 248 | error = lockd_up(IPPROTO_TCP); |
249 | if (error >= 0) { | 249 | if (error >= 0) { |
250 | error = svc_makesock(nfsd_serv, IPPROTO_TCP, port, | 250 | error = svc_create_xprt(nfsd_serv, "tcp", port, |
251 | SVC_SOCK_DEFAULTS); | 251 | SVC_SOCK_DEFAULTS); |
252 | if (error < 0) | 252 | if (error < 0) |
253 | lockd_down(); | 253 | lockd_down(); |
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index b86e3658a0af..61ad61743d94 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/nfsd/nfsd.h> | 15 | #include <linux/nfsd/nfsd.h> |
16 | #include <linux/nfsd/xdr.h> | 16 | #include <linux/nfsd/xdr.h> |
17 | #include <linux/mm.h> | 17 | #include <linux/mm.h> |
18 | #include "auth.h" | ||
18 | 19 | ||
19 | #define NFSDDBG_FACILITY NFSDDBG_XDR | 20 | #define NFSDDBG_FACILITY NFSDDBG_XDR |
20 | 21 | ||
@@ -62,10 +63,10 @@ encode_fh(__be32 *p, struct svc_fh *fhp) | |||
62 | * no slashes or null bytes. | 63 | * no slashes or null bytes. |
63 | */ | 64 | */ |
64 | static __be32 * | 65 | static __be32 * |
65 | decode_filename(__be32 *p, char **namp, int *lenp) | 66 | decode_filename(__be32 *p, char **namp, unsigned int *lenp) |
66 | { | 67 | { |
67 | char *name; | 68 | char *name; |
68 | int i; | 69 | unsigned int i; |
69 | 70 | ||
70 | if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS_MAXNAMLEN)) != NULL) { | 71 | if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS_MAXNAMLEN)) != NULL) { |
71 | for (i = 0, name = *namp; i < *lenp; i++, name++) { | 72 | for (i = 0, name = *namp; i < *lenp; i++, name++) { |
@@ -78,10 +79,10 @@ decode_filename(__be32 *p, char **namp, int *lenp) | |||
78 | } | 79 | } |
79 | 80 | ||
80 | static __be32 * | 81 | static __be32 * |
81 | decode_pathname(__be32 *p, char **namp, int *lenp) | 82 | decode_pathname(__be32 *p, char **namp, unsigned int *lenp) |
82 | { | 83 | { |
83 | char *name; | 84 | char *name; |
84 | int i; | 85 | unsigned int i; |
85 | 86 | ||
86 | if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS_MAXPATHLEN)) != NULL) { | 87 | if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS_MAXPATHLEN)) != NULL) { |
87 | for (i = 0, name = *namp; i < *lenp; i++, name++) { | 88 | for (i = 0, name = *namp; i < *lenp; i++, name++) { |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index d0199189924c..cc75e4fcd02b 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -132,7 +132,7 @@ out: | |||
132 | 132 | ||
133 | __be32 | 133 | __be32 |
134 | nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, | 134 | nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, |
135 | const char *name, int len, | 135 | const char *name, unsigned int len, |
136 | struct svc_export **exp_ret, struct dentry **dentry_ret) | 136 | struct svc_export **exp_ret, struct dentry **dentry_ret) |
137 | { | 137 | { |
138 | struct svc_export *exp; | 138 | struct svc_export *exp; |
@@ -226,7 +226,7 @@ out_nfserr: | |||
226 | */ | 226 | */ |
227 | __be32 | 227 | __be32 |
228 | nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, | 228 | nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, |
229 | int len, struct svc_fh *resfh) | 229 | unsigned int len, struct svc_fh *resfh) |
230 | { | 230 | { |
231 | struct svc_export *exp; | 231 | struct svc_export *exp; |
232 | struct dentry *dentry; | 232 | struct dentry *dentry; |
@@ -1151,6 +1151,26 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1151 | } | 1151 | } |
1152 | #endif /* CONFIG_NFSD_V3 */ | 1152 | #endif /* CONFIG_NFSD_V3 */ |
1153 | 1153 | ||
1154 | __be32 | ||
1155 | nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp, | ||
1156 | struct iattr *iap) | ||
1157 | { | ||
1158 | /* | ||
1159 | * Mode has already been set earlier in create: | ||
1160 | */ | ||
1161 | iap->ia_valid &= ~ATTR_MODE; | ||
1162 | /* | ||
1163 | * Setting uid/gid works only for root. Irix appears to | ||
1164 | * send along the gid on create when it tries to implement | ||
1165 | * setgid directories via NFS: | ||
1166 | */ | ||
1167 | if (current->fsuid != 0) | ||
1168 | iap->ia_valid &= ~(ATTR_UID|ATTR_GID); | ||
1169 | if (iap->ia_valid) | ||
1170 | return nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); | ||
1171 | return 0; | ||
1172 | } | ||
1173 | |||
1154 | /* | 1174 | /* |
1155 | * Create a file (regular, directory, device, fifo); UNIX sockets | 1175 | * Create a file (regular, directory, device, fifo); UNIX sockets |
1156 | * not yet implemented. | 1176 | * not yet implemented. |
@@ -1167,6 +1187,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1167 | struct dentry *dentry, *dchild = NULL; | 1187 | struct dentry *dentry, *dchild = NULL; |
1168 | struct inode *dirp; | 1188 | struct inode *dirp; |
1169 | __be32 err; | 1189 | __be32 err; |
1190 | __be32 err2; | ||
1170 | int host_err; | 1191 | int host_err; |
1171 | 1192 | ||
1172 | err = nfserr_perm; | 1193 | err = nfserr_perm; |
@@ -1257,16 +1278,9 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1257 | } | 1278 | } |
1258 | 1279 | ||
1259 | 1280 | ||
1260 | /* Set file attributes. Mode has already been set and | 1281 | err2 = nfsd_create_setattr(rqstp, resfhp, iap); |
1261 | * setting uid/gid works only for root. Irix appears to | 1282 | if (err2) |
1262 | * send along the gid when it tries to implement setgid | 1283 | err = err2; |
1263 | * directories via NFS. | ||
1264 | */ | ||
1265 | if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) { | ||
1266 | __be32 err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); | ||
1267 | if (err2) | ||
1268 | err = err2; | ||
1269 | } | ||
1270 | /* | 1284 | /* |
1271 | * Update the file handle to get the new inode info. | 1285 | * Update the file handle to get the new inode info. |
1272 | */ | 1286 | */ |
@@ -1295,6 +1309,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1295 | struct dentry *dentry, *dchild = NULL; | 1309 | struct dentry *dentry, *dchild = NULL; |
1296 | struct inode *dirp; | 1310 | struct inode *dirp; |
1297 | __be32 err; | 1311 | __be32 err; |
1312 | __be32 err2; | ||
1298 | int host_err; | 1313 | int host_err; |
1299 | __u32 v_mtime=0, v_atime=0; | 1314 | __u32 v_mtime=0, v_atime=0; |
1300 | 1315 | ||
@@ -1399,16 +1414,10 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1399 | iap->ia_atime.tv_nsec = 0; | 1414 | iap->ia_atime.tv_nsec = 0; |
1400 | } | 1415 | } |
1401 | 1416 | ||
1402 | /* Set file attributes. | ||
1403 | * Irix appears to send along the gid when it tries to | ||
1404 | * implement setgid directories via NFS. Clear out all that cruft. | ||
1405 | */ | ||
1406 | set_attr: | 1417 | set_attr: |
1407 | if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) { | 1418 | err2 = nfsd_create_setattr(rqstp, resfhp, iap); |
1408 | __be32 err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); | 1419 | if (err2) |
1409 | if (err2) | 1420 | err = err2; |
1410 | err = err2; | ||
1411 | } | ||
1412 | 1421 | ||
1413 | /* | 1422 | /* |
1414 | * Update the filehandle to get the new inode info. | 1423 | * Update the filehandle to get the new inode info. |