diff options
Diffstat (limited to 'fs/nfsd/nfs4proc.c')
-rw-r--r-- | fs/nfsd/nfs4proc.c | 129 |
1 files changed, 108 insertions, 21 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index b2883e9c6381..7c8801769a3c 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -51,6 +51,78 @@ | |||
51 | 51 | ||
52 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 52 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
53 | 53 | ||
54 | static u32 nfsd_attrmask[] = { | ||
55 | NFSD_WRITEABLE_ATTRS_WORD0, | ||
56 | NFSD_WRITEABLE_ATTRS_WORD1, | ||
57 | NFSD_WRITEABLE_ATTRS_WORD2 | ||
58 | }; | ||
59 | |||
60 | static u32 nfsd41_ex_attrmask[] = { | ||
61 | NFSD_SUPPATTR_EXCLCREAT_WORD0, | ||
62 | NFSD_SUPPATTR_EXCLCREAT_WORD1, | ||
63 | NFSD_SUPPATTR_EXCLCREAT_WORD2 | ||
64 | }; | ||
65 | |||
66 | static __be32 | ||
67 | check_attr_support(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | ||
68 | u32 *bmval, u32 *writable) | ||
69 | { | ||
70 | struct dentry *dentry = cstate->current_fh.fh_dentry; | ||
71 | struct svc_export *exp = cstate->current_fh.fh_export; | ||
72 | |||
73 | /* | ||
74 | * Check about attributes are supported by the NFSv4 server or not. | ||
75 | * According to spec, unsupported attributes return ERR_ATTRNOTSUPP. | ||
76 | */ | ||
77 | if ((bmval[0] & ~nfsd_suppattrs0(cstate->minorversion)) || | ||
78 | (bmval[1] & ~nfsd_suppattrs1(cstate->minorversion)) || | ||
79 | (bmval[2] & ~nfsd_suppattrs2(cstate->minorversion))) | ||
80 | return nfserr_attrnotsupp; | ||
81 | |||
82 | /* | ||
83 | * Check FATTR4_WORD0_ACL & FATTR4_WORD0_FS_LOCATIONS can be supported | ||
84 | * in current environment or not. | ||
85 | */ | ||
86 | if (bmval[0] & FATTR4_WORD0_ACL) { | ||
87 | if (!IS_POSIXACL(dentry->d_inode)) | ||
88 | return nfserr_attrnotsupp; | ||
89 | } | ||
90 | if (bmval[0] & FATTR4_WORD0_FS_LOCATIONS) { | ||
91 | if (exp->ex_fslocs.locations == NULL) | ||
92 | return nfserr_attrnotsupp; | ||
93 | } | ||
94 | |||
95 | /* | ||
96 | * According to spec, read-only attributes return ERR_INVAL. | ||
97 | */ | ||
98 | if (writable) { | ||
99 | if ((bmval[0] & ~writable[0]) || (bmval[1] & ~writable[1]) || | ||
100 | (bmval[2] & ~writable[2])) | ||
101 | return nfserr_inval; | ||
102 | } | ||
103 | |||
104 | return nfs_ok; | ||
105 | } | ||
106 | |||
107 | static __be32 | ||
108 | nfsd4_check_open_attributes(struct svc_rqst *rqstp, | ||
109 | struct nfsd4_compound_state *cstate, struct nfsd4_open *open) | ||
110 | { | ||
111 | __be32 status = nfs_ok; | ||
112 | |||
113 | if (open->op_create == NFS4_OPEN_CREATE) { | ||
114 | if (open->op_createmode == NFS4_CREATE_UNCHECKED | ||
115 | || open->op_createmode == NFS4_CREATE_GUARDED) | ||
116 | status = check_attr_support(rqstp, cstate, | ||
117 | open->op_bmval, nfsd_attrmask); | ||
118 | else if (open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1) | ||
119 | status = check_attr_support(rqstp, cstate, | ||
120 | open->op_bmval, nfsd41_ex_attrmask); | ||
121 | } | ||
122 | |||
123 | return status; | ||
124 | } | ||
125 | |||
54 | static inline void | 126 | static inline void |
55 | fh_dup2(struct svc_fh *dst, struct svc_fh *src) | 127 | fh_dup2(struct svc_fh *dst, struct svc_fh *src) |
56 | { | 128 | { |
@@ -225,6 +297,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
225 | if (status) | 297 | if (status) |
226 | goto out; | 298 | goto out; |
227 | 299 | ||
300 | status = nfsd4_check_open_attributes(rqstp, cstate, open); | ||
301 | if (status) | ||
302 | goto out; | ||
303 | |||
228 | /* Openowner is now set, so sequence id will get bumped. Now we need | 304 | /* Openowner is now set, so sequence id will get bumped. Now we need |
229 | * these checks before we do any creates: */ | 305 | * these checks before we do any creates: */ |
230 | status = nfserr_grace; | 306 | status = nfserr_grace; |
@@ -395,6 +471,11 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
395 | if (status) | 471 | if (status) |
396 | return status; | 472 | return status; |
397 | 473 | ||
474 | status = check_attr_support(rqstp, cstate, create->cr_bmval, | ||
475 | nfsd_attrmask); | ||
476 | if (status) | ||
477 | return status; | ||
478 | |||
398 | switch (create->cr_type) { | 479 | switch (create->cr_type) { |
399 | case NF4LNK: | 480 | case NF4LNK: |
400 | /* ugh! we have to null-terminate the linktext, or | 481 | /* ugh! we have to null-terminate the linktext, or |
@@ -689,6 +770,12 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
689 | if (status) | 770 | if (status) |
690 | return status; | 771 | return status; |
691 | status = nfs_ok; | 772 | status = nfs_ok; |
773 | |||
774 | status = check_attr_support(rqstp, cstate, setattr->sa_bmval, | ||
775 | nfsd_attrmask); | ||
776 | if (status) | ||
777 | goto out; | ||
778 | |||
692 | if (setattr->sa_acl != NULL) | 779 | if (setattr->sa_acl != NULL) |
693 | status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh, | 780 | status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh, |
694 | setattr->sa_acl); | 781 | setattr->sa_acl); |
@@ -763,10 +850,10 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
763 | if (status) | 850 | if (status) |
764 | return status; | 851 | return status; |
765 | 852 | ||
766 | if ((verify->ve_bmval[0] & ~nfsd_suppattrs0(cstate->minorversion)) | 853 | status = check_attr_support(rqstp, cstate, verify->ve_bmval, NULL); |
767 | || (verify->ve_bmval[1] & ~nfsd_suppattrs1(cstate->minorversion)) | 854 | if (status) |
768 | || (verify->ve_bmval[2] & ~nfsd_suppattrs2(cstate->minorversion))) | 855 | return status; |
769 | return nfserr_attrnotsupp; | 856 | |
770 | if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR) | 857 | if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR) |
771 | || (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)) | 858 | || (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)) |
772 | return nfserr_inval; | 859 | return nfserr_inval; |
@@ -1226,24 +1313,9 @@ static const char *nfsd4_op_name(unsigned opnum) | |||
1226 | return "unknown_operation"; | 1313 | return "unknown_operation"; |
1227 | } | 1314 | } |
1228 | 1315 | ||
1229 | #define nfs4svc_decode_voidargs NULL | ||
1230 | #define nfs4svc_release_void NULL | ||
1231 | #define nfsd4_voidres nfsd4_voidargs | 1316 | #define nfsd4_voidres nfsd4_voidargs |
1232 | #define nfs4svc_release_compound NULL | ||
1233 | struct nfsd4_voidargs { int dummy; }; | 1317 | struct nfsd4_voidargs { int dummy; }; |
1234 | 1318 | ||
1235 | #define PROC(name, argt, rest, relt, cache, respsize) \ | ||
1236 | { (svc_procfunc) nfsd4_proc_##name, \ | ||
1237 | (kxdrproc_t) nfs4svc_decode_##argt##args, \ | ||
1238 | (kxdrproc_t) nfs4svc_encode_##rest##res, \ | ||
1239 | (kxdrproc_t) nfs4svc_release_##relt, \ | ||
1240 | sizeof(struct nfsd4_##argt##args), \ | ||
1241 | sizeof(struct nfsd4_##rest##res), \ | ||
1242 | 0, \ | ||
1243 | cache, \ | ||
1244 | respsize, \ | ||
1245 | } | ||
1246 | |||
1247 | /* | 1319 | /* |
1248 | * TODO: At the present time, the NFSv4 server does not do XID caching | 1320 | * TODO: At the present time, the NFSv4 server does not do XID caching |
1249 | * of requests. Implementing XID caching would not be a serious problem, | 1321 | * of requests. Implementing XID caching would not be a serious problem, |
@@ -1255,8 +1327,23 @@ struct nfsd4_voidargs { int dummy; }; | |||
1255 | * better XID's. | 1327 | * better XID's. |
1256 | */ | 1328 | */ |
1257 | static struct svc_procedure nfsd_procedures4[2] = { | 1329 | static struct svc_procedure nfsd_procedures4[2] = { |
1258 | PROC(null, void, void, void, RC_NOCACHE, 1), | 1330 | [NFSPROC4_NULL] = { |
1259 | PROC(compound, compound, compound, compound, RC_NOCACHE, NFSD_BUFSIZE/4) | 1331 | .pc_func = (svc_procfunc) nfsd4_proc_null, |
1332 | .pc_encode = (kxdrproc_t) nfs4svc_encode_voidres, | ||
1333 | .pc_argsize = sizeof(struct nfsd4_voidargs), | ||
1334 | .pc_ressize = sizeof(struct nfsd4_voidres), | ||
1335 | .pc_cachetype = RC_NOCACHE, | ||
1336 | .pc_xdrressize = 1, | ||
1337 | }, | ||
1338 | [NFSPROC4_COMPOUND] = { | ||
1339 | .pc_func = (svc_procfunc) nfsd4_proc_compound, | ||
1340 | .pc_decode = (kxdrproc_t) nfs4svc_decode_compoundargs, | ||
1341 | .pc_encode = (kxdrproc_t) nfs4svc_encode_compoundres, | ||
1342 | .pc_argsize = sizeof(struct nfsd4_compoundargs), | ||
1343 | .pc_ressize = sizeof(struct nfsd4_compoundres), | ||
1344 | .pc_cachetype = RC_NOCACHE, | ||
1345 | .pc_xdrressize = NFSD_BUFSIZE/4, | ||
1346 | }, | ||
1260 | }; | 1347 | }; |
1261 | 1348 | ||
1262 | struct svc_version nfsd_version4 = { | 1349 | struct svc_version nfsd_version4 = { |