diff options
Diffstat (limited to 'fs/nfsd/nfs4proc.c')
-rw-r--r-- | fs/nfsd/nfs4proc.c | 97 |
1 files changed, 57 insertions, 40 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index ae73175e6e68..8ae5abfe6ba2 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -191,9 +191,18 @@ static __be32 nfsd_check_obj_isreg(struct svc_fh *fh) | |||
191 | return nfserr_symlink; | 191 | return nfserr_symlink; |
192 | } | 192 | } |
193 | 193 | ||
194 | static void nfsd4_set_open_owner_reply_cache(struct nfsd4_compound_state *cstate, struct nfsd4_open *open, struct svc_fh *resfh) | ||
195 | { | ||
196 | if (nfsd4_has_session(cstate)) | ||
197 | return; | ||
198 | fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh, | ||
199 | &resfh->fh_handle); | ||
200 | } | ||
201 | |||
194 | static __be32 | 202 | static __be32 |
195 | do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) | 203 | do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_open *open) |
196 | { | 204 | { |
205 | struct svc_fh *current_fh = &cstate->current_fh; | ||
197 | struct svc_fh *resfh; | 206 | struct svc_fh *resfh; |
198 | int accmode; | 207 | int accmode; |
199 | __be32 status; | 208 | __be32 status; |
@@ -252,9 +261,7 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o | |||
252 | if (is_create_with_attrs(open) && open->op_acl != NULL) | 261 | if (is_create_with_attrs(open) && open->op_acl != NULL) |
253 | do_set_nfs4_acl(rqstp, resfh, open->op_acl, open->op_bmval); | 262 | do_set_nfs4_acl(rqstp, resfh, open->op_acl, open->op_bmval); |
254 | 263 | ||
255 | /* set reply cache */ | 264 | nfsd4_set_open_owner_reply_cache(cstate, open, resfh); |
256 | fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh, | ||
257 | &resfh->fh_handle); | ||
258 | accmode = NFSD_MAY_NOP; | 265 | accmode = NFSD_MAY_NOP; |
259 | if (open->op_created) | 266 | if (open->op_created) |
260 | accmode |= NFSD_MAY_OWNER_OVERRIDE; | 267 | accmode |= NFSD_MAY_OWNER_OVERRIDE; |
@@ -268,8 +275,9 @@ out: | |||
268 | } | 275 | } |
269 | 276 | ||
270 | static __be32 | 277 | static __be32 |
271 | do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) | 278 | do_open_fhandle(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_open *open) |
272 | { | 279 | { |
280 | struct svc_fh *current_fh = &cstate->current_fh; | ||
273 | __be32 status; | 281 | __be32 status; |
274 | 282 | ||
275 | /* We don't know the target directory, and therefore can not | 283 | /* We don't know the target directory, and therefore can not |
@@ -278,9 +286,7 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ | |||
278 | 286 | ||
279 | memset(&open->op_cinfo, 0, sizeof(struct nfsd4_change_info)); | 287 | memset(&open->op_cinfo, 0, sizeof(struct nfsd4_change_info)); |
280 | 288 | ||
281 | /* set replay cache */ | 289 | nfsd4_set_open_owner_reply_cache(cstate, open, current_fh); |
282 | fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh, | ||
283 | ¤t_fh->fh_handle); | ||
284 | 290 | ||
285 | open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) && | 291 | open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) && |
286 | (open->op_iattr.ia_size == 0); | 292 | (open->op_iattr.ia_size == 0); |
@@ -351,6 +357,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
351 | } | 357 | } |
352 | if (status) | 358 | if (status) |
353 | goto out; | 359 | goto out; |
360 | if (open->op_xdr_error) { | ||
361 | status = open->op_xdr_error; | ||
362 | goto out; | ||
363 | } | ||
354 | 364 | ||
355 | status = nfsd4_check_open_attributes(rqstp, cstate, open); | 365 | status = nfsd4_check_open_attributes(rqstp, cstate, open); |
356 | if (status) | 366 | if (status) |
@@ -368,8 +378,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
368 | switch (open->op_claim_type) { | 378 | switch (open->op_claim_type) { |
369 | case NFS4_OPEN_CLAIM_DELEGATE_CUR: | 379 | case NFS4_OPEN_CLAIM_DELEGATE_CUR: |
370 | case NFS4_OPEN_CLAIM_NULL: | 380 | case NFS4_OPEN_CLAIM_NULL: |
371 | status = do_open_lookup(rqstp, &cstate->current_fh, | 381 | status = do_open_lookup(rqstp, cstate, open); |
372 | open); | ||
373 | if (status) | 382 | if (status) |
374 | goto out; | 383 | goto out; |
375 | break; | 384 | break; |
@@ -382,8 +391,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
382 | goto out; | 391 | goto out; |
383 | case NFS4_OPEN_CLAIM_FH: | 392 | case NFS4_OPEN_CLAIM_FH: |
384 | case NFS4_OPEN_CLAIM_DELEG_CUR_FH: | 393 | case NFS4_OPEN_CLAIM_DELEG_CUR_FH: |
385 | status = do_open_fhandle(rqstp, &cstate->current_fh, | 394 | status = do_open_fhandle(rqstp, cstate, open); |
386 | open); | ||
387 | if (status) | 395 | if (status) |
388 | goto out; | 396 | goto out; |
389 | break; | 397 | break; |
@@ -409,14 +417,33 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
409 | WARN_ON(status && open->op_created); | 417 | WARN_ON(status && open->op_created); |
410 | out: | 418 | out: |
411 | nfsd4_cleanup_open_state(open, status); | 419 | nfsd4_cleanup_open_state(open, status); |
412 | if (open->op_openowner) | 420 | if (open->op_openowner && !nfsd4_has_session(cstate)) |
413 | cstate->replay_owner = &open->op_openowner->oo_owner; | 421 | cstate->replay_owner = &open->op_openowner->oo_owner; |
414 | else | 422 | nfsd4_bump_seqid(cstate, status); |
423 | if (!cstate->replay_owner) | ||
415 | nfs4_unlock_state(); | 424 | nfs4_unlock_state(); |
416 | return status; | 425 | return status; |
417 | } | 426 | } |
418 | 427 | ||
419 | /* | 428 | /* |
429 | * OPEN is the only seqid-mutating operation whose decoding can fail | ||
430 | * with a seqid-mutating error (specifically, decoding of user names in | ||
431 | * the attributes). Therefore we have to do some processing to look up | ||
432 | * the stateowner so that we can bump the seqid. | ||
433 | */ | ||
434 | static __be32 nfsd4_open_omfg(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_op *op) | ||
435 | { | ||
436 | struct nfsd4_open *open = (struct nfsd4_open *)&op->u; | ||
437 | |||
438 | if (!seqid_mutating_err(ntohl(op->status))) | ||
439 | return op->status; | ||
440 | if (nfsd4_has_session(cstate)) | ||
441 | return op->status; | ||
442 | open->op_xdr_error = op->status; | ||
443 | return nfsd4_open(rqstp, cstate, open); | ||
444 | } | ||
445 | |||
446 | /* | ||
420 | * filehandle-manipulating ops. | 447 | * filehandle-manipulating ops. |
421 | */ | 448 | */ |
422 | static __be32 | 449 | static __be32 |
@@ -786,21 +813,11 @@ nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
786 | status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname, | 813 | status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname, |
787 | rename->rn_snamelen, &cstate->current_fh, | 814 | rename->rn_snamelen, &cstate->current_fh, |
788 | rename->rn_tname, rename->rn_tnamelen); | 815 | rename->rn_tname, rename->rn_tnamelen); |
789 | 816 | if (status) | |
790 | /* the underlying filesystem returns different error's than required | 817 | return status; |
791 | * by NFSv4. both save_fh and current_fh have been verified.. */ | 818 | set_change_info(&rename->rn_sinfo, &cstate->current_fh); |
792 | if (status == nfserr_isdir) | 819 | set_change_info(&rename->rn_tinfo, &cstate->save_fh); |
793 | status = nfserr_exist; | 820 | return nfs_ok; |
794 | else if ((status == nfserr_notdir) && | ||
795 | (S_ISDIR(cstate->save_fh.fh_dentry->d_inode->i_mode) && | ||
796 | S_ISDIR(cstate->current_fh.fh_dentry->d_inode->i_mode))) | ||
797 | status = nfserr_exist; | ||
798 | |||
799 | if (!status) { | ||
800 | set_change_info(&rename->rn_sinfo, &cstate->current_fh); | ||
801 | set_change_info(&rename->rn_tinfo, &cstate->save_fh); | ||
802 | } | ||
803 | return status; | ||
804 | } | 821 | } |
805 | 822 | ||
806 | static __be32 | 823 | static __be32 |
@@ -931,14 +948,14 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
931 | nfs4_lock_state(); | 948 | nfs4_lock_state(); |
932 | status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), | 949 | status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), |
933 | cstate, stateid, WR_STATE, &filp); | 950 | cstate, stateid, WR_STATE, &filp); |
934 | if (filp) | ||
935 | get_file(filp); | ||
936 | nfs4_unlock_state(); | ||
937 | |||
938 | if (status) { | 951 | if (status) { |
952 | nfs4_unlock_state(); | ||
939 | dprintk("NFSD: nfsd4_write: couldn't process stateid!\n"); | 953 | dprintk("NFSD: nfsd4_write: couldn't process stateid!\n"); |
940 | return status; | 954 | return status; |
941 | } | 955 | } |
956 | if (filp) | ||
957 | get_file(filp); | ||
958 | nfs4_unlock_state(); | ||
942 | 959 | ||
943 | cnt = write->wr_buflen; | 960 | cnt = write->wr_buflen; |
944 | write->wr_how_written = write->wr_stable_how; | 961 | write->wr_how_written = write->wr_stable_how; |
@@ -1244,8 +1261,11 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1244 | * for example, if there is a miscellaneous XDR error | 1261 | * for example, if there is a miscellaneous XDR error |
1245 | * it will be set to nfserr_bad_xdr. | 1262 | * it will be set to nfserr_bad_xdr. |
1246 | */ | 1263 | */ |
1247 | if (op->status) | 1264 | if (op->status) { |
1265 | if (op->opnum == OP_OPEN) | ||
1266 | op->status = nfsd4_open_omfg(rqstp, cstate, op); | ||
1248 | goto encode_op; | 1267 | goto encode_op; |
1268 | } | ||
1249 | 1269 | ||
1250 | /* We must be able to encode a successful response to | 1270 | /* We must be able to encode a successful response to |
1251 | * this operation, with enough room left over to encode a | 1271 | * this operation, with enough room left over to encode a |
@@ -1282,12 +1302,9 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1282 | if (op->status) | 1302 | if (op->status) |
1283 | goto encode_op; | 1303 | goto encode_op; |
1284 | 1304 | ||
1285 | if (opdesc->op_func) { | 1305 | if (opdesc->op_get_currentstateid) |
1286 | if (opdesc->op_get_currentstateid) | 1306 | opdesc->op_get_currentstateid(cstate, &op->u); |
1287 | opdesc->op_get_currentstateid(cstate, &op->u); | 1307 | op->status = opdesc->op_func(rqstp, cstate, &op->u); |
1288 | op->status = opdesc->op_func(rqstp, cstate, &op->u); | ||
1289 | } else | ||
1290 | BUG_ON(op->status == nfs_ok); | ||
1291 | 1308 | ||
1292 | if (!op->status) { | 1309 | if (!op->status) { |
1293 | if (opdesc->op_set_currentstateid) | 1310 | if (opdesc->op_set_currentstateid) |