diff options
Diffstat (limited to 'fs/nfsd/nfs4proc.c')
-rw-r--r-- | fs/nfsd/nfs4proc.c | 58 |
1 files changed, 47 insertions, 11 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 3a6dbd70b34b..e80777666618 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -291,6 +291,15 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL) return nfserr_inval; + /* + * RFC5661 18.51.3 + * Before RECLAIM_COMPLETE done, server should deny new lock + */ + if (nfsd4_has_session(cstate) && + !cstate->session->se_client->cl_firststate && + open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS) + return nfserr_grace; + if (nfsd4_has_session(cstate)) copy_clientid(&open->op_clientid, cstate->session); @@ -998,6 +1007,15 @@ struct nfsd4_operation { nfsd4op_func op_func; u32 op_flags; char *op_name; + /* + * We use the DRC for compounds containing non-idempotent + * operations, *except* those that are 4.1-specific (since + * sessions provide their own EOS), and except for stateful + * operations other than setclientid and setclientid_confirm + * (since sequence numbers provide EOS for open, lock, etc in + * the v4.0 case). + */ + bool op_cacheresult; }; static struct nfsd4_operation nfsd4_ops[]; @@ -1042,6 +1060,11 @@ static inline struct nfsd4_operation *OPDESC(struct nfsd4_op *op) return &nfsd4_ops[op->opnum]; } +bool nfsd4_cache_this_op(struct nfsd4_op *op) +{ + return OPDESC(op)->op_cacheresult; +} + static bool need_wrongsec_check(struct svc_rqst *rqstp) { struct nfsd4_compoundres *resp = rqstp->rq_resp; @@ -1209,7 +1232,6 @@ encode_op: fh_put(&resp->cstate.save_fh); BUG_ON(resp->cstate.replay_owner); out: - nfsd4_release_compoundargs(args); /* Reset deferral mechanism for RPC deferrals */ rqstp->rq_usedeferral = 1; dprintk("nfsv4 compound returned %d\n", ntohl(status)); @@ -1232,6 +1254,7 @@ static struct nfsd4_operation nfsd4_ops[] = { [OP_CREATE] = { .op_func = (nfsd4op_func)nfsd4_create, .op_name = "OP_CREATE", + .op_cacheresult = true, }, [OP_DELEGRETURN] = { .op_func = (nfsd4op_func)nfsd4_delegreturn, @@ -1249,6 +1272,7 @@ static struct nfsd4_operation nfsd4_ops[] = { [OP_LINK] = { .op_func = (nfsd4op_func)nfsd4_link, .op_name = "OP_LINK", + .op_cacheresult = true, }, [OP_LOCK] = { .op_func = (nfsd4op_func)nfsd4_lock, @@ -1322,10 +1346,12 @@ static struct nfsd4_operation nfsd4_ops[] = { [OP_REMOVE] = { .op_func = (nfsd4op_func)nfsd4_remove, .op_name = "OP_REMOVE", + .op_cacheresult = true, }, [OP_RENAME] = { .op_name = "OP_RENAME", .op_func = (nfsd4op_func)nfsd4_rename, + .op_cacheresult = true, }, [OP_RENEW] = { .op_func = (nfsd4op_func)nfsd4_renew, @@ -1351,16 +1377,19 @@ static struct nfsd4_operation nfsd4_ops[] = { [OP_SETATTR] = { .op_func = (nfsd4op_func)nfsd4_setattr, .op_name = "OP_SETATTR", + .op_cacheresult = true, }, [OP_SETCLIENTID] = { .op_func = (nfsd4op_func)nfsd4_setclientid, .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, .op_name = "OP_SETCLIENTID", + .op_cacheresult = true, }, [OP_SETCLIENTID_CONFIRM] = { .op_func = (nfsd4op_func)nfsd4_setclientid_confirm, .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, .op_name = "OP_SETCLIENTID_CONFIRM", + .op_cacheresult = true, }, [OP_VERIFY] = { .op_func = (nfsd4op_func)nfsd4_verify, @@ -1369,6 +1398,7 @@ static struct nfsd4_operation nfsd4_ops[] = { [OP_WRITE] = { .op_func = (nfsd4op_func)nfsd4_write, .op_name = "OP_WRITE", + .op_cacheresult = true, }, [OP_RELEASE_LOCKOWNER] = { .op_func = (nfsd4op_func)nfsd4_release_lockowner, @@ -1402,6 +1432,11 @@ static struct nfsd4_operation nfsd4_ops[] = { .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, .op_name = "OP_SEQUENCE", }, + [OP_DESTROY_CLIENTID] = { + .op_func = NULL, + .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, + .op_name = "OP_DESTROY_CLIENTID", + }, [OP_RECLAIM_COMPLETE] = { .op_func = (nfsd4op_func)nfsd4_reclaim_complete, .op_flags = ALLOWED_WITHOUT_FH, @@ -1412,6 +1447,16 @@ static struct nfsd4_operation nfsd4_ops[] = { .op_flags = OP_HANDLES_WRONGSEC, .op_name = "OP_SECINFO_NO_NAME", }, + [OP_TEST_STATEID] = { + .op_func = (nfsd4op_func)nfsd4_test_stateid, + .op_flags = ALLOWED_WITHOUT_FH, + .op_name = "OP_TEST_STATEID", + }, + [OP_FREE_STATEID] = { + .op_func = (nfsd4op_func)nfsd4_free_stateid, + .op_flags = ALLOWED_WITHOUT_FH, + .op_name = "OP_FREE_STATEID", + }, }; static const char *nfsd4_op_name(unsigned opnum) @@ -1424,16 +1469,6 @@ static const char *nfsd4_op_name(unsigned opnum) #define nfsd4_voidres nfsd4_voidargs struct nfsd4_voidargs { int dummy; }; -/* - * TODO: At the present time, the NFSv4 server does not do XID caching - * of requests. Implementing XID caching would not be a serious problem, - * although it would require a mild change in interfaces since one - * doesn't know whether an NFSv4 request is idempotent until after the - * XDR decode. However, XID caching totally confuses pynfs (Peter - * Astrand's regression testsuite for NFSv4 servers), which reuses - * XID's liberally, so I've left it unimplemented until pynfs generates - * better XID's. - */ static struct svc_procedure nfsd_procedures4[2] = { [NFSPROC4_NULL] = { .pc_func = (svc_procfunc) nfsd4_proc_null, @@ -1449,6 +1484,7 @@ static struct svc_procedure nfsd_procedures4[2] = { .pc_encode = (kxdrproc_t) nfs4svc_encode_compoundres, .pc_argsize = sizeof(struct nfsd4_compoundargs), .pc_ressize = sizeof(struct nfsd4_compoundres), + .pc_release = nfsd4_release_compoundargs, .pc_cachetype = RC_NOCACHE, .pc_xdrressize = NFSD_BUFSIZE/4, }, |