aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2011-01-24 12:11:02 -0500
committerJ. Bruce Fields <bfields@redhat.com>2011-07-18 09:39:01 -0400
commit1091006c5eb15cba56785bd5b498a8d0b9546903 (patch)
treeb51fad1bb57284b3eea4308c02652c4888b85860
parent3e98abffd1665b884a322aedcd528577842f762f (diff)
nfsd: turn on reply cache for NFSv4
It's sort of ridiculous that we've never had a working reply cache for NFSv4. On the other hand, we may still not: our current reply cache is likely not very good, especially in the TCP case (which is the only case that matters for v4). What we really need here is some serious testing. Anyway, here's a start. Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-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