aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-07-21 00:21:46 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-21 00:21:46 -0400
commit14b395e35d1afdd8019d11b92e28041fad591b71 (patch)
treecff7ba9bed7a38300b19a5bacc632979d64fd9c8 /fs/nfsd
parent734b397cd14f3340394a8dd3266bec97d01f034b (diff)
parent5108b27651727b5aba0826e8fd7be71b42428701 (diff)
Merge branch 'for-2.6.27' of git://linux-nfs.org/~bfields/linux
* 'for-2.6.27' of git://linux-nfs.org/~bfields/linux: (51 commits) nfsd: nfs4xdr.c do-while is not a compound statement nfsd: Use C99 initializers in fs/nfsd/nfs4xdr.c lockd: Pass "struct sockaddr *" to new failover-by-IP function lockd: get host reference in nlmsvc_create_block() instead of callers lockd: minor svclock.c style fixes lockd: eliminate duplicate nlmsvc_lookup_host call from nlmsvc_lock lockd: eliminate duplicate nlmsvc_lookup_host call from nlmsvc_testlock lockd: nlm_release_host() checks for NULL, caller needn't file lock: reorder struct file_lock to save space on 64 bit builds nfsd: take file and mnt write in nfs4_upgrade_open nfsd: document open share bit tracking nfsd: tabulate nfs4 xdr encoding functions nfsd: dprint operation names svcrdma: Change WR context get/put to use the kmem cache svcrdma: Create a kmem cache for the WR contexts svcrdma: Add flush_scheduled_work to module exit function svcrdma: Limit ORD based on client's advertised IRD svcrdma: Remove unused wait q from svcrdma_xprt structure svcrdma: Remove unneeded spin locks from __svc_rdma_free svcrdma: Add dma map count and WARN_ON ...
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/lockd.c2
-rw-r--r--fs/nfsd/nfs2acl.c7
-rw-r--r--fs/nfsd/nfs3acl.c5
-rw-r--r--fs/nfsd/nfs3proc.c8
-rw-r--r--fs/nfsd/nfs4proc.c76
-rw-r--r--fs/nfsd/nfs4state.c49
-rw-r--r--fs/nfsd/nfs4xdr.c392
-rw-r--r--fs/nfsd/nfsctl.c118
-rw-r--r--fs/nfsd/nfsfh.c31
-rw-r--r--fs/nfsd/nfsproc.c9
-rw-r--r--fs/nfsd/nfssvc.c148
-rw-r--r--fs/nfsd/vfs.c140
12 files changed, 544 insertions, 441 deletions
diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c
index 9e4a568a5013..6b6225ac4926 100644
--- a/fs/nfsd/lockd.c
+++ b/fs/nfsd/lockd.c
@@ -35,7 +35,7 @@ nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp)
35 fh.fh_export = NULL; 35 fh.fh_export = NULL;
36 36
37 exp_readlock(); 37 exp_readlock();
38 nfserr = nfsd_open(rqstp, &fh, S_IFREG, MAY_LOCK, filp); 38 nfserr = nfsd_open(rqstp, &fh, S_IFREG, NFSD_MAY_LOCK, filp);
39 fh_put(&fh); 39 fh_put(&fh);
40 rqstp->rq_client = NULL; 40 rqstp->rq_client = NULL;
41 exp_readunlock(); 41 exp_readunlock();
diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c
index 1c3b7654e966..4e3219e84116 100644
--- a/fs/nfsd/nfs2acl.c
+++ b/fs/nfsd/nfs2acl.c
@@ -40,7 +40,8 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp,
40 dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); 40 dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp->fh));
41 41
42 fh = fh_copy(&resp->fh, &argp->fh); 42 fh = fh_copy(&resp->fh, &argp->fh);
43 if ((nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP))) 43 nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
44 if (nfserr)
44 RETURN_STATUS(nfserr); 45 RETURN_STATUS(nfserr);
45 46
46 if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) 47 if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
@@ -107,7 +108,7 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst * rqstp,
107 dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); 108 dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh));
108 109
109 fh = fh_copy(&resp->fh, &argp->fh); 110 fh = fh_copy(&resp->fh, &argp->fh);
110 nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_SATTR); 111 nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
111 112
112 if (!nfserr) { 113 if (!nfserr) {
113 nfserr = nfserrno( nfsd_set_posix_acl( 114 nfserr = nfserrno( nfsd_set_posix_acl(
@@ -134,7 +135,7 @@ static __be32 nfsacld_proc_getattr(struct svc_rqst * rqstp,
134 dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh)); 135 dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh));
135 136
136 fh_copy(&resp->fh, &argp->fh); 137 fh_copy(&resp->fh, &argp->fh);
137 return fh_verify(rqstp, &resp->fh, 0, MAY_NOP); 138 return fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
138} 139}
139 140
140/* 141/*
diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c
index b647f2f872dc..9981dbb377a3 100644
--- a/fs/nfsd/nfs3acl.c
+++ b/fs/nfsd/nfs3acl.c
@@ -36,7 +36,8 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp,
36 __be32 nfserr = 0; 36 __be32 nfserr = 0;
37 37
38 fh = fh_copy(&resp->fh, &argp->fh); 38 fh = fh_copy(&resp->fh, &argp->fh);
39 if ((nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP))) 39 nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
40 if (nfserr)
40 RETURN_STATUS(nfserr); 41 RETURN_STATUS(nfserr);
41 42
42 if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) 43 if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
@@ -101,7 +102,7 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst * rqstp,
101 __be32 nfserr = 0; 102 __be32 nfserr = 0;
102 103
103 fh = fh_copy(&resp->fh, &argp->fh); 104 fh = fh_copy(&resp->fh, &argp->fh);
104 nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_SATTR); 105 nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
105 106
106 if (!nfserr) { 107 if (!nfserr) {
107 nfserr = nfserrno( nfsd_set_posix_acl( 108 nfserr = nfserrno( nfsd_set_posix_acl(
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index c721a1e6e9dd..4d617ea28cfc 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -63,7 +63,7 @@ nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
63 SVCFH_fmt(&argp->fh)); 63 SVCFH_fmt(&argp->fh));
64 64
65 fh_copy(&resp->fh, &argp->fh); 65 fh_copy(&resp->fh, &argp->fh);
66 nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP); 66 nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
67 if (nfserr) 67 if (nfserr)
68 RETURN_STATUS(nfserr); 68 RETURN_STATUS(nfserr);
69 69
@@ -242,7 +242,7 @@ nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
242 attr = &argp->attrs; 242 attr = &argp->attrs;
243 243
244 /* Get the directory inode */ 244 /* Get the directory inode */
245 nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, MAY_CREATE); 245 nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_CREATE);
246 if (nfserr) 246 if (nfserr)
247 RETURN_STATUS(nfserr); 247 RETURN_STATUS(nfserr);
248 248
@@ -558,7 +558,7 @@ nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
558 resp->f_maxfilesize = ~(u32) 0; 558 resp->f_maxfilesize = ~(u32) 0;
559 resp->f_properties = NFS3_FSF_DEFAULT; 559 resp->f_properties = NFS3_FSF_DEFAULT;
560 560
561 nfserr = fh_verify(rqstp, &argp->fh, 0, MAY_NOP); 561 nfserr = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP);
562 562
563 /* Check special features of the file system. May request 563 /* Check special features of the file system. May request
564 * different read/write sizes for file systems known to have 564 * different read/write sizes for file systems known to have
@@ -597,7 +597,7 @@ nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
597 resp->p_case_insensitive = 0; 597 resp->p_case_insensitive = 0;
598 resp->p_case_preserving = 1; 598 resp->p_case_preserving = 1;
599 599
600 nfserr = fh_verify(rqstp, &argp->fh, 0, MAY_NOP); 600 nfserr = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP);
601 601
602 if (nfserr == 0) { 602 if (nfserr == 0) {
603 struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb; 603 struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb;
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index c309c881bd4e..eef1629806f5 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -71,11 +71,11 @@ do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs
71 return nfserr_inval; 71 return nfserr_inval;
72 72
73 if (open->op_share_access & NFS4_SHARE_ACCESS_READ) 73 if (open->op_share_access & NFS4_SHARE_ACCESS_READ)
74 accmode |= MAY_READ; 74 accmode |= NFSD_MAY_READ;
75 if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) 75 if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
76 accmode |= (MAY_WRITE | MAY_TRUNC); 76 accmode |= (NFSD_MAY_WRITE | NFSD_MAY_TRUNC);
77 if (open->op_share_deny & NFS4_SHARE_DENY_WRITE) 77 if (open->op_share_deny & NFS4_SHARE_DENY_WRITE)
78 accmode |= MAY_WRITE; 78 accmode |= NFSD_MAY_WRITE;
79 79
80 status = fh_verify(rqstp, current_fh, S_IFREG, accmode); 80 status = fh_verify(rqstp, current_fh, S_IFREG, accmode);
81 81
@@ -126,7 +126,8 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o
126 &resfh.fh_handle.fh_base, resfh.fh_handle.fh_size); 126 &resfh.fh_handle.fh_base, resfh.fh_handle.fh_size);
127 127
128 if (!created) 128 if (!created)
129 status = do_open_permission(rqstp, current_fh, open, MAY_NOP); 129 status = do_open_permission(rqstp, current_fh, open,
130 NFSD_MAY_NOP);
130 131
131out: 132out:
132 fh_put(&resfh); 133 fh_put(&resfh);
@@ -157,7 +158,8 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_
157 open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) && 158 open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) &&
158 (open->op_iattr.ia_size == 0); 159 (open->op_iattr.ia_size == 0);
159 160
160 status = do_open_permission(rqstp, current_fh, open, MAY_OWNER_OVERRIDE); 161 status = do_open_permission(rqstp, current_fh, open,
162 NFSD_MAY_OWNER_OVERRIDE);
161 163
162 return status; 164 return status;
163} 165}
@@ -186,7 +188,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
186 cstate->current_fh.fh_handle.fh_size = rp->rp_openfh_len; 188 cstate->current_fh.fh_handle.fh_size = rp->rp_openfh_len;
187 memcpy(&cstate->current_fh.fh_handle.fh_base, rp->rp_openfh, 189 memcpy(&cstate->current_fh.fh_handle.fh_base, rp->rp_openfh,
188 rp->rp_openfh_len); 190 rp->rp_openfh_len);
189 status = fh_verify(rqstp, &cstate->current_fh, 0, MAY_NOP); 191 status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
190 if (status) 192 if (status)
191 dprintk("nfsd4_open: replay failed" 193 dprintk("nfsd4_open: replay failed"
192 " restoring previous filehandle\n"); 194 " restoring previous filehandle\n");
@@ -285,7 +287,7 @@ nfsd4_putfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
285 cstate->current_fh.fh_handle.fh_size = putfh->pf_fhlen; 287 cstate->current_fh.fh_handle.fh_size = putfh->pf_fhlen;
286 memcpy(&cstate->current_fh.fh_handle.fh_base, putfh->pf_fhval, 288 memcpy(&cstate->current_fh.fh_handle.fh_base, putfh->pf_fhval,
287 putfh->pf_fhlen); 289 putfh->pf_fhlen);
288 return fh_verify(rqstp, &cstate->current_fh, 0, MAY_NOP); 290 return fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
289} 291}
290 292
291static __be32 293static __be32
@@ -363,7 +365,8 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
363 365
364 fh_init(&resfh, NFS4_FHSIZE); 366 fh_init(&resfh, NFS4_FHSIZE);
365 367
366 status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, MAY_CREATE); 368 status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR,
369 NFSD_MAY_CREATE);
367 if (status == nfserr_symlink) 370 if (status == nfserr_symlink)
368 status = nfserr_notdir; 371 status = nfserr_notdir;
369 if (status) 372 if (status)
@@ -445,7 +448,7 @@ nfsd4_getattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
445{ 448{
446 __be32 status; 449 __be32 status;
447 450
448 status = fh_verify(rqstp, &cstate->current_fh, 0, MAY_NOP); 451 status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
449 if (status) 452 if (status)
450 return status; 453 return status;
451 454
@@ -730,7 +733,7 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
730 int count; 733 int count;
731 __be32 status; 734 __be32 status;
732 735
733 status = fh_verify(rqstp, &cstate->current_fh, 0, MAY_NOP); 736 status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
734 if (status) 737 if (status)
735 return status; 738 return status;
736 739
@@ -843,10 +846,13 @@ struct nfsd4_operation {
843#define ALLOWED_WITHOUT_FH 1 846#define ALLOWED_WITHOUT_FH 1
844/* GETATTR and ops not listed as returning NFS4ERR_MOVED: */ 847/* GETATTR and ops not listed as returning NFS4ERR_MOVED: */
845#define ALLOWED_ON_ABSENT_FS 2 848#define ALLOWED_ON_ABSENT_FS 2
849 char *op_name;
846}; 850};
847 851
848static struct nfsd4_operation nfsd4_ops[]; 852static struct nfsd4_operation nfsd4_ops[];
849 853
854static inline char *nfsd4_op_name(unsigned opnum);
855
850/* 856/*
851 * COMPOUND call. 857 * COMPOUND call.
852 */ 858 */
@@ -888,7 +894,9 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
888 while (!status && resp->opcnt < args->opcnt) { 894 while (!status && resp->opcnt < args->opcnt) {
889 op = &args->ops[resp->opcnt++]; 895 op = &args->ops[resp->opcnt++];
890 896
891 dprintk("nfsv4 compound op #%d: %d\n", resp->opcnt, op->opnum); 897 dprintk("nfsv4 compound op #%d/%d: %d (%s)\n",
898 resp->opcnt, args->opcnt, op->opnum,
899 nfsd4_op_name(op->opnum));
892 900
893 /* 901 /*
894 * The XDR decode routines may have pre-set op->status; 902 * The XDR decode routines may have pre-set op->status;
@@ -952,126 +960,170 @@ encode_op:
952out: 960out:
953 nfsd4_release_compoundargs(args); 961 nfsd4_release_compoundargs(args);
954 cstate_free(cstate); 962 cstate_free(cstate);
963 dprintk("nfsv4 compound returned %d\n", ntohl(status));
955 return status; 964 return status;
956} 965}
957 966
958static struct nfsd4_operation nfsd4_ops[OP_RELEASE_LOCKOWNER+1] = { 967static struct nfsd4_operation nfsd4_ops[OP_RELEASE_LOCKOWNER+1] = {
959 [OP_ACCESS] = { 968 [OP_ACCESS] = {
960 .op_func = (nfsd4op_func)nfsd4_access, 969 .op_func = (nfsd4op_func)nfsd4_access,
970 .op_name = "OP_ACCESS",
961 }, 971 },
962 [OP_CLOSE] = { 972 [OP_CLOSE] = {
963 .op_func = (nfsd4op_func)nfsd4_close, 973 .op_func = (nfsd4op_func)nfsd4_close,
974 .op_name = "OP_CLOSE",
964 }, 975 },
965 [OP_COMMIT] = { 976 [OP_COMMIT] = {
966 .op_func = (nfsd4op_func)nfsd4_commit, 977 .op_func = (nfsd4op_func)nfsd4_commit,
978 .op_name = "OP_COMMIT",
967 }, 979 },
968 [OP_CREATE] = { 980 [OP_CREATE] = {
969 .op_func = (nfsd4op_func)nfsd4_create, 981 .op_func = (nfsd4op_func)nfsd4_create,
982 .op_name = "OP_CREATE",
970 }, 983 },
971 [OP_DELEGRETURN] = { 984 [OP_DELEGRETURN] = {
972 .op_func = (nfsd4op_func)nfsd4_delegreturn, 985 .op_func = (nfsd4op_func)nfsd4_delegreturn,
986 .op_name = "OP_DELEGRETURN",
973 }, 987 },
974 [OP_GETATTR] = { 988 [OP_GETATTR] = {
975 .op_func = (nfsd4op_func)nfsd4_getattr, 989 .op_func = (nfsd4op_func)nfsd4_getattr,
976 .op_flags = ALLOWED_ON_ABSENT_FS, 990 .op_flags = ALLOWED_ON_ABSENT_FS,
991 .op_name = "OP_GETATTR",
977 }, 992 },
978 [OP_GETFH] = { 993 [OP_GETFH] = {
979 .op_func = (nfsd4op_func)nfsd4_getfh, 994 .op_func = (nfsd4op_func)nfsd4_getfh,
995 .op_name = "OP_GETFH",
980 }, 996 },
981 [OP_LINK] = { 997 [OP_LINK] = {
982 .op_func = (nfsd4op_func)nfsd4_link, 998 .op_func = (nfsd4op_func)nfsd4_link,
999 .op_name = "OP_LINK",
983 }, 1000 },
984 [OP_LOCK] = { 1001 [OP_LOCK] = {
985 .op_func = (nfsd4op_func)nfsd4_lock, 1002 .op_func = (nfsd4op_func)nfsd4_lock,
1003 .op_name = "OP_LOCK",
986 }, 1004 },
987 [OP_LOCKT] = { 1005 [OP_LOCKT] = {
988 .op_func = (nfsd4op_func)nfsd4_lockt, 1006 .op_func = (nfsd4op_func)nfsd4_lockt,
1007 .op_name = "OP_LOCKT",
989 }, 1008 },
990 [OP_LOCKU] = { 1009 [OP_LOCKU] = {
991 .op_func = (nfsd4op_func)nfsd4_locku, 1010 .op_func = (nfsd4op_func)nfsd4_locku,
1011 .op_name = "OP_LOCKU",
992 }, 1012 },
993 [OP_LOOKUP] = { 1013 [OP_LOOKUP] = {
994 .op_func = (nfsd4op_func)nfsd4_lookup, 1014 .op_func = (nfsd4op_func)nfsd4_lookup,
1015 .op_name = "OP_LOOKUP",
995 }, 1016 },
996 [OP_LOOKUPP] = { 1017 [OP_LOOKUPP] = {
997 .op_func = (nfsd4op_func)nfsd4_lookupp, 1018 .op_func = (nfsd4op_func)nfsd4_lookupp,
1019 .op_name = "OP_LOOKUPP",
998 }, 1020 },
999 [OP_NVERIFY] = { 1021 [OP_NVERIFY] = {
1000 .op_func = (nfsd4op_func)nfsd4_nverify, 1022 .op_func = (nfsd4op_func)nfsd4_nverify,
1023 .op_name = "OP_NVERIFY",
1001 }, 1024 },
1002 [OP_OPEN] = { 1025 [OP_OPEN] = {
1003 .op_func = (nfsd4op_func)nfsd4_open, 1026 .op_func = (nfsd4op_func)nfsd4_open,
1027 .op_name = "OP_OPEN",
1004 }, 1028 },
1005 [OP_OPEN_CONFIRM] = { 1029 [OP_OPEN_CONFIRM] = {
1006 .op_func = (nfsd4op_func)nfsd4_open_confirm, 1030 .op_func = (nfsd4op_func)nfsd4_open_confirm,
1031 .op_name = "OP_OPEN_CONFIRM",
1007 }, 1032 },
1008 [OP_OPEN_DOWNGRADE] = { 1033 [OP_OPEN_DOWNGRADE] = {
1009 .op_func = (nfsd4op_func)nfsd4_open_downgrade, 1034 .op_func = (nfsd4op_func)nfsd4_open_downgrade,
1035 .op_name = "OP_OPEN_DOWNGRADE",
1010 }, 1036 },
1011 [OP_PUTFH] = { 1037 [OP_PUTFH] = {
1012 .op_func = (nfsd4op_func)nfsd4_putfh, 1038 .op_func = (nfsd4op_func)nfsd4_putfh,
1013 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, 1039 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
1040 .op_name = "OP_PUTFH",
1014 }, 1041 },
1015 [OP_PUTPUBFH] = { 1042 [OP_PUTPUBFH] = {
1016 /* unsupported; just for future reference: */ 1043 /* unsupported, just for future reference: */
1017 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, 1044 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
1045 .op_name = "OP_PUTPUBFH",
1018 }, 1046 },
1019 [OP_PUTROOTFH] = { 1047 [OP_PUTROOTFH] = {
1020 .op_func = (nfsd4op_func)nfsd4_putrootfh, 1048 .op_func = (nfsd4op_func)nfsd4_putrootfh,
1021 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, 1049 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
1050 .op_name = "OP_PUTROOTFH",
1022 }, 1051 },
1023 [OP_READ] = { 1052 [OP_READ] = {
1024 .op_func = (nfsd4op_func)nfsd4_read, 1053 .op_func = (nfsd4op_func)nfsd4_read,
1054 .op_name = "OP_READ",
1025 }, 1055 },
1026 [OP_READDIR] = { 1056 [OP_READDIR] = {
1027 .op_func = (nfsd4op_func)nfsd4_readdir, 1057 .op_func = (nfsd4op_func)nfsd4_readdir,
1058 .op_name = "OP_READDIR",
1028 }, 1059 },
1029 [OP_READLINK] = { 1060 [OP_READLINK] = {
1030 .op_func = (nfsd4op_func)nfsd4_readlink, 1061 .op_func = (nfsd4op_func)nfsd4_readlink,
1062 .op_name = "OP_READLINK",
1031 }, 1063 },
1032 [OP_REMOVE] = { 1064 [OP_REMOVE] = {
1033 .op_func = (nfsd4op_func)nfsd4_remove, 1065 .op_func = (nfsd4op_func)nfsd4_remove,
1066 .op_name = "OP_REMOVE",
1034 }, 1067 },
1035 [OP_RENAME] = { 1068 [OP_RENAME] = {
1069 .op_name = "OP_RENAME",
1036 .op_func = (nfsd4op_func)nfsd4_rename, 1070 .op_func = (nfsd4op_func)nfsd4_rename,
1037 }, 1071 },
1038 [OP_RENEW] = { 1072 [OP_RENEW] = {
1039 .op_func = (nfsd4op_func)nfsd4_renew, 1073 .op_func = (nfsd4op_func)nfsd4_renew,
1040 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, 1074 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
1075 .op_name = "OP_RENEW",
1041 }, 1076 },
1042 [OP_RESTOREFH] = { 1077 [OP_RESTOREFH] = {
1043 .op_func = (nfsd4op_func)nfsd4_restorefh, 1078 .op_func = (nfsd4op_func)nfsd4_restorefh,
1044 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, 1079 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
1080 .op_name = "OP_RESTOREFH",
1045 }, 1081 },
1046 [OP_SAVEFH] = { 1082 [OP_SAVEFH] = {
1047 .op_func = (nfsd4op_func)nfsd4_savefh, 1083 .op_func = (nfsd4op_func)nfsd4_savefh,
1084 .op_name = "OP_SAVEFH",
1048 }, 1085 },
1049 [OP_SECINFO] = { 1086 [OP_SECINFO] = {
1050 .op_func = (nfsd4op_func)nfsd4_secinfo, 1087 .op_func = (nfsd4op_func)nfsd4_secinfo,
1088 .op_name = "OP_SECINFO",
1051 }, 1089 },
1052 [OP_SETATTR] = { 1090 [OP_SETATTR] = {
1053 .op_func = (nfsd4op_func)nfsd4_setattr, 1091 .op_func = (nfsd4op_func)nfsd4_setattr,
1092 .op_name = "OP_SETATTR",
1054 }, 1093 },
1055 [OP_SETCLIENTID] = { 1094 [OP_SETCLIENTID] = {
1056 .op_func = (nfsd4op_func)nfsd4_setclientid, 1095 .op_func = (nfsd4op_func)nfsd4_setclientid,
1057 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, 1096 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
1097 .op_name = "OP_SETCLIENTID",
1058 }, 1098 },
1059 [OP_SETCLIENTID_CONFIRM] = { 1099 [OP_SETCLIENTID_CONFIRM] = {
1060 .op_func = (nfsd4op_func)nfsd4_setclientid_confirm, 1100 .op_func = (nfsd4op_func)nfsd4_setclientid_confirm,
1061 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, 1101 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
1102 .op_name = "OP_SETCLIENTID_CONFIRM",
1062 }, 1103 },
1063 [OP_VERIFY] = { 1104 [OP_VERIFY] = {
1064 .op_func = (nfsd4op_func)nfsd4_verify, 1105 .op_func = (nfsd4op_func)nfsd4_verify,
1106 .op_name = "OP_VERIFY",
1065 }, 1107 },
1066 [OP_WRITE] = { 1108 [OP_WRITE] = {
1067 .op_func = (nfsd4op_func)nfsd4_write, 1109 .op_func = (nfsd4op_func)nfsd4_write,
1110 .op_name = "OP_WRITE",
1068 }, 1111 },
1069 [OP_RELEASE_LOCKOWNER] = { 1112 [OP_RELEASE_LOCKOWNER] = {
1070 .op_func = (nfsd4op_func)nfsd4_release_lockowner, 1113 .op_func = (nfsd4op_func)nfsd4_release_lockowner,
1071 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, 1114 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
1115 .op_name = "OP_RELEASE_LOCKOWNER",
1072 }, 1116 },
1073}; 1117};
1074 1118
1119static inline char *
1120nfsd4_op_name(unsigned opnum)
1121{
1122 if (opnum < ARRAY_SIZE(nfsd4_ops))
1123 return nfsd4_ops[opnum].op_name;
1124 return "unknown_operation";
1125}
1126
1075#define nfs4svc_decode_voidargs NULL 1127#define nfs4svc_decode_voidargs NULL
1076#define nfs4svc_release_void NULL 1128#define nfs4svc_release_void NULL
1077#define nfsd4_voidres nfsd4_voidargs 1129#define nfsd4_voidres nfsd4_voidargs
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 8799b8708188..1578d7a2667e 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1173,6 +1173,24 @@ static inline int deny_valid(u32 x)
1173 return x <= NFS4_SHARE_DENY_BOTH; 1173 return x <= NFS4_SHARE_DENY_BOTH;
1174} 1174}
1175 1175
1176/*
1177 * We store the NONE, READ, WRITE, and BOTH bits separately in the
1178 * st_{access,deny}_bmap field of the stateid, in order to track not
1179 * only what share bits are currently in force, but also what
1180 * combinations of share bits previous opens have used. This allows us
1181 * to enforce the recommendation of rfc 3530 14.2.19 that the server
1182 * return an error if the client attempt to downgrade to a combination
1183 * of share bits not explicable by closing some of its previous opens.
1184 *
1185 * XXX: This enforcement is actually incomplete, since we don't keep
1186 * track of access/deny bit combinations; so, e.g., we allow:
1187 *
1188 * OPEN allow read, deny write
1189 * OPEN allow both, deny none
1190 * DOWNGRADE allow read, deny none
1191 *
1192 * which we should reject.
1193 */
1176static void 1194static void
1177set_access(unsigned int *access, unsigned long bmap) { 1195set_access(unsigned int *access, unsigned long bmap) {
1178 int i; 1196 int i;
@@ -1570,6 +1588,10 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_sta
1570 int err = get_write_access(inode); 1588 int err = get_write_access(inode);
1571 if (err) 1589 if (err)
1572 return nfserrno(err); 1590 return nfserrno(err);
1591 err = mnt_want_write(cur_fh->fh_export->ex_path.mnt);
1592 if (err)
1593 return nfserrno(err);
1594 file_take_write(filp);
1573 } 1595 }
1574 status = nfsd4_truncate(rqstp, cur_fh, open); 1596 status = nfsd4_truncate(rqstp, cur_fh, open);
1575 if (status) { 1597 if (status) {
@@ -1579,8 +1601,8 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_sta
1579 } 1601 }
1580 /* remember the open */ 1602 /* remember the open */
1581 filp->f_mode |= open->op_share_access; 1603 filp->f_mode |= open->op_share_access;
1582 set_bit(open->op_share_access, &stp->st_access_bmap); 1604 __set_bit(open->op_share_access, &stp->st_access_bmap);
1583 set_bit(open->op_share_deny, &stp->st_deny_bmap); 1605 __set_bit(open->op_share_deny, &stp->st_deny_bmap);
1584 1606
1585 return nfs_ok; 1607 return nfs_ok;
1586} 1608}
@@ -1722,9 +1744,9 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
1722 /* Stateid was not found, this is a new OPEN */ 1744 /* Stateid was not found, this is a new OPEN */
1723 int flags = 0; 1745 int flags = 0;
1724 if (open->op_share_access & NFS4_SHARE_ACCESS_READ) 1746 if (open->op_share_access & NFS4_SHARE_ACCESS_READ)
1725 flags |= MAY_READ; 1747 flags |= NFSD_MAY_READ;
1726 if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) 1748 if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
1727 flags |= MAY_WRITE; 1749 flags |= NFSD_MAY_WRITE;
1728 status = nfs4_new_open(rqstp, &stp, dp, current_fh, flags); 1750 status = nfs4_new_open(rqstp, &stp, dp, current_fh, flags);
1729 if (status) 1751 if (status)
1730 goto out; 1752 goto out;
@@ -2610,7 +2632,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2610 return nfserr_inval; 2632 return nfserr_inval;
2611 2633
2612 if ((status = fh_verify(rqstp, &cstate->current_fh, 2634 if ((status = fh_verify(rqstp, &cstate->current_fh,
2613 S_IFREG, MAY_LOCK))) { 2635 S_IFREG, NFSD_MAY_LOCK))) {
2614 dprintk("NFSD: nfsd4_lock: permission denied!\n"); 2636 dprintk("NFSD: nfsd4_lock: permission denied!\n");
2615 return status; 2637 return status;
2616 } 2638 }
@@ -3249,12 +3271,14 @@ nfs4_state_shutdown(void)
3249 nfs4_unlock_state(); 3271 nfs4_unlock_state();
3250} 3272}
3251 3273
3274/*
3275 * user_recovery_dirname is protected by the nfsd_mutex since it's only
3276 * accessed when nfsd is starting.
3277 */
3252static void 3278static void
3253nfs4_set_recdir(char *recdir) 3279nfs4_set_recdir(char *recdir)
3254{ 3280{
3255 nfs4_lock_state();
3256 strcpy(user_recovery_dirname, recdir); 3281 strcpy(user_recovery_dirname, recdir);
3257 nfs4_unlock_state();
3258} 3282}
3259 3283
3260/* 3284/*
@@ -3278,6 +3302,12 @@ nfs4_reset_recoverydir(char *recdir)
3278 return status; 3302 return status;
3279} 3303}
3280 3304
3305char *
3306nfs4_recoverydir(void)
3307{
3308 return user_recovery_dirname;
3309}
3310
3281/* 3311/*
3282 * Called when leasetime is changed. 3312 * Called when leasetime is changed.
3283 * 3313 *
@@ -3286,11 +3316,12 @@ nfs4_reset_recoverydir(char *recdir)
3286 * we start to register any changes in lease time. If the administrator 3316 * we start to register any changes in lease time. If the administrator
3287 * really wants to change the lease time *now*, they can go ahead and bring 3317 * really wants to change the lease time *now*, they can go ahead and bring
3288 * nfsd down and then back up again after changing the lease time. 3318 * nfsd down and then back up again after changing the lease time.
3319 *
3320 * user_lease_time is protected by nfsd_mutex since it's only really accessed
3321 * when nfsd is starting
3289 */ 3322 */
3290void 3323void
3291nfs4_reset_lease(time_t leasetime) 3324nfs4_reset_lease(time_t leasetime)
3292{ 3325{
3293 lock_kernel();
3294 user_lease_time = leasetime; 3326 user_lease_time = leasetime;
3295 unlock_kernel();
3296} 3327}
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index c513bbdf2d36..14ba4d9b2859 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -986,10 +986,74 @@ nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_rel
986} 986}
987 987
988static __be32 988static __be32
989nfsd4_decode_noop(struct nfsd4_compoundargs *argp, void *p)
990{
991 return nfs_ok;
992}
993
994static __be32
995nfsd4_decode_notsupp(struct nfsd4_compoundargs *argp, void *p)
996{
997 return nfserr_opnotsupp;
998}
999
1000typedef __be32(*nfsd4_dec)(struct nfsd4_compoundargs *argp, void *);
1001
1002static nfsd4_dec nfsd4_dec_ops[] = {
1003 [OP_ACCESS] = (nfsd4_dec)nfsd4_decode_access,
1004 [OP_CLOSE] = (nfsd4_dec)nfsd4_decode_close,
1005 [OP_COMMIT] = (nfsd4_dec)nfsd4_decode_commit,
1006 [OP_CREATE] = (nfsd4_dec)nfsd4_decode_create,
1007 [OP_DELEGPURGE] = (nfsd4_dec)nfsd4_decode_notsupp,
1008 [OP_DELEGRETURN] = (nfsd4_dec)nfsd4_decode_delegreturn,
1009 [OP_GETATTR] = (nfsd4_dec)nfsd4_decode_getattr,
1010 [OP_GETFH] = (nfsd4_dec)nfsd4_decode_noop,
1011 [OP_LINK] = (nfsd4_dec)nfsd4_decode_link,
1012 [OP_LOCK] = (nfsd4_dec)nfsd4_decode_lock,
1013 [OP_LOCKT] = (nfsd4_dec)nfsd4_decode_lockt,
1014 [OP_LOCKU] = (nfsd4_dec)nfsd4_decode_locku,
1015 [OP_LOOKUP] = (nfsd4_dec)nfsd4_decode_lookup,
1016 [OP_LOOKUPP] = (nfsd4_dec)nfsd4_decode_noop,
1017 [OP_NVERIFY] = (nfsd4_dec)nfsd4_decode_verify,
1018 [OP_OPEN] = (nfsd4_dec)nfsd4_decode_open,
1019 [OP_OPENATTR] = (nfsd4_dec)nfsd4_decode_notsupp,
1020 [OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_open_confirm,
1021 [OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade,
1022 [OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh,
1023 [OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_notsupp,
1024 [OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop,
1025 [OP_READ] = (nfsd4_dec)nfsd4_decode_read,
1026 [OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir,
1027 [OP_READLINK] = (nfsd4_dec)nfsd4_decode_noop,
1028 [OP_REMOVE] = (nfsd4_dec)nfsd4_decode_remove,
1029 [OP_RENAME] = (nfsd4_dec)nfsd4_decode_rename,
1030 [OP_RENEW] = (nfsd4_dec)nfsd4_decode_renew,
1031 [OP_RESTOREFH] = (nfsd4_dec)nfsd4_decode_noop,
1032 [OP_SAVEFH] = (nfsd4_dec)nfsd4_decode_noop,
1033 [OP_SECINFO] = (nfsd4_dec)nfsd4_decode_secinfo,
1034 [OP_SETATTR] = (nfsd4_dec)nfsd4_decode_setattr,
1035 [OP_SETCLIENTID] = (nfsd4_dec)nfsd4_decode_setclientid,
1036 [OP_SETCLIENTID_CONFIRM] = (nfsd4_dec)nfsd4_decode_setclientid_confirm,
1037 [OP_VERIFY] = (nfsd4_dec)nfsd4_decode_verify,
1038 [OP_WRITE] = (nfsd4_dec)nfsd4_decode_write,
1039 [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_release_lockowner,
1040};
1041
1042struct nfsd4_minorversion_ops {
1043 nfsd4_dec *decoders;
1044 int nops;
1045};
1046
1047static struct nfsd4_minorversion_ops nfsd4_minorversion[] = {
1048 [0] = { nfsd4_dec_ops, ARRAY_SIZE(nfsd4_dec_ops) },
1049};
1050
1051static __be32
989nfsd4_decode_compound(struct nfsd4_compoundargs *argp) 1052nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
990{ 1053{
991 DECODE_HEAD; 1054 DECODE_HEAD;
992 struct nfsd4_op *op; 1055 struct nfsd4_op *op;
1056 struct nfsd4_minorversion_ops *ops;
993 int i; 1057 int i;
994 1058
995 /* 1059 /*
@@ -1019,6 +1083,10 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
1019 } 1083 }
1020 } 1084 }
1021 1085
1086 if (argp->minorversion >= ARRAY_SIZE(nfsd4_minorversion))
1087 argp->opcnt = 0;
1088
1089 ops = &nfsd4_minorversion[argp->minorversion];
1022 for (i = 0; i < argp->opcnt; i++) { 1090 for (i = 0; i < argp->opcnt; i++) {
1023 op = &argp->ops[i]; 1091 op = &argp->ops[i];
1024 op->replay = NULL; 1092 op->replay = NULL;
@@ -1056,120 +1124,11 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
1056 } 1124 }
1057 op->opnum = ntohl(*argp->p++); 1125 op->opnum = ntohl(*argp->p++);
1058 1126
1059 switch (op->opnum) { 1127 if (op->opnum >= OP_ACCESS && op->opnum < ops->nops)
1060 case 2: /* Reserved operation */ 1128 op->status = ops->decoders[op->opnum](argp, &op->u);
1061 op->opnum = OP_ILLEGAL; 1129 else {
1062 if (argp->minorversion == 0)
1063 op->status = nfserr_op_illegal;
1064 else
1065 op->status = nfserr_minor_vers_mismatch;
1066 break;
1067 case OP_ACCESS:
1068 op->status = nfsd4_decode_access(argp, &op->u.access);
1069 break;
1070 case OP_CLOSE:
1071 op->status = nfsd4_decode_close(argp, &op->u.close);
1072 break;
1073 case OP_COMMIT:
1074 op->status = nfsd4_decode_commit(argp, &op->u.commit);
1075 break;
1076 case OP_CREATE:
1077 op->status = nfsd4_decode_create(argp, &op->u.create);
1078 break;
1079 case OP_DELEGRETURN:
1080 op->status = nfsd4_decode_delegreturn(argp, &op->u.delegreturn);
1081 break;
1082 case OP_GETATTR:
1083 op->status = nfsd4_decode_getattr(argp, &op->u.getattr);
1084 break;
1085 case OP_GETFH:
1086 op->status = nfs_ok;
1087 break;
1088 case OP_LINK:
1089 op->status = nfsd4_decode_link(argp, &op->u.link);
1090 break;
1091 case OP_LOCK:
1092 op->status = nfsd4_decode_lock(argp, &op->u.lock);
1093 break;
1094 case OP_LOCKT:
1095 op->status = nfsd4_decode_lockt(argp, &op->u.lockt);
1096 break;
1097 case OP_LOCKU:
1098 op->status = nfsd4_decode_locku(argp, &op->u.locku);
1099 break;
1100 case OP_LOOKUP:
1101 op->status = nfsd4_decode_lookup(argp, &op->u.lookup);
1102 break;
1103 case OP_LOOKUPP:
1104 op->status = nfs_ok;
1105 break;
1106 case OP_NVERIFY:
1107 op->status = nfsd4_decode_verify(argp, &op->u.nverify);
1108 break;
1109 case OP_OPEN:
1110 op->status = nfsd4_decode_open(argp, &op->u.open);
1111 break;
1112 case OP_OPEN_CONFIRM:
1113 op->status = nfsd4_decode_open_confirm(argp, &op->u.open_confirm);
1114 break;
1115 case OP_OPEN_DOWNGRADE:
1116 op->status = nfsd4_decode_open_downgrade(argp, &op->u.open_downgrade);
1117 break;
1118 case OP_PUTFH:
1119 op->status = nfsd4_decode_putfh(argp, &op->u.putfh);
1120 break;
1121 case OP_PUTROOTFH:
1122 op->status = nfs_ok;
1123 break;
1124 case OP_READ:
1125 op->status = nfsd4_decode_read(argp, &op->u.read);
1126 break;
1127 case OP_READDIR:
1128 op->status = nfsd4_decode_readdir(argp, &op->u.readdir);
1129 break;
1130 case OP_READLINK:
1131 op->status = nfs_ok;
1132 break;
1133 case OP_REMOVE:
1134 op->status = nfsd4_decode_remove(argp, &op->u.remove);
1135 break;
1136 case OP_RENAME:
1137 op->status = nfsd4_decode_rename(argp, &op->u.rename);
1138 break;
1139 case OP_RESTOREFH:
1140 op->status = nfs_ok;
1141 break;
1142 case OP_RENEW:
1143 op->status = nfsd4_decode_renew(argp, &op->u.renew);
1144 break;
1145 case OP_SAVEFH:
1146 op->status = nfs_ok;
1147 break;
1148 case OP_SECINFO:
1149 op->status = nfsd4_decode_secinfo(argp, &op->u.secinfo);
1150 break;
1151 case OP_SETATTR:
1152 op->status = nfsd4_decode_setattr(argp, &op->u.setattr);
1153 break;
1154 case OP_SETCLIENTID:
1155 op->status = nfsd4_decode_setclientid(argp, &op->u.setclientid);
1156 break;
1157 case OP_SETCLIENTID_CONFIRM:
1158 op->status = nfsd4_decode_setclientid_confirm(argp, &op->u.setclientid_confirm);
1159 break;
1160 case OP_VERIFY:
1161 op->status = nfsd4_decode_verify(argp, &op->u.verify);
1162 break;
1163 case OP_WRITE:
1164 op->status = nfsd4_decode_write(argp, &op->u.write);
1165 break;
1166 case OP_RELEASE_LOCKOWNER:
1167 op->status = nfsd4_decode_release_lockowner(argp, &op->u.release_lockowner);
1168 break;
1169 default:
1170 op->opnum = OP_ILLEGAL; 1130 op->opnum = OP_ILLEGAL;
1171 op->status = nfserr_op_illegal; 1131 op->status = nfserr_op_illegal;
1172 break;
1173 } 1132 }
1174 1133
1175 if (op->status) { 1134 if (op->status) {
@@ -1201,11 +1160,11 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
1201 *p++ = htonl((u32)((n) >> 32)); \ 1160 *p++ = htonl((u32)((n) >> 32)); \
1202 *p++ = htonl((u32)(n)); \ 1161 *p++ = htonl((u32)(n)); \
1203} while (0) 1162} while (0)
1204#define WRITEMEM(ptr,nbytes) do { \ 1163#define WRITEMEM(ptr,nbytes) do { if (nbytes > 0) { \
1205 *(p + XDR_QUADLEN(nbytes) -1) = 0; \ 1164 *(p + XDR_QUADLEN(nbytes) -1) = 0; \
1206 memcpy(p, ptr, nbytes); \ 1165 memcpy(p, ptr, nbytes); \
1207 p += XDR_QUADLEN(nbytes); \ 1166 p += XDR_QUADLEN(nbytes); \
1208} while (0) 1167}} while (0)
1209#define WRITECINFO(c) do { \ 1168#define WRITECINFO(c) do { \
1210 *p++ = htonl(c.atomic); \ 1169 *p++ = htonl(c.atomic); \
1211 *p++ = htonl(c.before_ctime_sec); \ 1170 *p++ = htonl(c.before_ctime_sec); \
@@ -1991,7 +1950,7 @@ fail:
1991 return -EINVAL; 1950 return -EINVAL;
1992} 1951}
1993 1952
1994static void 1953static __be32
1995nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access) 1954nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access)
1996{ 1955{
1997 ENCODE_HEAD; 1956 ENCODE_HEAD;
@@ -2002,9 +1961,10 @@ nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
2002 WRITE32(access->ac_resp_access); 1961 WRITE32(access->ac_resp_access);
2003 ADJUST_ARGS(); 1962 ADJUST_ARGS();
2004 } 1963 }
1964 return nfserr;
2005} 1965}
2006 1966
2007static void 1967static __be32
2008nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close) 1968nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close)
2009{ 1969{
2010 ENCODE_SEQID_OP_HEAD; 1970 ENCODE_SEQID_OP_HEAD;
@@ -2016,10 +1976,11 @@ nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_c
2016 ADJUST_ARGS(); 1976 ADJUST_ARGS();
2017 } 1977 }
2018 ENCODE_SEQID_OP_TAIL(close->cl_stateowner); 1978 ENCODE_SEQID_OP_TAIL(close->cl_stateowner);
1979 return nfserr;
2019} 1980}
2020 1981
2021 1982
2022static void 1983static __be32
2023nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit) 1984nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit)
2024{ 1985{
2025 ENCODE_HEAD; 1986 ENCODE_HEAD;
@@ -2029,9 +1990,10 @@ nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
2029 WRITEMEM(commit->co_verf.data, 8); 1990 WRITEMEM(commit->co_verf.data, 8);
2030 ADJUST_ARGS(); 1991 ADJUST_ARGS();
2031 } 1992 }
1993 return nfserr;
2032} 1994}
2033 1995
2034static void 1996static __be32
2035nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create) 1997nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create)
2036{ 1998{
2037 ENCODE_HEAD; 1999 ENCODE_HEAD;
@@ -2044,6 +2006,7 @@ nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
2044 WRITE32(create->cr_bmval[1]); 2006 WRITE32(create->cr_bmval[1]);
2045 ADJUST_ARGS(); 2007 ADJUST_ARGS();
2046 } 2008 }
2009 return nfserr;
2047} 2010}
2048 2011
2049static __be32 2012static __be32
@@ -2064,9 +2027,10 @@ nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
2064 return nfserr; 2027 return nfserr;
2065} 2028}
2066 2029
2067static void 2030static __be32
2068nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh *fhp) 2031nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh **fhpp)
2069{ 2032{
2033 struct svc_fh *fhp = *fhpp;
2070 unsigned int len; 2034 unsigned int len;
2071 ENCODE_HEAD; 2035 ENCODE_HEAD;
2072 2036
@@ -2077,6 +2041,7 @@ nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh
2077 WRITEMEM(&fhp->fh_handle.fh_base, len); 2041 WRITEMEM(&fhp->fh_handle.fh_base, len);
2078 ADJUST_ARGS(); 2042 ADJUST_ARGS();
2079 } 2043 }
2044 return nfserr;
2080} 2045}
2081 2046
2082/* 2047/*
@@ -2104,7 +2069,7 @@ nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denie
2104 ADJUST_ARGS(); 2069 ADJUST_ARGS();
2105} 2070}
2106 2071
2107static void 2072static __be32
2108nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lock *lock) 2073nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lock *lock)
2109{ 2074{
2110 ENCODE_SEQID_OP_HEAD; 2075 ENCODE_SEQID_OP_HEAD;
@@ -2118,16 +2083,18 @@ nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lo
2118 nfsd4_encode_lock_denied(resp, &lock->lk_denied); 2083 nfsd4_encode_lock_denied(resp, &lock->lk_denied);
2119 2084
2120 ENCODE_SEQID_OP_TAIL(lock->lk_replay_owner); 2085 ENCODE_SEQID_OP_TAIL(lock->lk_replay_owner);
2086 return nfserr;
2121} 2087}
2122 2088
2123static void 2089static __be32
2124nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lockt *lockt) 2090nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lockt *lockt)
2125{ 2091{
2126 if (nfserr == nfserr_denied) 2092 if (nfserr == nfserr_denied)
2127 nfsd4_encode_lock_denied(resp, &lockt->lt_denied); 2093 nfsd4_encode_lock_denied(resp, &lockt->lt_denied);
2094 return nfserr;
2128} 2095}
2129 2096
2130static void 2097static __be32
2131nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_locku *locku) 2098nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_locku *locku)
2132{ 2099{
2133 ENCODE_SEQID_OP_HEAD; 2100 ENCODE_SEQID_OP_HEAD;
@@ -2140,10 +2107,11 @@ nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l
2140 } 2107 }
2141 2108
2142 ENCODE_SEQID_OP_TAIL(locku->lu_stateowner); 2109 ENCODE_SEQID_OP_TAIL(locku->lu_stateowner);
2110 return nfserr;
2143} 2111}
2144 2112
2145 2113
2146static void 2114static __be32
2147nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link) 2115nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link)
2148{ 2116{
2149 ENCODE_HEAD; 2117 ENCODE_HEAD;
@@ -2153,10 +2121,11 @@ nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_li
2153 WRITECINFO(link->li_cinfo); 2121 WRITECINFO(link->li_cinfo);
2154 ADJUST_ARGS(); 2122 ADJUST_ARGS();
2155 } 2123 }
2124 return nfserr;
2156} 2125}
2157 2126
2158 2127
2159static void 2128static __be32
2160nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open) 2129nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open)
2161{ 2130{
2162 ENCODE_SEQID_OP_HEAD; 2131 ENCODE_SEQID_OP_HEAD;
@@ -2219,9 +2188,10 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op
2219 /* XXX save filehandle here */ 2188 /* XXX save filehandle here */
2220out: 2189out:
2221 ENCODE_SEQID_OP_TAIL(open->op_stateowner); 2190 ENCODE_SEQID_OP_TAIL(open->op_stateowner);
2191 return nfserr;
2222} 2192}
2223 2193
2224static void 2194static __be32
2225nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc) 2195nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc)
2226{ 2196{
2227 ENCODE_SEQID_OP_HEAD; 2197 ENCODE_SEQID_OP_HEAD;
@@ -2234,9 +2204,10 @@ nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct
2234 } 2204 }
2235 2205
2236 ENCODE_SEQID_OP_TAIL(oc->oc_stateowner); 2206 ENCODE_SEQID_OP_TAIL(oc->oc_stateowner);
2207 return nfserr;
2237} 2208}
2238 2209
2239static void 2210static __be32
2240nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od) 2211nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od)
2241{ 2212{
2242 ENCODE_SEQID_OP_HEAD; 2213 ENCODE_SEQID_OP_HEAD;
@@ -2249,6 +2220,7 @@ nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struc
2249 } 2220 }
2250 2221
2251 ENCODE_SEQID_OP_TAIL(od->od_stateowner); 2222 ENCODE_SEQID_OP_TAIL(od->od_stateowner);
2223 return nfserr;
2252} 2224}
2253 2225
2254static __be32 2226static __be32
@@ -2443,7 +2415,7 @@ err_no_verf:
2443 return nfserr; 2415 return nfserr;
2444} 2416}
2445 2417
2446static void 2418static __be32
2447nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove) 2419nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove)
2448{ 2420{
2449 ENCODE_HEAD; 2421 ENCODE_HEAD;
@@ -2453,9 +2425,10 @@ nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
2453 WRITECINFO(remove->rm_cinfo); 2425 WRITECINFO(remove->rm_cinfo);
2454 ADJUST_ARGS(); 2426 ADJUST_ARGS();
2455 } 2427 }
2428 return nfserr;
2456} 2429}
2457 2430
2458static void 2431static __be32
2459nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename) 2432nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename)
2460{ 2433{
2461 ENCODE_HEAD; 2434 ENCODE_HEAD;
@@ -2466,9 +2439,10 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
2466 WRITECINFO(rename->rn_tinfo); 2439 WRITECINFO(rename->rn_tinfo);
2467 ADJUST_ARGS(); 2440 ADJUST_ARGS();
2468 } 2441 }
2442 return nfserr;
2469} 2443}
2470 2444
2471static void 2445static __be32
2472nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr, 2446nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
2473 struct nfsd4_secinfo *secinfo) 2447 struct nfsd4_secinfo *secinfo)
2474{ 2448{
@@ -2532,13 +2506,14 @@ nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
2532out: 2506out:
2533 if (exp) 2507 if (exp)
2534 exp_put(exp); 2508 exp_put(exp);
2509 return nfserr;
2535} 2510}
2536 2511
2537/* 2512/*
2538 * The SETATTR encode routine is special -- it always encodes a bitmap, 2513 * The SETATTR encode routine is special -- it always encodes a bitmap,
2539 * regardless of the error status. 2514 * regardless of the error status.
2540 */ 2515 */
2541static void 2516static __be32
2542nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr) 2517nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr)
2543{ 2518{
2544 ENCODE_HEAD; 2519 ENCODE_HEAD;
@@ -2555,9 +2530,10 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
2555 WRITE32(setattr->sa_bmval[1]); 2530 WRITE32(setattr->sa_bmval[1]);
2556 } 2531 }
2557 ADJUST_ARGS(); 2532 ADJUST_ARGS();
2533 return nfserr;
2558} 2534}
2559 2535
2560static void 2536static __be32
2561nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd) 2537nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd)
2562{ 2538{
2563 ENCODE_HEAD; 2539 ENCODE_HEAD;
@@ -2574,9 +2550,10 @@ nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct n
2574 WRITE32(0); 2550 WRITE32(0);
2575 ADJUST_ARGS(); 2551 ADJUST_ARGS();
2576 } 2552 }
2553 return nfserr;
2577} 2554}
2578 2555
2579static void 2556static __be32
2580nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write) 2557nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write)
2581{ 2558{
2582 ENCODE_HEAD; 2559 ENCODE_HEAD;
@@ -2588,8 +2565,56 @@ nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_w
2588 WRITEMEM(write->wr_verifier.data, 8); 2565 WRITEMEM(write->wr_verifier.data, 8);
2589 ADJUST_ARGS(); 2566 ADJUST_ARGS();
2590 } 2567 }
2568 return nfserr;
2591} 2569}
2592 2570
2571static __be32
2572nfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr, void *p)
2573{
2574 return nfserr;
2575}
2576
2577typedef __be32(* nfsd4_enc)(struct nfsd4_compoundres *, __be32, void *);
2578
2579static nfsd4_enc nfsd4_enc_ops[] = {
2580 [OP_ACCESS] = (nfsd4_enc)nfsd4_encode_access,
2581 [OP_CLOSE] = (nfsd4_enc)nfsd4_encode_close,
2582 [OP_COMMIT] = (nfsd4_enc)nfsd4_encode_commit,
2583 [OP_CREATE] = (nfsd4_enc)nfsd4_encode_create,
2584 [OP_DELEGPURGE] = (nfsd4_enc)nfsd4_encode_noop,
2585 [OP_DELEGRETURN] = (nfsd4_enc)nfsd4_encode_noop,
2586 [OP_GETATTR] = (nfsd4_enc)nfsd4_encode_getattr,
2587 [OP_GETFH] = (nfsd4_enc)nfsd4_encode_getfh,
2588 [OP_LINK] = (nfsd4_enc)nfsd4_encode_link,
2589 [OP_LOCK] = (nfsd4_enc)nfsd4_encode_lock,
2590 [OP_LOCKT] = (nfsd4_enc)nfsd4_encode_lockt,
2591 [OP_LOCKU] = (nfsd4_enc)nfsd4_encode_locku,
2592 [OP_LOOKUP] = (nfsd4_enc)nfsd4_encode_noop,
2593 [OP_LOOKUPP] = (nfsd4_enc)nfsd4_encode_noop,
2594 [OP_NVERIFY] = (nfsd4_enc)nfsd4_encode_noop,
2595 [OP_OPEN] = (nfsd4_enc)nfsd4_encode_open,
2596 [OP_OPEN_CONFIRM] = (nfsd4_enc)nfsd4_encode_open_confirm,
2597 [OP_OPEN_DOWNGRADE] = (nfsd4_enc)nfsd4_encode_open_downgrade,
2598 [OP_PUTFH] = (nfsd4_enc)nfsd4_encode_noop,
2599 [OP_PUTPUBFH] = (nfsd4_enc)nfsd4_encode_noop,
2600 [OP_PUTROOTFH] = (nfsd4_enc)nfsd4_encode_noop,
2601 [OP_READ] = (nfsd4_enc)nfsd4_encode_read,
2602 [OP_READDIR] = (nfsd4_enc)nfsd4_encode_readdir,
2603 [OP_READLINK] = (nfsd4_enc)nfsd4_encode_readlink,
2604 [OP_REMOVE] = (nfsd4_enc)nfsd4_encode_remove,
2605 [OP_RENAME] = (nfsd4_enc)nfsd4_encode_rename,
2606 [OP_RENEW] = (nfsd4_enc)nfsd4_encode_noop,
2607 [OP_RESTOREFH] = (nfsd4_enc)nfsd4_encode_noop,
2608 [OP_SAVEFH] = (nfsd4_enc)nfsd4_encode_noop,
2609 [OP_SECINFO] = (nfsd4_enc)nfsd4_encode_secinfo,
2610 [OP_SETATTR] = (nfsd4_enc)nfsd4_encode_setattr,
2611 [OP_SETCLIENTID] = (nfsd4_enc)nfsd4_encode_setclientid,
2612 [OP_SETCLIENTID_CONFIRM] = (nfsd4_enc)nfsd4_encode_noop,
2613 [OP_VERIFY] = (nfsd4_enc)nfsd4_encode_noop,
2614 [OP_WRITE] = (nfsd4_enc)nfsd4_encode_write,
2615 [OP_RELEASE_LOCKOWNER] = (nfsd4_enc)nfsd4_encode_noop,
2616};
2617
2593void 2618void
2594nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) 2619nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
2595{ 2620{
@@ -2601,101 +2626,12 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
2601 statp = p++; /* to be backfilled at the end */ 2626 statp = p++; /* to be backfilled at the end */
2602 ADJUST_ARGS(); 2627 ADJUST_ARGS();
2603 2628
2604 switch (op->opnum) { 2629 if (op->opnum == OP_ILLEGAL)
2605 case OP_ACCESS: 2630 goto status;
2606 nfsd4_encode_access(resp, op->status, &op->u.access); 2631 BUG_ON(op->opnum < 0 || op->opnum >= ARRAY_SIZE(nfsd4_enc_ops) ||
2607 break; 2632 !nfsd4_enc_ops[op->opnum]);
2608 case OP_CLOSE: 2633 op->status = nfsd4_enc_ops[op->opnum](resp, op->status, &op->u);
2609 nfsd4_encode_close(resp, op->status, &op->u.close); 2634status:
2610 break;
2611 case OP_COMMIT:
2612 nfsd4_encode_commit(resp, op->status, &op->u.commit);
2613 break;
2614 case OP_CREATE:
2615 nfsd4_encode_create(resp, op->status, &op->u.create);
2616 break;
2617 case OP_DELEGRETURN:
2618 break;
2619 case OP_GETATTR:
2620 op->status = nfsd4_encode_getattr(resp, op->status, &op->u.getattr);
2621 break;
2622 case OP_GETFH:
2623 nfsd4_encode_getfh(resp, op->status, op->u.getfh);
2624 break;
2625 case OP_LINK:
2626 nfsd4_encode_link(resp, op->status, &op->u.link);
2627 break;
2628 case OP_LOCK:
2629 nfsd4_encode_lock(resp, op->status, &op->u.lock);
2630 break;
2631 case OP_LOCKT:
2632 nfsd4_encode_lockt(resp, op->status, &op->u.lockt);
2633 break;
2634 case OP_LOCKU:
2635 nfsd4_encode_locku(resp, op->status, &op->u.locku);
2636 break;
2637 case OP_LOOKUP:
2638 break;
2639 case OP_LOOKUPP:
2640 break;
2641 case OP_NVERIFY:
2642 break;
2643 case OP_OPEN:
2644 nfsd4_encode_open(resp, op->status, &op->u.open);
2645 break;
2646 case OP_OPEN_CONFIRM:
2647 nfsd4_encode_open_confirm(resp, op->status, &op->u.open_confirm);
2648 break;
2649 case OP_OPEN_DOWNGRADE:
2650 nfsd4_encode_open_downgrade(resp, op->status, &op->u.open_downgrade);
2651 break;
2652 case OP_PUTFH:
2653 break;
2654 case OP_PUTROOTFH:
2655 break;
2656 case OP_READ:
2657 op->status = nfsd4_encode_read(resp, op->status, &op->u.read);
2658 break;
2659 case OP_READDIR:
2660 op->status = nfsd4_encode_readdir(resp, op->status, &op->u.readdir);
2661 break;
2662 case OP_READLINK:
2663 op->status = nfsd4_encode_readlink(resp, op->status, &op->u.readlink);
2664 break;
2665 case OP_REMOVE:
2666 nfsd4_encode_remove(resp, op->status, &op->u.remove);
2667 break;
2668 case OP_RENAME:
2669 nfsd4_encode_rename(resp, op->status, &op->u.rename);
2670 break;
2671 case OP_RENEW:
2672 break;
2673 case OP_RESTOREFH:
2674 break;
2675 case OP_SAVEFH:
2676 break;
2677 case OP_SECINFO:
2678 nfsd4_encode_secinfo(resp, op->status, &op->u.secinfo);
2679 break;
2680 case OP_SETATTR:
2681 nfsd4_encode_setattr(resp, op->status, &op->u.setattr);
2682 break;
2683 case OP_SETCLIENTID:
2684 nfsd4_encode_setclientid(resp, op->status, &op->u.setclientid);
2685 break;
2686 case OP_SETCLIENTID_CONFIRM:
2687 break;
2688 case OP_VERIFY:
2689 break;
2690 case OP_WRITE:
2691 nfsd4_encode_write(resp, op->status, &op->u.write);
2692 break;
2693 case OP_RELEASE_LOCKOWNER:
2694 break;
2695 default:
2696 break;
2697 }
2698
2699 /* 2635 /*
2700 * Note: We write the status directly, instead of using WRITE32(), 2636 * Note: We write the status directly, instead of using WRITE32(),
2701 * since it is already in network byte order. 2637 * since it is already in network byte order.
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 5ac00c4fee91..1955a2702e60 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -310,9 +310,12 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size)
310 310
311static ssize_t failover_unlock_ip(struct file *file, char *buf, size_t size) 311static ssize_t failover_unlock_ip(struct file *file, char *buf, size_t size)
312{ 312{
313 __be32 server_ip; 313 struct sockaddr_in sin = {
314 char *fo_path, c; 314 .sin_family = AF_INET,
315 };
315 int b1, b2, b3, b4; 316 int b1, b2, b3, b4;
317 char c;
318 char *fo_path;
316 319
317 /* sanity check */ 320 /* sanity check */
318 if (size == 0) 321 if (size == 0)
@@ -326,11 +329,13 @@ static ssize_t failover_unlock_ip(struct file *file, char *buf, size_t size)
326 return -EINVAL; 329 return -EINVAL;
327 330
328 /* get ipv4 address */ 331 /* get ipv4 address */
329 if (sscanf(fo_path, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4) 332 if (sscanf(fo_path, NIPQUAD_FMT "%c", &b1, &b2, &b3, &b4, &c) != 4)
330 return -EINVAL; 333 return -EINVAL;
331 server_ip = htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4); 334 if (b1 > 255 || b2 > 255 || b3 > 255 || b4 > 255)
335 return -EINVAL;
336 sin.sin_addr.s_addr = htonl((b1 << 24) | (b2 << 16) | (b3 << 8) | b4);
332 337
333 return nlmsvc_unlock_all_by_ip(server_ip); 338 return nlmsvc_unlock_all_by_ip((struct sockaddr *)&sin);
334} 339}
335 340
336static ssize_t failover_unlock_fs(struct file *file, char *buf, size_t size) 341static ssize_t failover_unlock_fs(struct file *file, char *buf, size_t size)
@@ -450,22 +455,26 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
450 int i; 455 int i;
451 int rv; 456 int rv;
452 int len; 457 int len;
453 int npools = nfsd_nrpools(); 458 int npools;
454 int *nthreads; 459 int *nthreads;
455 460
461 mutex_lock(&nfsd_mutex);
462 npools = nfsd_nrpools();
456 if (npools == 0) { 463 if (npools == 0) {
457 /* 464 /*
458 * NFS is shut down. The admin can start it by 465 * NFS is shut down. The admin can start it by
459 * writing to the threads file but NOT the pool_threads 466 * writing to the threads file but NOT the pool_threads
460 * file, sorry. Report zero threads. 467 * file, sorry. Report zero threads.
461 */ 468 */
469 mutex_unlock(&nfsd_mutex);
462 strcpy(buf, "0\n"); 470 strcpy(buf, "0\n");
463 return strlen(buf); 471 return strlen(buf);
464 } 472 }
465 473
466 nthreads = kcalloc(npools, sizeof(int), GFP_KERNEL); 474 nthreads = kcalloc(npools, sizeof(int), GFP_KERNEL);
475 rv = -ENOMEM;
467 if (nthreads == NULL) 476 if (nthreads == NULL)
468 return -ENOMEM; 477 goto out_free;
469 478
470 if (size > 0) { 479 if (size > 0) {
471 for (i = 0; i < npools; i++) { 480 for (i = 0; i < npools; i++) {
@@ -496,14 +505,16 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
496 mesg += len; 505 mesg += len;
497 } 506 }
498 507
508 mutex_unlock(&nfsd_mutex);
499 return (mesg-buf); 509 return (mesg-buf);
500 510
501out_free: 511out_free:
502 kfree(nthreads); 512 kfree(nthreads);
513 mutex_unlock(&nfsd_mutex);
503 return rv; 514 return rv;
504} 515}
505 516
506static ssize_t write_versions(struct file *file, char *buf, size_t size) 517static ssize_t __write_versions(struct file *file, char *buf, size_t size)
507{ 518{
508 /* 519 /*
509 * Format: 520 * Format:
@@ -566,14 +577,23 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size)
566 return len; 577 return len;
567} 578}
568 579
569static ssize_t write_ports(struct file *file, char *buf, size_t size) 580static ssize_t write_versions(struct file *file, char *buf, size_t size)
581{
582 ssize_t rv;
583
584 mutex_lock(&nfsd_mutex);
585 rv = __write_versions(file, buf, size);
586 mutex_unlock(&nfsd_mutex);
587 return rv;
588}
589
590static ssize_t __write_ports(struct file *file, char *buf, size_t size)
570{ 591{
571 if (size == 0) { 592 if (size == 0) {
572 int len = 0; 593 int len = 0;
573 lock_kernel(); 594
574 if (nfsd_serv) 595 if (nfsd_serv)
575 len = svc_xprt_names(nfsd_serv, buf, 0); 596 len = svc_xprt_names(nfsd_serv, buf, 0);
576 unlock_kernel();
577 return len; 597 return len;
578 } 598 }
579 /* Either a single 'fd' number is written, in which 599 /* Either a single 'fd' number is written, in which
@@ -603,9 +623,7 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size)
603 /* Decrease the count, but don't shutdown the 623 /* Decrease the count, but don't shutdown the
604 * the service 624 * the service
605 */ 625 */
606 lock_kernel();
607 nfsd_serv->sv_nrthreads--; 626 nfsd_serv->sv_nrthreads--;
608 unlock_kernel();
609 } 627 }
610 return err < 0 ? err : 0; 628 return err < 0 ? err : 0;
611 } 629 }
@@ -614,10 +632,8 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size)
614 int len = 0; 632 int len = 0;
615 if (!toclose) 633 if (!toclose)
616 return -ENOMEM; 634 return -ENOMEM;
617 lock_kernel();
618 if (nfsd_serv) 635 if (nfsd_serv)
619 len = svc_sock_names(buf, nfsd_serv, toclose); 636 len = svc_sock_names(buf, nfsd_serv, toclose);
620 unlock_kernel();
621 if (len >= 0) 637 if (len >= 0)
622 lockd_down(); 638 lockd_down();
623 kfree(toclose); 639 kfree(toclose);
@@ -655,7 +671,6 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size)
655 if (sscanf(&buf[1], "%15s %4d", transport, &port) == 2) { 671 if (sscanf(&buf[1], "%15s %4d", transport, &port) == 2) {
656 if (port == 0) 672 if (port == 0)
657 return -EINVAL; 673 return -EINVAL;
658 lock_kernel();
659 if (nfsd_serv) { 674 if (nfsd_serv) {
660 xprt = svc_find_xprt(nfsd_serv, transport, 675 xprt = svc_find_xprt(nfsd_serv, transport,
661 AF_UNSPEC, port); 676 AF_UNSPEC, port);
@@ -666,13 +681,23 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size)
666 } else 681 } else
667 err = -ENOTCONN; 682 err = -ENOTCONN;
668 } 683 }
669 unlock_kernel();
670 return err < 0 ? err : 0; 684 return err < 0 ? err : 0;
671 } 685 }
672 } 686 }
673 return -EINVAL; 687 return -EINVAL;
674} 688}
675 689
690static ssize_t write_ports(struct file *file, char *buf, size_t size)
691{
692 ssize_t rv;
693
694 mutex_lock(&nfsd_mutex);
695 rv = __write_ports(file, buf, size);
696 mutex_unlock(&nfsd_mutex);
697 return rv;
698}
699
700
676int nfsd_max_blksize; 701int nfsd_max_blksize;
677 702
678static ssize_t write_maxblksize(struct file *file, char *buf, size_t size) 703static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
@@ -691,13 +716,13 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
691 if (bsize > NFSSVC_MAXBLKSIZE) 716 if (bsize > NFSSVC_MAXBLKSIZE)
692 bsize = NFSSVC_MAXBLKSIZE; 717 bsize = NFSSVC_MAXBLKSIZE;
693 bsize &= ~(1024-1); 718 bsize &= ~(1024-1);
694 lock_kernel(); 719 mutex_lock(&nfsd_mutex);
695 if (nfsd_serv && nfsd_serv->sv_nrthreads) { 720 if (nfsd_serv && nfsd_serv->sv_nrthreads) {
696 unlock_kernel(); 721 mutex_unlock(&nfsd_mutex);
697 return -EBUSY; 722 return -EBUSY;
698 } 723 }
699 nfsd_max_blksize = bsize; 724 nfsd_max_blksize = bsize;
700 unlock_kernel(); 725 mutex_unlock(&nfsd_mutex);
701 } 726 }
702 return sprintf(buf, "%d\n", nfsd_max_blksize); 727 return sprintf(buf, "%d\n", nfsd_max_blksize);
703} 728}
@@ -705,16 +730,17 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
705#ifdef CONFIG_NFSD_V4 730#ifdef CONFIG_NFSD_V4
706extern time_t nfs4_leasetime(void); 731extern time_t nfs4_leasetime(void);
707 732
708static ssize_t write_leasetime(struct file *file, char *buf, size_t size) 733static ssize_t __write_leasetime(struct file *file, char *buf, size_t size)
709{ 734{
710 /* if size > 10 seconds, call 735 /* if size > 10 seconds, call
711 * nfs4_reset_lease() then write out the new lease (seconds) as reply 736 * nfs4_reset_lease() then write out the new lease (seconds) as reply
712 */ 737 */
713 char *mesg = buf; 738 char *mesg = buf;
714 int rv; 739 int rv, lease;
715 740
716 if (size > 0) { 741 if (size > 0) {
717 int lease; 742 if (nfsd_serv)
743 return -EBUSY;
718 rv = get_int(&mesg, &lease); 744 rv = get_int(&mesg, &lease);
719 if (rv) 745 if (rv)
720 return rv; 746 return rv;
@@ -726,24 +752,52 @@ static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
726 return strlen(buf); 752 return strlen(buf);
727} 753}
728 754
729static ssize_t write_recoverydir(struct file *file, char *buf, size_t size) 755static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
756{
757 ssize_t rv;
758
759 mutex_lock(&nfsd_mutex);
760 rv = __write_leasetime(file, buf, size);
761 mutex_unlock(&nfsd_mutex);
762 return rv;
763}
764
765extern char *nfs4_recoverydir(void);
766
767static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size)
730{ 768{
731 char *mesg = buf; 769 char *mesg = buf;
732 char *recdir; 770 char *recdir;
733 int len, status; 771 int len, status;
734 772
735 if (size == 0 || size > PATH_MAX || buf[size-1] != '\n') 773 if (size > 0) {
736 return -EINVAL; 774 if (nfsd_serv)
737 buf[size-1] = 0; 775 return -EBUSY;
776 if (size > PATH_MAX || buf[size-1] != '\n')
777 return -EINVAL;
778 buf[size-1] = 0;
738 779
739 recdir = mesg; 780 recdir = mesg;
740 len = qword_get(&mesg, recdir, size); 781 len = qword_get(&mesg, recdir, size);
741 if (len <= 0) 782 if (len <= 0)
742 return -EINVAL; 783 return -EINVAL;
743 784
744 status = nfs4_reset_recoverydir(recdir); 785 status = nfs4_reset_recoverydir(recdir);
786 }
787 sprintf(buf, "%s\n", nfs4_recoverydir());
745 return strlen(buf); 788 return strlen(buf);
746} 789}
790
791static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
792{
793 ssize_t rv;
794
795 mutex_lock(&nfsd_mutex);
796 rv = __write_recoverydir(file, buf, size);
797 mutex_unlock(&nfsd_mutex);
798 return rv;
799}
800
747#endif 801#endif
748 802
749/*----------------------------------------------------------------------------*/ 803/*----------------------------------------------------------------------------*/
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 100ae5641162..f45451eb1e38 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -176,9 +176,24 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
176 if (IS_ERR(exp)) 176 if (IS_ERR(exp))
177 return nfserrno(PTR_ERR(exp)); 177 return nfserrno(PTR_ERR(exp));
178 178
179 error = nfsd_setuser_and_check_port(rqstp, exp); 179 if (exp->ex_flags & NFSEXP_NOSUBTREECHECK) {
180 if (error) 180 /* Elevate privileges so that the lack of 'r' or 'x'
181 goto out; 181 * permission on some parent directory will
182 * not stop exportfs_decode_fh from being able
183 * to reconnect a directory into the dentry cache.
184 * The same problem can affect "SUBTREECHECK" exports,
185 * but as nfsd_acceptable depends on correct
186 * access control settings being in effect, we cannot
187 * fix that case easily.
188 */
189 current->cap_effective =
190 cap_raise_nfsd_set(current->cap_effective,
191 current->cap_permitted);
192 } else {
193 error = nfsd_setuser_and_check_port(rqstp, exp);
194 if (error)
195 goto out;
196 }
182 197
183 /* 198 /*
184 * Look up the dentry using the NFS file handle. 199 * Look up the dentry using the NFS file handle.
@@ -215,6 +230,14 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
215 goto out; 230 goto out;
216 } 231 }
217 232
233 if (exp->ex_flags & NFSEXP_NOSUBTREECHECK) {
234 error = nfsd_setuser_and_check_port(rqstp, exp);
235 if (error) {
236 dput(dentry);
237 goto out;
238 }
239 }
240
218 if (S_ISDIR(dentry->d_inode->i_mode) && 241 if (S_ISDIR(dentry->d_inode->i_mode) &&
219 (dentry->d_flags & DCACHE_DISCONNECTED)) { 242 (dentry->d_flags & DCACHE_DISCONNECTED)) {
220 printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n", 243 printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n",
@@ -279,7 +302,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
279 if (error) 302 if (error)
280 goto out; 303 goto out;
281 304
282 if (!(access & MAY_LOCK)) { 305 if (!(access & NFSD_MAY_LOCK)) {
283 /* 306 /*
284 * pseudoflavor restrictions are not enforced on NLM, 307 * pseudoflavor restrictions are not enforced on NLM,
285 * which clients virtually always use auth_sys for, 308 * which clients virtually always use auth_sys for,
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 6cfc96a12483..0766f95d236a 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -65,7 +65,7 @@ nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
65 dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh)); 65 dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh));
66 66
67 fh_copy(&resp->fh, &argp->fh); 67 fh_copy(&resp->fh, &argp->fh);
68 nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP); 68 nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
69 return nfsd_return_attrs(nfserr, resp); 69 return nfsd_return_attrs(nfserr, resp);
70} 70}
71 71
@@ -215,11 +215,11 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
215 SVCFH_fmt(dirfhp), argp->len, argp->name); 215 SVCFH_fmt(dirfhp), argp->len, argp->name);
216 216
217 /* First verify the parent file handle */ 217 /* First verify the parent file handle */
218 nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, MAY_EXEC); 218 nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_EXEC);
219 if (nfserr) 219 if (nfserr)
220 goto done; /* must fh_put dirfhp even on error */ 220 goto done; /* must fh_put dirfhp even on error */
221 221
222 /* Check for MAY_WRITE in nfsd_create if necessary */ 222 /* Check for NFSD_MAY_WRITE in nfsd_create if necessary */
223 223
224 nfserr = nfserr_acces; 224 nfserr = nfserr_acces;
225 if (!argp->len) 225 if (!argp->len)
@@ -281,7 +281,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
281 nfserr = nfsd_permission(rqstp, 281 nfserr = nfsd_permission(rqstp,
282 newfhp->fh_export, 282 newfhp->fh_export,
283 newfhp->fh_dentry, 283 newfhp->fh_dentry,
284 MAY_WRITE|MAY_LOCAL_ACCESS); 284 NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS);
285 if (nfserr && nfserr != nfserr_rofs) 285 if (nfserr && nfserr != nfserr_rofs)
286 goto out_unlock; 286 goto out_unlock;
287 } 287 }
@@ -614,6 +614,7 @@ nfserrno (int errno)
614#endif 614#endif
615 { nfserr_stale, -ESTALE }, 615 { nfserr_stale, -ESTALE },
616 { nfserr_jukebox, -ETIMEDOUT }, 616 { nfserr_jukebox, -ETIMEDOUT },
617 { nfserr_jukebox, -ERESTARTSYS },
617 { nfserr_dropit, -EAGAIN }, 618 { nfserr_dropit, -EAGAIN },
618 { nfserr_dropit, -ENOMEM }, 619 { nfserr_dropit, -ENOMEM },
619 { nfserr_badname, -ESRCH }, 620 { nfserr_badname, -ESRCH },
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 941041f4b136..80292ff5e924 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -21,6 +21,7 @@
21#include <linux/smp_lock.h> 21#include <linux/smp_lock.h>
22#include <linux/freezer.h> 22#include <linux/freezer.h>
23#include <linux/fs_struct.h> 23#include <linux/fs_struct.h>
24#include <linux/kthread.h>
24 25
25#include <linux/sunrpc/types.h> 26#include <linux/sunrpc/types.h>
26#include <linux/sunrpc/stats.h> 27#include <linux/sunrpc/stats.h>
@@ -36,28 +37,38 @@
36 37
37#define NFSDDBG_FACILITY NFSDDBG_SVC 38#define NFSDDBG_FACILITY NFSDDBG_SVC
38 39
39/* these signals will be delivered to an nfsd thread
40 * when handling a request
41 */
42#define ALLOWED_SIGS (sigmask(SIGKILL))
43/* these signals will be delivered to an nfsd thread
44 * when not handling a request. i.e. when waiting
45 */
46#define SHUTDOWN_SIGS (sigmask(SIGKILL) | sigmask(SIGHUP) | sigmask(SIGINT) | sigmask(SIGQUIT))
47/* if the last thread dies with SIGHUP, then the exports table is
48 * left unchanged ( like 2.4-{0-9} ). Any other signal will clear
49 * the exports table (like 2.2).
50 */
51#define SIG_NOCLEAN SIGHUP
52
53extern struct svc_program nfsd_program; 40extern struct svc_program nfsd_program;
54static void nfsd(struct svc_rqst *rqstp); 41static int nfsd(void *vrqstp);
55struct timeval nfssvc_boot; 42struct timeval nfssvc_boot;
56 struct svc_serv *nfsd_serv;
57static atomic_t nfsd_busy; 43static atomic_t nfsd_busy;
58static unsigned long nfsd_last_call; 44static unsigned long nfsd_last_call;
59static DEFINE_SPINLOCK(nfsd_call_lock); 45static DEFINE_SPINLOCK(nfsd_call_lock);
60 46
47/*
48 * nfsd_mutex protects nfsd_serv -- both the pointer itself and the members
49 * of the svc_serv struct. In particular, ->sv_nrthreads but also to some
50 * extent ->sv_temp_socks and ->sv_permsocks. It also protects nfsdstats.th_cnt
51 *
52 * If (out side the lock) nfsd_serv is non-NULL, then it must point to a
53 * properly initialised 'struct svc_serv' with ->sv_nrthreads > 0. That number
54 * of nfsd threads must exist and each must listed in ->sp_all_threads in each
55 * entry of ->sv_pools[].
56 *
57 * Transitions of the thread count between zero and non-zero are of particular
58 * interest since the svc_serv needs to be created and initialized at that
59 * point, or freed.
60 *
61 * Finally, the nfsd_mutex also protects some of the global variables that are
62 * accessed when nfsd starts and that are settable via the write_* routines in
63 * nfsctl.c. In particular:
64 *
65 * user_recovery_dirname
66 * user_lease_time
67 * nfsd_versions
68 */
69DEFINE_MUTEX(nfsd_mutex);
70struct svc_serv *nfsd_serv;
71
61#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) 72#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
62static struct svc_stat nfsd_acl_svcstats; 73static struct svc_stat nfsd_acl_svcstats;
63static struct svc_version * nfsd_acl_version[] = { 74static struct svc_version * nfsd_acl_version[] = {
@@ -145,13 +156,14 @@ int nfsd_vers(int vers, enum vers_op change)
145 156
146int nfsd_nrthreads(void) 157int nfsd_nrthreads(void)
147{ 158{
148 if (nfsd_serv == NULL) 159 int rv = 0;
149 return 0; 160 mutex_lock(&nfsd_mutex);
150 else 161 if (nfsd_serv)
151 return nfsd_serv->sv_nrthreads; 162 rv = nfsd_serv->sv_nrthreads;
163 mutex_unlock(&nfsd_mutex);
164 return rv;
152} 165}
153 166
154static int killsig; /* signal that was used to kill last nfsd */
155static void nfsd_last_thread(struct svc_serv *serv) 167static void nfsd_last_thread(struct svc_serv *serv)
156{ 168{
157 /* When last nfsd thread exits we need to do some clean-up */ 169 /* When last nfsd thread exits we need to do some clean-up */
@@ -162,11 +174,9 @@ static void nfsd_last_thread(struct svc_serv *serv)
162 nfsd_racache_shutdown(); 174 nfsd_racache_shutdown();
163 nfs4_state_shutdown(); 175 nfs4_state_shutdown();
164 176
165 printk(KERN_WARNING "nfsd: last server has exited\n"); 177 printk(KERN_WARNING "nfsd: last server has exited, flushing export "
166 if (killsig != SIG_NOCLEAN) { 178 "cache\n");
167 printk(KERN_WARNING "nfsd: unexporting all filesystems\n"); 179 nfsd_export_flush();
168 nfsd_export_flush();
169 }
170} 180}
171 181
172void nfsd_reset_versions(void) 182void nfsd_reset_versions(void)
@@ -190,13 +200,14 @@ void nfsd_reset_versions(void)
190 } 200 }
191} 201}
192 202
203
193int nfsd_create_serv(void) 204int nfsd_create_serv(void)
194{ 205{
195 int err = 0; 206 int err = 0;
196 lock_kernel(); 207
208 WARN_ON(!mutex_is_locked(&nfsd_mutex));
197 if (nfsd_serv) { 209 if (nfsd_serv) {
198 svc_get(nfsd_serv); 210 svc_get(nfsd_serv);
199 unlock_kernel();
200 return 0; 211 return 0;
201 } 212 }
202 if (nfsd_max_blksize == 0) { 213 if (nfsd_max_blksize == 0) {
@@ -217,13 +228,11 @@ int nfsd_create_serv(void)
217 } 228 }
218 229
219 atomic_set(&nfsd_busy, 0); 230 atomic_set(&nfsd_busy, 0);
220 nfsd_serv = svc_create_pooled(&nfsd_program, 231 nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
221 nfsd_max_blksize, 232 nfsd_last_thread, nfsd, THIS_MODULE);
222 nfsd_last_thread,
223 nfsd, SIG_NOCLEAN, THIS_MODULE);
224 if (nfsd_serv == NULL) 233 if (nfsd_serv == NULL)
225 err = -ENOMEM; 234 err = -ENOMEM;
226 unlock_kernel(); 235
227 do_gettimeofday(&nfssvc_boot); /* record boot time */ 236 do_gettimeofday(&nfssvc_boot); /* record boot time */
228 return err; 237 return err;
229} 238}
@@ -282,6 +291,8 @@ int nfsd_set_nrthreads(int n, int *nthreads)
282 int tot = 0; 291 int tot = 0;
283 int err = 0; 292 int err = 0;
284 293
294 WARN_ON(!mutex_is_locked(&nfsd_mutex));
295
285 if (nfsd_serv == NULL || n <= 0) 296 if (nfsd_serv == NULL || n <= 0)
286 return 0; 297 return 0;
287 298
@@ -316,7 +327,6 @@ int nfsd_set_nrthreads(int n, int *nthreads)
316 nthreads[0] = 1; 327 nthreads[0] = 1;
317 328
318 /* apply the new numbers */ 329 /* apply the new numbers */
319 lock_kernel();
320 svc_get(nfsd_serv); 330 svc_get(nfsd_serv);
321 for (i = 0; i < n; i++) { 331 for (i = 0; i < n; i++) {
322 err = svc_set_num_threads(nfsd_serv, &nfsd_serv->sv_pools[i], 332 err = svc_set_num_threads(nfsd_serv, &nfsd_serv->sv_pools[i],
@@ -325,7 +335,6 @@ int nfsd_set_nrthreads(int n, int *nthreads)
325 break; 335 break;
326 } 336 }
327 svc_destroy(nfsd_serv); 337 svc_destroy(nfsd_serv);
328 unlock_kernel();
329 338
330 return err; 339 return err;
331} 340}
@@ -334,8 +343,8 @@ int
334nfsd_svc(unsigned short port, int nrservs) 343nfsd_svc(unsigned short port, int nrservs)
335{ 344{
336 int error; 345 int error;
337 346
338 lock_kernel(); 347 mutex_lock(&nfsd_mutex);
339 dprintk("nfsd: creating service\n"); 348 dprintk("nfsd: creating service\n");
340 error = -EINVAL; 349 error = -EINVAL;
341 if (nrservs <= 0) 350 if (nrservs <= 0)
@@ -363,7 +372,7 @@ nfsd_svc(unsigned short port, int nrservs)
363 failure: 372 failure:
364 svc_destroy(nfsd_serv); /* Release server */ 373 svc_destroy(nfsd_serv); /* Release server */
365 out: 374 out:
366 unlock_kernel(); 375 mutex_unlock(&nfsd_mutex);
367 return error; 376 return error;
368} 377}
369 378
@@ -391,18 +400,17 @@ update_thread_usage(int busy_threads)
391/* 400/*
392 * This is the NFS server kernel thread 401 * This is the NFS server kernel thread
393 */ 402 */
394static void 403static int
395nfsd(struct svc_rqst *rqstp) 404nfsd(void *vrqstp)
396{ 405{
406 struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp;
397 struct fs_struct *fsp; 407 struct fs_struct *fsp;
398 int err; 408 int err, preverr = 0;
399 sigset_t shutdown_mask, allowed_mask;
400 409
401 /* Lock module and set up kernel thread */ 410 /* Lock module and set up kernel thread */
402 lock_kernel(); 411 mutex_lock(&nfsd_mutex);
403 daemonize("nfsd");
404 412
405 /* After daemonize() this kernel thread shares current->fs 413 /* At this point, the thread shares current->fs
406 * with the init process. We need to create files with a 414 * with the init process. We need to create files with a
407 * umask of 0 instead of init's umask. */ 415 * umask of 0 instead of init's umask. */
408 fsp = copy_fs_struct(current->fs); 416 fsp = copy_fs_struct(current->fs);
@@ -414,14 +422,17 @@ nfsd(struct svc_rqst *rqstp)
414 current->fs = fsp; 422 current->fs = fsp;
415 current->fs->umask = 0; 423 current->fs->umask = 0;
416 424
417 siginitsetinv(&shutdown_mask, SHUTDOWN_SIGS); 425 /*
418 siginitsetinv(&allowed_mask, ALLOWED_SIGS); 426 * thread is spawned with all signals set to SIG_IGN, re-enable
427 * the ones that will bring down the thread
428 */
429 allow_signal(SIGKILL);
430 allow_signal(SIGHUP);
431 allow_signal(SIGINT);
432 allow_signal(SIGQUIT);
419 433
420 nfsdstats.th_cnt++; 434 nfsdstats.th_cnt++;
421 435 mutex_unlock(&nfsd_mutex);
422 rqstp->rq_task = current;
423
424 unlock_kernel();
425 436
426 /* 437 /*
427 * We want less throttling in balance_dirty_pages() so that nfs to 438 * We want less throttling in balance_dirty_pages() so that nfs to
@@ -435,26 +446,30 @@ nfsd(struct svc_rqst *rqstp)
435 * The main request loop 446 * The main request loop
436 */ 447 */
437 for (;;) { 448 for (;;) {
438 /* Block all but the shutdown signals */
439 sigprocmask(SIG_SETMASK, &shutdown_mask, NULL);
440
441 /* 449 /*
442 * Find a socket with data available and call its 450 * Find a socket with data available and call its
443 * recvfrom routine. 451 * recvfrom routine.
444 */ 452 */
445 while ((err = svc_recv(rqstp, 60*60*HZ)) == -EAGAIN) 453 while ((err = svc_recv(rqstp, 60*60*HZ)) == -EAGAIN)
446 ; 454 ;
447 if (err < 0) 455 if (err == -EINTR)
448 break; 456 break;
457 else if (err < 0) {
458 if (err != preverr) {
459 printk(KERN_WARNING "%s: unexpected error "
460 "from svc_recv (%d)\n", __func__, -err);
461 preverr = err;
462 }
463 schedule_timeout_uninterruptible(HZ);
464 continue;
465 }
466
449 update_thread_usage(atomic_read(&nfsd_busy)); 467 update_thread_usage(atomic_read(&nfsd_busy));
450 atomic_inc(&nfsd_busy); 468 atomic_inc(&nfsd_busy);
451 469
452 /* Lock the export hash tables for reading. */ 470 /* Lock the export hash tables for reading. */
453 exp_readlock(); 471 exp_readlock();
454 472
455 /* Process request with signals blocked. */
456 sigprocmask(SIG_SETMASK, &allowed_mask, NULL);
457
458 svc_process(rqstp); 473 svc_process(rqstp);
459 474
460 /* Unlock export hash tables */ 475 /* Unlock export hash tables */
@@ -463,22 +478,10 @@ nfsd(struct svc_rqst *rqstp)
463 atomic_dec(&nfsd_busy); 478 atomic_dec(&nfsd_busy);
464 } 479 }
465 480
466 if (err != -EINTR) {
467 printk(KERN_WARNING "nfsd: terminating on error %d\n", -err);
468 } else {
469 unsigned int signo;
470
471 for (signo = 1; signo <= _NSIG; signo++)
472 if (sigismember(&current->pending.signal, signo) &&
473 !sigismember(&current->blocked, signo))
474 break;
475 killsig = signo;
476 }
477 /* Clear signals before calling svc_exit_thread() */ 481 /* Clear signals before calling svc_exit_thread() */
478 flush_signals(current); 482 flush_signals(current);
479 483
480 lock_kernel(); 484 mutex_lock(&nfsd_mutex);
481
482 nfsdstats.th_cnt --; 485 nfsdstats.th_cnt --;
483 486
484out: 487out:
@@ -486,8 +489,9 @@ out:
486 svc_exit_thread(rqstp); 489 svc_exit_thread(rqstp);
487 490
488 /* Release module */ 491 /* Release module */
489 unlock_kernel(); 492 mutex_unlock(&nfsd_mutex);
490 module_put_and_exit(0); 493 module_put_and_exit(0);
494 return 0;
491} 495}
492 496
493static __be32 map_new_errors(u32 vers, __be32 nfserr) 497static __be32 map_new_errors(u32 vers, __be32 nfserr)
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index a3a291f771f4..0f4481e0502d 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -144,7 +144,7 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
144 dprintk("nfsd: nfsd_lookup(fh %s, %.*s)\n", SVCFH_fmt(fhp), len,name); 144 dprintk("nfsd: nfsd_lookup(fh %s, %.*s)\n", SVCFH_fmt(fhp), len,name);
145 145
146 /* Obtain dentry and export. */ 146 /* Obtain dentry and export. */
147 err = fh_verify(rqstp, fhp, S_IFDIR, MAY_EXEC); 147 err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC);
148 if (err) 148 if (err)
149 return err; 149 return err;
150 150
@@ -262,14 +262,14 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
262{ 262{
263 struct dentry *dentry; 263 struct dentry *dentry;
264 struct inode *inode; 264 struct inode *inode;
265 int accmode = MAY_SATTR; 265 int accmode = NFSD_MAY_SATTR;
266 int ftype = 0; 266 int ftype = 0;
267 __be32 err; 267 __be32 err;
268 int host_err; 268 int host_err;
269 int size_change = 0; 269 int size_change = 0;
270 270
271 if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE)) 271 if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
272 accmode |= MAY_WRITE|MAY_OWNER_OVERRIDE; 272 accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE;
273 if (iap->ia_valid & ATTR_SIZE) 273 if (iap->ia_valid & ATTR_SIZE)
274 ftype = S_IFREG; 274 ftype = S_IFREG;
275 275
@@ -331,7 +331,8 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
331 */ 331 */
332 if (iap->ia_valid & ATTR_SIZE) { 332 if (iap->ia_valid & ATTR_SIZE) {
333 if (iap->ia_size < inode->i_size) { 333 if (iap->ia_size < inode->i_size) {
334 err = nfsd_permission(rqstp, fhp->fh_export, dentry, MAY_TRUNC|MAY_OWNER_OVERRIDE); 334 err = nfsd_permission(rqstp, fhp->fh_export, dentry,
335 NFSD_MAY_TRUNC|NFSD_MAY_OWNER_OVERRIDE);
335 if (err) 336 if (err)
336 goto out; 337 goto out;
337 } 338 }
@@ -462,7 +463,7 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
462 unsigned int flags = 0; 463 unsigned int flags = 0;
463 464
464 /* Get inode */ 465 /* Get inode */
465 error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, MAY_SATTR); 466 error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, NFSD_MAY_SATTR);
466 if (error) 467 if (error)
467 return error; 468 return error;
468 469
@@ -563,20 +564,20 @@ struct accessmap {
563 int how; 564 int how;
564}; 565};
565static struct accessmap nfs3_regaccess[] = { 566static struct accessmap nfs3_regaccess[] = {
566 { NFS3_ACCESS_READ, MAY_READ }, 567 { NFS3_ACCESS_READ, NFSD_MAY_READ },
567 { NFS3_ACCESS_EXECUTE, MAY_EXEC }, 568 { NFS3_ACCESS_EXECUTE, NFSD_MAY_EXEC },
568 { NFS3_ACCESS_MODIFY, MAY_WRITE|MAY_TRUNC }, 569 { NFS3_ACCESS_MODIFY, NFSD_MAY_WRITE|NFSD_MAY_TRUNC },
569 { NFS3_ACCESS_EXTEND, MAY_WRITE }, 570 { NFS3_ACCESS_EXTEND, NFSD_MAY_WRITE },
570 571
571 { 0, 0 } 572 { 0, 0 }
572}; 573};
573 574
574static struct accessmap nfs3_diraccess[] = { 575static struct accessmap nfs3_diraccess[] = {
575 { NFS3_ACCESS_READ, MAY_READ }, 576 { NFS3_ACCESS_READ, NFSD_MAY_READ },
576 { NFS3_ACCESS_LOOKUP, MAY_EXEC }, 577 { NFS3_ACCESS_LOOKUP, NFSD_MAY_EXEC },
577 { NFS3_ACCESS_MODIFY, MAY_EXEC|MAY_WRITE|MAY_TRUNC }, 578 { NFS3_ACCESS_MODIFY, NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC},
578 { NFS3_ACCESS_EXTEND, MAY_EXEC|MAY_WRITE }, 579 { NFS3_ACCESS_EXTEND, NFSD_MAY_EXEC|NFSD_MAY_WRITE },
579 { NFS3_ACCESS_DELETE, MAY_REMOVE }, 580 { NFS3_ACCESS_DELETE, NFSD_MAY_REMOVE },
580 581
581 { 0, 0 } 582 { 0, 0 }
582}; 583};
@@ -589,10 +590,10 @@ static struct accessmap nfs3_anyaccess[] = {
589 * mainly at mode bits, and we make sure to ignore read-only 590 * mainly at mode bits, and we make sure to ignore read-only
590 * filesystem checks 591 * filesystem checks
591 */ 592 */
592 { NFS3_ACCESS_READ, MAY_READ }, 593 { NFS3_ACCESS_READ, NFSD_MAY_READ },
593 { NFS3_ACCESS_EXECUTE, MAY_EXEC }, 594 { NFS3_ACCESS_EXECUTE, NFSD_MAY_EXEC },
594 { NFS3_ACCESS_MODIFY, MAY_WRITE|MAY_LOCAL_ACCESS }, 595 { NFS3_ACCESS_MODIFY, NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS },
595 { NFS3_ACCESS_EXTEND, MAY_WRITE|MAY_LOCAL_ACCESS }, 596 { NFS3_ACCESS_EXTEND, NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS },
596 597
597 { 0, 0 } 598 { 0, 0 }
598}; 599};
@@ -606,7 +607,7 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *suppor
606 u32 query, result = 0, sresult = 0; 607 u32 query, result = 0, sresult = 0;
607 __be32 error; 608 __be32 error;
608 609
609 error = fh_verify(rqstp, fhp, 0, MAY_NOP); 610 error = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP);
610 if (error) 611 if (error)
611 goto out; 612 goto out;
612 613
@@ -678,7 +679,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
678 * and (hopefully) checked permission - so allow OWNER_OVERRIDE 679 * and (hopefully) checked permission - so allow OWNER_OVERRIDE
679 * in case a chmod has now revoked permission. 680 * in case a chmod has now revoked permission.
680 */ 681 */
681 err = fh_verify(rqstp, fhp, type, access | MAY_OWNER_OVERRIDE); 682 err = fh_verify(rqstp, fhp, type, access | NFSD_MAY_OWNER_OVERRIDE);
682 if (err) 683 if (err)
683 goto out; 684 goto out;
684 685
@@ -689,7 +690,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
689 * or any access when mandatory locking enabled 690 * or any access when mandatory locking enabled
690 */ 691 */
691 err = nfserr_perm; 692 err = nfserr_perm;
692 if (IS_APPEND(inode) && (access & MAY_WRITE)) 693 if (IS_APPEND(inode) && (access & NFSD_MAY_WRITE))
693 goto out; 694 goto out;
694 /* 695 /*
695 * We must ignore files (but only files) which might have mandatory 696 * We must ignore files (but only files) which might have mandatory
@@ -706,14 +707,14 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
706 * Check to see if there are any leases on this file. 707 * Check to see if there are any leases on this file.
707 * This may block while leases are broken. 708 * This may block while leases are broken.
708 */ 709 */
709 host_err = break_lease(inode, O_NONBLOCK | ((access & MAY_WRITE) ? FMODE_WRITE : 0)); 710 host_err = break_lease(inode, O_NONBLOCK | ((access & NFSD_MAY_WRITE) ? FMODE_WRITE : 0));
710 if (host_err == -EWOULDBLOCK) 711 if (host_err == -EWOULDBLOCK)
711 host_err = -ETIMEDOUT; 712 host_err = -ETIMEDOUT;
712 if (host_err) /* NOMEM or WOULDBLOCK */ 713 if (host_err) /* NOMEM or WOULDBLOCK */
713 goto out_nfserr; 714 goto out_nfserr;
714 715
715 if (access & MAY_WRITE) { 716 if (access & NFSD_MAY_WRITE) {
716 if (access & MAY_READ) 717 if (access & NFSD_MAY_READ)
717 flags = O_RDWR|O_LARGEFILE; 718 flags = O_RDWR|O_LARGEFILE;
718 else 719 else
719 flags = O_WRONLY|O_LARGEFILE; 720 flags = O_WRONLY|O_LARGEFILE;
@@ -1069,12 +1070,12 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
1069 1070
1070 if (file) { 1071 if (file) {
1071 err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, 1072 err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
1072 MAY_READ|MAY_OWNER_OVERRIDE); 1073 NFSD_MAY_READ|NFSD_MAY_OWNER_OVERRIDE);
1073 if (err) 1074 if (err)
1074 goto out; 1075 goto out;
1075 err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count); 1076 err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count);
1076 } else { 1077 } else {
1077 err = nfsd_open(rqstp, fhp, S_IFREG, MAY_READ, &file); 1078 err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
1078 if (err) 1079 if (err)
1079 goto out; 1080 goto out;
1080 err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count); 1081 err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count);
@@ -1098,13 +1099,13 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
1098 1099
1099 if (file) { 1100 if (file) {
1100 err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, 1101 err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
1101 MAY_WRITE|MAY_OWNER_OVERRIDE); 1102 NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE);
1102 if (err) 1103 if (err)
1103 goto out; 1104 goto out;
1104 err = nfsd_vfs_write(rqstp, fhp, file, offset, vec, vlen, cnt, 1105 err = nfsd_vfs_write(rqstp, fhp, file, offset, vec, vlen, cnt,
1105 stablep); 1106 stablep);
1106 } else { 1107 } else {
1107 err = nfsd_open(rqstp, fhp, S_IFREG, MAY_WRITE, &file); 1108 err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &file);
1108 if (err) 1109 if (err)
1109 goto out; 1110 goto out;
1110 1111
@@ -1136,7 +1137,8 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
1136 if ((u64)count > ~(u64)offset) 1137 if ((u64)count > ~(u64)offset)
1137 return nfserr_inval; 1138 return nfserr_inval;
1138 1139
1139 if ((err = nfsd_open(rqstp, fhp, S_IFREG, MAY_WRITE, &file)) != 0) 1140 err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &file);
1141 if (err)
1140 return err; 1142 return err;
1141 if (EX_ISSYNC(fhp->fh_export)) { 1143 if (EX_ISSYNC(fhp->fh_export)) {
1142 if (file->f_op && file->f_op->fsync) { 1144 if (file->f_op && file->f_op->fsync) {
@@ -1197,7 +1199,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
1197 if (isdotent(fname, flen)) 1199 if (isdotent(fname, flen))
1198 goto out; 1200 goto out;
1199 1201
1200 err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE); 1202 err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE);
1201 if (err) 1203 if (err)
1202 goto out; 1204 goto out;
1203 1205
@@ -1248,36 +1250,34 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
1248 iap->ia_mode = 0; 1250 iap->ia_mode = 0;
1249 iap->ia_mode = (iap->ia_mode & S_IALLUGO) | type; 1251 iap->ia_mode = (iap->ia_mode & S_IALLUGO) | type;
1250 1252
1253 err = nfserr_inval;
1254 if (!S_ISREG(type) && !S_ISDIR(type) && !special_file(type)) {
1255 printk(KERN_WARNING "nfsd: bad file type %o in nfsd_create\n",
1256 type);
1257 goto out;
1258 }
1259
1260 host_err = mnt_want_write(fhp->fh_export->ex_path.mnt);
1261 if (host_err)
1262 goto out_nfserr;
1263
1251 /* 1264 /*
1252 * Get the dir op function pointer. 1265 * Get the dir op function pointer.
1253 */ 1266 */
1254 err = 0; 1267 err = 0;
1255 switch (type) { 1268 switch (type) {
1256 case S_IFREG: 1269 case S_IFREG:
1257 host_err = mnt_want_write(fhp->fh_export->ex_path.mnt);
1258 if (host_err)
1259 goto out_nfserr;
1260 host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL); 1270 host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
1261 break; 1271 break;
1262 case S_IFDIR: 1272 case S_IFDIR:
1263 host_err = mnt_want_write(fhp->fh_export->ex_path.mnt);
1264 if (host_err)
1265 goto out_nfserr;
1266 host_err = vfs_mkdir(dirp, dchild, iap->ia_mode); 1273 host_err = vfs_mkdir(dirp, dchild, iap->ia_mode);
1267 break; 1274 break;
1268 case S_IFCHR: 1275 case S_IFCHR:
1269 case S_IFBLK: 1276 case S_IFBLK:
1270 case S_IFIFO: 1277 case S_IFIFO:
1271 case S_IFSOCK: 1278 case S_IFSOCK:
1272 host_err = mnt_want_write(fhp->fh_export->ex_path.mnt);
1273 if (host_err)
1274 goto out_nfserr;
1275 host_err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev); 1279 host_err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
1276 break; 1280 break;
1277 default:
1278 printk("nfsd: bad file type %o in nfsd_create\n", type);
1279 host_err = -EINVAL;
1280 goto out_nfserr;
1281 } 1281 }
1282 if (host_err < 0) { 1282 if (host_err < 0) {
1283 mnt_drop_write(fhp->fh_export->ex_path.mnt); 1283 mnt_drop_write(fhp->fh_export->ex_path.mnt);
@@ -1289,7 +1289,6 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
1289 write_inode_now(dchild->d_inode, 1); 1289 write_inode_now(dchild->d_inode, 1);
1290 } 1290 }
1291 1291
1292
1293 err2 = nfsd_create_setattr(rqstp, resfhp, iap); 1292 err2 = nfsd_create_setattr(rqstp, resfhp, iap);
1294 if (err2) 1293 if (err2)
1295 err = err2; 1294 err = err2;
@@ -1334,7 +1333,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
1334 goto out; 1333 goto out;
1335 if (!(iap->ia_valid & ATTR_MODE)) 1334 if (!(iap->ia_valid & ATTR_MODE))
1336 iap->ia_mode = 0; 1335 iap->ia_mode = 0;
1337 err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE); 1336 err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE);
1338 if (err) 1337 if (err)
1339 goto out; 1338 goto out;
1340 1339
@@ -1471,7 +1470,7 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)
1471 __be32 err; 1470 __be32 err;
1472 int host_err; 1471 int host_err;
1473 1472
1474 err = fh_verify(rqstp, fhp, S_IFLNK, MAY_NOP); 1473 err = fh_verify(rqstp, fhp, S_IFLNK, NFSD_MAY_NOP);
1475 if (err) 1474 if (err)
1476 goto out; 1475 goto out;
1477 1476
@@ -1526,7 +1525,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
1526 if (isdotent(fname, flen)) 1525 if (isdotent(fname, flen))
1527 goto out; 1526 goto out;
1528 1527
1529 err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE); 1528 err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE);
1530 if (err) 1529 if (err)
1531 goto out; 1530 goto out;
1532 fh_lock(fhp); 1531 fh_lock(fhp);
@@ -1591,10 +1590,10 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
1591 __be32 err; 1590 __be32 err;
1592 int host_err; 1591 int host_err;
1593 1592
1594 err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_CREATE); 1593 err = fh_verify(rqstp, ffhp, S_IFDIR, NFSD_MAY_CREATE);
1595 if (err) 1594 if (err)
1596 goto out; 1595 goto out;
1597 err = fh_verify(rqstp, tfhp, -S_IFDIR, MAY_NOP); 1596 err = fh_verify(rqstp, tfhp, -S_IFDIR, NFSD_MAY_NOP);
1598 if (err) 1597 if (err)
1599 goto out; 1598 goto out;
1600 1599
@@ -1661,10 +1660,10 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
1661 __be32 err; 1660 __be32 err;
1662 int host_err; 1661 int host_err;
1663 1662
1664 err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_REMOVE); 1663 err = fh_verify(rqstp, ffhp, S_IFDIR, NFSD_MAY_REMOVE);
1665 if (err) 1664 if (err)
1666 goto out; 1665 goto out;
1667 err = fh_verify(rqstp, tfhp, S_IFDIR, MAY_CREATE); 1666 err = fh_verify(rqstp, tfhp, S_IFDIR, NFSD_MAY_CREATE);
1668 if (err) 1667 if (err)
1669 goto out; 1668 goto out;
1670 1669
@@ -1768,7 +1767,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
1768 err = nfserr_acces; 1767 err = nfserr_acces;
1769 if (!flen || isdotent(fname, flen)) 1768 if (!flen || isdotent(fname, flen))
1770 goto out; 1769 goto out;
1771 err = fh_verify(rqstp, fhp, S_IFDIR, MAY_REMOVE); 1770 err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_REMOVE);
1772 if (err) 1771 if (err)
1773 goto out; 1772 goto out;
1774 1773
@@ -1834,7 +1833,7 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp,
1834 struct file *file; 1833 struct file *file;
1835 loff_t offset = *offsetp; 1834 loff_t offset = *offsetp;
1836 1835
1837 err = nfsd_open(rqstp, fhp, S_IFDIR, MAY_READ, &file); 1836 err = nfsd_open(rqstp, fhp, S_IFDIR, NFSD_MAY_READ, &file);
1838 if (err) 1837 if (err)
1839 goto out; 1838 goto out;
1840 1839
@@ -1875,7 +1874,7 @@ out:
1875__be32 1874__be32
1876nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat) 1875nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat)
1877{ 1876{
1878 __be32 err = fh_verify(rqstp, fhp, 0, MAY_NOP); 1877 __be32 err = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP);
1879 if (!err && vfs_statfs(fhp->fh_dentry,stat)) 1878 if (!err && vfs_statfs(fhp->fh_dentry,stat))
1880 err = nfserr_io; 1879 err = nfserr_io;
1881 return err; 1880 return err;
@@ -1896,18 +1895,18 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
1896 struct inode *inode = dentry->d_inode; 1895 struct inode *inode = dentry->d_inode;
1897 int err; 1896 int err;
1898 1897
1899 if (acc == MAY_NOP) 1898 if (acc == NFSD_MAY_NOP)
1900 return 0; 1899 return 0;
1901#if 0 1900#if 0
1902 dprintk("nfsd: permission 0x%x%s%s%s%s%s%s%s mode 0%o%s%s%s\n", 1901 dprintk("nfsd: permission 0x%x%s%s%s%s%s%s%s mode 0%o%s%s%s\n",
1903 acc, 1902 acc,
1904 (acc & MAY_READ)? " read" : "", 1903 (acc & NFSD_MAY_READ)? " read" : "",
1905 (acc & MAY_WRITE)? " write" : "", 1904 (acc & NFSD_MAY_WRITE)? " write" : "",
1906 (acc & MAY_EXEC)? " exec" : "", 1905 (acc & NFSD_MAY_EXEC)? " exec" : "",
1907 (acc & MAY_SATTR)? " sattr" : "", 1906 (acc & NFSD_MAY_SATTR)? " sattr" : "",
1908 (acc & MAY_TRUNC)? " trunc" : "", 1907 (acc & NFSD_MAY_TRUNC)? " trunc" : "",
1909 (acc & MAY_LOCK)? " lock" : "", 1908 (acc & NFSD_MAY_LOCK)? " lock" : "",
1910 (acc & MAY_OWNER_OVERRIDE)? " owneroverride" : "", 1909 (acc & NFSD_MAY_OWNER_OVERRIDE)? " owneroverride" : "",
1911 inode->i_mode, 1910 inode->i_mode,
1912 IS_IMMUTABLE(inode)? " immut" : "", 1911 IS_IMMUTABLE(inode)? " immut" : "",
1913 IS_APPEND(inode)? " append" : "", 1912 IS_APPEND(inode)? " append" : "",
@@ -1920,18 +1919,18 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
1920 * system. But if it is IRIX doing check on write-access for a 1919 * system. But if it is IRIX doing check on write-access for a
1921 * device special file, we ignore rofs. 1920 * device special file, we ignore rofs.
1922 */ 1921 */
1923 if (!(acc & MAY_LOCAL_ACCESS)) 1922 if (!(acc & NFSD_MAY_LOCAL_ACCESS))
1924 if (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC)) { 1923 if (acc & (NFSD_MAY_WRITE | NFSD_MAY_SATTR | NFSD_MAY_TRUNC)) {
1925 if (exp_rdonly(rqstp, exp) || 1924 if (exp_rdonly(rqstp, exp) ||
1926 __mnt_is_readonly(exp->ex_path.mnt)) 1925 __mnt_is_readonly(exp->ex_path.mnt))
1927 return nfserr_rofs; 1926 return nfserr_rofs;
1928 if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode)) 1927 if (/* (acc & NFSD_MAY_WRITE) && */ IS_IMMUTABLE(inode))
1929 return nfserr_perm; 1928 return nfserr_perm;
1930 } 1929 }
1931 if ((acc & MAY_TRUNC) && IS_APPEND(inode)) 1930 if ((acc & NFSD_MAY_TRUNC) && IS_APPEND(inode))
1932 return nfserr_perm; 1931 return nfserr_perm;
1933 1932
1934 if (acc & MAY_LOCK) { 1933 if (acc & NFSD_MAY_LOCK) {
1935 /* If we cannot rely on authentication in NLM requests, 1934 /* If we cannot rely on authentication in NLM requests,
1936 * just allow locks, otherwise require read permission, or 1935 * just allow locks, otherwise require read permission, or
1937 * ownership 1936 * ownership
@@ -1939,7 +1938,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
1939 if (exp->ex_flags & NFSEXP_NOAUTHNLM) 1938 if (exp->ex_flags & NFSEXP_NOAUTHNLM)
1940 return 0; 1939 return 0;
1941 else 1940 else
1942 acc = MAY_READ | MAY_OWNER_OVERRIDE; 1941 acc = NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE;
1943 } 1942 }
1944 /* 1943 /*
1945 * The file owner always gets access permission for accesses that 1944 * The file owner always gets access permission for accesses that
@@ -1955,15 +1954,16 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
1955 * We must trust the client to do permission checking - using "ACCESS" 1954 * We must trust the client to do permission checking - using "ACCESS"
1956 * with NFSv3. 1955 * with NFSv3.
1957 */ 1956 */
1958 if ((acc & MAY_OWNER_OVERRIDE) && 1957 if ((acc & NFSD_MAY_OWNER_OVERRIDE) &&
1959 inode->i_uid == current->fsuid) 1958 inode->i_uid == current->fsuid)
1960 return 0; 1959 return 0;
1961 1960
1961 /* This assumes NFSD_MAY_{READ,WRITE,EXEC} == MAY_{READ,WRITE,EXEC} */
1962 err = permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC), NULL); 1962 err = permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC), NULL);
1963 1963
1964 /* Allow read access to binaries even when mode 111 */ 1964 /* Allow read access to binaries even when mode 111 */
1965 if (err == -EACCES && S_ISREG(inode->i_mode) && 1965 if (err == -EACCES && S_ISREG(inode->i_mode) &&
1966 acc == (MAY_READ | MAY_OWNER_OVERRIDE)) 1966 acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE))
1967 err = permission(inode, MAY_EXEC, NULL); 1967 err = permission(inode, MAY_EXEC, NULL);
1968 1968
1969 return err? nfserrno(err) : 0; 1969 return err? nfserrno(err) : 0;