diff options
Diffstat (limited to 'fs/nfsd/nfs4proc.c')
-rw-r--r-- | fs/nfsd/nfs4proc.c | 374 |
1 files changed, 295 insertions, 79 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index e80777666618..fa383361bc61 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/file.h> | 35 | #include <linux/file.h> |
36 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
37 | 37 | ||
38 | #include "idmap.h" | ||
38 | #include "cache.h" | 39 | #include "cache.h" |
39 | #include "xdr4.h" | 40 | #include "xdr4.h" |
40 | #include "vfs.h" | 41 | #include "vfs.h" |
@@ -156,6 +157,8 @@ do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs | |||
156 | !(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) | 157 | !(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) |
157 | return nfserr_inval; | 158 | return nfserr_inval; |
158 | 159 | ||
160 | accmode |= NFSD_MAY_READ_IF_EXEC; | ||
161 | |||
159 | if (open->op_share_access & NFS4_SHARE_ACCESS_READ) | 162 | if (open->op_share_access & NFS4_SHARE_ACCESS_READ) |
160 | accmode |= NFSD_MAY_READ; | 163 | accmode |= NFSD_MAY_READ; |
161 | if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) | 164 | if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) |
@@ -168,12 +171,29 @@ do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs | |||
168 | return status; | 171 | return status; |
169 | } | 172 | } |
170 | 173 | ||
174 | static __be32 nfsd_check_obj_isreg(struct svc_fh *fh) | ||
175 | { | ||
176 | umode_t mode = fh->fh_dentry->d_inode->i_mode; | ||
177 | |||
178 | if (S_ISREG(mode)) | ||
179 | return nfs_ok; | ||
180 | if (S_ISDIR(mode)) | ||
181 | return nfserr_isdir; | ||
182 | /* | ||
183 | * Using err_symlink as our catch-all case may look odd; but | ||
184 | * there's no other obvious error for this case in 4.0, and we | ||
185 | * happen to know that it will cause the linux v4 client to do | ||
186 | * the right thing on attempts to open something other than a | ||
187 | * regular file. | ||
188 | */ | ||
189 | return nfserr_symlink; | ||
190 | } | ||
191 | |||
171 | static __be32 | 192 | static __be32 |
172 | do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) | 193 | do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) |
173 | { | 194 | { |
174 | struct svc_fh resfh; | 195 | struct svc_fh resfh; |
175 | __be32 status; | 196 | __be32 status; |
176 | int created = 0; | ||
177 | 197 | ||
178 | fh_init(&resfh, NFS4_FHSIZE); | 198 | fh_init(&resfh, NFS4_FHSIZE); |
179 | open->op_truncate = 0; | 199 | open->op_truncate = 0; |
@@ -202,7 +222,7 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o | |||
202 | open->op_fname.len, &open->op_iattr, | 222 | open->op_fname.len, &open->op_iattr, |
203 | &resfh, open->op_createmode, | 223 | &resfh, open->op_createmode, |
204 | (u32 *)open->op_verf.data, | 224 | (u32 *)open->op_verf.data, |
205 | &open->op_truncate, &created); | 225 | &open->op_truncate, &open->op_created); |
206 | 226 | ||
207 | /* | 227 | /* |
208 | * Following rfc 3530 14.2.16, use the returned bitmask | 228 | * Following rfc 3530 14.2.16, use the returned bitmask |
@@ -216,6 +236,9 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o | |||
216 | status = nfsd_lookup(rqstp, current_fh, | 236 | status = nfsd_lookup(rqstp, current_fh, |
217 | open->op_fname.data, open->op_fname.len, &resfh); | 237 | open->op_fname.data, open->op_fname.len, &resfh); |
218 | fh_unlock(current_fh); | 238 | fh_unlock(current_fh); |
239 | if (status) | ||
240 | goto out; | ||
241 | status = nfsd_check_obj_isreg(&resfh); | ||
219 | } | 242 | } |
220 | if (status) | 243 | if (status) |
221 | goto out; | 244 | goto out; |
@@ -227,9 +250,9 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o | |||
227 | fh_dup2(current_fh, &resfh); | 250 | fh_dup2(current_fh, &resfh); |
228 | 251 | ||
229 | /* set reply cache */ | 252 | /* set reply cache */ |
230 | fh_copy_shallow(&open->op_stateowner->so_replay.rp_openfh, | 253 | fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh, |
231 | &resfh.fh_handle); | 254 | &resfh.fh_handle); |
232 | if (!created) | 255 | if (!open->op_created) |
233 | status = do_open_permission(rqstp, current_fh, open, | 256 | status = do_open_permission(rqstp, current_fh, open, |
234 | NFSD_MAY_NOP); | 257 | NFSD_MAY_NOP); |
235 | 258 | ||
@@ -254,7 +277,7 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ | |||
254 | memset(&open->op_cinfo, 0, sizeof(struct nfsd4_change_info)); | 277 | memset(&open->op_cinfo, 0, sizeof(struct nfsd4_change_info)); |
255 | 278 | ||
256 | /* set replay cache */ | 279 | /* set replay cache */ |
257 | fh_copy_shallow(&open->op_stateowner->so_replay.rp_openfh, | 280 | fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh, |
258 | ¤t_fh->fh_handle); | 281 | ¤t_fh->fh_handle); |
259 | 282 | ||
260 | open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) && | 283 | open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) && |
@@ -283,14 +306,18 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
283 | __be32 status; | 306 | __be32 status; |
284 | struct nfsd4_compoundres *resp; | 307 | struct nfsd4_compoundres *resp; |
285 | 308 | ||
286 | dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n", | 309 | dprintk("NFSD: nfsd4_open filename %.*s op_openowner %p\n", |
287 | (int)open->op_fname.len, open->op_fname.data, | 310 | (int)open->op_fname.len, open->op_fname.data, |
288 | open->op_stateowner); | 311 | open->op_openowner); |
289 | 312 | ||
290 | /* This check required by spec. */ | 313 | /* This check required by spec. */ |
291 | if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL) | 314 | if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL) |
292 | return nfserr_inval; | 315 | return nfserr_inval; |
293 | 316 | ||
317 | /* We don't yet support WANT bits: */ | ||
318 | open->op_share_access &= NFS4_SHARE_ACCESS_MASK; | ||
319 | |||
320 | open->op_created = 0; | ||
294 | /* | 321 | /* |
295 | * RFC5661 18.51.3 | 322 | * RFC5661 18.51.3 |
296 | * Before RECLAIM_COMPLETE done, server should deny new lock | 323 | * Before RECLAIM_COMPLETE done, server should deny new lock |
@@ -309,7 +336,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
309 | resp = rqstp->rq_resp; | 336 | resp = rqstp->rq_resp; |
310 | status = nfsd4_process_open1(&resp->cstate, open); | 337 | status = nfsd4_process_open1(&resp->cstate, open); |
311 | if (status == nfserr_replay_me) { | 338 | if (status == nfserr_replay_me) { |
312 | struct nfs4_replay *rp = &open->op_stateowner->so_replay; | 339 | struct nfs4_replay *rp = &open->op_openowner->oo_owner.so_replay; |
313 | fh_put(&cstate->current_fh); | 340 | fh_put(&cstate->current_fh); |
314 | fh_copy_shallow(&cstate->current_fh.fh_handle, | 341 | fh_copy_shallow(&cstate->current_fh.fh_handle, |
315 | &rp->rp_openfh); | 342 | &rp->rp_openfh); |
@@ -339,32 +366,23 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
339 | switch (open->op_claim_type) { | 366 | switch (open->op_claim_type) { |
340 | case NFS4_OPEN_CLAIM_DELEGATE_CUR: | 367 | case NFS4_OPEN_CLAIM_DELEGATE_CUR: |
341 | case NFS4_OPEN_CLAIM_NULL: | 368 | case NFS4_OPEN_CLAIM_NULL: |
342 | /* | ||
343 | * (1) set CURRENT_FH to the file being opened, | ||
344 | * creating it if necessary, (2) set open->op_cinfo, | ||
345 | * (3) set open->op_truncate if the file is to be | ||
346 | * truncated after opening, (4) do permission checking. | ||
347 | */ | ||
348 | status = do_open_lookup(rqstp, &cstate->current_fh, | 369 | status = do_open_lookup(rqstp, &cstate->current_fh, |
349 | open); | 370 | open); |
350 | if (status) | 371 | if (status) |
351 | goto out; | 372 | goto out; |
352 | break; | 373 | break; |
353 | case NFS4_OPEN_CLAIM_PREVIOUS: | 374 | case NFS4_OPEN_CLAIM_PREVIOUS: |
354 | open->op_stateowner->so_confirmed = 1; | 375 | open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; |
355 | /* | 376 | case NFS4_OPEN_CLAIM_FH: |
356 | * The CURRENT_FH is already set to the file being | 377 | case NFS4_OPEN_CLAIM_DELEG_CUR_FH: |
357 | * opened. (1) set open->op_cinfo, (2) set | ||
358 | * open->op_truncate if the file is to be truncated | ||
359 | * after opening, (3) do permission checking. | ||
360 | */ | ||
361 | status = do_open_fhandle(rqstp, &cstate->current_fh, | 378 | status = do_open_fhandle(rqstp, &cstate->current_fh, |
362 | open); | 379 | open); |
363 | if (status) | 380 | if (status) |
364 | goto out; | 381 | goto out; |
365 | break; | 382 | break; |
383 | case NFS4_OPEN_CLAIM_DELEG_PREV_FH: | ||
366 | case NFS4_OPEN_CLAIM_DELEGATE_PREV: | 384 | case NFS4_OPEN_CLAIM_DELEGATE_PREV: |
367 | open->op_stateowner->so_confirmed = 1; | 385 | open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; |
368 | dprintk("NFSD: unsupported OPEN claim type %d\n", | 386 | dprintk("NFSD: unsupported OPEN claim type %d\n", |
369 | open->op_claim_type); | 387 | open->op_claim_type); |
370 | status = nfserr_notsupp; | 388 | status = nfserr_notsupp; |
@@ -381,12 +399,13 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
381 | * set, (2) sets open->op_stateid, (3) sets open->op_delegation. | 399 | * set, (2) sets open->op_stateid, (3) sets open->op_delegation. |
382 | */ | 400 | */ |
383 | status = nfsd4_process_open2(rqstp, &cstate->current_fh, open); | 401 | status = nfsd4_process_open2(rqstp, &cstate->current_fh, open); |
402 | WARN_ON(status && open->op_created); | ||
384 | out: | 403 | out: |
385 | if (open->op_stateowner) { | 404 | nfsd4_cleanup_open_state(open, status); |
386 | nfs4_get_stateowner(open->op_stateowner); | 405 | if (open->op_openowner) |
387 | cstate->replay_owner = open->op_stateowner; | 406 | cstate->replay_owner = &open->op_openowner->oo_owner; |
388 | } | 407 | else |
389 | nfs4_unlock_state(); | 408 | nfs4_unlock_state(); |
390 | return status; | 409 | return status; |
391 | } | 410 | } |
392 | 411 | ||
@@ -467,17 +486,12 @@ static __be32 | |||
467 | nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 486 | nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
468 | struct nfsd4_commit *commit) | 487 | struct nfsd4_commit *commit) |
469 | { | 488 | { |
470 | __be32 status; | ||
471 | |||
472 | u32 *p = (u32 *)commit->co_verf.data; | 489 | u32 *p = (u32 *)commit->co_verf.data; |
473 | *p++ = nfssvc_boot.tv_sec; | 490 | *p++ = nfssvc_boot.tv_sec; |
474 | *p++ = nfssvc_boot.tv_usec; | 491 | *p++ = nfssvc_boot.tv_usec; |
475 | 492 | ||
476 | status = nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset, | 493 | return nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset, |
477 | commit->co_count); | 494 | commit->co_count); |
478 | if (status == nfserr_symlink) | ||
479 | status = nfserr_inval; | ||
480 | return status; | ||
481 | } | 495 | } |
482 | 496 | ||
483 | static __be32 | 497 | static __be32 |
@@ -492,8 +506,6 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
492 | 506 | ||
493 | status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, | 507 | status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, |
494 | NFSD_MAY_CREATE); | 508 | NFSD_MAY_CREATE); |
495 | if (status == nfserr_symlink) | ||
496 | status = nfserr_notdir; | ||
497 | if (status) | 509 | if (status) |
498 | return status; | 510 | return status; |
499 | 511 | ||
@@ -691,7 +703,7 @@ nfsd4_readdir(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
691 | readdir->rd_bmval[1] &= nfsd_suppattrs1(cstate->minorversion); | 703 | readdir->rd_bmval[1] &= nfsd_suppattrs1(cstate->minorversion); |
692 | readdir->rd_bmval[2] &= nfsd_suppattrs2(cstate->minorversion); | 704 | readdir->rd_bmval[2] &= nfsd_suppattrs2(cstate->minorversion); |
693 | 705 | ||
694 | if ((cookie > ~(u32)0) || (cookie == 1) || (cookie == 2) || | 706 | if ((cookie == 1) || (cookie == 2) || |
695 | (cookie == 0 && memcmp(readdir->rd_verf.data, zeroverf.data, NFS4_VERIFIER_SIZE))) | 707 | (cookie == 0 && memcmp(readdir->rd_verf.data, zeroverf.data, NFS4_VERIFIER_SIZE))) |
696 | return nfserr_bad_cookie; | 708 | return nfserr_bad_cookie; |
697 | 709 | ||
@@ -719,8 +731,6 @@ nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
719 | return nfserr_grace; | 731 | return nfserr_grace; |
720 | status = nfsd_unlink(rqstp, &cstate->current_fh, 0, | 732 | status = nfsd_unlink(rqstp, &cstate->current_fh, 0, |
721 | remove->rm_name, remove->rm_namelen); | 733 | remove->rm_name, remove->rm_namelen); |
722 | if (status == nfserr_symlink) | ||
723 | return nfserr_notdir; | ||
724 | if (!status) { | 734 | if (!status) { |
725 | fh_unlock(&cstate->current_fh); | 735 | fh_unlock(&cstate->current_fh); |
726 | set_change_info(&remove->rm_cinfo, &cstate->current_fh); | 736 | set_change_info(&remove->rm_cinfo, &cstate->current_fh); |
@@ -751,8 +761,6 @@ nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
751 | (S_ISDIR(cstate->save_fh.fh_dentry->d_inode->i_mode) && | 761 | (S_ISDIR(cstate->save_fh.fh_dentry->d_inode->i_mode) && |
752 | S_ISDIR(cstate->current_fh.fh_dentry->d_inode->i_mode))) | 762 | S_ISDIR(cstate->current_fh.fh_dentry->d_inode->i_mode))) |
753 | status = nfserr_exist; | 763 | status = nfserr_exist; |
754 | else if (status == nfserr_symlink) | ||
755 | status = nfserr_notdir; | ||
756 | 764 | ||
757 | if (!status) { | 765 | if (!status) { |
758 | set_change_info(&rename->rn_sinfo, &cstate->current_fh); | 766 | set_change_info(&rename->rn_sinfo, &cstate->current_fh); |
@@ -892,8 +900,6 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
892 | 900 | ||
893 | write->wr_bytes_written = cnt; | 901 | write->wr_bytes_written = cnt; |
894 | 902 | ||
895 | if (status == nfserr_symlink) | ||
896 | status = nfserr_inval; | ||
897 | return status; | 903 | return status; |
898 | } | 904 | } |
899 | 905 | ||
@@ -930,7 +936,7 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
930 | count = 4 + (verify->ve_attrlen >> 2); | 936 | count = 4 + (verify->ve_attrlen >> 2); |
931 | buf = kmalloc(count << 2, GFP_KERNEL); | 937 | buf = kmalloc(count << 2, GFP_KERNEL); |
932 | if (!buf) | 938 | if (!buf) |
933 | return nfserr_resource; | 939 | return nfserr_jukebox; |
934 | 940 | ||
935 | status = nfsd4_encode_fattr(&cstate->current_fh, | 941 | status = nfsd4_encode_fattr(&cstate->current_fh, |
936 | cstate->current_fh.fh_export, | 942 | cstate->current_fh.fh_export, |
@@ -994,6 +1000,8 @@ static inline void nfsd4_increment_op_stats(u32 opnum) | |||
994 | 1000 | ||
995 | typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *, | 1001 | typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *, |
996 | void *); | 1002 | void *); |
1003 | typedef u32(*nfsd4op_rsize)(struct svc_rqst *, struct nfsd4_op *op); | ||
1004 | |||
997 | enum nfsd4_op_flags { | 1005 | enum nfsd4_op_flags { |
998 | ALLOWED_WITHOUT_FH = 1 << 0, /* No current filehandle required */ | 1006 | ALLOWED_WITHOUT_FH = 1 << 0, /* No current filehandle required */ |
999 | ALLOWED_ON_ABSENT_FS = 1 << 1, /* ops processed on absent fs */ | 1007 | ALLOWED_ON_ABSENT_FS = 1 << 1, /* ops processed on absent fs */ |
@@ -1001,13 +1009,15 @@ enum nfsd4_op_flags { | |||
1001 | /* For rfc 5661 section 2.6.3.1.1: */ | 1009 | /* For rfc 5661 section 2.6.3.1.1: */ |
1002 | OP_HANDLES_WRONGSEC = 1 << 3, | 1010 | OP_HANDLES_WRONGSEC = 1 << 3, |
1003 | OP_IS_PUTFH_LIKE = 1 << 4, | 1011 | OP_IS_PUTFH_LIKE = 1 << 4, |
1004 | }; | ||
1005 | |||
1006 | struct nfsd4_operation { | ||
1007 | nfsd4op_func op_func; | ||
1008 | u32 op_flags; | ||
1009 | char *op_name; | ||
1010 | /* | 1012 | /* |
1013 | * These are the ops whose result size we estimate before | ||
1014 | * encoding, to avoid performing an op then not being able to | ||
1015 | * respond or cache a response. This includes writes and setattrs | ||
1016 | * as well as the operations usually called "nonidempotent": | ||
1017 | */ | ||
1018 | OP_MODIFIES_SOMETHING = 1 << 5, | ||
1019 | /* | ||
1020 | * Cache compounds containing these ops in the xid-based drc: | ||
1011 | * We use the DRC for compounds containing non-idempotent | 1021 | * We use the DRC for compounds containing non-idempotent |
1012 | * operations, *except* those that are 4.1-specific (since | 1022 | * operations, *except* those that are 4.1-specific (since |
1013 | * sessions provide their own EOS), and except for stateful | 1023 | * sessions provide their own EOS), and except for stateful |
@@ -1015,7 +1025,15 @@ struct nfsd4_operation { | |||
1015 | * (since sequence numbers provide EOS for open, lock, etc in | 1025 | * (since sequence numbers provide EOS for open, lock, etc in |
1016 | * the v4.0 case). | 1026 | * the v4.0 case). |
1017 | */ | 1027 | */ |
1018 | bool op_cacheresult; | 1028 | OP_CACHEME = 1 << 6, |
1029 | }; | ||
1030 | |||
1031 | struct nfsd4_operation { | ||
1032 | nfsd4op_func op_func; | ||
1033 | u32 op_flags; | ||
1034 | char *op_name; | ||
1035 | /* Try to get response size before operation */ | ||
1036 | nfsd4op_rsize op_rsize_bop; | ||
1019 | }; | 1037 | }; |
1020 | 1038 | ||
1021 | static struct nfsd4_operation nfsd4_ops[]; | 1039 | static struct nfsd4_operation nfsd4_ops[]; |
@@ -1062,7 +1080,7 @@ static inline struct nfsd4_operation *OPDESC(struct nfsd4_op *op) | |||
1062 | 1080 | ||
1063 | bool nfsd4_cache_this_op(struct nfsd4_op *op) | 1081 | bool nfsd4_cache_this_op(struct nfsd4_op *op) |
1064 | { | 1082 | { |
1065 | return OPDESC(op)->op_cacheresult; | 1083 | return OPDESC(op)->op_flags & OP_CACHEME; |
1066 | } | 1084 | } |
1067 | 1085 | ||
1068 | static bool need_wrongsec_check(struct svc_rqst *rqstp) | 1086 | static bool need_wrongsec_check(struct svc_rqst *rqstp) |
@@ -1110,6 +1128,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1110 | struct nfsd4_operation *opdesc; | 1128 | struct nfsd4_operation *opdesc; |
1111 | struct nfsd4_compound_state *cstate = &resp->cstate; | 1129 | struct nfsd4_compound_state *cstate = &resp->cstate; |
1112 | int slack_bytes; | 1130 | int slack_bytes; |
1131 | u32 plen = 0; | ||
1113 | __be32 status; | 1132 | __be32 status; |
1114 | 1133 | ||
1115 | resp->xbuf = &rqstp->rq_res; | 1134 | resp->xbuf = &rqstp->rq_res; |
@@ -1188,6 +1207,15 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1188 | goto encode_op; | 1207 | goto encode_op; |
1189 | } | 1208 | } |
1190 | 1209 | ||
1210 | /* If op is non-idempotent */ | ||
1211 | if (opdesc->op_flags & OP_MODIFIES_SOMETHING) { | ||
1212 | plen = opdesc->op_rsize_bop(rqstp, op); | ||
1213 | op->status = nfsd4_check_resp_size(resp, plen); | ||
1214 | } | ||
1215 | |||
1216 | if (op->status) | ||
1217 | goto encode_op; | ||
1218 | |||
1191 | if (opdesc->op_func) | 1219 | if (opdesc->op_func) |
1192 | op->status = opdesc->op_func(rqstp, cstate, &op->u); | 1220 | op->status = opdesc->op_func(rqstp, cstate, &op->u); |
1193 | else | 1221 | else |
@@ -1217,7 +1245,7 @@ encode_op: | |||
1217 | be32_to_cpu(status)); | 1245 | be32_to_cpu(status)); |
1218 | 1246 | ||
1219 | if (cstate->replay_owner) { | 1247 | if (cstate->replay_owner) { |
1220 | nfs4_put_stateowner(cstate->replay_owner); | 1248 | nfs4_unlock_state(); |
1221 | cstate->replay_owner = NULL; | 1249 | cstate->replay_owner = NULL; |
1222 | } | 1250 | } |
1223 | /* XXX Ugh, we need to get rid of this kind of special case: */ | 1251 | /* XXX Ugh, we need to get rid of this kind of special case: */ |
@@ -1238,6 +1266,144 @@ out: | |||
1238 | return status; | 1266 | return status; |
1239 | } | 1267 | } |
1240 | 1268 | ||
1269 | #define op_encode_hdr_size (2) | ||
1270 | #define op_encode_stateid_maxsz (XDR_QUADLEN(NFS4_STATEID_SIZE)) | ||
1271 | #define op_encode_verifier_maxsz (XDR_QUADLEN(NFS4_VERIFIER_SIZE)) | ||
1272 | #define op_encode_change_info_maxsz (5) | ||
1273 | #define nfs4_fattr_bitmap_maxsz (4) | ||
1274 | |||
1275 | #define op_encode_lockowner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ)) | ||
1276 | #define op_encode_lock_denied_maxsz (8 + op_encode_lockowner_maxsz) | ||
1277 | |||
1278 | #define nfs4_owner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ)) | ||
1279 | |||
1280 | #define op_encode_ace_maxsz (3 + nfs4_owner_maxsz) | ||
1281 | #define op_encode_delegation_maxsz (1 + op_encode_stateid_maxsz + 1 + \ | ||
1282 | op_encode_ace_maxsz) | ||
1283 | |||
1284 | #define op_encode_channel_attrs_maxsz (6 + 1 + 1) | ||
1285 | |||
1286 | static inline u32 nfsd4_only_status_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1287 | { | ||
1288 | return (op_encode_hdr_size) * sizeof(__be32); | ||
1289 | } | ||
1290 | |||
1291 | static inline u32 nfsd4_status_stateid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1292 | { | ||
1293 | return (op_encode_hdr_size + op_encode_stateid_maxsz)* sizeof(__be32); | ||
1294 | } | ||
1295 | |||
1296 | static inline u32 nfsd4_commit_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1297 | { | ||
1298 | return (op_encode_hdr_size + op_encode_verifier_maxsz) * sizeof(__be32); | ||
1299 | } | ||
1300 | |||
1301 | static inline u32 nfsd4_create_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1302 | { | ||
1303 | return (op_encode_hdr_size + op_encode_change_info_maxsz | ||
1304 | + nfs4_fattr_bitmap_maxsz) * sizeof(__be32); | ||
1305 | } | ||
1306 | |||
1307 | static inline u32 nfsd4_link_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1308 | { | ||
1309 | return (op_encode_hdr_size + op_encode_change_info_maxsz) | ||
1310 | * sizeof(__be32); | ||
1311 | } | ||
1312 | |||
1313 | static inline u32 nfsd4_lock_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1314 | { | ||
1315 | return (op_encode_hdr_size + op_encode_lock_denied_maxsz) | ||
1316 | * sizeof(__be32); | ||
1317 | } | ||
1318 | |||
1319 | static inline u32 nfsd4_open_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1320 | { | ||
1321 | return (op_encode_hdr_size + op_encode_stateid_maxsz | ||
1322 | + op_encode_change_info_maxsz + 1 | ||
1323 | + nfs4_fattr_bitmap_maxsz | ||
1324 | + op_encode_delegation_maxsz) * sizeof(__be32); | ||
1325 | } | ||
1326 | |||
1327 | static inline u32 nfsd4_read_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1328 | { | ||
1329 | u32 maxcount = 0, rlen = 0; | ||
1330 | |||
1331 | maxcount = svc_max_payload(rqstp); | ||
1332 | rlen = op->u.read.rd_length; | ||
1333 | |||
1334 | if (rlen > maxcount) | ||
1335 | rlen = maxcount; | ||
1336 | |||
1337 | return (op_encode_hdr_size + 2) * sizeof(__be32) + rlen; | ||
1338 | } | ||
1339 | |||
1340 | static inline u32 nfsd4_readdir_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1341 | { | ||
1342 | u32 rlen = op->u.readdir.rd_maxcount; | ||
1343 | |||
1344 | if (rlen > PAGE_SIZE) | ||
1345 | rlen = PAGE_SIZE; | ||
1346 | |||
1347 | return (op_encode_hdr_size + op_encode_verifier_maxsz) | ||
1348 | * sizeof(__be32) + rlen; | ||
1349 | } | ||
1350 | |||
1351 | static inline u32 nfsd4_remove_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1352 | { | ||
1353 | return (op_encode_hdr_size + op_encode_change_info_maxsz) | ||
1354 | * sizeof(__be32); | ||
1355 | } | ||
1356 | |||
1357 | static inline u32 nfsd4_rename_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1358 | { | ||
1359 | return (op_encode_hdr_size + op_encode_change_info_maxsz | ||
1360 | + op_encode_change_info_maxsz) * sizeof(__be32); | ||
1361 | } | ||
1362 | |||
1363 | static inline u32 nfsd4_setattr_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1364 | { | ||
1365 | return (op_encode_hdr_size + nfs4_fattr_bitmap_maxsz) * sizeof(__be32); | ||
1366 | } | ||
1367 | |||
1368 | static inline u32 nfsd4_setclientid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1369 | { | ||
1370 | return (op_encode_hdr_size + 2 + 1024) * sizeof(__be32); | ||
1371 | } | ||
1372 | |||
1373 | static inline u32 nfsd4_write_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1374 | { | ||
1375 | return (op_encode_hdr_size + op_encode_verifier_maxsz) * sizeof(__be32); | ||
1376 | } | ||
1377 | |||
1378 | static inline u32 nfsd4_exchange_id_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1379 | { | ||
1380 | return (op_encode_hdr_size + 2 + 1 + /* eir_clientid, eir_sequenceid */\ | ||
1381 | 1 + 1 + 0 + /* eir_flags, spr_how, SP4_NONE (for now) */\ | ||
1382 | 2 + /*eir_server_owner.so_minor_id */\ | ||
1383 | /* eir_server_owner.so_major_id<> */\ | ||
1384 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 +\ | ||
1385 | /* eir_server_scope<> */\ | ||
1386 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 +\ | ||
1387 | 1 + /* eir_server_impl_id array length */\ | ||
1388 | 0 /* ignored eir_server_impl_id contents */) * sizeof(__be32); | ||
1389 | } | ||
1390 | |||
1391 | static inline u32 nfsd4_bind_conn_to_session_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1392 | { | ||
1393 | return (op_encode_hdr_size + \ | ||
1394 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + /* bctsr_sessid */\ | ||
1395 | 2 /* bctsr_dir, use_conn_in_rdma_mode */) * sizeof(__be32); | ||
1396 | } | ||
1397 | |||
1398 | static inline u32 nfsd4_create_session_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1399 | { | ||
1400 | return (op_encode_hdr_size + \ | ||
1401 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + /* sessionid */\ | ||
1402 | 2 + /* csr_sequence, csr_flags */\ | ||
1403 | op_encode_channel_attrs_maxsz + \ | ||
1404 | op_encode_channel_attrs_maxsz) * sizeof(__be32); | ||
1405 | } | ||
1406 | |||
1241 | static struct nfsd4_operation nfsd4_ops[] = { | 1407 | static struct nfsd4_operation nfsd4_ops[] = { |
1242 | [OP_ACCESS] = { | 1408 | [OP_ACCESS] = { |
1243 | .op_func = (nfsd4op_func)nfsd4_access, | 1409 | .op_func = (nfsd4op_func)nfsd4_access, |
@@ -1245,20 +1411,27 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1245 | }, | 1411 | }, |
1246 | [OP_CLOSE] = { | 1412 | [OP_CLOSE] = { |
1247 | .op_func = (nfsd4op_func)nfsd4_close, | 1413 | .op_func = (nfsd4op_func)nfsd4_close, |
1414 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1248 | .op_name = "OP_CLOSE", | 1415 | .op_name = "OP_CLOSE", |
1416 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize, | ||
1249 | }, | 1417 | }, |
1250 | [OP_COMMIT] = { | 1418 | [OP_COMMIT] = { |
1251 | .op_func = (nfsd4op_func)nfsd4_commit, | 1419 | .op_func = (nfsd4op_func)nfsd4_commit, |
1420 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1252 | .op_name = "OP_COMMIT", | 1421 | .op_name = "OP_COMMIT", |
1422 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_commit_rsize, | ||
1253 | }, | 1423 | }, |
1254 | [OP_CREATE] = { | 1424 | [OP_CREATE] = { |
1255 | .op_func = (nfsd4op_func)nfsd4_create, | 1425 | .op_func = (nfsd4op_func)nfsd4_create, |
1426 | .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME, | ||
1256 | .op_name = "OP_CREATE", | 1427 | .op_name = "OP_CREATE", |
1257 | .op_cacheresult = true, | 1428 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_create_rsize, |
1258 | }, | 1429 | }, |
1259 | [OP_DELEGRETURN] = { | 1430 | [OP_DELEGRETURN] = { |
1260 | .op_func = (nfsd4op_func)nfsd4_delegreturn, | 1431 | .op_func = (nfsd4op_func)nfsd4_delegreturn, |
1432 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1261 | .op_name = "OP_DELEGRETURN", | 1433 | .op_name = "OP_DELEGRETURN", |
1434 | .op_rsize_bop = nfsd4_only_status_rsize, | ||
1262 | }, | 1435 | }, |
1263 | [OP_GETATTR] = { | 1436 | [OP_GETATTR] = { |
1264 | .op_func = (nfsd4op_func)nfsd4_getattr, | 1437 | .op_func = (nfsd4op_func)nfsd4_getattr, |
@@ -1271,12 +1444,16 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1271 | }, | 1444 | }, |
1272 | [OP_LINK] = { | 1445 | [OP_LINK] = { |
1273 | .op_func = (nfsd4op_func)nfsd4_link, | 1446 | .op_func = (nfsd4op_func)nfsd4_link, |
1447 | .op_flags = ALLOWED_ON_ABSENT_FS | OP_MODIFIES_SOMETHING | ||
1448 | | OP_CACHEME, | ||
1274 | .op_name = "OP_LINK", | 1449 | .op_name = "OP_LINK", |
1275 | .op_cacheresult = true, | 1450 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_link_rsize, |
1276 | }, | 1451 | }, |
1277 | [OP_LOCK] = { | 1452 | [OP_LOCK] = { |
1278 | .op_func = (nfsd4op_func)nfsd4_lock, | 1453 | .op_func = (nfsd4op_func)nfsd4_lock, |
1454 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1279 | .op_name = "OP_LOCK", | 1455 | .op_name = "OP_LOCK", |
1456 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_lock_rsize, | ||
1280 | }, | 1457 | }, |
1281 | [OP_LOCKT] = { | 1458 | [OP_LOCKT] = { |
1282 | .op_func = (nfsd4op_func)nfsd4_lockt, | 1459 | .op_func = (nfsd4op_func)nfsd4_lockt, |
@@ -1284,7 +1461,9 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1284 | }, | 1461 | }, |
1285 | [OP_LOCKU] = { | 1462 | [OP_LOCKU] = { |
1286 | .op_func = (nfsd4op_func)nfsd4_locku, | 1463 | .op_func = (nfsd4op_func)nfsd4_locku, |
1464 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1287 | .op_name = "OP_LOCKU", | 1465 | .op_name = "OP_LOCKU", |
1466 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize, | ||
1288 | }, | 1467 | }, |
1289 | [OP_LOOKUP] = { | 1468 | [OP_LOOKUP] = { |
1290 | .op_func = (nfsd4op_func)nfsd4_lookup, | 1469 | .op_func = (nfsd4op_func)nfsd4_lookup, |
@@ -1302,42 +1481,54 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1302 | }, | 1481 | }, |
1303 | [OP_OPEN] = { | 1482 | [OP_OPEN] = { |
1304 | .op_func = (nfsd4op_func)nfsd4_open, | 1483 | .op_func = (nfsd4op_func)nfsd4_open, |
1305 | .op_flags = OP_HANDLES_WRONGSEC, | 1484 | .op_flags = OP_HANDLES_WRONGSEC | OP_MODIFIES_SOMETHING, |
1306 | .op_name = "OP_OPEN", | 1485 | .op_name = "OP_OPEN", |
1486 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_open_rsize, | ||
1307 | }, | 1487 | }, |
1308 | [OP_OPEN_CONFIRM] = { | 1488 | [OP_OPEN_CONFIRM] = { |
1309 | .op_func = (nfsd4op_func)nfsd4_open_confirm, | 1489 | .op_func = (nfsd4op_func)nfsd4_open_confirm, |
1490 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1310 | .op_name = "OP_OPEN_CONFIRM", | 1491 | .op_name = "OP_OPEN_CONFIRM", |
1492 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize, | ||
1311 | }, | 1493 | }, |
1312 | [OP_OPEN_DOWNGRADE] = { | 1494 | [OP_OPEN_DOWNGRADE] = { |
1313 | .op_func = (nfsd4op_func)nfsd4_open_downgrade, | 1495 | .op_func = (nfsd4op_func)nfsd4_open_downgrade, |
1496 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1314 | .op_name = "OP_OPEN_DOWNGRADE", | 1497 | .op_name = "OP_OPEN_DOWNGRADE", |
1498 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize, | ||
1315 | }, | 1499 | }, |
1316 | [OP_PUTFH] = { | 1500 | [OP_PUTFH] = { |
1317 | .op_func = (nfsd4op_func)nfsd4_putfh, | 1501 | .op_func = (nfsd4op_func)nfsd4_putfh, |
1318 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS | 1502 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1319 | | OP_IS_PUTFH_LIKE, | 1503 | | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING, |
1320 | .op_name = "OP_PUTFH", | 1504 | .op_name = "OP_PUTFH", |
1505 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1321 | }, | 1506 | }, |
1322 | [OP_PUTPUBFH] = { | 1507 | [OP_PUTPUBFH] = { |
1323 | .op_func = (nfsd4op_func)nfsd4_putrootfh, | 1508 | .op_func = (nfsd4op_func)nfsd4_putrootfh, |
1324 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS | 1509 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1325 | | OP_IS_PUTFH_LIKE, | 1510 | | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING, |
1326 | .op_name = "OP_PUTPUBFH", | 1511 | .op_name = "OP_PUTPUBFH", |
1512 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1327 | }, | 1513 | }, |
1328 | [OP_PUTROOTFH] = { | 1514 | [OP_PUTROOTFH] = { |
1329 | .op_func = (nfsd4op_func)nfsd4_putrootfh, | 1515 | .op_func = (nfsd4op_func)nfsd4_putrootfh, |
1330 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS | 1516 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1331 | | OP_IS_PUTFH_LIKE, | 1517 | | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING, |
1332 | .op_name = "OP_PUTROOTFH", | 1518 | .op_name = "OP_PUTROOTFH", |
1519 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1333 | }, | 1520 | }, |
1334 | [OP_READ] = { | 1521 | [OP_READ] = { |
1335 | .op_func = (nfsd4op_func)nfsd4_read, | 1522 | .op_func = (nfsd4op_func)nfsd4_read, |
1523 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1336 | .op_name = "OP_READ", | 1524 | .op_name = "OP_READ", |
1525 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_read_rsize, | ||
1337 | }, | 1526 | }, |
1338 | [OP_READDIR] = { | 1527 | [OP_READDIR] = { |
1339 | .op_func = (nfsd4op_func)nfsd4_readdir, | 1528 | .op_func = (nfsd4op_func)nfsd4_readdir, |
1529 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1340 | .op_name = "OP_READDIR", | 1530 | .op_name = "OP_READDIR", |
1531 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_readdir_rsize, | ||
1341 | }, | 1532 | }, |
1342 | [OP_READLINK] = { | 1533 | [OP_READLINK] = { |
1343 | .op_func = (nfsd4op_func)nfsd4_readlink, | 1534 | .op_func = (nfsd4op_func)nfsd4_readlink, |
@@ -1345,29 +1536,36 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1345 | }, | 1536 | }, |
1346 | [OP_REMOVE] = { | 1537 | [OP_REMOVE] = { |
1347 | .op_func = (nfsd4op_func)nfsd4_remove, | 1538 | .op_func = (nfsd4op_func)nfsd4_remove, |
1539 | .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME, | ||
1348 | .op_name = "OP_REMOVE", | 1540 | .op_name = "OP_REMOVE", |
1349 | .op_cacheresult = true, | 1541 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_remove_rsize, |
1350 | }, | 1542 | }, |
1351 | [OP_RENAME] = { | 1543 | [OP_RENAME] = { |
1352 | .op_name = "OP_RENAME", | ||
1353 | .op_func = (nfsd4op_func)nfsd4_rename, | 1544 | .op_func = (nfsd4op_func)nfsd4_rename, |
1354 | .op_cacheresult = true, | 1545 | .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME, |
1546 | .op_name = "OP_RENAME", | ||
1547 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_rename_rsize, | ||
1355 | }, | 1548 | }, |
1356 | [OP_RENEW] = { | 1549 | [OP_RENEW] = { |
1357 | .op_func = (nfsd4op_func)nfsd4_renew, | 1550 | .op_func = (nfsd4op_func)nfsd4_renew, |
1358 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | 1551 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1552 | | OP_MODIFIES_SOMETHING, | ||
1359 | .op_name = "OP_RENEW", | 1553 | .op_name = "OP_RENEW", |
1554 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1555 | |||
1360 | }, | 1556 | }, |
1361 | [OP_RESTOREFH] = { | 1557 | [OP_RESTOREFH] = { |
1362 | .op_func = (nfsd4op_func)nfsd4_restorefh, | 1558 | .op_func = (nfsd4op_func)nfsd4_restorefh, |
1363 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS | 1559 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1364 | | OP_IS_PUTFH_LIKE, | 1560 | | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING, |
1365 | .op_name = "OP_RESTOREFH", | 1561 | .op_name = "OP_RESTOREFH", |
1562 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1366 | }, | 1563 | }, |
1367 | [OP_SAVEFH] = { | 1564 | [OP_SAVEFH] = { |
1368 | .op_func = (nfsd4op_func)nfsd4_savefh, | 1565 | .op_func = (nfsd4op_func)nfsd4_savefh, |
1369 | .op_flags = OP_HANDLES_WRONGSEC, | 1566 | .op_flags = OP_HANDLES_WRONGSEC | OP_MODIFIES_SOMETHING, |
1370 | .op_name = "OP_SAVEFH", | 1567 | .op_name = "OP_SAVEFH", |
1568 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1371 | }, | 1569 | }, |
1372 | [OP_SECINFO] = { | 1570 | [OP_SECINFO] = { |
1373 | .op_func = (nfsd4op_func)nfsd4_secinfo, | 1571 | .op_func = (nfsd4op_func)nfsd4_secinfo, |
@@ -1377,19 +1575,22 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1377 | [OP_SETATTR] = { | 1575 | [OP_SETATTR] = { |
1378 | .op_func = (nfsd4op_func)nfsd4_setattr, | 1576 | .op_func = (nfsd4op_func)nfsd4_setattr, |
1379 | .op_name = "OP_SETATTR", | 1577 | .op_name = "OP_SETATTR", |
1380 | .op_cacheresult = true, | 1578 | .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME, |
1579 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_setattr_rsize, | ||
1381 | }, | 1580 | }, |
1382 | [OP_SETCLIENTID] = { | 1581 | [OP_SETCLIENTID] = { |
1383 | .op_func = (nfsd4op_func)nfsd4_setclientid, | 1582 | .op_func = (nfsd4op_func)nfsd4_setclientid, |
1384 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | 1583 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1584 | | OP_MODIFIES_SOMETHING | OP_CACHEME, | ||
1385 | .op_name = "OP_SETCLIENTID", | 1585 | .op_name = "OP_SETCLIENTID", |
1386 | .op_cacheresult = true, | 1586 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_setclientid_rsize, |
1387 | }, | 1587 | }, |
1388 | [OP_SETCLIENTID_CONFIRM] = { | 1588 | [OP_SETCLIENTID_CONFIRM] = { |
1389 | .op_func = (nfsd4op_func)nfsd4_setclientid_confirm, | 1589 | .op_func = (nfsd4op_func)nfsd4_setclientid_confirm, |
1390 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | 1590 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1591 | | OP_MODIFIES_SOMETHING | OP_CACHEME, | ||
1391 | .op_name = "OP_SETCLIENTID_CONFIRM", | 1592 | .op_name = "OP_SETCLIENTID_CONFIRM", |
1392 | .op_cacheresult = true, | 1593 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, |
1393 | }, | 1594 | }, |
1394 | [OP_VERIFY] = { | 1595 | [OP_VERIFY] = { |
1395 | .op_func = (nfsd4op_func)nfsd4_verify, | 1596 | .op_func = (nfsd4op_func)nfsd4_verify, |
@@ -1397,35 +1598,46 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1397 | }, | 1598 | }, |
1398 | [OP_WRITE] = { | 1599 | [OP_WRITE] = { |
1399 | .op_func = (nfsd4op_func)nfsd4_write, | 1600 | .op_func = (nfsd4op_func)nfsd4_write, |
1601 | .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME, | ||
1400 | .op_name = "OP_WRITE", | 1602 | .op_name = "OP_WRITE", |
1401 | .op_cacheresult = true, | 1603 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_write_rsize, |
1402 | }, | 1604 | }, |
1403 | [OP_RELEASE_LOCKOWNER] = { | 1605 | [OP_RELEASE_LOCKOWNER] = { |
1404 | .op_func = (nfsd4op_func)nfsd4_release_lockowner, | 1606 | .op_func = (nfsd4op_func)nfsd4_release_lockowner, |
1405 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | 1607 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1608 | | OP_MODIFIES_SOMETHING, | ||
1406 | .op_name = "OP_RELEASE_LOCKOWNER", | 1609 | .op_name = "OP_RELEASE_LOCKOWNER", |
1610 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1407 | }, | 1611 | }, |
1408 | 1612 | ||
1409 | /* NFSv4.1 operations */ | 1613 | /* NFSv4.1 operations */ |
1410 | [OP_EXCHANGE_ID] = { | 1614 | [OP_EXCHANGE_ID] = { |
1411 | .op_func = (nfsd4op_func)nfsd4_exchange_id, | 1615 | .op_func = (nfsd4op_func)nfsd4_exchange_id, |
1412 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, | 1616 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP |
1617 | | OP_MODIFIES_SOMETHING, | ||
1413 | .op_name = "OP_EXCHANGE_ID", | 1618 | .op_name = "OP_EXCHANGE_ID", |
1619 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_exchange_id_rsize, | ||
1414 | }, | 1620 | }, |
1415 | [OP_BIND_CONN_TO_SESSION] = { | 1621 | [OP_BIND_CONN_TO_SESSION] = { |
1416 | .op_func = (nfsd4op_func)nfsd4_bind_conn_to_session, | 1622 | .op_func = (nfsd4op_func)nfsd4_bind_conn_to_session, |
1417 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, | 1623 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP |
1624 | | OP_MODIFIES_SOMETHING, | ||
1418 | .op_name = "OP_BIND_CONN_TO_SESSION", | 1625 | .op_name = "OP_BIND_CONN_TO_SESSION", |
1626 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_bind_conn_to_session_rsize, | ||
1419 | }, | 1627 | }, |
1420 | [OP_CREATE_SESSION] = { | 1628 | [OP_CREATE_SESSION] = { |
1421 | .op_func = (nfsd4op_func)nfsd4_create_session, | 1629 | .op_func = (nfsd4op_func)nfsd4_create_session, |
1422 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, | 1630 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP |
1631 | | OP_MODIFIES_SOMETHING, | ||
1423 | .op_name = "OP_CREATE_SESSION", | 1632 | .op_name = "OP_CREATE_SESSION", |
1633 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_create_session_rsize, | ||
1424 | }, | 1634 | }, |
1425 | [OP_DESTROY_SESSION] = { | 1635 | [OP_DESTROY_SESSION] = { |
1426 | .op_func = (nfsd4op_func)nfsd4_destroy_session, | 1636 | .op_func = (nfsd4op_func)nfsd4_destroy_session, |
1427 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, | 1637 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP |
1638 | | OP_MODIFIES_SOMETHING, | ||
1428 | .op_name = "OP_DESTROY_SESSION", | 1639 | .op_name = "OP_DESTROY_SESSION", |
1640 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1429 | }, | 1641 | }, |
1430 | [OP_SEQUENCE] = { | 1642 | [OP_SEQUENCE] = { |
1431 | .op_func = (nfsd4op_func)nfsd4_sequence, | 1643 | .op_func = (nfsd4op_func)nfsd4_sequence, |
@@ -1433,14 +1645,17 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1433 | .op_name = "OP_SEQUENCE", | 1645 | .op_name = "OP_SEQUENCE", |
1434 | }, | 1646 | }, |
1435 | [OP_DESTROY_CLIENTID] = { | 1647 | [OP_DESTROY_CLIENTID] = { |
1436 | .op_func = NULL, | 1648 | .op_func = (nfsd4op_func)nfsd4_destroy_clientid, |
1437 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, | 1649 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP |
1650 | | OP_MODIFIES_SOMETHING, | ||
1438 | .op_name = "OP_DESTROY_CLIENTID", | 1651 | .op_name = "OP_DESTROY_CLIENTID", |
1652 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1439 | }, | 1653 | }, |
1440 | [OP_RECLAIM_COMPLETE] = { | 1654 | [OP_RECLAIM_COMPLETE] = { |
1441 | .op_func = (nfsd4op_func)nfsd4_reclaim_complete, | 1655 | .op_func = (nfsd4op_func)nfsd4_reclaim_complete, |
1442 | .op_flags = ALLOWED_WITHOUT_FH, | 1656 | .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING, |
1443 | .op_name = "OP_RECLAIM_COMPLETE", | 1657 | .op_name = "OP_RECLAIM_COMPLETE", |
1658 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1444 | }, | 1659 | }, |
1445 | [OP_SECINFO_NO_NAME] = { | 1660 | [OP_SECINFO_NO_NAME] = { |
1446 | .op_func = (nfsd4op_func)nfsd4_secinfo_no_name, | 1661 | .op_func = (nfsd4op_func)nfsd4_secinfo_no_name, |
@@ -1454,8 +1669,9 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1454 | }, | 1669 | }, |
1455 | [OP_FREE_STATEID] = { | 1670 | [OP_FREE_STATEID] = { |
1456 | .op_func = (nfsd4op_func)nfsd4_free_stateid, | 1671 | .op_func = (nfsd4op_func)nfsd4_free_stateid, |
1457 | .op_flags = ALLOWED_WITHOUT_FH, | 1672 | .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING, |
1458 | .op_name = "OP_FREE_STATEID", | 1673 | .op_name = "OP_FREE_STATEID", |
1674 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1459 | }, | 1675 | }, |
1460 | }; | 1676 | }; |
1461 | 1677 | ||