Merge branch 'for-3.1' of git://linux-nfs.org/~bfields/linux
[pandora-kernel.git] / fs / nfsd / nfs4proc.c
index 3a6dbd7..e807776 100644 (file)
@@ -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,
        },