diff options
| -rw-r--r-- | fs/nfsd/cache.h | 2 | ||||
| -rw-r--r-- | fs/nfsd/nfs4proc.c | 32 | ||||
| -rw-r--r-- | fs/nfsd/nfs4xdr.c | 11 | ||||
| -rw-r--r-- | fs/nfsd/nfscache.c | 3 | ||||
| -rw-r--r-- | fs/nfsd/nfssvc.c | 26 | ||||
| -rw-r--r-- | fs/nfsd/xdr4.h | 3 | ||||
| -rw-r--r-- | include/linux/sunrpc/svc.h | 1 |
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 | ||
| 70 | int nfsd_reply_cache_init(void); | 70 | int nfsd_reply_cache_init(void); |
| 71 | void nfsd_reply_cache_shutdown(void); | 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 | void nfsd_cache_update(struct svc_rqst *, int, __be32 *); | 73 | void 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 | ||
| 1012 | static struct nfsd4_operation nfsd4_ops[]; | 1021 | static 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 | ||
| 1063 | bool nfsd4_cache_this_op(struct nfsd4_op *op) | ||
| 1064 | { | ||
| 1065 | return OPDESC(op)->op_cacheresult; | ||
| 1066 | } | ||
| 1067 | |||
| 1054 | static bool need_wrongsec_check(struct svc_rqst *rqstp) | 1068 | static 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 |
| 1448 | struct nfsd4_voidargs { int dummy; }; | 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 | static struct svc_procedure nfsd_procedures4[2] = { | 1472 | static 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 | */ |
| 120 | int | 120 | int |
| 121 | nfsd_cache_lookup(struct svc_rqst *rqstp, int type) | 121 | nfsd_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 | ||
| 460 | bool nfsd4_cache_this_op(struct nfsd4_op *); | ||
| 461 | |||
| 460 | struct nfsd4_compoundargs { | 462 | struct 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 | ||
| 484 | struct nfsd4_compoundres { | 487 | struct 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 |
