diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-06-01 11:32:58 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-06-01 11:32:58 -0400 |
commit | 419f4319495043a9507ac3e616be9ca60af09744 (patch) | |
tree | 0f747d80d11a6d4cd726ad6556839d5cd40b23ac /fs/nfsd | |
parent | fb21affa49204acd409328415b49bfe90136653c (diff) | |
parent | 6eccece90b6addf80ef9e6db79b0bc873301034b (diff) |
Merge branch 'for-3.5' of git://linux-nfs.org/~bfields/linux
Pull the rest of the nfsd commits from Bruce Fields:
"... and then I cherry-picked the remainder of the patches from the
head of my previous branch"
This is the rest of the original nfsd branch, rebased without the
delegation stuff that I thought really needed to be redone.
I don't like rebasing things like this in general, but in this situation
this was the lesser of two evils.
* 'for-3.5' of git://linux-nfs.org/~bfields/linux: (50 commits)
nfsd4: fix, consolidate client_has_state
nfsd4: don't remove rebooted client record until confirmation
nfsd4: remove some dprintk's and a comment
nfsd4: return "real" sequence id in confirmed case
nfsd4: fix exchange_id to return confirm flag
nfsd4: clarify that renewing expired client is a bug
nfsd4: simpler ordering of setclientid_confirm checks
nfsd4: setclientid: remove pointless assignment
nfsd4: fix error return in non-matching-creds case
nfsd4: fix setclientid_confirm same_cred check
nfsd4: merge 3 setclientid cases to 2
nfsd4: pull out common code from setclientid cases
nfsd4: merge last two setclientid cases
nfsd4: setclientid/confirm comment cleanup
nfsd4: setclientid remove unnecessary terms from a logical expression
nfsd4: move rq_flavor into svc_cred
nfsd4: stricter cred comparison for setclientid/exchange_id
nfsd4: move principal name into svc_cred
nfsd4: allow removing clients not holding state
nfsd4: rearrange exchange_id logic to simplify
...
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/auth.c | 2 | ||||
-rw-r--r-- | fs/nfsd/export.c | 8 | ||||
-rw-r--r-- | fs/nfsd/fault_inject.c | 1 | ||||
-rw-r--r-- | fs/nfsd/nfs4callback.c | 5 | ||||
-rw-r--r-- | fs/nfsd/nfs4idmap.c | 4 | ||||
-rw-r--r-- | fs/nfsd/nfs4recover.c | 4 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 525 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 62 | ||||
-rw-r--r-- | fs/nfsd/nfsctl.c | 12 | ||||
-rw-r--r-- | fs/nfsd/nfssvc.c | 23 | ||||
-rw-r--r-- | fs/nfsd/state.h | 1 | ||||
-rw-r--r-- | fs/nfsd/xdr4.h | 6 |
12 files changed, 334 insertions, 319 deletions
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c index 204438cc914e..34a10d78b839 100644 --- a/fs/nfsd/auth.c +++ b/fs/nfsd/auth.c | |||
@@ -11,7 +11,7 @@ int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp) | |||
11 | struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors; | 11 | struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors; |
12 | 12 | ||
13 | for (f = exp->ex_flavors; f < end; f++) { | 13 | for (f = exp->ex_flavors; f < end; f++) { |
14 | if (f->pseudoflavor == rqstp->rq_flavor) | 14 | if (f->pseudoflavor == rqstp->rq_cred.cr_flavor) |
15 | return f->flags; | 15 | return f->flags; |
16 | } | 16 | } |
17 | return exp->ex_flags; | 17 | return exp->ex_flags; |
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index dcb52b884519..ba233499b9a5 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
@@ -706,7 +706,7 @@ static struct cache_head *svc_export_alloc(void) | |||
706 | return NULL; | 706 | return NULL; |
707 | } | 707 | } |
708 | 708 | ||
709 | struct cache_detail svc_export_cache_template = { | 709 | static struct cache_detail svc_export_cache_template = { |
710 | .owner = THIS_MODULE, | 710 | .owner = THIS_MODULE, |
711 | .hash_size = EXPORT_HASHMAX, | 711 | .hash_size = EXPORT_HASHMAX, |
712 | .name = "nfsd.export", | 712 | .name = "nfsd.export", |
@@ -904,13 +904,13 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp) | |||
904 | return 0; | 904 | return 0; |
905 | /* ip-address based client; check sec= export option: */ | 905 | /* ip-address based client; check sec= export option: */ |
906 | for (f = exp->ex_flavors; f < end; f++) { | 906 | for (f = exp->ex_flavors; f < end; f++) { |
907 | if (f->pseudoflavor == rqstp->rq_flavor) | 907 | if (f->pseudoflavor == rqstp->rq_cred.cr_flavor) |
908 | return 0; | 908 | return 0; |
909 | } | 909 | } |
910 | /* defaults in absence of sec= options: */ | 910 | /* defaults in absence of sec= options: */ |
911 | if (exp->ex_nflavors == 0) { | 911 | if (exp->ex_nflavors == 0) { |
912 | if (rqstp->rq_flavor == RPC_AUTH_NULL || | 912 | if (rqstp->rq_cred.cr_flavor == RPC_AUTH_NULL || |
913 | rqstp->rq_flavor == RPC_AUTH_UNIX) | 913 | rqstp->rq_cred.cr_flavor == RPC_AUTH_UNIX) |
914 | return 0; | 914 | return 0; |
915 | } | 915 | } |
916 | return nfserr_wrongsec; | 916 | return nfserr_wrongsec; |
diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c index 9559ce468732..e6c38159622f 100644 --- a/fs/nfsd/fault_inject.c +++ b/fs/nfsd/fault_inject.c | |||
@@ -58,6 +58,7 @@ static int nfsd_inject_set(void *op_ptr, u64 val) | |||
58 | 58 | ||
59 | static int nfsd_inject_get(void *data, u64 *val) | 59 | static int nfsd_inject_get(void *data, u64 *val) |
60 | { | 60 | { |
61 | *val = 0; | ||
61 | return 0; | 62 | return 0; |
62 | } | 63 | } |
63 | 64 | ||
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index c8e9f637153a..a5fd6b982f27 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -650,9 +650,10 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c | |||
650 | struct rpc_clnt *client; | 650 | struct rpc_clnt *client; |
651 | 651 | ||
652 | if (clp->cl_minorversion == 0) { | 652 | if (clp->cl_minorversion == 0) { |
653 | if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) | 653 | if (!clp->cl_cred.cr_principal && |
654 | (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) | ||
654 | return -EINVAL; | 655 | return -EINVAL; |
655 | args.client_name = clp->cl_principal; | 656 | args.client_name = clp->cl_cred.cr_principal; |
656 | args.prognumber = conn->cb_prog, | 657 | args.prognumber = conn->cb_prog, |
657 | args.protocol = XPRT_TRANSPORT_TCP; | 658 | args.protocol = XPRT_TRANSPORT_TCP; |
658 | args.authflavor = clp->cl_flavor; | 659 | args.authflavor = clp->cl_flavor; |
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index 286a7f8f2024..dae36f1dee95 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c | |||
@@ -605,7 +605,7 @@ numeric_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namel | |||
605 | static __be32 | 605 | static __be32 |
606 | do_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, uid_t *id) | 606 | do_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, uid_t *id) |
607 | { | 607 | { |
608 | if (nfs4_disable_idmapping && rqstp->rq_flavor < RPC_AUTH_GSS) | 608 | if (nfs4_disable_idmapping && rqstp->rq_cred.cr_flavor < RPC_AUTH_GSS) |
609 | if (numeric_name_to_id(rqstp, type, name, namelen, id)) | 609 | if (numeric_name_to_id(rqstp, type, name, namelen, id)) |
610 | return 0; | 610 | return 0; |
611 | /* | 611 | /* |
@@ -618,7 +618,7 @@ do_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, u | |||
618 | static int | 618 | static int |
619 | do_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name) | 619 | do_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name) |
620 | { | 620 | { |
621 | if (nfs4_disable_idmapping && rqstp->rq_flavor < RPC_AUTH_GSS) | 621 | if (nfs4_disable_idmapping && rqstp->rq_cred.cr_flavor < RPC_AUTH_GSS) |
622 | return sprintf(name, "%u", id); | 622 | return sprintf(name, "%u", id); |
623 | return idmap_id_to_name(rqstp, type, id, name); | 623 | return idmap_id_to_name(rqstp, type, id, name); |
624 | } | 624 | } |
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index ed3f9206a0ee..5ff0b7b9fc08 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c | |||
@@ -570,7 +570,7 @@ static ssize_t | |||
570 | cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) | 570 | cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) |
571 | { | 571 | { |
572 | struct cld_upcall *tmp, *cup; | 572 | struct cld_upcall *tmp, *cup; |
573 | struct cld_msg *cmsg = (struct cld_msg *)src; | 573 | struct cld_msg __user *cmsg = (struct cld_msg __user *)src; |
574 | uint32_t xid; | 574 | uint32_t xid; |
575 | struct nfsd_net *nn = net_generic(filp->f_dentry->d_sb->s_fs_info, | 575 | struct nfsd_net *nn = net_generic(filp->f_dentry->d_sb->s_fs_info, |
576 | nfsd_net_id); | 576 | nfsd_net_id); |
@@ -1029,7 +1029,7 @@ rpc_pipefs_event(struct notifier_block *nb, unsigned long event, void *ptr) | |||
1029 | return ret; | 1029 | return ret; |
1030 | } | 1030 | } |
1031 | 1031 | ||
1032 | struct notifier_block nfsd4_cld_block = { | 1032 | static struct notifier_block nfsd4_cld_block = { |
1033 | .notifier_call = rpc_pipefs_event, | 1033 | .notifier_call = rpc_pipefs_event, |
1034 | }; | 1034 | }; |
1035 | 1035 | ||
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 03f82c0bc35d..8fdc9ec5c5d3 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <linux/sunrpc/clnt.h> | 42 | #include <linux/sunrpc/clnt.h> |
43 | #include "xdr4.h" | 43 | #include "xdr4.h" |
44 | #include "vfs.h" | 44 | #include "vfs.h" |
45 | #include "current_stateid.h" | ||
45 | 46 | ||
46 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 47 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
47 | 48 | ||
@@ -447,37 +448,69 @@ static struct list_head close_lru; | |||
447 | * | 448 | * |
448 | * which we should reject. | 449 | * which we should reject. |
449 | */ | 450 | */ |
450 | static void | 451 | static unsigned int |
451 | set_access(unsigned int *access, unsigned long bmap) { | 452 | bmap_to_share_mode(unsigned long bmap) { |
452 | int i; | 453 | int i; |
454 | unsigned int access = 0; | ||
453 | 455 | ||
454 | *access = 0; | ||
455 | for (i = 1; i < 4; i++) { | 456 | for (i = 1; i < 4; i++) { |
456 | if (test_bit(i, &bmap)) | 457 | if (test_bit(i, &bmap)) |
457 | *access |= i; | 458 | access |= i; |
458 | } | ||
459 | } | ||
460 | |||
461 | static void | ||
462 | set_deny(unsigned int *deny, unsigned long bmap) { | ||
463 | int i; | ||
464 | |||
465 | *deny = 0; | ||
466 | for (i = 0; i < 4; i++) { | ||
467 | if (test_bit(i, &bmap)) | ||
468 | *deny |= i ; | ||
469 | } | 459 | } |
460 | return access; | ||
470 | } | 461 | } |
471 | 462 | ||
472 | static int | 463 | static bool |
473 | test_share(struct nfs4_ol_stateid *stp, struct nfsd4_open *open) { | 464 | test_share(struct nfs4_ol_stateid *stp, struct nfsd4_open *open) { |
474 | unsigned int access, deny; | 465 | unsigned int access, deny; |
475 | 466 | ||
476 | set_access(&access, stp->st_access_bmap); | 467 | access = bmap_to_share_mode(stp->st_access_bmap); |
477 | set_deny(&deny, stp->st_deny_bmap); | 468 | deny = bmap_to_share_mode(stp->st_deny_bmap); |
478 | if ((access & open->op_share_deny) || (deny & open->op_share_access)) | 469 | if ((access & open->op_share_deny) || (deny & open->op_share_access)) |
479 | return 0; | 470 | return false; |
480 | return 1; | 471 | return true; |
472 | } | ||
473 | |||
474 | /* set share access for a given stateid */ | ||
475 | static inline void | ||
476 | set_access(u32 access, struct nfs4_ol_stateid *stp) | ||
477 | { | ||
478 | __set_bit(access, &stp->st_access_bmap); | ||
479 | } | ||
480 | |||
481 | /* clear share access for a given stateid */ | ||
482 | static inline void | ||
483 | clear_access(u32 access, struct nfs4_ol_stateid *stp) | ||
484 | { | ||
485 | __clear_bit(access, &stp->st_access_bmap); | ||
486 | } | ||
487 | |||
488 | /* test whether a given stateid has access */ | ||
489 | static inline bool | ||
490 | test_access(u32 access, struct nfs4_ol_stateid *stp) | ||
491 | { | ||
492 | return test_bit(access, &stp->st_access_bmap); | ||
493 | } | ||
494 | |||
495 | /* set share deny for a given stateid */ | ||
496 | static inline void | ||
497 | set_deny(u32 access, struct nfs4_ol_stateid *stp) | ||
498 | { | ||
499 | __set_bit(access, &stp->st_deny_bmap); | ||
500 | } | ||
501 | |||
502 | /* clear share deny for a given stateid */ | ||
503 | static inline void | ||
504 | clear_deny(u32 access, struct nfs4_ol_stateid *stp) | ||
505 | { | ||
506 | __clear_bit(access, &stp->st_deny_bmap); | ||
507 | } | ||
508 | |||
509 | /* test whether a given stateid is denying specific access */ | ||
510 | static inline bool | ||
511 | test_deny(u32 access, struct nfs4_ol_stateid *stp) | ||
512 | { | ||
513 | return test_bit(access, &stp->st_deny_bmap); | ||
481 | } | 514 | } |
482 | 515 | ||
483 | static int nfs4_access_to_omode(u32 access) | 516 | static int nfs4_access_to_omode(u32 access) |
@@ -493,6 +526,20 @@ static int nfs4_access_to_omode(u32 access) | |||
493 | BUG(); | 526 | BUG(); |
494 | } | 527 | } |
495 | 528 | ||
529 | /* release all access and file references for a given stateid */ | ||
530 | static void | ||
531 | release_all_access(struct nfs4_ol_stateid *stp) | ||
532 | { | ||
533 | int i; | ||
534 | |||
535 | for (i = 1; i < 4; i++) { | ||
536 | if (test_access(i, stp)) | ||
537 | nfs4_file_put_access(stp->st_file, | ||
538 | nfs4_access_to_omode(i)); | ||
539 | clear_access(i, stp); | ||
540 | } | ||
541 | } | ||
542 | |||
496 | static void unhash_generic_stateid(struct nfs4_ol_stateid *stp) | 543 | static void unhash_generic_stateid(struct nfs4_ol_stateid *stp) |
497 | { | 544 | { |
498 | list_del(&stp->st_perfile); | 545 | list_del(&stp->st_perfile); |
@@ -501,16 +548,7 @@ static void unhash_generic_stateid(struct nfs4_ol_stateid *stp) | |||
501 | 548 | ||
502 | static void close_generic_stateid(struct nfs4_ol_stateid *stp) | 549 | static void close_generic_stateid(struct nfs4_ol_stateid *stp) |
503 | { | 550 | { |
504 | int i; | 551 | release_all_access(stp); |
505 | |||
506 | if (stp->st_access_bmap) { | ||
507 | for (i = 1; i < 4; i++) { | ||
508 | if (test_bit(i, &stp->st_access_bmap)) | ||
509 | nfs4_file_put_access(stp->st_file, | ||
510 | nfs4_access_to_omode(i)); | ||
511 | __clear_bit(i, &stp->st_access_bmap); | ||
512 | } | ||
513 | } | ||
514 | put_nfs4_file(stp->st_file); | 552 | put_nfs4_file(stp->st_file); |
515 | stp->st_file = NULL; | 553 | stp->st_file = NULL; |
516 | } | 554 | } |
@@ -885,7 +923,7 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n | |||
885 | struct nfsd4_session *new; | 923 | struct nfsd4_session *new; |
886 | struct nfsd4_channel_attrs *fchan = &cses->fore_channel; | 924 | struct nfsd4_channel_attrs *fchan = &cses->fore_channel; |
887 | int numslots, slotsize; | 925 | int numslots, slotsize; |
888 | int status; | 926 | __be32 status; |
889 | int idx; | 927 | int idx; |
890 | 928 | ||
891 | /* | 929 | /* |
@@ -984,7 +1022,8 @@ static inline void | |||
984 | renew_client_locked(struct nfs4_client *clp) | 1022 | renew_client_locked(struct nfs4_client *clp) |
985 | { | 1023 | { |
986 | if (is_client_expired(clp)) { | 1024 | if (is_client_expired(clp)) { |
987 | dprintk("%s: client (clientid %08x/%08x) already expired\n", | 1025 | WARN_ON(1); |
1026 | printk("%s: client (clientid %08x/%08x) already expired\n", | ||
988 | __func__, | 1027 | __func__, |
989 | clp->cl_clientid.cl_boot, | 1028 | clp->cl_clientid.cl_boot, |
990 | clp->cl_clientid.cl_id); | 1029 | clp->cl_clientid.cl_id); |
@@ -1049,9 +1088,7 @@ free_client(struct nfs4_client *clp) | |||
1049 | list_del(&ses->se_perclnt); | 1088 | list_del(&ses->se_perclnt); |
1050 | nfsd4_put_session_locked(ses); | 1089 | nfsd4_put_session_locked(ses); |
1051 | } | 1090 | } |
1052 | if (clp->cl_cred.cr_group_info) | 1091 | free_svc_cred(&clp->cl_cred); |
1053 | put_group_info(clp->cl_cred.cr_group_info); | ||
1054 | kfree(clp->cl_principal); | ||
1055 | kfree(clp->cl_name.data); | 1092 | kfree(clp->cl_name.data); |
1056 | kfree(clp); | 1093 | kfree(clp); |
1057 | } | 1094 | } |
@@ -1132,12 +1169,21 @@ static void copy_clid(struct nfs4_client *target, struct nfs4_client *source) | |||
1132 | target->cl_clientid.cl_id = source->cl_clientid.cl_id; | 1169 | target->cl_clientid.cl_id = source->cl_clientid.cl_id; |
1133 | } | 1170 | } |
1134 | 1171 | ||
1135 | static void copy_cred(struct svc_cred *target, struct svc_cred *source) | 1172 | static int copy_cred(struct svc_cred *target, struct svc_cred *source) |
1136 | { | 1173 | { |
1174 | if (source->cr_principal) { | ||
1175 | target->cr_principal = | ||
1176 | kstrdup(source->cr_principal, GFP_KERNEL); | ||
1177 | if (target->cr_principal == NULL) | ||
1178 | return -ENOMEM; | ||
1179 | } else | ||
1180 | target->cr_principal = NULL; | ||
1181 | target->cr_flavor = source->cr_flavor; | ||
1137 | target->cr_uid = source->cr_uid; | 1182 | target->cr_uid = source->cr_uid; |
1138 | target->cr_gid = source->cr_gid; | 1183 | target->cr_gid = source->cr_gid; |
1139 | target->cr_group_info = source->cr_group_info; | 1184 | target->cr_group_info = source->cr_group_info; |
1140 | get_group_info(target->cr_group_info); | 1185 | get_group_info(target->cr_group_info); |
1186 | return 0; | ||
1141 | } | 1187 | } |
1142 | 1188 | ||
1143 | static int same_name(const char *n1, const char *n2) | 1189 | static int same_name(const char *n1, const char *n2) |
@@ -1157,11 +1203,31 @@ same_clid(clientid_t *cl1, clientid_t *cl2) | |||
1157 | return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id); | 1203 | return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id); |
1158 | } | 1204 | } |
1159 | 1205 | ||
1160 | /* XXX what about NGROUP */ | 1206 | static bool groups_equal(struct group_info *g1, struct group_info *g2) |
1207 | { | ||
1208 | int i; | ||
1209 | |||
1210 | if (g1->ngroups != g2->ngroups) | ||
1211 | return false; | ||
1212 | for (i=0; i<g1->ngroups; i++) | ||
1213 | if (GROUP_AT(g1, i) != GROUP_AT(g2, i)) | ||
1214 | return false; | ||
1215 | return true; | ||
1216 | } | ||
1217 | |||
1161 | static int | 1218 | static int |
1162 | same_creds(struct svc_cred *cr1, struct svc_cred *cr2) | 1219 | same_creds(struct svc_cred *cr1, struct svc_cred *cr2) |
1163 | { | 1220 | { |
1164 | return cr1->cr_uid == cr2->cr_uid; | 1221 | if ((cr1->cr_flavor != cr2->cr_flavor) |
1222 | || (cr1->cr_uid != cr2->cr_uid) | ||
1223 | || (cr1->cr_gid != cr2->cr_gid) | ||
1224 | || !groups_equal(cr1->cr_group_info, cr2->cr_group_info)) | ||
1225 | return false; | ||
1226 | if (cr1->cr_principal == cr2->cr_principal) | ||
1227 | return true; | ||
1228 | if (!cr1->cr_principal || !cr2->cr_principal) | ||
1229 | return false; | ||
1230 | return 0 == strcmp(cr1->cr_principal, cr1->cr_principal); | ||
1165 | } | 1231 | } |
1166 | 1232 | ||
1167 | static void gen_clid(struct nfs4_client *clp) | 1233 | static void gen_clid(struct nfs4_client *clp) |
@@ -1204,25 +1270,20 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | |||
1204 | { | 1270 | { |
1205 | struct nfs4_client *clp; | 1271 | struct nfs4_client *clp; |
1206 | struct sockaddr *sa = svc_addr(rqstp); | 1272 | struct sockaddr *sa = svc_addr(rqstp); |
1207 | char *princ; | 1273 | int ret; |
1208 | 1274 | ||
1209 | clp = alloc_client(name); | 1275 | clp = alloc_client(name); |
1210 | if (clp == NULL) | 1276 | if (clp == NULL) |
1211 | return NULL; | 1277 | return NULL; |
1212 | 1278 | ||
1213 | INIT_LIST_HEAD(&clp->cl_sessions); | 1279 | INIT_LIST_HEAD(&clp->cl_sessions); |
1214 | 1280 | ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred); | |
1215 | princ = svc_gss_principal(rqstp); | 1281 | if (ret) { |
1216 | if (princ) { | 1282 | spin_lock(&client_lock); |
1217 | clp->cl_principal = kstrdup(princ, GFP_KERNEL); | 1283 | free_client(clp); |
1218 | if (clp->cl_principal == NULL) { | 1284 | spin_unlock(&client_lock); |
1219 | spin_lock(&client_lock); | 1285 | return NULL; |
1220 | free_client(clp); | ||
1221 | spin_unlock(&client_lock); | ||
1222 | return NULL; | ||
1223 | } | ||
1224 | } | 1286 | } |
1225 | |||
1226 | idr_init(&clp->cl_stateids); | 1287 | idr_init(&clp->cl_stateids); |
1227 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); | 1288 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); |
1228 | atomic_set(&clp->cl_refcount, 0); | 1289 | atomic_set(&clp->cl_refcount, 0); |
@@ -1240,8 +1301,6 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | |||
1240 | rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); | 1301 | rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); |
1241 | copy_verf(clp, verf); | 1302 | copy_verf(clp, verf); |
1242 | rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); | 1303 | rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); |
1243 | clp->cl_flavor = rqstp->rq_flavor; | ||
1244 | copy_cred(&clp->cl_cred, &rqstp->rq_cred); | ||
1245 | gen_confirm(clp); | 1304 | gen_confirm(clp); |
1246 | clp->cl_cb_session = NULL; | 1305 | clp->cl_cb_session = NULL; |
1247 | return clp; | 1306 | return clp; |
@@ -1470,18 +1529,32 @@ nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid) | |||
1470 | clid->flags = new->cl_exchange_flags; | 1529 | clid->flags = new->cl_exchange_flags; |
1471 | } | 1530 | } |
1472 | 1531 | ||
1532 | static bool client_has_state(struct nfs4_client *clp) | ||
1533 | { | ||
1534 | /* | ||
1535 | * Note clp->cl_openowners check isn't quite right: there's no | ||
1536 | * need to count owners without stateid's. | ||
1537 | * | ||
1538 | * Also note we should probably be using this in 4.0 case too. | ||
1539 | */ | ||
1540 | return !list_empty(&clp->cl_openowners) | ||
1541 | || !list_empty(&clp->cl_delegations) | ||
1542 | || !list_empty(&clp->cl_sessions); | ||
1543 | } | ||
1544 | |||
1473 | __be32 | 1545 | __be32 |
1474 | nfsd4_exchange_id(struct svc_rqst *rqstp, | 1546 | nfsd4_exchange_id(struct svc_rqst *rqstp, |
1475 | struct nfsd4_compound_state *cstate, | 1547 | struct nfsd4_compound_state *cstate, |
1476 | struct nfsd4_exchange_id *exid) | 1548 | struct nfsd4_exchange_id *exid) |
1477 | { | 1549 | { |
1478 | struct nfs4_client *unconf, *conf, *new; | 1550 | struct nfs4_client *unconf, *conf, *new; |
1479 | int status; | 1551 | __be32 status; |
1480 | unsigned int strhashval; | 1552 | unsigned int strhashval; |
1481 | char dname[HEXDIR_LEN]; | 1553 | char dname[HEXDIR_LEN]; |
1482 | char addr_str[INET6_ADDRSTRLEN]; | 1554 | char addr_str[INET6_ADDRSTRLEN]; |
1483 | nfs4_verifier verf = exid->verifier; | 1555 | nfs4_verifier verf = exid->verifier; |
1484 | struct sockaddr *sa = svc_addr(rqstp); | 1556 | struct sockaddr *sa = svc_addr(rqstp); |
1557 | bool update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A; | ||
1485 | 1558 | ||
1486 | rpc_ntop(sa, addr_str, sizeof(addr_str)); | 1559 | rpc_ntop(sa, addr_str, sizeof(addr_str)); |
1487 | dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " | 1560 | dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " |
@@ -1507,71 +1580,63 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1507 | status = nfs4_make_rec_clidname(dname, &exid->clname); | 1580 | status = nfs4_make_rec_clidname(dname, &exid->clname); |
1508 | 1581 | ||
1509 | if (status) | 1582 | if (status) |
1510 | goto error; | 1583 | return status; |
1511 | 1584 | ||
1512 | strhashval = clientstr_hashval(dname); | 1585 | strhashval = clientstr_hashval(dname); |
1513 | 1586 | ||
1587 | /* Cases below refer to rfc 5661 section 18.35.4: */ | ||
1514 | nfs4_lock_state(); | 1588 | nfs4_lock_state(); |
1515 | status = nfs_ok; | ||
1516 | |||
1517 | conf = find_confirmed_client_by_str(dname, strhashval); | 1589 | conf = find_confirmed_client_by_str(dname, strhashval); |
1518 | if (conf) { | 1590 | if (conf) { |
1519 | if (!clp_used_exchangeid(conf)) { | 1591 | bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); |
1520 | status = nfserr_clid_inuse; /* XXX: ? */ | 1592 | bool verfs_match = same_verf(&verf, &conf->cl_verifier); |
1521 | goto out; | 1593 | |
1522 | } | 1594 | if (update) { |
1523 | if (!same_verf(&verf, &conf->cl_verifier)) { | 1595 | if (!clp_used_exchangeid(conf)) { /* buggy client */ |
1524 | /* 18.35.4 case 8 */ | 1596 | status = nfserr_inval; |
1525 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { | 1597 | goto out; |
1598 | } | ||
1599 | if (!creds_match) { /* case 9 */ | ||
1600 | status = nfserr_perm; | ||
1601 | goto out; | ||
1602 | } | ||
1603 | if (!verfs_match) { /* case 8 */ | ||
1526 | status = nfserr_not_same; | 1604 | status = nfserr_not_same; |
1527 | goto out; | 1605 | goto out; |
1528 | } | 1606 | } |
1529 | /* Client reboot: destroy old state */ | 1607 | /* case 6 */ |
1530 | expire_client(conf); | 1608 | exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; |
1531 | goto out_new; | 1609 | new = conf; |
1610 | goto out_copy; | ||
1532 | } | 1611 | } |
1533 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { | 1612 | if (!creds_match) { /* case 3 */ |
1534 | /* 18.35.4 case 9 */ | 1613 | if (client_has_state(conf)) { |
1535 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { | 1614 | status = nfserr_clid_inuse; |
1536 | status = nfserr_perm; | ||
1537 | goto out; | 1615 | goto out; |
1538 | } | 1616 | } |
1539 | expire_client(conf); | 1617 | expire_client(conf); |
1540 | goto out_new; | 1618 | goto out_new; |
1541 | } | 1619 | } |
1542 | /* | 1620 | if (verfs_match) { /* case 2 */ |
1543 | * Set bit when the owner id and verifier map to an already | 1621 | conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R; |
1544 | * confirmed client id (18.35.3). | 1622 | new = conf; |
1545 | */ | 1623 | goto out_copy; |
1546 | exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; | 1624 | } |
1547 | 1625 | /* case 5, client reboot */ | |
1548 | /* | 1626 | goto out_new; |
1549 | * Falling into 18.35.4 case 2, possible router replay. | ||
1550 | * Leave confirmed record intact and return same result. | ||
1551 | */ | ||
1552 | copy_verf(conf, &verf); | ||
1553 | new = conf; | ||
1554 | goto out_copy; | ||
1555 | } | 1627 | } |
1556 | 1628 | ||
1557 | /* 18.35.4 case 7 */ | 1629 | if (update) { /* case 7 */ |
1558 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { | ||
1559 | status = nfserr_noent; | 1630 | status = nfserr_noent; |
1560 | goto out; | 1631 | goto out; |
1561 | } | 1632 | } |
1562 | 1633 | ||
1563 | unconf = find_unconfirmed_client_by_str(dname, strhashval); | 1634 | unconf = find_unconfirmed_client_by_str(dname, strhashval); |
1564 | if (unconf) { | 1635 | if (unconf) /* case 4, possible retry or client restart */ |
1565 | /* | ||
1566 | * Possible retry or client restart. Per 18.35.4 case 4, | ||
1567 | * a new unconfirmed record should be generated regardless | ||
1568 | * of whether any properties have changed. | ||
1569 | */ | ||
1570 | expire_client(unconf); | 1636 | expire_client(unconf); |
1571 | } | ||
1572 | 1637 | ||
1638 | /* case 1 (normal case) */ | ||
1573 | out_new: | 1639 | out_new: |
1574 | /* Normal case */ | ||
1575 | new = create_client(exid->clname, dname, rqstp, &verf); | 1640 | new = create_client(exid->clname, dname, rqstp, &verf); |
1576 | if (new == NULL) { | 1641 | if (new == NULL) { |
1577 | status = nfserr_jukebox; | 1642 | status = nfserr_jukebox; |
@@ -1584,7 +1649,7 @@ out_copy: | |||
1584 | exid->clientid.cl_boot = new->cl_clientid.cl_boot; | 1649 | exid->clientid.cl_boot = new->cl_clientid.cl_boot; |
1585 | exid->clientid.cl_id = new->cl_clientid.cl_id; | 1650 | exid->clientid.cl_id = new->cl_clientid.cl_id; |
1586 | 1651 | ||
1587 | exid->seqid = 1; | 1652 | exid->seqid = new->cl_cs_slot.sl_seqid + 1; |
1588 | nfsd4_set_ex_flags(new, exid); | 1653 | nfsd4_set_ex_flags(new, exid); |
1589 | 1654 | ||
1590 | dprintk("nfsd4_exchange_id seqid %d flags %x\n", | 1655 | dprintk("nfsd4_exchange_id seqid %d flags %x\n", |
@@ -1593,12 +1658,10 @@ out_copy: | |||
1593 | 1658 | ||
1594 | out: | 1659 | out: |
1595 | nfs4_unlock_state(); | 1660 | nfs4_unlock_state(); |
1596 | error: | ||
1597 | dprintk("nfsd4_exchange_id returns %d\n", ntohl(status)); | ||
1598 | return status; | 1661 | return status; |
1599 | } | 1662 | } |
1600 | 1663 | ||
1601 | static int | 1664 | static __be32 |
1602 | check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) | 1665 | check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) |
1603 | { | 1666 | { |
1604 | dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid, | 1667 | dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid, |
@@ -1626,7 +1689,7 @@ check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) | |||
1626 | */ | 1689 | */ |
1627 | static void | 1690 | static void |
1628 | nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses, | 1691 | nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses, |
1629 | struct nfsd4_clid_slot *slot, int nfserr) | 1692 | struct nfsd4_clid_slot *slot, __be32 nfserr) |
1630 | { | 1693 | { |
1631 | slot->sl_status = nfserr; | 1694 | slot->sl_status = nfserr; |
1632 | memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses)); | 1695 | memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses)); |
@@ -1657,7 +1720,7 @@ nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses, | |||
1657 | /* seqid, slotID, slotID, slotID, status */ \ | 1720 | /* seqid, slotID, slotID, slotID, status */ \ |
1658 | 5 ) * sizeof(__be32)) | 1721 | 5 ) * sizeof(__be32)) |
1659 | 1722 | ||
1660 | static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs fchannel) | 1723 | static bool check_forechannel_attrs(struct nfsd4_channel_attrs fchannel) |
1661 | { | 1724 | { |
1662 | return fchannel.maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ | 1725 | return fchannel.maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ |
1663 | || fchannel.maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ; | 1726 | || fchannel.maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ; |
@@ -1673,7 +1736,7 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1673 | struct nfsd4_session *new; | 1736 | struct nfsd4_session *new; |
1674 | struct nfsd4_clid_slot *cs_slot = NULL; | 1737 | struct nfsd4_clid_slot *cs_slot = NULL; |
1675 | bool confirm_me = false; | 1738 | bool confirm_me = false; |
1676 | int status = 0; | 1739 | __be32 status = 0; |
1677 | 1740 | ||
1678 | if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) | 1741 | if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) |
1679 | return nfserr_inval; | 1742 | return nfserr_inval; |
@@ -1686,16 +1749,10 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1686 | cs_slot = &conf->cl_cs_slot; | 1749 | cs_slot = &conf->cl_cs_slot; |
1687 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); | 1750 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); |
1688 | if (status == nfserr_replay_cache) { | 1751 | if (status == nfserr_replay_cache) { |
1689 | dprintk("Got a create_session replay! seqid= %d\n", | ||
1690 | cs_slot->sl_seqid); | ||
1691 | /* Return the cached reply status */ | ||
1692 | status = nfsd4_replay_create_session(cr_ses, cs_slot); | 1752 | status = nfsd4_replay_create_session(cr_ses, cs_slot); |
1693 | goto out; | 1753 | goto out; |
1694 | } else if (cr_ses->seqid != cs_slot->sl_seqid + 1) { | 1754 | } else if (cr_ses->seqid != cs_slot->sl_seqid + 1) { |
1695 | status = nfserr_seq_misordered; | 1755 | status = nfserr_seq_misordered; |
1696 | dprintk("Sequence misordered!\n"); | ||
1697 | dprintk("Expected seqid= %d but got seqid= %d\n", | ||
1698 | cs_slot->sl_seqid, cr_ses->seqid); | ||
1699 | goto out; | 1756 | goto out; |
1700 | } | 1757 | } |
1701 | } else if (unconf) { | 1758 | } else if (unconf) { |
@@ -1704,7 +1761,6 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1704 | status = nfserr_clid_inuse; | 1761 | status = nfserr_clid_inuse; |
1705 | goto out; | 1762 | goto out; |
1706 | } | 1763 | } |
1707 | |||
1708 | cs_slot = &unconf->cl_cs_slot; | 1764 | cs_slot = &unconf->cl_cs_slot; |
1709 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); | 1765 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); |
1710 | if (status) { | 1766 | if (status) { |
@@ -1712,7 +1768,6 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1712 | status = nfserr_seq_misordered; | 1768 | status = nfserr_seq_misordered; |
1713 | goto out; | 1769 | goto out; |
1714 | } | 1770 | } |
1715 | |||
1716 | confirm_me = true; | 1771 | confirm_me = true; |
1717 | conf = unconf; | 1772 | conf = unconf; |
1718 | } else { | 1773 | } else { |
@@ -1749,8 +1804,14 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1749 | 1804 | ||
1750 | /* cache solo and embedded create sessions under the state lock */ | 1805 | /* cache solo and embedded create sessions under the state lock */ |
1751 | nfsd4_cache_create_session(cr_ses, cs_slot, status); | 1806 | nfsd4_cache_create_session(cr_ses, cs_slot, status); |
1752 | if (confirm_me) | 1807 | if (confirm_me) { |
1808 | unsigned int hash = clientstr_hashval(unconf->cl_recdir); | ||
1809 | struct nfs4_client *old = | ||
1810 | find_confirmed_client_by_str(conf->cl_recdir, hash); | ||
1811 | if (old) | ||
1812 | expire_client(old); | ||
1753 | move_to_confirmed(conf); | 1813 | move_to_confirmed(conf); |
1814 | } | ||
1754 | out: | 1815 | out: |
1755 | nfs4_unlock_state(); | 1816 | nfs4_unlock_state(); |
1756 | dprintk("%s returns %d\n", __func__, ntohl(status)); | 1817 | dprintk("%s returns %d\n", __func__, ntohl(status)); |
@@ -1818,7 +1879,7 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
1818 | struct nfsd4_destroy_session *sessionid) | 1879 | struct nfsd4_destroy_session *sessionid) |
1819 | { | 1880 | { |
1820 | struct nfsd4_session *ses; | 1881 | struct nfsd4_session *ses; |
1821 | u32 status = nfserr_badsession; | 1882 | __be32 status = nfserr_badsession; |
1822 | 1883 | ||
1823 | /* Notes: | 1884 | /* Notes: |
1824 | * - The confirmed nfs4_client->cl_sessionid holds destroyed sessinid | 1885 | * - The confirmed nfs4_client->cl_sessionid holds destroyed sessinid |
@@ -1914,7 +1975,7 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
1914 | struct nfsd4_session *session; | 1975 | struct nfsd4_session *session; |
1915 | struct nfsd4_slot *slot; | 1976 | struct nfsd4_slot *slot; |
1916 | struct nfsd4_conn *conn; | 1977 | struct nfsd4_conn *conn; |
1917 | int status; | 1978 | __be32 status; |
1918 | 1979 | ||
1919 | if (resp->opcnt != 1) | 1980 | if (resp->opcnt != 1) |
1920 | return nfserr_sequence_pos; | 1981 | return nfserr_sequence_pos; |
@@ -2008,18 +2069,11 @@ out: | |||
2008 | return status; | 2069 | return status; |
2009 | } | 2070 | } |
2010 | 2071 | ||
2011 | static inline bool has_resources(struct nfs4_client *clp) | ||
2012 | { | ||
2013 | return !list_empty(&clp->cl_openowners) | ||
2014 | || !list_empty(&clp->cl_delegations) | ||
2015 | || !list_empty(&clp->cl_sessions); | ||
2016 | } | ||
2017 | |||
2018 | __be32 | 2072 | __be32 |
2019 | nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_destroy_clientid *dc) | 2073 | nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_destroy_clientid *dc) |
2020 | { | 2074 | { |
2021 | struct nfs4_client *conf, *unconf, *clp; | 2075 | struct nfs4_client *conf, *unconf, *clp; |
2022 | int status = 0; | 2076 | __be32 status = 0; |
2023 | 2077 | ||
2024 | nfs4_lock_state(); | 2078 | nfs4_lock_state(); |
2025 | unconf = find_unconfirmed_client(&dc->clientid); | 2079 | unconf = find_unconfirmed_client(&dc->clientid); |
@@ -2028,7 +2082,7 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta | |||
2028 | if (conf) { | 2082 | if (conf) { |
2029 | clp = conf; | 2083 | clp = conf; |
2030 | 2084 | ||
2031 | if (!is_client_expired(conf) && has_resources(conf)) { | 2085 | if (!is_client_expired(conf) && client_has_state(conf)) { |
2032 | status = nfserr_clientid_busy; | 2086 | status = nfserr_clientid_busy; |
2033 | goto out; | 2087 | goto out; |
2034 | } | 2088 | } |
@@ -2055,7 +2109,7 @@ out: | |||
2055 | __be32 | 2109 | __be32 |
2056 | nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc) | 2110 | nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc) |
2057 | { | 2111 | { |
2058 | int status = 0; | 2112 | __be32 status = 0; |
2059 | 2113 | ||
2060 | if (rc->rca_one_fs) { | 2114 | if (rc->rca_one_fs) { |
2061 | if (!cstate->current_fh.fh_dentry) | 2115 | if (!cstate->current_fh.fh_dentry) |
@@ -2106,17 +2160,13 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2106 | if (status) | 2160 | if (status) |
2107 | return status; | 2161 | return status; |
2108 | 2162 | ||
2109 | /* | ||
2110 | * XXX The Duplicate Request Cache (DRC) has been checked (??) | ||
2111 | * We get here on a DRC miss. | ||
2112 | */ | ||
2113 | |||
2114 | strhashval = clientstr_hashval(dname); | 2163 | strhashval = clientstr_hashval(dname); |
2115 | 2164 | ||
2165 | /* Cases below refer to rfc 3530 section 14.2.33: */ | ||
2116 | nfs4_lock_state(); | 2166 | nfs4_lock_state(); |
2117 | conf = find_confirmed_client_by_str(dname, strhashval); | 2167 | conf = find_confirmed_client_by_str(dname, strhashval); |
2118 | if (conf) { | 2168 | if (conf) { |
2119 | /* RFC 3530 14.2.33 CASE 0: */ | 2169 | /* case 0: */ |
2120 | status = nfserr_clid_inuse; | 2170 | status = nfserr_clid_inuse; |
2121 | if (clp_used_exchangeid(conf)) | 2171 | if (clp_used_exchangeid(conf)) |
2122 | goto out; | 2172 | goto out; |
@@ -2129,63 +2179,18 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2129 | goto out; | 2179 | goto out; |
2130 | } | 2180 | } |
2131 | } | 2181 | } |
2132 | /* | ||
2133 | * section 14.2.33 of RFC 3530 (under the heading "IMPLEMENTATION") | ||
2134 | * has a description of SETCLIENTID request processing consisting | ||
2135 | * of 5 bullet points, labeled as CASE0 - CASE4 below. | ||
2136 | */ | ||
2137 | unconf = find_unconfirmed_client_by_str(dname, strhashval); | 2182 | unconf = find_unconfirmed_client_by_str(dname, strhashval); |
2183 | if (unconf) | ||
2184 | expire_client(unconf); | ||
2138 | status = nfserr_jukebox; | 2185 | status = nfserr_jukebox; |
2139 | if (!conf) { | 2186 | new = create_client(clname, dname, rqstp, &clverifier); |
2140 | /* | 2187 | if (new == NULL) |
2141 | * RFC 3530 14.2.33 CASE 4: | 2188 | goto out; |
2142 | * placed first, because it is the normal case | 2189 | if (conf && same_verf(&conf->cl_verifier, &clverifier)) |
2143 | */ | 2190 | /* case 1: probable callback update */ |
2144 | if (unconf) | ||
2145 | expire_client(unconf); | ||
2146 | new = create_client(clname, dname, rqstp, &clverifier); | ||
2147 | if (new == NULL) | ||
2148 | goto out; | ||
2149 | gen_clid(new); | ||
2150 | } else if (same_verf(&conf->cl_verifier, &clverifier)) { | ||
2151 | /* | ||
2152 | * RFC 3530 14.2.33 CASE 1: | ||
2153 | * probable callback update | ||
2154 | */ | ||
2155 | if (unconf) { | ||
2156 | /* Note this is removing unconfirmed {*x***}, | ||
2157 | * which is stronger than RFC recommended {vxc**}. | ||
2158 | * This has the advantage that there is at most | ||
2159 | * one {*x***} in either list at any time. | ||
2160 | */ | ||
2161 | expire_client(unconf); | ||
2162 | } | ||
2163 | new = create_client(clname, dname, rqstp, &clverifier); | ||
2164 | if (new == NULL) | ||
2165 | goto out; | ||
2166 | copy_clid(new, conf); | 2191 | copy_clid(new, conf); |
2167 | } else if (!unconf) { | 2192 | else /* case 4 (new client) or cases 2, 3 (client reboot): */ |
2168 | /* | ||
2169 | * RFC 3530 14.2.33 CASE 2: | ||
2170 | * probable client reboot; state will be removed if | ||
2171 | * confirmed. | ||
2172 | */ | ||
2173 | new = create_client(clname, dname, rqstp, &clverifier); | ||
2174 | if (new == NULL) | ||
2175 | goto out; | ||
2176 | gen_clid(new); | ||
2177 | } else { | ||
2178 | /* | ||
2179 | * RFC 3530 14.2.33 CASE 3: | ||
2180 | * probable client reboot; state will be removed if | ||
2181 | * confirmed. | ||
2182 | */ | ||
2183 | expire_client(unconf); | ||
2184 | new = create_client(clname, dname, rqstp, &clverifier); | ||
2185 | if (new == NULL) | ||
2186 | goto out; | ||
2187 | gen_clid(new); | 2193 | gen_clid(new); |
2188 | } | ||
2189 | /* | 2194 | /* |
2190 | * XXX: we should probably set this at creation time, and check | 2195 | * XXX: we should probably set this at creation time, and check |
2191 | * for consistent minorversion use throughout: | 2196 | * for consistent minorversion use throughout: |
@@ -2203,17 +2208,11 @@ out: | |||
2203 | } | 2208 | } |
2204 | 2209 | ||
2205 | 2210 | ||
2206 | /* | ||
2207 | * Section 14.2.34 of RFC 3530 (under the heading "IMPLEMENTATION") has | ||
2208 | * a description of SETCLIENTID_CONFIRM request processing consisting of 4 | ||
2209 | * bullets, labeled as CASE1 - CASE4 below. | ||
2210 | */ | ||
2211 | __be32 | 2211 | __be32 |
2212 | nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | 2212 | nfsd4_setclientid_confirm(struct svc_rqst *rqstp, |
2213 | struct nfsd4_compound_state *cstate, | 2213 | struct nfsd4_compound_state *cstate, |
2214 | struct nfsd4_setclientid_confirm *setclientid_confirm) | 2214 | struct nfsd4_setclientid_confirm *setclientid_confirm) |
2215 | { | 2215 | { |
2216 | struct sockaddr *sa = svc_addr(rqstp); | ||
2217 | struct nfs4_client *conf, *unconf; | 2216 | struct nfs4_client *conf, *unconf; |
2218 | nfs4_verifier confirm = setclientid_confirm->sc_confirm; | 2217 | nfs4_verifier confirm = setclientid_confirm->sc_confirm; |
2219 | clientid_t * clid = &setclientid_confirm->sc_clientid; | 2218 | clientid_t * clid = &setclientid_confirm->sc_clientid; |
@@ -2221,84 +2220,44 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
2221 | 2220 | ||
2222 | if (STALE_CLIENTID(clid)) | 2221 | if (STALE_CLIENTID(clid)) |
2223 | return nfserr_stale_clientid; | 2222 | return nfserr_stale_clientid; |
2224 | /* | ||
2225 | * XXX The Duplicate Request Cache (DRC) has been checked (??) | ||
2226 | * We get here on a DRC miss. | ||
2227 | */ | ||
2228 | |||
2229 | nfs4_lock_state(); | 2223 | nfs4_lock_state(); |
2230 | 2224 | ||
2231 | conf = find_confirmed_client(clid); | 2225 | conf = find_confirmed_client(clid); |
2232 | unconf = find_unconfirmed_client(clid); | 2226 | unconf = find_unconfirmed_client(clid); |
2233 | |||
2234 | status = nfserr_clid_inuse; | ||
2235 | if (conf && !rpc_cmp_addr((struct sockaddr *) &conf->cl_addr, sa)) | ||
2236 | goto out; | ||
2237 | if (unconf && !rpc_cmp_addr((struct sockaddr *) &unconf->cl_addr, sa)) | ||
2238 | goto out; | ||
2239 | |||
2240 | /* | 2227 | /* |
2241 | * section 14.2.34 of RFC 3530 has a description of | 2228 | * We try hard to give out unique clientid's, so if we get an |
2242 | * SETCLIENTID_CONFIRM request processing consisting | 2229 | * attempt to confirm the same clientid with a different cred, |
2243 | * of 4 bullet points, labeled as CASE1 - CASE4 below. | 2230 | * there's a bug somewhere. Let's charitably assume it's our |
2231 | * bug. | ||
2244 | */ | 2232 | */ |
2245 | if (conf && unconf && same_verf(&confirm, &unconf->cl_confirm)) { | 2233 | status = nfserr_serverfault; |
2246 | /* | 2234 | if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred)) |
2247 | * RFC 3530 14.2.34 CASE 1: | 2235 | goto out; |
2248 | * callback update | 2236 | if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred)) |
2249 | */ | 2237 | goto out; |
2250 | if (!same_creds(&conf->cl_cred, &unconf->cl_cred)) | 2238 | /* cases below refer to rfc 3530 section 14.2.34: */ |
2251 | status = nfserr_clid_inuse; | 2239 | if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) { |
2252 | else { | 2240 | if (conf && !unconf) /* case 2: probable retransmit */ |
2253 | nfsd4_change_callback(conf, &unconf->cl_cb_conn); | ||
2254 | nfsd4_probe_callback(conf); | ||
2255 | expire_client(unconf); | ||
2256 | status = nfs_ok; | 2241 | status = nfs_ok; |
2242 | else /* case 4: client hasn't noticed we rebooted yet? */ | ||
2243 | status = nfserr_stale_clientid; | ||
2244 | goto out; | ||
2245 | } | ||
2246 | status = nfs_ok; | ||
2247 | if (conf) { /* case 1: callback update */ | ||
2248 | nfsd4_change_callback(conf, &unconf->cl_cb_conn); | ||
2249 | nfsd4_probe_callback(conf); | ||
2250 | expire_client(unconf); | ||
2251 | } else { /* case 3: normal case; new or rebooted client */ | ||
2252 | unsigned int hash = clientstr_hashval(unconf->cl_recdir); | ||
2257 | 2253 | ||
2254 | conf = find_confirmed_client_by_str(unconf->cl_recdir, hash); | ||
2255 | if (conf) { | ||
2256 | nfsd4_client_record_remove(conf); | ||
2257 | expire_client(conf); | ||
2258 | } | 2258 | } |
2259 | } else if (conf && !unconf) { | 2259 | move_to_confirmed(unconf); |
2260 | /* | 2260 | nfsd4_probe_callback(unconf); |
2261 | * RFC 3530 14.2.34 CASE 2: | ||
2262 | * probable retransmitted request; play it safe and | ||
2263 | * do nothing. | ||
2264 | */ | ||
2265 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) | ||
2266 | status = nfserr_clid_inuse; | ||
2267 | else | ||
2268 | status = nfs_ok; | ||
2269 | } else if (!conf && unconf | ||
2270 | && same_verf(&unconf->cl_confirm, &confirm)) { | ||
2271 | /* | ||
2272 | * RFC 3530 14.2.34 CASE 3: | ||
2273 | * Normal case; new or rebooted client: | ||
2274 | */ | ||
2275 | if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred)) { | ||
2276 | status = nfserr_clid_inuse; | ||
2277 | } else { | ||
2278 | unsigned int hash = | ||
2279 | clientstr_hashval(unconf->cl_recdir); | ||
2280 | conf = find_confirmed_client_by_str(unconf->cl_recdir, | ||
2281 | hash); | ||
2282 | if (conf) { | ||
2283 | nfsd4_client_record_remove(conf); | ||
2284 | expire_client(conf); | ||
2285 | } | ||
2286 | move_to_confirmed(unconf); | ||
2287 | conf = unconf; | ||
2288 | nfsd4_probe_callback(conf); | ||
2289 | status = nfs_ok; | ||
2290 | } | ||
2291 | } else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm))) | ||
2292 | && (!unconf || (unconf && !same_verf(&unconf->cl_confirm, | ||
2293 | &confirm)))) { | ||
2294 | /* | ||
2295 | * RFC 3530 14.2.34 CASE 4: | ||
2296 | * Client probably hasn't noticed that we rebooted yet. | ||
2297 | */ | ||
2298 | status = nfserr_stale_clientid; | ||
2299 | } else { | ||
2300 | /* check that we have hit one of the cases...*/ | ||
2301 | status = nfserr_clid_inuse; | ||
2302 | } | 2261 | } |
2303 | out: | 2262 | out: |
2304 | nfs4_unlock_state(); | 2263 | nfs4_unlock_state(); |
@@ -2454,8 +2413,8 @@ static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, | |||
2454 | stp->st_file = fp; | 2413 | stp->st_file = fp; |
2455 | stp->st_access_bmap = 0; | 2414 | stp->st_access_bmap = 0; |
2456 | stp->st_deny_bmap = 0; | 2415 | stp->st_deny_bmap = 0; |
2457 | __set_bit(open->op_share_access, &stp->st_access_bmap); | 2416 | set_access(open->op_share_access, stp); |
2458 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); | 2417 | set_deny(open->op_share_deny, stp); |
2459 | stp->st_openstp = NULL; | 2418 | stp->st_openstp = NULL; |
2460 | } | 2419 | } |
2461 | 2420 | ||
@@ -2534,8 +2493,8 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) | |||
2534 | ret = nfserr_locked; | 2493 | ret = nfserr_locked; |
2535 | /* Search for conflicting share reservations */ | 2494 | /* Search for conflicting share reservations */ |
2536 | list_for_each_entry(stp, &fp->fi_stateids, st_perfile) { | 2495 | list_for_each_entry(stp, &fp->fi_stateids, st_perfile) { |
2537 | if (test_bit(deny_type, &stp->st_deny_bmap) || | 2496 | if (test_deny(deny_type, stp) || |
2538 | test_bit(NFS4_SHARE_DENY_BOTH, &stp->st_deny_bmap)) | 2497 | test_deny(NFS4_SHARE_DENY_BOTH, stp)) |
2539 | goto out; | 2498 | goto out; |
2540 | } | 2499 | } |
2541 | ret = nfs_ok; | 2500 | ret = nfs_ok; |
@@ -2791,7 +2750,7 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *c | |||
2791 | bool new_access; | 2750 | bool new_access; |
2792 | __be32 status; | 2751 | __be32 status; |
2793 | 2752 | ||
2794 | new_access = !test_bit(op_share_access, &stp->st_access_bmap); | 2753 | new_access = !test_access(op_share_access, stp); |
2795 | if (new_access) { | 2754 | if (new_access) { |
2796 | status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open); | 2755 | status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open); |
2797 | if (status) | 2756 | if (status) |
@@ -2806,8 +2765,8 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *c | |||
2806 | return status; | 2765 | return status; |
2807 | } | 2766 | } |
2808 | /* remember the open */ | 2767 | /* remember the open */ |
2809 | __set_bit(op_share_access, &stp->st_access_bmap); | 2768 | set_access(op_share_access, stp); |
2810 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); | 2769 | set_deny(open->op_share_deny, stp); |
2811 | 2770 | ||
2812 | return nfs_ok; | 2771 | return nfs_ok; |
2813 | } | 2772 | } |
@@ -3282,18 +3241,18 @@ STALE_STATEID(stateid_t *stateid) | |||
3282 | } | 3241 | } |
3283 | 3242 | ||
3284 | static inline int | 3243 | static inline int |
3285 | access_permit_read(unsigned long access_bmap) | 3244 | access_permit_read(struct nfs4_ol_stateid *stp) |
3286 | { | 3245 | { |
3287 | return test_bit(NFS4_SHARE_ACCESS_READ, &access_bmap) || | 3246 | return test_access(NFS4_SHARE_ACCESS_READ, stp) || |
3288 | test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap) || | 3247 | test_access(NFS4_SHARE_ACCESS_BOTH, stp) || |
3289 | test_bit(NFS4_SHARE_ACCESS_WRITE, &access_bmap); | 3248 | test_access(NFS4_SHARE_ACCESS_WRITE, stp); |
3290 | } | 3249 | } |
3291 | 3250 | ||
3292 | static inline int | 3251 | static inline int |
3293 | access_permit_write(unsigned long access_bmap) | 3252 | access_permit_write(struct nfs4_ol_stateid *stp) |
3294 | { | 3253 | { |
3295 | return test_bit(NFS4_SHARE_ACCESS_WRITE, &access_bmap) || | 3254 | return test_access(NFS4_SHARE_ACCESS_WRITE, stp) || |
3296 | test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap); | 3255 | test_access(NFS4_SHARE_ACCESS_BOTH, stp); |
3297 | } | 3256 | } |
3298 | 3257 | ||
3299 | static | 3258 | static |
@@ -3304,9 +3263,9 @@ __be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags) | |||
3304 | /* For lock stateid's, we test the parent open, not the lock: */ | 3263 | /* For lock stateid's, we test the parent open, not the lock: */ |
3305 | if (stp->st_openstp) | 3264 | if (stp->st_openstp) |
3306 | stp = stp->st_openstp; | 3265 | stp = stp->st_openstp; |
3307 | if ((flags & WR_STATE) && (!access_permit_write(stp->st_access_bmap))) | 3266 | if ((flags & WR_STATE) && !access_permit_write(stp)) |
3308 | goto out; | 3267 | goto out; |
3309 | if ((flags & RD_STATE) && (!access_permit_read(stp->st_access_bmap))) | 3268 | if ((flags & RD_STATE) && !access_permit_read(stp)) |
3310 | goto out; | 3269 | goto out; |
3311 | status = nfs_ok; | 3270 | status = nfs_ok; |
3312 | out: | 3271 | out: |
@@ -3346,7 +3305,7 @@ static bool stateid_generation_after(stateid_t *a, stateid_t *b) | |||
3346 | return (s32)a->si_generation - (s32)b->si_generation > 0; | 3305 | return (s32)a->si_generation - (s32)b->si_generation > 0; |
3347 | } | 3306 | } |
3348 | 3307 | ||
3349 | static int check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) | 3308 | static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) |
3350 | { | 3309 | { |
3351 | /* | 3310 | /* |
3352 | * When sessions are used the stateid generation number is ignored | 3311 | * When sessions are used the stateid generation number is ignored |
@@ -3655,10 +3614,10 @@ out: | |||
3655 | 3614 | ||
3656 | static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access) | 3615 | static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access) |
3657 | { | 3616 | { |
3658 | if (!test_bit(access, &stp->st_access_bmap)) | 3617 | if (!test_access(access, stp)) |
3659 | return; | 3618 | return; |
3660 | nfs4_file_put_access(stp->st_file, nfs4_access_to_omode(access)); | 3619 | nfs4_file_put_access(stp->st_file, nfs4_access_to_omode(access)); |
3661 | __clear_bit(access, &stp->st_access_bmap); | 3620 | clear_access(access, stp); |
3662 | } | 3621 | } |
3663 | 3622 | ||
3664 | static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access) | 3623 | static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access) |
@@ -3680,12 +3639,12 @@ static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_ac | |||
3680 | } | 3639 | } |
3681 | 3640 | ||
3682 | static void | 3641 | static void |
3683 | reset_union_bmap_deny(unsigned long deny, unsigned long *bmap) | 3642 | reset_union_bmap_deny(unsigned long deny, struct nfs4_ol_stateid *stp) |
3684 | { | 3643 | { |
3685 | int i; | 3644 | int i; |
3686 | for (i = 0; i < 4; i++) { | 3645 | for (i = 0; i < 4; i++) { |
3687 | if ((i & deny) != i) | 3646 | if ((i & deny) != i) |
3688 | __clear_bit(i, bmap); | 3647 | clear_deny(i, stp); |
3689 | } | 3648 | } |
3690 | } | 3649 | } |
3691 | 3650 | ||
@@ -3712,19 +3671,19 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, | |||
3712 | if (status) | 3671 | if (status) |
3713 | goto out; | 3672 | goto out; |
3714 | status = nfserr_inval; | 3673 | status = nfserr_inval; |
3715 | if (!test_bit(od->od_share_access, &stp->st_access_bmap)) { | 3674 | if (!test_access(od->od_share_access, stp)) { |
3716 | dprintk("NFSD:access not a subset current bitmap: 0x%lx, input access=%08x\n", | 3675 | dprintk("NFSD: access not a subset current bitmap: 0x%lx, input access=%08x\n", |
3717 | stp->st_access_bmap, od->od_share_access); | 3676 | stp->st_access_bmap, od->od_share_access); |
3718 | goto out; | 3677 | goto out; |
3719 | } | 3678 | } |
3720 | if (!test_bit(od->od_share_deny, &stp->st_deny_bmap)) { | 3679 | if (!test_deny(od->od_share_deny, stp)) { |
3721 | dprintk("NFSD:deny not a subset current bitmap: 0x%lx, input deny=%08x\n", | 3680 | dprintk("NFSD:deny not a subset current bitmap: 0x%lx, input deny=%08x\n", |
3722 | stp->st_deny_bmap, od->od_share_deny); | 3681 | stp->st_deny_bmap, od->od_share_deny); |
3723 | goto out; | 3682 | goto out; |
3724 | } | 3683 | } |
3725 | nfs4_stateid_downgrade(stp, od->od_share_access); | 3684 | nfs4_stateid_downgrade(stp, od->od_share_access); |
3726 | 3685 | ||
3727 | reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap); | 3686 | reset_union_bmap_deny(od->od_share_deny, stp); |
3728 | 3687 | ||
3729 | update_stateid(&stp->st_stid.sc_stateid); | 3688 | update_stateid(&stp->st_stid.sc_stateid); |
3730 | memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); | 3689 | memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); |
@@ -4014,13 +3973,13 @@ static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access) | |||
4014 | struct nfs4_file *fp = lock_stp->st_file; | 3973 | struct nfs4_file *fp = lock_stp->st_file; |
4015 | int oflag = nfs4_access_to_omode(access); | 3974 | int oflag = nfs4_access_to_omode(access); |
4016 | 3975 | ||
4017 | if (test_bit(access, &lock_stp->st_access_bmap)) | 3976 | if (test_access(access, lock_stp)) |
4018 | return; | 3977 | return; |
4019 | nfs4_file_get_access(fp, oflag); | 3978 | nfs4_file_get_access(fp, oflag); |
4020 | __set_bit(access, &lock_stp->st_access_bmap); | 3979 | set_access(access, lock_stp); |
4021 | } | 3980 | } |
4022 | 3981 | ||
4023 | __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, struct nfs4_ol_stateid *ost, struct nfsd4_lock *lock, struct nfs4_ol_stateid **lst, bool *new) | 3982 | static __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, struct nfs4_ol_stateid *ost, struct nfsd4_lock *lock, struct nfs4_ol_stateid **lst, bool *new) |
4024 | { | 3983 | { |
4025 | struct nfs4_file *fi = ost->st_file; | 3984 | struct nfs4_file *fi = ost->st_file; |
4026 | struct nfs4_openowner *oo = openowner(ost->st_stateowner); | 3985 | struct nfs4_openowner *oo = openowner(ost->st_stateowner); |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 74c00bc92b9a..4949667c84ea 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -1674,12 +1674,12 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) | |||
1674 | 1674 | ||
1675 | static void write32(__be32 **p, u32 n) | 1675 | static void write32(__be32 **p, u32 n) |
1676 | { | 1676 | { |
1677 | *(*p)++ = n; | 1677 | *(*p)++ = htonl(n); |
1678 | } | 1678 | } |
1679 | 1679 | ||
1680 | static void write64(__be32 **p, u64 n) | 1680 | static void write64(__be32 **p, u64 n) |
1681 | { | 1681 | { |
1682 | write32(p, (u32)(n >> 32)); | 1682 | write32(p, (n >> 32)); |
1683 | write32(p, (u32)n); | 1683 | write32(p, (u32)n); |
1684 | } | 1684 | } |
1685 | 1685 | ||
@@ -1744,15 +1744,16 @@ static void encode_seqid_op_tail(struct nfsd4_compoundres *resp, __be32 *save, _ | |||
1744 | } | 1744 | } |
1745 | 1745 | ||
1746 | /* Encode as an array of strings the string given with components | 1746 | /* Encode as an array of strings the string given with components |
1747 | * separated @sep. | 1747 | * separated @sep, escaped with esc_enter and esc_exit. |
1748 | */ | 1748 | */ |
1749 | static __be32 nfsd4_encode_components(char sep, char *components, | 1749 | static __be32 nfsd4_encode_components_esc(char sep, char *components, |
1750 | __be32 **pp, int *buflen) | 1750 | __be32 **pp, int *buflen, |
1751 | char esc_enter, char esc_exit) | ||
1751 | { | 1752 | { |
1752 | __be32 *p = *pp; | 1753 | __be32 *p = *pp; |
1753 | __be32 *countp = p; | 1754 | __be32 *countp = p; |
1754 | int strlen, count=0; | 1755 | int strlen, count=0; |
1755 | char *str, *end; | 1756 | char *str, *end, *next; |
1756 | 1757 | ||
1757 | dprintk("nfsd4_encode_components(%s)\n", components); | 1758 | dprintk("nfsd4_encode_components(%s)\n", components); |
1758 | if ((*buflen -= 4) < 0) | 1759 | if ((*buflen -= 4) < 0) |
@@ -1760,8 +1761,23 @@ static __be32 nfsd4_encode_components(char sep, char *components, | |||
1760 | WRITE32(0); /* We will fill this in with @count later */ | 1761 | WRITE32(0); /* We will fill this in with @count later */ |
1761 | end = str = components; | 1762 | end = str = components; |
1762 | while (*end) { | 1763 | while (*end) { |
1763 | for (; *end && (*end != sep); end++) | 1764 | bool found_esc = false; |
1764 | ; /* Point to end of component */ | 1765 | |
1766 | /* try to parse as esc_start, ..., esc_end, sep */ | ||
1767 | if (*str == esc_enter) { | ||
1768 | for (; *end && (*end != esc_exit); end++) | ||
1769 | /* find esc_exit or end of string */; | ||
1770 | next = end + 1; | ||
1771 | if (*end && (!*next || *next == sep)) { | ||
1772 | str++; | ||
1773 | found_esc = true; | ||
1774 | } | ||
1775 | } | ||
1776 | |||
1777 | if (!found_esc) | ||
1778 | for (; *end && (*end != sep); end++) | ||
1779 | /* find sep or end of string */; | ||
1780 | |||
1765 | strlen = end - str; | 1781 | strlen = end - str; |
1766 | if (strlen) { | 1782 | if (strlen) { |
1767 | if ((*buflen -= ((XDR_QUADLEN(strlen) << 2) + 4)) < 0) | 1783 | if ((*buflen -= ((XDR_QUADLEN(strlen) << 2) + 4)) < 0) |
@@ -1780,6 +1796,15 @@ static __be32 nfsd4_encode_components(char sep, char *components, | |||
1780 | return 0; | 1796 | return 0; |
1781 | } | 1797 | } |
1782 | 1798 | ||
1799 | /* Encode as an array of strings the string given with components | ||
1800 | * separated @sep. | ||
1801 | */ | ||
1802 | static __be32 nfsd4_encode_components(char sep, char *components, | ||
1803 | __be32 **pp, int *buflen) | ||
1804 | { | ||
1805 | return nfsd4_encode_components_esc(sep, components, pp, buflen, 0, 0); | ||
1806 | } | ||
1807 | |||
1783 | /* | 1808 | /* |
1784 | * encode a location element of a fs_locations structure | 1809 | * encode a location element of a fs_locations structure |
1785 | */ | 1810 | */ |
@@ -1789,7 +1814,8 @@ static __be32 nfsd4_encode_fs_location4(struct nfsd4_fs_location *location, | |||
1789 | __be32 status; | 1814 | __be32 status; |
1790 | __be32 *p = *pp; | 1815 | __be32 *p = *pp; |
1791 | 1816 | ||
1792 | status = nfsd4_encode_components(':', location->hosts, &p, buflen); | 1817 | status = nfsd4_encode_components_esc(':', location->hosts, &p, buflen, |
1818 | '[', ']'); | ||
1793 | if (status) | 1819 | if (status) |
1794 | return status; | 1820 | return status; |
1795 | status = nfsd4_encode_components('/', location->path, &p, buflen); | 1821 | status = nfsd4_encode_components('/', location->path, &p, buflen); |
@@ -3251,7 +3277,7 @@ nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_w | |||
3251 | } | 3277 | } |
3252 | 3278 | ||
3253 | static __be32 | 3279 | static __be32 |
3254 | nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, int nfserr, | 3280 | nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, |
3255 | struct nfsd4_exchange_id *exid) | 3281 | struct nfsd4_exchange_id *exid) |
3256 | { | 3282 | { |
3257 | __be32 *p; | 3283 | __be32 *p; |
@@ -3306,7 +3332,7 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, int nfserr, | |||
3306 | } | 3332 | } |
3307 | 3333 | ||
3308 | static __be32 | 3334 | static __be32 |
3309 | nfsd4_encode_create_session(struct nfsd4_compoundres *resp, int nfserr, | 3335 | nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr, |
3310 | struct nfsd4_create_session *sess) | 3336 | struct nfsd4_create_session *sess) |
3311 | { | 3337 | { |
3312 | __be32 *p; | 3338 | __be32 *p; |
@@ -3355,14 +3381,14 @@ nfsd4_encode_create_session(struct nfsd4_compoundres *resp, int nfserr, | |||
3355 | } | 3381 | } |
3356 | 3382 | ||
3357 | static __be32 | 3383 | static __be32 |
3358 | nfsd4_encode_destroy_session(struct nfsd4_compoundres *resp, int nfserr, | 3384 | nfsd4_encode_destroy_session(struct nfsd4_compoundres *resp, __be32 nfserr, |
3359 | struct nfsd4_destroy_session *destroy_session) | 3385 | struct nfsd4_destroy_session *destroy_session) |
3360 | { | 3386 | { |
3361 | return nfserr; | 3387 | return nfserr; |
3362 | } | 3388 | } |
3363 | 3389 | ||
3364 | static __be32 | 3390 | static __be32 |
3365 | nfsd4_encode_free_stateid(struct nfsd4_compoundres *resp, int nfserr, | 3391 | nfsd4_encode_free_stateid(struct nfsd4_compoundres *resp, __be32 nfserr, |
3366 | struct nfsd4_free_stateid *free_stateid) | 3392 | struct nfsd4_free_stateid *free_stateid) |
3367 | { | 3393 | { |
3368 | __be32 *p; | 3394 | __be32 *p; |
@@ -3371,13 +3397,13 @@ nfsd4_encode_free_stateid(struct nfsd4_compoundres *resp, int nfserr, | |||
3371 | return nfserr; | 3397 | return nfserr; |
3372 | 3398 | ||
3373 | RESERVE_SPACE(4); | 3399 | RESERVE_SPACE(4); |
3374 | WRITE32(nfserr); | 3400 | *p++ = nfserr; |
3375 | ADJUST_ARGS(); | 3401 | ADJUST_ARGS(); |
3376 | return nfserr; | 3402 | return nfserr; |
3377 | } | 3403 | } |
3378 | 3404 | ||
3379 | static __be32 | 3405 | static __be32 |
3380 | nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, | 3406 | nfsd4_encode_sequence(struct nfsd4_compoundres *resp, __be32 nfserr, |
3381 | struct nfsd4_sequence *seq) | 3407 | struct nfsd4_sequence *seq) |
3382 | { | 3408 | { |
3383 | __be32 *p; | 3409 | __be32 *p; |
@@ -3399,8 +3425,8 @@ nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, | |||
3399 | return 0; | 3425 | return 0; |
3400 | } | 3426 | } |
3401 | 3427 | ||
3402 | __be32 | 3428 | static __be32 |
3403 | nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, int nfserr, | 3429 | nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr, |
3404 | struct nfsd4_test_stateid *test_stateid) | 3430 | struct nfsd4_test_stateid *test_stateid) |
3405 | { | 3431 | { |
3406 | struct nfsd4_test_stateid_id *stateid, *next; | 3432 | struct nfsd4_test_stateid_id *stateid, *next; |
@@ -3503,7 +3529,7 @@ static nfsd4_enc nfsd4_enc_ops[] = { | |||
3503 | * Our se_fmaxresp_cached will always be a multiple of PAGE_SIZE, and so | 3529 | * Our se_fmaxresp_cached will always be a multiple of PAGE_SIZE, and so |
3504 | * will be at least a page and will therefore hold the xdr_buf head. | 3530 | * will be at least a page and will therefore hold the xdr_buf head. |
3505 | */ | 3531 | */ |
3506 | int nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 pad) | 3532 | __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 pad) |
3507 | { | 3533 | { |
3508 | struct xdr_buf *xb = &resp->rqstp->rq_res; | 3534 | struct xdr_buf *xb = &resp->rqstp->rq_res; |
3509 | struct nfsd4_session *session = NULL; | 3535 | struct nfsd4_session *session = NULL; |
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 72699885ac48..c55298ed5772 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
@@ -661,6 +661,7 @@ static ssize_t __write_ports_addfd(char *buf) | |||
661 | { | 661 | { |
662 | char *mesg = buf; | 662 | char *mesg = buf; |
663 | int fd, err; | 663 | int fd, err; |
664 | struct net *net = &init_net; | ||
664 | 665 | ||
665 | err = get_int(&mesg, &fd); | 666 | err = get_int(&mesg, &fd); |
666 | if (err != 0 || fd < 0) | 667 | if (err != 0 || fd < 0) |
@@ -672,6 +673,8 @@ static ssize_t __write_ports_addfd(char *buf) | |||
672 | 673 | ||
673 | err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT); | 674 | err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT); |
674 | if (err < 0) { | 675 | if (err < 0) { |
676 | if (nfsd_serv->sv_nrthreads == 1) | ||
677 | svc_shutdown_net(nfsd_serv, net); | ||
675 | svc_destroy(nfsd_serv); | 678 | svc_destroy(nfsd_serv); |
676 | return err; | 679 | return err; |
677 | } | 680 | } |
@@ -709,6 +712,7 @@ static ssize_t __write_ports_addxprt(char *buf) | |||
709 | char transport[16]; | 712 | char transport[16]; |
710 | struct svc_xprt *xprt; | 713 | struct svc_xprt *xprt; |
711 | int port, err; | 714 | int port, err; |
715 | struct net *net = &init_net; | ||
712 | 716 | ||
713 | if (sscanf(buf, "%15s %4u", transport, &port) != 2) | 717 | if (sscanf(buf, "%15s %4u", transport, &port) != 2) |
714 | return -EINVAL; | 718 | return -EINVAL; |
@@ -720,12 +724,12 @@ static ssize_t __write_ports_addxprt(char *buf) | |||
720 | if (err != 0) | 724 | if (err != 0) |
721 | return err; | 725 | return err; |
722 | 726 | ||
723 | err = svc_create_xprt(nfsd_serv, transport, &init_net, | 727 | err = svc_create_xprt(nfsd_serv, transport, net, |
724 | PF_INET, port, SVC_SOCK_ANONYMOUS); | 728 | PF_INET, port, SVC_SOCK_ANONYMOUS); |
725 | if (err < 0) | 729 | if (err < 0) |
726 | goto out_err; | 730 | goto out_err; |
727 | 731 | ||
728 | err = svc_create_xprt(nfsd_serv, transport, &init_net, | 732 | err = svc_create_xprt(nfsd_serv, transport, net, |
729 | PF_INET6, port, SVC_SOCK_ANONYMOUS); | 733 | PF_INET6, port, SVC_SOCK_ANONYMOUS); |
730 | if (err < 0 && err != -EAFNOSUPPORT) | 734 | if (err < 0 && err != -EAFNOSUPPORT) |
731 | goto out_close; | 735 | goto out_close; |
@@ -734,12 +738,14 @@ static ssize_t __write_ports_addxprt(char *buf) | |||
734 | nfsd_serv->sv_nrthreads--; | 738 | nfsd_serv->sv_nrthreads--; |
735 | return 0; | 739 | return 0; |
736 | out_close: | 740 | out_close: |
737 | xprt = svc_find_xprt(nfsd_serv, transport, &init_net, PF_INET, port); | 741 | xprt = svc_find_xprt(nfsd_serv, transport, net, PF_INET, port); |
738 | if (xprt != NULL) { | 742 | if (xprt != NULL) { |
739 | svc_close_xprt(xprt); | 743 | svc_close_xprt(xprt); |
740 | svc_xprt_put(xprt); | 744 | svc_xprt_put(xprt); |
741 | } | 745 | } |
742 | out_err: | 746 | out_err: |
747 | if (nfsd_serv->sv_nrthreads == 1) | ||
748 | svc_shutdown_net(nfsd_serv, net); | ||
743 | svc_destroy(nfsd_serv); | 749 | svc_destroy(nfsd_serv); |
744 | return err; | 750 | return err; |
745 | } | 751 | } |
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index cb4d51d8cbdb..ee709fc8f58b 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/fs_struct.h> | 12 | #include <linux/fs_struct.h> |
13 | #include <linux/swap.h> | 13 | #include <linux/swap.h> |
14 | #include <linux/nsproxy.h> | ||
14 | 15 | ||
15 | #include <linux/sunrpc/stats.h> | 16 | #include <linux/sunrpc/stats.h> |
16 | #include <linux/sunrpc/svcsock.h> | 17 | #include <linux/sunrpc/svcsock.h> |
@@ -330,6 +331,8 @@ static int nfsd_get_default_max_blksize(void) | |||
330 | 331 | ||
331 | int nfsd_create_serv(void) | 332 | int nfsd_create_serv(void) |
332 | { | 333 | { |
334 | int error; | ||
335 | |||
333 | WARN_ON(!mutex_is_locked(&nfsd_mutex)); | 336 | WARN_ON(!mutex_is_locked(&nfsd_mutex)); |
334 | if (nfsd_serv) { | 337 | if (nfsd_serv) { |
335 | svc_get(nfsd_serv); | 338 | svc_get(nfsd_serv); |
@@ -343,6 +346,12 @@ int nfsd_create_serv(void) | |||
343 | if (nfsd_serv == NULL) | 346 | if (nfsd_serv == NULL) |
344 | return -ENOMEM; | 347 | return -ENOMEM; |
345 | 348 | ||
349 | error = svc_bind(nfsd_serv, current->nsproxy->net_ns); | ||
350 | if (error < 0) { | ||
351 | svc_destroy(nfsd_serv); | ||
352 | return error; | ||
353 | } | ||
354 | |||
346 | set_max_drc(); | 355 | set_max_drc(); |
347 | do_gettimeofday(&nfssvc_boot); /* record boot time */ | 356 | do_gettimeofday(&nfssvc_boot); /* record boot time */ |
348 | return 0; | 357 | return 0; |
@@ -373,6 +382,7 @@ int nfsd_set_nrthreads(int n, int *nthreads) | |||
373 | int i = 0; | 382 | int i = 0; |
374 | int tot = 0; | 383 | int tot = 0; |
375 | int err = 0; | 384 | int err = 0; |
385 | struct net *net = &init_net; | ||
376 | 386 | ||
377 | WARN_ON(!mutex_is_locked(&nfsd_mutex)); | 387 | WARN_ON(!mutex_is_locked(&nfsd_mutex)); |
378 | 388 | ||
@@ -417,6 +427,9 @@ int nfsd_set_nrthreads(int n, int *nthreads) | |||
417 | if (err) | 427 | if (err) |
418 | break; | 428 | break; |
419 | } | 429 | } |
430 | |||
431 | if (nfsd_serv->sv_nrthreads == 1) | ||
432 | svc_shutdown_net(nfsd_serv, net); | ||
420 | svc_destroy(nfsd_serv); | 433 | svc_destroy(nfsd_serv); |
421 | 434 | ||
422 | return err; | 435 | return err; |
@@ -432,6 +445,7 @@ nfsd_svc(unsigned short port, int nrservs) | |||
432 | { | 445 | { |
433 | int error; | 446 | int error; |
434 | bool nfsd_up_before; | 447 | bool nfsd_up_before; |
448 | struct net *net = &init_net; | ||
435 | 449 | ||
436 | mutex_lock(&nfsd_mutex); | 450 | mutex_lock(&nfsd_mutex); |
437 | dprintk("nfsd: creating service\n"); | 451 | dprintk("nfsd: creating service\n"); |
@@ -464,6 +478,8 @@ out_shutdown: | |||
464 | if (error < 0 && !nfsd_up_before) | 478 | if (error < 0 && !nfsd_up_before) |
465 | nfsd_shutdown(); | 479 | nfsd_shutdown(); |
466 | out_destroy: | 480 | out_destroy: |
481 | if (nfsd_serv->sv_nrthreads == 1) | ||
482 | svc_shutdown_net(nfsd_serv, net); | ||
467 | svc_destroy(nfsd_serv); /* Release server */ | 483 | svc_destroy(nfsd_serv); /* Release server */ |
468 | out: | 484 | out: |
469 | mutex_unlock(&nfsd_mutex); | 485 | mutex_unlock(&nfsd_mutex); |
@@ -547,6 +563,9 @@ nfsd(void *vrqstp) | |||
547 | nfsdstats.th_cnt --; | 563 | nfsdstats.th_cnt --; |
548 | 564 | ||
549 | out: | 565 | out: |
566 | if (rqstp->rq_server->sv_nrthreads == 1) | ||
567 | svc_shutdown_net(rqstp->rq_server, &init_net); | ||
568 | |||
550 | /* Release the thread */ | 569 | /* Release the thread */ |
551 | svc_exit_thread(rqstp); | 570 | svc_exit_thread(rqstp); |
552 | 571 | ||
@@ -659,8 +678,12 @@ int nfsd_pool_stats_open(struct inode *inode, struct file *file) | |||
659 | int nfsd_pool_stats_release(struct inode *inode, struct file *file) | 678 | int nfsd_pool_stats_release(struct inode *inode, struct file *file) |
660 | { | 679 | { |
661 | int ret = seq_release(inode, file); | 680 | int ret = seq_release(inode, file); |
681 | struct net *net = &init_net; | ||
682 | |||
662 | mutex_lock(&nfsd_mutex); | 683 | mutex_lock(&nfsd_mutex); |
663 | /* this function really, really should have been called svc_put() */ | 684 | /* this function really, really should have been called svc_put() */ |
685 | if (nfsd_serv->sv_nrthreads == 1) | ||
686 | svc_shutdown_net(nfsd_serv, net); | ||
664 | svc_destroy(nfsd_serv); | 687 | svc_destroy(nfsd_serv); |
665 | mutex_unlock(&nfsd_mutex); | 688 | mutex_unlock(&nfsd_mutex); |
666 | return ret; | 689 | return ret; |
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 89ab137d379a..849091e16ea6 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -232,7 +232,6 @@ struct nfs4_client { | |||
232 | time_t cl_time; /* time of last lease renewal */ | 232 | time_t cl_time; /* time of last lease renewal */ |
233 | struct sockaddr_storage cl_addr; /* client ipaddress */ | 233 | struct sockaddr_storage cl_addr; /* client ipaddress */ |
234 | u32 cl_flavor; /* setclientid pseudoflavor */ | 234 | u32 cl_flavor; /* setclientid pseudoflavor */ |
235 | char *cl_principal; /* setclientid principal name */ | ||
236 | struct svc_cred cl_cred; /* setclientid principal */ | 235 | struct svc_cred cl_cred; /* setclientid principal */ |
237 | clientid_t cl_clientid; /* generated by server */ | 236 | clientid_t cl_clientid; /* generated by server */ |
238 | nfs4_verifier cl_confirm; /* generated by server */ | 237 | nfs4_verifier cl_confirm; /* generated by server */ |
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 1b3501598ab5..acd127d4ee82 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h | |||
@@ -60,7 +60,7 @@ struct nfsd4_compound_state { | |||
60 | __be32 *datap; | 60 | __be32 *datap; |
61 | size_t iovlen; | 61 | size_t iovlen; |
62 | u32 minorversion; | 62 | u32 minorversion; |
63 | u32 status; | 63 | __be32 status; |
64 | stateid_t current_stateid; | 64 | stateid_t current_stateid; |
65 | stateid_t save_stateid; | 65 | stateid_t save_stateid; |
66 | /* to indicate current and saved state id presents */ | 66 | /* to indicate current and saved state id presents */ |
@@ -364,7 +364,7 @@ struct nfsd4_test_stateid_id { | |||
364 | }; | 364 | }; |
365 | 365 | ||
366 | struct nfsd4_test_stateid { | 366 | struct nfsd4_test_stateid { |
367 | __be32 ts_num_ids; | 367 | u32 ts_num_ids; |
368 | struct list_head ts_stateid_list; | 368 | struct list_head ts_stateid_list; |
369 | }; | 369 | }; |
370 | 370 | ||
@@ -549,7 +549,7 @@ int nfs4svc_decode_compoundargs(struct svc_rqst *, __be32 *, | |||
549 | struct nfsd4_compoundargs *); | 549 | struct nfsd4_compoundargs *); |
550 | int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *, | 550 | int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *, |
551 | struct nfsd4_compoundres *); | 551 | struct nfsd4_compoundres *); |
552 | int nfsd4_check_resp_size(struct nfsd4_compoundres *, u32); | 552 | __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *, u32); |
553 | void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *); | 553 | void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *); |
554 | void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op); | 554 | void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op); |
555 | __be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | 555 | __be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, |