Skip to contentSkip to conversation

kNFSd - 3 of 7 - Subject: PATCH - nfsv4 - 1 of 1 idempotent replay cache for OPEN state

PATCH New NeilBrown 1 participant 1 message Sep 22, 2003

Subsystems (2)
lore
Share & tools
lore

NeilBrown

author
#0 lore raw

PATCH 1/1 kNFSd - 3 of 7 - Subject: PATCH - nfsv4 - 1 of 1 idempotent replay cache for OPEN state

### Comments for ChangeSet

this patch implements the idempotent replay cache need for NFSv4 OPEN state. each state owner (open owner or lock owner) is required to store the last sequence number mutating operation, and retransmit it when replayed sequence number is presented for the operation. i've implemented the cache as a static buffer of size 112 bytes (NFSD4_REPLAY_ISIZE) which is large enough to hold the OPEN, the largest of the sequence mutation operations. this patch implements the cache for OPEN, OPEN_CONFIRM, OPEN_DOWNGRADE, and CLOSE. LOCK and UNLOCK will be added when byte-range locking is done (soon!).

-->Andy

----------- Diffstat output ------------

 ./fs/nfsd/nfs4proc.c         |   13 +++++++-
 ./fs/nfsd/nfs4state.c        |   35 ++++++++++++++++-------
 ./fs/nfsd/nfs4xdr.c          |   65 +++++++++++++++++++++++++++++++++----------
 ./include/linux/nfsd/state.h |   22 ++++++++++++++
 ./include/linux/nfsd/xdr4.h  |    2 +
 5 files changed, 111 insertions(+), 26 deletions(-)
