diff options
Diffstat (limited to 'fs/nfsd/nfs4proc.c')
-rw-r--r-- | fs/nfsd/nfs4proc.c | 39 |
1 files changed, 25 insertions, 14 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 82189b208af3..d543222babf3 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -1273,6 +1273,8 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1273 | struct nfsd4_op *op; | 1273 | struct nfsd4_op *op; |
1274 | struct nfsd4_operation *opdesc; | 1274 | struct nfsd4_operation *opdesc; |
1275 | struct nfsd4_compound_state *cstate = &resp->cstate; | 1275 | struct nfsd4_compound_state *cstate = &resp->cstate; |
1276 | struct svc_fh *current_fh = &cstate->current_fh; | ||
1277 | struct svc_fh *save_fh = &cstate->save_fh; | ||
1276 | int slack_bytes; | 1278 | int slack_bytes; |
1277 | u32 plen = 0; | 1279 | u32 plen = 0; |
1278 | __be32 status; | 1280 | __be32 status; |
@@ -1288,11 +1290,11 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1288 | resp->tag = args->tag; | 1290 | resp->tag = args->tag; |
1289 | resp->opcnt = 0; | 1291 | resp->opcnt = 0; |
1290 | resp->rqstp = rqstp; | 1292 | resp->rqstp = rqstp; |
1291 | resp->cstate.minorversion = args->minorversion; | 1293 | cstate->minorversion = args->minorversion; |
1292 | resp->cstate.replay_owner = NULL; | 1294 | cstate->replay_owner = NULL; |
1293 | resp->cstate.session = NULL; | 1295 | cstate->session = NULL; |
1294 | fh_init(&resp->cstate.current_fh, NFS4_FHSIZE); | 1296 | fh_init(current_fh, NFS4_FHSIZE); |
1295 | fh_init(&resp->cstate.save_fh, NFS4_FHSIZE); | 1297 | fh_init(save_fh, NFS4_FHSIZE); |
1296 | /* | 1298 | /* |
1297 | * Don't use the deferral mechanism for NFSv4; compounds make it | 1299 | * Don't use the deferral mechanism for NFSv4; compounds make it |
1298 | * too hard to avoid non-idempotency problems. | 1300 | * too hard to avoid non-idempotency problems. |
@@ -1345,20 +1347,28 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1345 | 1347 | ||
1346 | opdesc = OPDESC(op); | 1348 | opdesc = OPDESC(op); |
1347 | 1349 | ||
1348 | if (!cstate->current_fh.fh_dentry) { | 1350 | if (!current_fh->fh_dentry) { |
1349 | if (!(opdesc->op_flags & ALLOWED_WITHOUT_FH)) { | 1351 | if (!(opdesc->op_flags & ALLOWED_WITHOUT_FH)) { |
1350 | op->status = nfserr_nofilehandle; | 1352 | op->status = nfserr_nofilehandle; |
1351 | goto encode_op; | 1353 | goto encode_op; |
1352 | } | 1354 | } |
1353 | } else if (cstate->current_fh.fh_export->ex_fslocs.migrated && | 1355 | } else if (current_fh->fh_export->ex_fslocs.migrated && |
1354 | !(opdesc->op_flags & ALLOWED_ON_ABSENT_FS)) { | 1356 | !(opdesc->op_flags & ALLOWED_ON_ABSENT_FS)) { |
1355 | op->status = nfserr_moved; | 1357 | op->status = nfserr_moved; |
1356 | goto encode_op; | 1358 | goto encode_op; |
1357 | } | 1359 | } |
1358 | 1360 | ||
1361 | fh_clear_wcc(current_fh); | ||
1362 | |||
1359 | /* If op is non-idempotent */ | 1363 | /* If op is non-idempotent */ |
1360 | if (opdesc->op_flags & OP_MODIFIES_SOMETHING) { | 1364 | if (opdesc->op_flags & OP_MODIFIES_SOMETHING) { |
1361 | plen = opdesc->op_rsize_bop(rqstp, op); | 1365 | plen = opdesc->op_rsize_bop(rqstp, op); |
1366 | /* | ||
1367 | * If there's still another operation, make sure | ||
1368 | * we'll have space to at least encode an error: | ||
1369 | */ | ||
1370 | if (resp->opcnt < args->opcnt) | ||
1371 | plen += COMPOUND_ERR_SLACK_SPACE; | ||
1362 | op->status = nfsd4_check_resp_size(resp, plen); | 1372 | op->status = nfsd4_check_resp_size(resp, plen); |
1363 | } | 1373 | } |
1364 | 1374 | ||
@@ -1377,12 +1387,12 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1377 | clear_current_stateid(cstate); | 1387 | clear_current_stateid(cstate); |
1378 | 1388 | ||
1379 | if (need_wrongsec_check(rqstp)) | 1389 | if (need_wrongsec_check(rqstp)) |
1380 | op->status = check_nfsd_access(cstate->current_fh.fh_export, rqstp); | 1390 | op->status = check_nfsd_access(current_fh->fh_export, rqstp); |
1381 | } | 1391 | } |
1382 | 1392 | ||
1383 | encode_op: | 1393 | encode_op: |
1384 | /* Only from SEQUENCE */ | 1394 | /* Only from SEQUENCE */ |
1385 | if (resp->cstate.status == nfserr_replay_cache) { | 1395 | if (cstate->status == nfserr_replay_cache) { |
1386 | dprintk("%s NFS4.1 replay from cache\n", __func__); | 1396 | dprintk("%s NFS4.1 replay from cache\n", __func__); |
1387 | status = op->status; | 1397 | status = op->status; |
1388 | goto out; | 1398 | goto out; |
@@ -1411,10 +1421,10 @@ encode_op: | |||
1411 | nfsd4_increment_op_stats(op->opnum); | 1421 | nfsd4_increment_op_stats(op->opnum); |
1412 | } | 1422 | } |
1413 | 1423 | ||
1414 | resp->cstate.status = status; | 1424 | cstate->status = status; |
1415 | fh_put(&resp->cstate.current_fh); | 1425 | fh_put(current_fh); |
1416 | fh_put(&resp->cstate.save_fh); | 1426 | fh_put(save_fh); |
1417 | BUG_ON(resp->cstate.replay_owner); | 1427 | BUG_ON(cstate->replay_owner); |
1418 | out: | 1428 | out: |
1419 | /* Reset deferral mechanism for RPC deferrals */ | 1429 | /* Reset deferral mechanism for RPC deferrals */ |
1420 | rqstp->rq_usedeferral = 1; | 1430 | rqstp->rq_usedeferral = 1; |
@@ -1523,7 +1533,8 @@ static inline u32 nfsd4_setattr_rsize(struct svc_rqst *rqstp, struct nfsd4_op *o | |||
1523 | 1533 | ||
1524 | static inline u32 nfsd4_setclientid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | 1534 | static inline u32 nfsd4_setclientid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) |
1525 | { | 1535 | { |
1526 | return (op_encode_hdr_size + 2 + 1024) * sizeof(__be32); | 1536 | return (op_encode_hdr_size + 2 + XDR_QUADLEN(NFS4_VERIFIER_SIZE)) * |
1537 | sizeof(__be32); | ||
1527 | } | 1538 | } |
1528 | 1539 | ||
1529 | static inline u32 nfsd4_write_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | 1540 | static inline u32 nfsd4_write_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) |