aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfsd/nfs4proc.c34
-rw-r--r--fs/nfsd/nfs4state.c47
-rw-r--r--fs/nfsd/nfs4xdr.c5
-rw-r--r--include/linux/nfsd/state.h1
-rw-r--r--include/linux/nfsd/xdr4.h15
5 files changed, 91 insertions, 11 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 9e2ee75e0f7c..ae21a4efe36c 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -828,6 +828,34 @@ static struct nfsd4_operation nfsd4_ops[];
828static const char *nfsd4_op_name(unsigned opnum); 828static const char *nfsd4_op_name(unsigned opnum);
829 829
830/* 830/*
831 * This is a replay of a compound for which no cache entry pages
832 * were used. Encode the sequence operation, and if cachethis is FALSE
833 * encode the uncache rep error on the next operation.
834 */
835static __be32
836nfsd4_enc_uncached_replay(struct nfsd4_compoundargs *args,
837 struct nfsd4_compoundres *resp)
838{
839 struct nfsd4_op *op;
840
841 dprintk("--> %s resp->opcnt %d ce_cachethis %u \n", __func__,
842 resp->opcnt, resp->cstate.slot->sl_cache_entry.ce_cachethis);
843
844 /* Encode the replayed sequence operation */
845 BUG_ON(resp->opcnt != 1);
846 op = &args->ops[resp->opcnt - 1];
847 nfsd4_encode_operation(resp, op);
848
849 /*return nfserr_retry_uncached_rep in next operation. */
850 if (resp->cstate.slot->sl_cache_entry.ce_cachethis == 0) {
851 op = &args->ops[resp->opcnt++];
852 op->status = nfserr_retry_uncached_rep;
853 nfsd4_encode_operation(resp, op);
854 }
855 return op->status;
856}
857
858/*
831 * Enforce NFSv4.1 COMPOUND ordering rules. 859 * Enforce NFSv4.1 COMPOUND ordering rules.
832 * 860 *
833 * TODO: 861 * TODO:
@@ -895,7 +923,6 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
895 dprintk("nfsv4 compound op #%d/%d: %d (%s)\n", 923 dprintk("nfsv4 compound op #%d/%d: %d (%s)\n",
896 resp->opcnt, args->opcnt, op->opnum, 924 resp->opcnt, args->opcnt, op->opnum,
897 nfsd4_op_name(op->opnum)); 925 nfsd4_op_name(op->opnum));
898
899 /* 926 /*
900 * The XDR decode routines may have pre-set op->status; 927 * The XDR decode routines may have pre-set op->status;
901 * for example, if there is a miscellaneous XDR error 928 * for example, if there is a miscellaneous XDR error
@@ -939,7 +966,10 @@ encode_op:
939 /* Only from SEQUENCE or CREATE_SESSION */ 966 /* Only from SEQUENCE or CREATE_SESSION */
940 if (resp->cstate.status == nfserr_replay_cache) { 967 if (resp->cstate.status == nfserr_replay_cache) {
941 dprintk("%s NFS4.1 replay from cache\n", __func__); 968 dprintk("%s NFS4.1 replay from cache\n", __func__);
942 status = op->status; 969 if (nfsd4_not_cached(resp))
970 status = nfsd4_enc_uncached_replay(args, resp);
971 else
972 status = op->status;
943 goto out; 973 goto out;
944 } 974 }
945 if (op->status == nfserr_replay_me) { 975 if (op->status == nfserr_replay_me) {
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 58f9797eb09e..04a395fb5dce 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1049,17 +1049,31 @@ nfsd4_store_cache_entry(struct nfsd4_compoundres *resp)
1049 /* Don't cache a failed OP_SEQUENCE. */ 1049 /* Don't cache a failed OP_SEQUENCE. */
1050 if (resp->opcnt == 1 && op->opnum == OP_SEQUENCE && resp->cstate.status) 1050 if (resp->opcnt == 1 && op->opnum == OP_SEQUENCE && resp->cstate.status)
1051 return; 1051 return;
1052
1052 nfsd4_release_respages(entry->ce_respages, entry->ce_resused); 1053 nfsd4_release_respages(entry->ce_respages, entry->ce_resused);
1054 entry->ce_opcnt = resp->opcnt;
1055 entry->ce_status = resp->cstate.status;
1056
1057 /*
1058 * Don't need a page to cache just the sequence operation - the slot
1059 * does this for us!
1060 */
1061
1062 if (nfsd4_not_cached(resp)) {
1063 entry->ce_resused = 0;
1064 entry->ce_rpchdrlen = 0;
1065 dprintk("%s Just cache SEQUENCE. ce_cachethis %d\n", __func__,
1066 resp->cstate.slot->sl_cache_entry.ce_cachethis);
1067 return;
1068 }
1053 entry->ce_resused = rqstp->rq_resused; 1069 entry->ce_resused = rqstp->rq_resused;
1054 if (entry->ce_resused > NFSD_PAGES_PER_SLOT + 1) 1070 if (entry->ce_resused > NFSD_PAGES_PER_SLOT + 1)
1055 entry->ce_resused = NFSD_PAGES_PER_SLOT + 1; 1071 entry->ce_resused = NFSD_PAGES_PER_SLOT + 1;
1056 nfsd4_copy_pages(entry->ce_respages, rqstp->rq_respages, 1072 nfsd4_copy_pages(entry->ce_respages, rqstp->rq_respages,
1057 entry->ce_resused); 1073 entry->ce_resused);
1058 entry->ce_status = resp->cstate.status;
1059 entry->ce_datav.iov_base = resp->cstate.statp; 1074 entry->ce_datav.iov_base = resp->cstate.statp;
1060 entry->ce_datav.iov_len = resv->iov_len - ((char *)resp->cstate.statp - 1075 entry->ce_datav.iov_len = resv->iov_len - ((char *)resp->cstate.statp -
1061 (char *)page_address(rqstp->rq_respages[0])); 1076 (char *)page_address(rqstp->rq_respages[0]));
1062 entry->ce_opcnt = resp->opcnt;
1063 /* Current request rpc header length*/ 1077 /* Current request rpc header length*/
1064 entry->ce_rpchdrlen = (char *)resp->cstate.statp - 1078 entry->ce_rpchdrlen = (char *)resp->cstate.statp -
1065 (char *)page_address(rqstp->rq_respages[0]); 1079 (char *)page_address(rqstp->rq_respages[0]);
@@ -1096,13 +1110,28 @@ nfsd41_copy_replay_data(struct nfsd4_compoundres *resp,
1096 * cached page. Replace any futher replay pages from the cache. 1110 * cached page. Replace any futher replay pages from the cache.
1097 */ 1111 */
1098__be32 1112__be32
1099nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp) 1113nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp,
1114 struct nfsd4_sequence *seq)
1100{ 1115{
1101 struct nfsd4_cache_entry *entry = &resp->cstate.slot->sl_cache_entry; 1116 struct nfsd4_cache_entry *entry = &resp->cstate.slot->sl_cache_entry;
1102 __be32 status; 1117 __be32 status;
1103 1118
1104 dprintk("--> %s entry %p\n", __func__, entry); 1119 dprintk("--> %s entry %p\n", __func__, entry);
1105 1120
1121 /*
1122 * If this is just the sequence operation, we did not keep
1123 * a page in the cache entry because we can just use the
1124 * slot info stored in struct nfsd4_sequence that was checked
1125 * against the slot in nfsd4_sequence().
1126 *
1127 * This occurs when seq->cachethis is FALSE, or when the client
1128 * session inactivity timer fires and a solo sequence operation
1129 * is sent (lease renewal).
1130 */
1131 if (seq && nfsd4_not_cached(resp)) {
1132 seq->maxslots = resp->cstate.session->se_fnumslots;
1133 return nfs_ok;
1134 }
1106 1135
1107 if (!nfsd41_copy_replay_data(resp, entry)) { 1136 if (!nfsd41_copy_replay_data(resp, entry)) {
1108 /* 1137 /*
@@ -1330,7 +1359,7 @@ nfsd4_create_session(struct svc_rqst *rqstp,
1330 cstate->slot = slot; 1359 cstate->slot = slot;
1331 cstate->status = status; 1360 cstate->status = status;
1332 /* Return the cached reply status */ 1361 /* Return the cached reply status */
1333 status = nfsd4_replay_cache_entry(resp); 1362 status = nfsd4_replay_cache_entry(resp, NULL);
1334 goto out; 1363 goto out;
1335 } else if (cr_ses->seqid != conf->cl_slot.sl_seqid + 1) { 1364 } else if (cr_ses->seqid != conf->cl_slot.sl_seqid + 1) {
1336 status = nfserr_seq_misordered; 1365 status = nfserr_seq_misordered;
@@ -1380,6 +1409,8 @@ nfsd4_create_session(struct svc_rqst *rqstp,
1380 1409
1381 slot->sl_inuse = true; 1410 slot->sl_inuse = true;
1382 cstate->slot = slot; 1411 cstate->slot = slot;
1412 /* Ensure a page is used for the cache */
1413 slot->sl_cache_entry.ce_cachethis = 1;
1383out: 1414out:
1384 nfs4_unlock_state(); 1415 nfs4_unlock_state();
1385 dprintk("%s returns %d\n", __func__, ntohl(status)); 1416 dprintk("%s returns %d\n", __func__, ntohl(status));
@@ -1425,8 +1456,8 @@ nfsd4_sequence(struct svc_rqst *rqstp,
1425 cstate->slot = slot; 1456 cstate->slot = slot;
1426 cstate->session = session; 1457 cstate->session = session;
1427 /* Return the cached reply status and set cstate->status 1458 /* Return the cached reply status and set cstate->status
1428 * for nfsd4_svc_encode_compoundres processing*/ 1459 * for nfsd4_svc_encode_compoundres processing */
1429 status = nfsd4_replay_cache_entry(resp); 1460 status = nfsd4_replay_cache_entry(resp, seq);
1430 cstate->status = nfserr_replay_cache; 1461 cstate->status = nfserr_replay_cache;
1431 goto replay_cache; 1462 goto replay_cache;
1432 } 1463 }
@@ -1436,6 +1467,10 @@ nfsd4_sequence(struct svc_rqst *rqstp,
1436 /* Success! bump slot seqid */ 1467 /* Success! bump slot seqid */
1437 slot->sl_inuse = true; 1468 slot->sl_inuse = true;
1438 slot->sl_seqid = seq->seqid; 1469 slot->sl_seqid = seq->seqid;
1470 slot->sl_cache_entry.ce_cachethis = seq->cachethis;
1471 /* Always set the cache entry cachethis for solo sequence */
1472 if (nfsd4_is_solo_sequence(resp))
1473 slot->sl_cache_entry.ce_cachethis = 1;
1439 1474
1440 cstate->slot = slot; 1475 cstate->slot = slot;
1441 cstate->session = session; 1476 cstate->session = session;
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 671f9b96429b..64bc2150a6fa 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -2975,7 +2975,7 @@ nfsd4_encode_destroy_session(struct nfsd4_compoundres *resp, int nfserr,
2975 return nfserr; 2975 return nfserr;
2976} 2976}
2977 2977
2978static __be32 2978__be32
2979nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, 2979nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr,
2980 struct nfsd4_sequence *seq) 2980 struct nfsd4_sequence *seq)
2981{ 2981{
@@ -3192,7 +3192,8 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo
3192 iov->iov_len = ((char*)resp->p) - (char*)iov->iov_base; 3192 iov->iov_len = ((char*)resp->p) - (char*)iov->iov_base;
3193 BUG_ON(iov->iov_len > PAGE_SIZE); 3193 BUG_ON(iov->iov_len > PAGE_SIZE);
3194 if (resp->cstate.slot != NULL) { 3194 if (resp->cstate.slot != NULL) {
3195 if (resp->cstate.status == nfserr_replay_cache) { 3195 if (resp->cstate.status == nfserr_replay_cache &&
3196 !nfsd4_not_cached(resp)) {
3196 iov->iov_len = resp->cstate.iovlen; 3197 iov->iov_len = resp->cstate.iovlen;
3197 } else { 3198 } else {
3198 nfsd4_store_cache_entry(resp); 3199 nfsd4_store_cache_entry(resp);
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h
index f063df7ad134..18dcffa57f77 100644
--- a/include/linux/nfsd/state.h
+++ b/include/linux/nfsd/state.h
@@ -110,6 +110,7 @@ struct nfsd4_cache_entry {
110 __be32 ce_status; 110 __be32 ce_status;
111 struct kvec ce_datav; /* encoded NFSv4.1 data in rq_res.head[0] */ 111 struct kvec ce_datav; /* encoded NFSv4.1 data in rq_res.head[0] */
112 struct page *ce_respages[NFSD_PAGES_PER_SLOT + 1]; 112 struct page *ce_respages[NFSD_PAGES_PER_SLOT + 1];
113 int ce_cachethis;
113 short ce_resused; 114 short ce_resused;
114 int ce_opcnt; 115 int ce_opcnt;
115 int ce_rpchdrlen; 116 int ce_rpchdrlen;
diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h
index 9468829adb70..486188810a60 100644
--- a/include/linux/nfsd/xdr4.h
+++ b/include/linux/nfsd/xdr4.h
@@ -480,6 +480,18 @@ struct nfsd4_compoundres {
480 struct nfsd4_compound_state cstate; 480 struct nfsd4_compound_state cstate;
481}; 481};
482 482
483static inline bool nfsd4_is_solo_sequence(struct nfsd4_compoundres *resp)
484{
485 struct nfsd4_compoundargs *args = resp->rqstp->rq_argp;
486 return args->opcnt == 1;
487}
488
489static inline bool nfsd4_not_cached(struct nfsd4_compoundres *resp)
490{
491 return !resp->cstate.slot->sl_cache_entry.ce_cachethis ||
492 nfsd4_is_solo_sequence(resp);
493}
494
483#define NFS4_SVC_XDRSIZE sizeof(struct nfsd4_compoundargs) 495#define NFS4_SVC_XDRSIZE sizeof(struct nfsd4_compoundargs)
484 496
485static inline void 497static inline void
@@ -510,7 +522,8 @@ extern __be32 nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
510 struct nfsd4_compound_state *, 522 struct nfsd4_compound_state *,
511 struct nfsd4_setclientid_confirm *setclientid_confirm); 523 struct nfsd4_setclientid_confirm *setclientid_confirm);
512extern void nfsd4_store_cache_entry(struct nfsd4_compoundres *resp); 524extern void nfsd4_store_cache_entry(struct nfsd4_compoundres *resp);
513extern __be32 nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp); 525extern __be32 nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp,
526 struct nfsd4_sequence *seq);
514extern __be32 nfsd4_exchange_id(struct svc_rqst *rqstp, 527extern __be32 nfsd4_exchange_id(struct svc_rqst *rqstp,
515 struct nfsd4_compound_state *, 528 struct nfsd4_compound_state *,
516struct nfsd4_exchange_id *); 529struct nfsd4_exchange_id *);