fs/nfsd/nfs4proc.c renamed from fs/nfsd/nfs4proc.c~current~ +11 -2
diff ./fs/nfsd/nfs4proc.c~current~ ./fs/nfsd/nfs4proc.c
@@ -664,6 +664,7 @@ nfsd4_proc_compound(struct svc_rqst *rqs
 			break;
 		case OP_CLOSE:
 			op->status = nfsd4_close(rqstp, &current_fh, &op->u.close);
+			op->replay = &op->u.close.cl_stateowner->so_replay;
 			break;
 		case OP_COMMIT:
 			op->status = nfsd4_commit(rqstp, &current_fh, &op->u.commit);
@@ -693,12 +694,15 @@ nfsd4_proc_compound(struct svc_rqst *rqs
 			break;
 		case OP_OPEN:
 			op->status = nfsd4_open(rqstp, &current_fh, &op->u.open);
+			op->replay = &op->u.open.op_stateowner->so_replay;
 			break;
 		case OP_OPEN_CONFIRM:
 			op->status = nfsd4_open_confirm(rqstp, &current_fh, &op->u.open_confirm);
+			op->replay = &op->u.open_confirm.oc_stateowner->so_replay;
 			break;
 		case OP_OPEN_DOWNGRADE:
 			op->status = nfsd4_open_downgrade(rqstp, &current_fh, &op->u.open_downgrade);
+			op->replay = &op->u.open_downgrade.od_stateowner->so_replay;
 			break;
 		case OP_PUTFH:
 			op->status = nfsd4_putfh(rqstp, &current_fh, &op->u.putfh);
@@ -753,8 +757,13 @@ nfsd4_proc_compound(struct svc_rqst *rqs
 		}
 
 encode_op:
-		nfsd4_encode_operation(resp, op);
-		status = op->status;
+		if (op->status == NFSERR_REPLAY_ME) {
+			nfsd4_encode_replay(resp, op);
+			status = op->status = NFS_OK;
+		} else {
+			nfsd4_encode_operation(resp, op);
+			status = op->status;
+		}
 	}
 
 out:
fs/nfsd/nfs4state.c renamed from fs/nfsd/nfs4state.c~current~ +25 -10
diff ./fs/nfsd/nfs4state.c~current~ ./fs/nfsd/nfs4state.c
@@ -759,6 +759,7 @@ free_stateowner(struct nfs4_stateowner *
 static struct nfs4_stateowner *
 alloc_init_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_open *open) {
 	struct nfs4_stateowner *sop;
+	struct nfs4_replay *rp;
 	unsigned int idhashval;
 
 	if (!(sop = alloc_stateowner(&open->op_owner)))
@@ -776,6 +777,10 @@ alloc_init_stateowner(unsigned int strha
 	sop->so_client = clp;
 	sop->so_seqid = open->op_seqid;
 	sop->so_confirmed = 0;
+	rp = &sop->so_replay;
+	rp->rp_status = NFSERR_SERVERFAULT;
+	rp->rp_buflen = 0;
+	rp->rp_buf = rp->rp_ibuf;
 	alloc_sowner++;
 	return sop;
 }
@@ -1019,9 +1024,22 @@ nfsd4_process_open1(struct nfsd4_open *o
 	strhashval = ownerstr_hashval(clientid->cl_id, open->op_owner);
 	if (find_stateowner_str(strhashval, open, &sop)) {
 		open->op_stateowner = sop;
+		/* check for replay */
 		if (open->op_seqid == sop->so_seqid){
-			/* XXX retplay: for now, return bad seqid */
-			status = nfserr_bad_seqid;
+			if (!sop->so_replay.rp_buflen) {
+			/*
+			* The original OPEN failed in so spectacularly that we
+			* don't even have replay data saved!  Therefore, we
+			* have no choice but to continue processing
+			* this OPEN; presumably, we'll fail again for the same
+			* reason.
+			*/
+				dprintk("nfsd4_process_open1: replay with no replay cache\n");
+				status = NFS_OK;
+				goto renew;
+			}
+			/* replay: indicate to calling function */
+			status = NFSERR_REPLAY_ME;
 			goto out;
 		}
 		if (sop->so_confirmed) {
@@ -1033,9 +1051,8 @@ nfsd4_process_open1(struct nfsd4_open *o
 			goto out;
 		}
 		/* If we get here, we received and OPEN for an unconfirmed
-		 * nfs4_stateowner. If seqid's are the same then this 
-		 * is a replay.
-		 * If the sequid's are different, then purge the 
+		 * nfs4_stateowner. 
+		 * Since the sequid's are different, purge the 
 		 * existing nfs4_stateowner, and instantiate a new one.
 		 */
 		clp = sop->so_client;
@@ -1367,8 +1384,6 @@ out:
 
 /* 
  * Checks for sequence id mutating operations. 
- *
- * XXX need to code replay cache logic
  */
 int
 nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp)
@@ -1466,13 +1481,14 @@ no_nfs4_stateid:
 	}
 
 check_replay:
-	status = nfserr_bad_seqid;
 	if (seqid == sop->so_seqid) {
 		printk("NFSD: preprocess_seqid_op: retransmission?\n");
-		/* XXX will need to indicate replay to calling function here */
+		/* indicate replay to calling function */
+		status = NFSERR_REPLAY_ME;
 	} else 
 		printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d\n", sop->so_seqid +1, seqid);
 
+		status = nfserr_bad_seqid;
 	goto out;
 }
 
@@ -1499,7 +1515,6 @@ nfsd4_open_confirm(struct svc_rqst *rqst
 	sop->so_confirmed = 1;
 	update_stateid(&stp->st_stateid);
 	memcpy(&oc->oc_resp_stateid, &stp->st_stateid, sizeof(stateid_t));
-	/* XXX renew the client lease here */
 	dprintk("NFSD: nfsd4_open_confirm: success, seqid=%d " 
 		"stateid=(%08x/%08x/%08x/%08x)\n", oc->oc_seqid,
 		         stp->st_stateid.si_boot,
fs/nfsd/nfs4xdr.c renamed from fs/nfsd/nfs4xdr.c~current~ +51 -14

117 lines not on this page · raw message

include/linux/nfsd/state.h renamed from include/linux/nfsd/state.h~current~ +22 -0
diff ./include/linux/nfsd/state.h~current~ ./include/linux/nfsd/state.h
@@ -95,6 +95,27 @@ update_stateid(stateid_t *stateid)
 	stateid->si_generation++;
 }
 
+/* A reasonable value for REPLAY_ISIZE was estimated as follows:  
+ * The OPEN response, typically the largest, requires 
+ *   4(status) + 8(stateid) + 20(changeinfo) + 4(rflags) +  8(verifier) + 
+ *   4(deleg. type) + 8(deleg. stateid) + 4(deleg. recall flag) + 
+ *   20(deleg. space limit) + ~32(deleg. ace) = 112 bytes 
+ */
+
+#define NFSD4_REPLAY_ISIZE       112 
+
+/*
+ * Replay buffer, where the result of the last seqid-mutating operation 
+ * is cached. 
+ */
+struct nfs4_replay {
+	u32			rp_status;
+	unsigned int		rp_buflen;
+	char			*rp_buf;
+	unsigned		intrp_allocated;
+	char			rp_ibuf[NFSD4_REPLAY_ISIZE];
+};
+
 /*
 * nfs4_stateowner can either be an open_owner, or (eventually) a lock_owner
 *
@@ -111,6 +132,7 @@ struct nfs4_stateowner {
 	u32                     so_seqid;    
 	struct xdr_netobj       so_owner;     /* open owner name */
 	int                     so_confirmed; /* successful OPEN_CONFIRM? */
+	struct nfs4_replay	so_replay;
 };
 
 /*
include/linux/nfsd/xdr4.h renamed from include/linux/nfsd/xdr4.h~current~ +2 -0
diff ./include/linux/nfsd/xdr4.h~current~ ./include/linux/nfsd/xdr4.h
@@ -284,6 +284,7 @@ struct nfsd4_op {
 		struct nfsd4_verify		verify;
 		struct nfsd4_write		write;
 	} u;
+	struct nfs4_replay *			replay;
 };
 
 struct nfsd4_compoundargs {
@@ -339,6 +340,7 @@ int nfs4svc_decode_compoundargs(struct s
 int nfs4svc_encode_compoundres(struct svc_rqst *, u32 *, 
 		struct nfsd4_compoundres *);
 void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *);
+void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op);
 int nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
 		       struct dentry *dentry, u32 *buffer, int *countp, 
 		       u32 *bmval);

-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs