|
@@ -1007,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[];
|
|
@@ -1051,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;
|
|
@@ -1240,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,
|
|
@@ -1257,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,
|
|
@@ -1330,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,
|
|
@@ -1359,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,
|
|
@@ -1377,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,
|
|
@@ -1447,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,
|