Commit 1091006c5eb15cba56785bd5b498a8d0b9546903

Authored by J. Bruce Fields
1 parent 3e98abffd1

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>

Showing 7 changed files with 55 additions and 23 deletions Side-by-side Diff

... ... @@ -69,7 +69,7 @@
69 69  
70 70 int nfsd_reply_cache_init(void);
71 71 void nfsd_reply_cache_shutdown(void);
72   -int nfsd_cache_lookup(struct svc_rqst *, int);
  72 +int nfsd_cache_lookup(struct svc_rqst *);
73 73 void nfsd_cache_update(struct svc_rqst *, int, __be32 *);
74 74  
75 75 #ifdef CONFIG_NFSD_V4
... ... @@ -1007,6 +1007,15 @@
1007 1007 nfsd4op_func op_func;
1008 1008 u32 op_flags;
1009 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  
1012 1021 static struct nfsd4_operation nfsd4_ops[];
... ... @@ -1051,6 +1060,11 @@
1051 1060 return &nfsd4_ops[op->opnum];
1052 1061 }
1053 1062  
  1063 +bool nfsd4_cache_this_op(struct nfsd4_op *op)
  1064 +{
  1065 + return OPDESC(op)->op_cacheresult;
  1066 +}
  1067 +
1054 1068 static bool need_wrongsec_check(struct svc_rqst *rqstp)
1055 1069 {
1056 1070 struct nfsd4_compoundres *resp = rqstp->rq_resp;
... ... @@ -1240,6 +1254,7 @@
1240 1254 [OP_CREATE] = {
1241 1255 .op_func = (nfsd4op_func)nfsd4_create,
1242 1256 .op_name = "OP_CREATE",
  1257 + .op_cacheresult = true,
1243 1258 },
1244 1259 [OP_DELEGRETURN] = {
1245 1260 .op_func = (nfsd4op_func)nfsd4_delegreturn,
... ... @@ -1257,6 +1272,7 @@
1257 1272 [OP_LINK] = {
1258 1273 .op_func = (nfsd4op_func)nfsd4_link,
1259 1274 .op_name = "OP_LINK",
  1275 + .op_cacheresult = true,
1260 1276 },
1261 1277 [OP_LOCK] = {
1262 1278 .op_func = (nfsd4op_func)nfsd4_lock,
1263 1279  
... ... @@ -1330,10 +1346,12 @@
1330 1346 [OP_REMOVE] = {
1331 1347 .op_func = (nfsd4op_func)nfsd4_remove,
1332 1348 .op_name = "OP_REMOVE",
  1349 + .op_cacheresult = true,
1333 1350 },
1334 1351 [OP_RENAME] = {
1335 1352 .op_name = "OP_RENAME",
1336 1353 .op_func = (nfsd4op_func)nfsd4_rename,
  1354 + .op_cacheresult = true,
1337 1355 },
1338 1356 [OP_RENEW] = {
1339 1357 .op_func = (nfsd4op_func)nfsd4_renew,
1340 1358  
1341 1359  
... ... @@ -1359,16 +1377,19 @@
1359 1377 [OP_SETATTR] = {
1360 1378 .op_func = (nfsd4op_func)nfsd4_setattr,
1361 1379 .op_name = "OP_SETATTR",
  1380 + .op_cacheresult = true,
1362 1381 },
1363 1382 [OP_SETCLIENTID] = {
1364 1383 .op_func = (nfsd4op_func)nfsd4_setclientid,
1365 1384 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
1366 1385 .op_name = "OP_SETCLIENTID",
  1386 + .op_cacheresult = true,
1367 1387 },
1368 1388 [OP_SETCLIENTID_CONFIRM] = {
1369 1389 .op_func = (nfsd4op_func)nfsd4_setclientid_confirm,
1370 1390 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
1371 1391 .op_name = "OP_SETCLIENTID_CONFIRM",
  1392 + .op_cacheresult = true,
1372 1393 },
1373 1394 [OP_VERIFY] = {
1374 1395 .op_func = (nfsd4op_func)nfsd4_verify,
... ... @@ -1377,6 +1398,7 @@
1377 1398 [OP_WRITE] = {
1378 1399 .op_func = (nfsd4op_func)nfsd4_write,
1379 1400 .op_name = "OP_WRITE",
  1401 + .op_cacheresult = true,
1380 1402 },
1381 1403 [OP_RELEASE_LOCKOWNER] = {
1382 1404 .op_func = (nfsd4op_func)nfsd4_release_lockowner,
... ... @@ -1447,16 +1469,6 @@
1447 1469 #define nfsd4_voidres nfsd4_voidargs
1448 1470 struct 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   - */
1460 1472 static struct svc_procedure nfsd_procedures4[2] = {
1461 1473 [NFSPROC4_NULL] = {
1462 1474 .pc_func = (svc_procfunc) nfsd4_proc_null,
... ... @@ -52,6 +52,7 @@
52 52 #include "xdr4.h"
53 53 #include "vfs.h"
54 54 #include "state.h"
  55 +#include "cache.h"
55 56  
56 57 #define NFSDDBG_FACILITY NFSDDBG_XDR
57 58  
... ... @@ -1466,6 +1467,7 @@
1466 1467 DECODE_HEAD;
1467 1468 struct nfsd4_op *op;
1468 1469 struct nfsd4_minorversion_ops *ops;
  1470 + bool cachethis = false;
1469 1471 int i;
1470 1472  
1471 1473 /*
1472 1474  
... ... @@ -1547,7 +1549,16 @@
1547 1549 argp->opcnt = i+1;
1548 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 1563 DECODE_TAIL;
1553 1564 }
... ... @@ -118,7 +118,7 @@
118 118 * Note that no operation within the loop may sleep.
119 119 */
120 120 int
121   -nfsd_cache_lookup(struct svc_rqst *rqstp, int type)
  121 +nfsd_cache_lookup(struct svc_rqst *rqstp)
122 122 {
123 123 struct hlist_node *hn;
124 124 struct hlist_head *rh;
... ... @@ -128,6 +128,7 @@
128 128 vers = rqstp->rq_vers,
129 129 proc = rqstp->rq_proc;
130 130 unsigned long age;
  131 + int type = rqstp->rq_cachetype;
131 132 int rtn;
132 133  
133 134 rqstp->rq_cacherep = NULL;
... ... @@ -570,8 +570,22 @@
570 570 rqstp->rq_vers, rqstp->rq_proc);
571 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 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 589 case RC_INTR:
576 590 case RC_DROPIT:
577 591 return 0;
... ... @@ -579,16 +593,6 @@
579 593 return 1;
580 594 case RC_DOIT:;
581 595 /* do it */
582   - }
583   -
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 596 }
593 597  
594 598 /* need to grab the location to store the status, as
... ... @@ -457,6 +457,8 @@
457 457 struct nfs4_replay * replay;
458 458 };
459 459  
  460 +bool nfsd4_cache_this_op(struct nfsd4_op *);
  461 +
460 462 struct nfsd4_compoundargs {
461 463 /* scratch variables for XDR decode */
462 464 __be32 * p;
... ... @@ -479,6 +481,7 @@
479 481 u32 opcnt;
480 482 struct nfsd4_op *ops;
481 483 struct nfsd4_op iops[8];
  484 + int cachetype;
482 485 };
483 486  
484 487 struct nfsd4_compoundres {
include/linux/sunrpc/svc.h
... ... @@ -273,6 +273,7 @@
273 273 /* Catering to nfsd */
274 274 struct auth_domain * rq_client; /* RPC peer info */
275 275 struct auth_domain * rq_gssclient; /* "gss/"-style peer info */
  276 + int rq_cachetype;
276 277 struct svc_cacherep * rq_cacherep; /* cache info */
277 278 int rq_splice_ok; /* turned off in gss privacy
278 279 * to prevent encrypting page