Commit 1091006c5eb15cba56785bd5b498a8d0b9546903
1 parent
3e98abffd1
Exists in
master
and in
6 other branches
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
fs/nfsd/cache.h
... | ... | @@ -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 |
fs/nfsd/nfs4proc.c
... | ... | @@ -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, |
fs/nfsd/nfs4xdr.c
... | ... | @@ -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 | } |
fs/nfsd/nfscache.c
... | ... | @@ -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; |
fs/nfsd/nfssvc.c
... | ... | @@ -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 |
fs/nfsd/xdr4.h
... | ... | @@ -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 |