aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfsd/cache.h2
-rw-r--r--fs/nfsd/nfs4proc.c32
-rw-r--r--fs/nfsd/nfs4xdr.c11
-rw-r--r--fs/nfsd/nfscache.c3
-rw-r--r--fs/nfsd/nfssvc.c26
-rw-r--r--fs/nfsd/xdr4.h3
-rw-r--r--include/linux/sunrpc/svc.h1
7 files changed, 55 insertions, 23 deletions
diff --git a/fs/nfsd/cache.h b/fs/nfsd/cache.h
index d892be61016c..93cc9d34c459 100644
--- a/fs/nfsd/cache.h
+++ b/fs/nfsd/cache.h
@@ -69,7 +69,7 @@ enum {
69 69
70int nfsd_reply_cache_init(void); 70int nfsd_reply_cache_init(void);
71void nfsd_reply_cache_shutdown(void); 71void nfsd_reply_cache_shutdown(void);
72int nfsd_cache_lookup(struct svc_rqst *, int); 72int nfsd_cache_lookup(struct svc_rqst *);
73void nfsd_cache_update(struct svc_rqst *, int, __be32 *); 73void nfsd_cache_update(struct svc_rqst *, int, __be32 *);
74 74
75#ifdef CONFIG_NFSD_V4 75#ifdef CONFIG_NFSD_V4
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 7ef1b27f1125..e80777666618 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -1007,6 +1007,15 @@ struct nfsd4_operation {
1007 nfsd4op_func op_func; 1007 nfsd4op_func op_func;
1008 u32 op_flags; 1008 u32 op_flags;
1009 char *op_name; 1009 char *op_name;
1010 /*
1011 * We use the DRC for compounds containing non-idempotent
1012 * operations, *except* those that are 4.1-specific (since
1013 * sessions provide their own EOS), and except for stateful
1014 * operations other than setclientid and setclientid_confirm
1015 * (since sequence numbers provide EOS for open, lock, etc in
1016 * the v4.0 case).
1017 */
1018 bool op_cacheresult;
1010}; 1019};
1011 1020
1012static struct nfsd4_operation nfsd4_ops[]; 1021static struct nfsd4_operation nfsd4_ops[];
@@ -1051,6 +1060,11 @@ static inline struct nfsd4_operation *OPDESC(struct nfsd4_op *op)
1051 return &nfsd4_ops[op->opnum]; 1060 return &nfsd4_ops[op->opnum];
1052} 1061}
1053 1062
1063bool nfsd4_cache_this_op(struct nfsd4_op *op)
1064{
1065 return OPDESC(op)->op_cacheresult;
1066}
1067
1054static bool need_wrongsec_check(struct svc_rqst *rqstp) 1068static bool need_wrongsec_check(struct svc_rqst *rqstp)
1055{ 1069{
1056 struct nfsd4_compoundres *resp = rqstp->rq_resp; 1070 struct nfsd4_compoundres *resp = rqstp->rq_resp;
@@ -1240,6 +1254,7 @@ static struct nfsd4_operation nfsd4_ops[] = {
1240 [OP_CREATE] = { 1254 [OP_CREATE] = {
1241 .op_func = (nfsd4op_func)nfsd4_create, 1255 .op_func = (nfsd4op_func)nfsd4_create,
1242 .op_name = "OP_CREATE", 1256 .op_name = "OP_CREATE",
1257 .op_cacheresult = true,
1243 }, 1258 },
1244 [OP_DELEGRETURN] = { 1259 [OP_DELEGRETURN] = {
1245 .op_func = (nfsd4op_func)nfsd4_delegreturn, 1260 .op_func = (nfsd4op_func)nfsd4_delegreturn,
@@ -1257,6 +1272,7 @@ static struct nfsd4_operation nfsd4_ops[] = {
1257 [OP_LINK] = { 1272 [OP_LINK] = {
1258 .op_func = (nfsd4op_func)nfsd4_link, 1273 .op_func = (nfsd4op_func)nfsd4_link,
1259 .op_name = "OP_LINK", 1274 .op_name = "OP_LINK",
1275 .op_cacheresult = true,
1260 }, 1276 },
1261 [OP_LOCK] = { 1277 [OP_LOCK] = {
1262 .op_func = (nfsd4op_func)nfsd4_lock, 1278 .op_func = (nfsd4op_func)nfsd4_lock,
@@ -1330,10 +1346,12 @@ static struct nfsd4_operation nfsd4_ops[] = {
1330 [OP_REMOVE] = { 1346 [OP_REMOVE] = {
1331 .op_func = (nfsd4op_func)nfsd4_remove, 1347 .op_func = (nfsd4op_func)nfsd4_remove,
1332 .op_name = "OP_REMOVE", 1348 .op_name = "OP_REMOVE",
1349 .op_cacheresult = true,
1333 }, 1350 },
1334 [OP_RENAME] = { 1351 [OP_RENAME] = {
1335 .op_name = "OP_RENAME", 1352 .op_name = "OP_RENAME",
1336 .op_func = (nfsd4op_func)nfsd4_rename, 1353 .op_func = (nfsd4op_func)nfsd4_rename,
1354 .op_cacheresult = true,
1337 }, 1355 },
1338 [OP_RENEW] = { 1356 [OP_RENEW] = {
1339 .op_func = (nfsd4op_func)nfsd4_renew, 1357 .op_func = (nfsd4op_func)nfsd4_renew,
@@ -1359,16 +1377,19 @@ static struct nfsd4_operation nfsd4_ops[] = {
1359 [OP_SETATTR] = { 1377 [OP_SETATTR] = {
1360 .op_func = (nfsd4op_func)nfsd4_setattr, 1378 .op_func = (nfsd4op_func)nfsd4_setattr,
1361 .op_name = "OP_SETATTR", 1379 .op_name = "OP_SETATTR",
1380 .op_cacheresult = true,
1362 }, 1381 },
1363 [OP_SETCLIENTID] = { 1382 [OP_SETCLIENTID] = {
1364 .op_func = (nfsd4op_func)nfsd4_setclientid, 1383 .op_func = (nfsd4op_func)nfsd4_setclientid,
1365 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, 1384 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
1366 .op_name = "OP_SETCLIENTID", 1385 .op_name = "OP_SETCLIENTID",
1386 .op_cacheresult = true,
1367 }, 1387 },
1368 [OP_SETCLIENTID_CONFIRM] = { 1388 [OP_SETCLIENTID_CONFIRM] = {
1369 .op_func = (nfsd4op_func)nfsd4_setclientid_confirm, 1389 .op_func = (nfsd4op_func)nfsd4_setclientid_confirm,
1370 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, 1390 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
1371 .op_name = "OP_SETCLIENTID_CONFIRM", 1391 .op_name = "OP_SETCLIENTID_CONFIRM",
1392 .op_cacheresult = true,
1372 }, 1393 },
1373 [OP_VERIFY] = { 1394 [OP_VERIFY] = {
1374 .op_func = (nfsd4op_func)nfsd4_verify, 1395 .op_func = (nfsd4op_func)nfsd4_verify,
@@ -1377,6 +1398,7 @@ static struct nfsd4_operation nfsd4_ops[] = {
1377 [OP_WRITE] = { 1398 [OP_WRITE] = {
1378 .op_func = (nfsd4op_func)nfsd4_write, 1399 .op_func = (nfsd4op_func)nfsd4_write,
1379 .op_name = "OP_WRITE", 1400 .op_name = "OP_WRITE",
1401 .op_cacheresult = true,
1380 }, 1402 },
1381 [OP_RELEASE_LOCKOWNER] = { 1403 [OP_RELEASE_LOCKOWNER] = {
1382 .op_func = (nfsd4op_func)nfsd4_release_lockowner, 1404 .op_func = (nfsd4op_func)nfsd4_release_lockowner,
@@ -1447,16 +1469,6 @@ static const char *nfsd4_op_name(unsigned opnum)
1447#define nfsd4_voidres nfsd4_voidargs 1469#define nfsd4_voidres nfsd4_voidargs
1448struct nfsd4_voidargs { int dummy; }; 1470struct nfsd4_voidargs { int dummy; };
1449 1471
1450/*
1451 * TODO: At the present time, the NFSv4 server does not do XID caching
1452 * of requests. Implementing XID caching would not be a serious problem,
1453 * although it would require a mild change in interfaces since one
1454 * doesn't know whether an NFSv4 request is idempotent until after the
1455 * XDR decode. However, XID caching totally confuses pynfs (Peter
1456 * Astrand's regression testsuite for NFSv4 servers), which reuses
1457 * XID's liberally, so I've left it unimplemented until pynfs generates
1458 * better XID's.
1459 */
1460static struct svc_procedure nfsd_procedures4[2] = { 1472static struct svc_procedure nfsd_procedures4[2] = {
1461 [NFSPROC4_NULL] = { 1473 [NFSPROC4_NULL] = {
1462 .pc_func = (svc_procfunc) nfsd4_proc_null, 1474 .pc_func = (svc_procfunc) nfsd4_proc_null,
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index c43f56021501..c8bf405d19de 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -52,6 +52,7 @@
52#include "xdr4.h" 52#include "xdr4.h"
53#include "vfs.h" 53#include "vfs.h"
54#include "state.h" 54#include "state.h"
55#include "cache.h"
55 56
56#define NFSDDBG_FACILITY NFSDDBG_XDR 57#define NFSDDBG_FACILITY NFSDDBG_XDR
57 58
@@ -1466,6 +1467,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
1466 DECODE_HEAD; 1467 DECODE_HEAD;
1467 struct nfsd4_op *op; 1468 struct nfsd4_op *op;
1468 struct nfsd4_minorversion_ops *ops; 1469 struct nfsd4_minorversion_ops *ops;
1470 bool cachethis = false;
1469 int i; 1471 int i;
1470 1472
1471 /* 1473 /*
@@ -1547,7 +1549,16 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
1547 argp->opcnt = i+1; 1549 argp->opcnt = i+1;
1548 break; 1550 break;
1549 } 1551 }
1552 /*
1553 * We'll try to cache the result in the DRC if any one
1554 * op in the compound wants to be cached:
1555 */
1556 cachethis |= nfsd4_cache_this_op(op);
1550 } 1557 }
1558 /* Sessions make the DRC unnecessary: */
1559 if (argp->minorversion)
1560 cachethis = false;
1561 argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE;
1551 1562
1552 DECODE_TAIL; 1563 DECODE_TAIL;
1553} 1564}
diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c
index 4666a209678a..2cbac34a55da 100644
--- a/fs/nfsd/nfscache.c
+++ b/fs/nfsd/nfscache.c
@@ -118,7 +118,7 @@ hash_refile(struct svc_cacherep *rp)
118 * Note that no operation within the loop may sleep. 118 * Note that no operation within the loop may sleep.
119 */ 119 */
120int 120int
121nfsd_cache_lookup(struct svc_rqst *rqstp, int type) 121nfsd_cache_lookup(struct svc_rqst *rqstp)
122{ 122{
123 struct hlist_node *hn; 123 struct hlist_node *hn;
124 struct hlist_head *rh; 124 struct hlist_head *rh;
@@ -128,6 +128,7 @@ nfsd_cache_lookup(struct svc_rqst *rqstp, int type)
128 vers = rqstp->rq_vers, 128 vers = rqstp->rq_vers,
129 proc = rqstp->rq_proc; 129 proc = rqstp->rq_proc;
130 unsigned long age; 130 unsigned long age;
131 int type = rqstp->rq_cachetype;
131 int rtn; 132 int rtn;
132 133
133 rqstp->rq_cacherep = NULL; 134 rqstp->rq_cacherep = NULL;
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index bb8397f9da25..dc5a1bf476b1 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -570,8 +570,22 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
570 rqstp->rq_vers, rqstp->rq_proc); 570 rqstp->rq_vers, rqstp->rq_proc);
571 proc = rqstp->rq_procinfo; 571 proc = rqstp->rq_procinfo;
572 572
573 /*
574 * Give the xdr decoder a chance to change this if it wants
575 * (necessary in the NFSv4.0 compound case)
576 */
577 rqstp->rq_cachetype = proc->pc_cachetype;
578 /* Decode arguments */
579 xdr = proc->pc_decode;
580 if (xdr && !xdr(rqstp, (__be32*)rqstp->rq_arg.head[0].iov_base,
581 rqstp->rq_argp)) {
582 dprintk("nfsd: failed to decode arguments!\n");
583 *statp = rpc_garbage_args;
584 return 1;
585 }
586
573 /* Check whether we have this call in the cache. */ 587 /* Check whether we have this call in the cache. */
574 switch (nfsd_cache_lookup(rqstp, proc->pc_cachetype)) { 588 switch (nfsd_cache_lookup(rqstp)) {
575 case RC_INTR: 589 case RC_INTR:
576 case RC_DROPIT: 590 case RC_DROPIT:
577 return 0; 591 return 0;
@@ -581,16 +595,6 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
581 /* do it */ 595 /* do it */
582 } 596 }
583 597
584 /* Decode arguments */
585 xdr = proc->pc_decode;
586 if (xdr && !xdr(rqstp, (__be32*)rqstp->rq_arg.head[0].iov_base,
587 rqstp->rq_argp)) {
588 dprintk("nfsd: failed to decode arguments!\n");
589 nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
590 *statp = rpc_garbage_args;
591 return 1;
592 }
593
594 /* need to grab the location to store the status, as 598 /* need to grab the location to store the status, as
595 * nfsv4 does some encoding while processing 599 * nfsv4 does some encoding while processing
596 */ 600 */
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 351348c79631..d2a8d04428c7 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -457,6 +457,8 @@ struct nfsd4_op {
457 struct nfs4_replay * replay; 457 struct nfs4_replay * replay;
458}; 458};
459 459
460bool nfsd4_cache_this_op(struct nfsd4_op *);
461
460struct nfsd4_compoundargs { 462struct nfsd4_compoundargs {
461 /* scratch variables for XDR decode */ 463 /* scratch variables for XDR decode */
462 __be32 * p; 464 __be32 * p;
@@ -479,6 +481,7 @@ struct nfsd4_compoundargs {
479 u32 opcnt; 481 u32 opcnt;
480 struct nfsd4_op *ops; 482 struct nfsd4_op *ops;
481 struct nfsd4_op iops[8]; 483 struct nfsd4_op iops[8];
484 int cachetype;
482}; 485};
483 486
484struct nfsd4_compoundres { 487struct nfsd4_compoundres {
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index ea29330b78bd..2f1e5186e049 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -273,6 +273,7 @@ struct svc_rqst {
273 /* Catering to nfsd */ 273 /* Catering to nfsd */
274 struct auth_domain * rq_client; /* RPC peer info */ 274 struct auth_domain * rq_client; /* RPC peer info */
275 struct auth_domain * rq_gssclient; /* "gss/"-style peer info */ 275 struct auth_domain * rq_gssclient; /* "gss/"-style peer info */
276 int rq_cachetype;
276 struct svc_cacherep * rq_cacherep; /* cache info */ 277 struct svc_cacherep * rq_cacherep; /* cache info */
277 int rq_splice_ok; /* turned off in gss privacy 278 int rq_splice_ok; /* turned off in gss privacy
278 * to prevent encrypting page 279 * to prevent encrypting page