From: NeilBrown <neilb@cse.unsw.edu.au>

Since the open op changes the current filehandle, we can't correctly replay
compounds containing opens unless we save the filehandle resulting from the
open as well as the encoded reply.


---

 25-akpm/fs/nfsd/nfs4proc.c         |   19 +++++++++++++++++++
 25-akpm/fs/nfsd/nfs4xdr.c          |    1 +
 25-akpm/include/linux/nfsd/state.h |    2 ++
 3 files changed, 22 insertions(+)

diff -puN fs/nfsd/nfs4proc.c~knfsd-replaying-fixes fs/nfsd/nfs4proc.c
--- 25/fs/nfsd/nfs4proc.c~knfsd-replaying-fixes	Mon Feb 23 16:33:45 2004
+++ 25-akpm/fs/nfsd/nfs4proc.c	Mon Feb 23 16:33:45 2004
@@ -89,6 +89,12 @@ do_open_lookup(struct svc_rqst *rqstp, s
 	if (!status) {
 		set_change_info(&open->op_cinfo, current_fh);
 		fh_dup2(current_fh, &resfh);
+		/* XXXJBF: keep a saved svc_fh struct instead?? */
+		open->op_stateowner->so_replay.rp_openfh_len =
+			resfh.fh_handle.fh_size;
+		memcpy(open->op_stateowner->so_replay.rp_openfh,
+				&resfh.fh_handle.fh_base,
+				resfh.fh_handle.fh_size);
 
 		accmode = MAY_NOP;
 		if (open->op_share_access & NFS4_SHARE_ACCESS_READ)
@@ -116,6 +122,19 @@ nfsd4_open(struct svc_rqst *rqstp, struc
 
 	/* check seqid for replay. set nfs4_owner */
 	status = nfsd4_process_open1(open);
+	if (status == NFSERR_REPLAY_ME) {
+		struct nfs4_replay *rp = &open->op_stateowner->so_replay;
+		fh_put(current_fh);
+		current_fh->fh_handle.fh_size = rp->rp_openfh_len;
+		memcpy(&current_fh->fh_handle.fh_base, rp->rp_openfh,
+				rp->rp_openfh_len);
+		status = fh_verify(rqstp, current_fh, 0, MAY_NOP);
+		if (status)
+			dprintk("nfsd4_open: replay failed"
+				" restoring previous filehandle\n");
+		else
+			status = NFSERR_REPLAY_ME;
+	}
 	if (status)
 		return status;
 	/*
diff -puN fs/nfsd/nfs4xdr.c~knfsd-replaying-fixes fs/nfsd/nfs4xdr.c
--- 25/fs/nfsd/nfs4xdr.c~knfsd-replaying-fixes	Mon Feb 23 16:33:45 2004
+++ 25-akpm/fs/nfsd/nfs4xdr.c	Mon Feb 23 16:33:45 2004
@@ -1913,6 +1913,7 @@ nfsd4_encode_open(struct nfsd4_compoundr
 	default:
 		BUG();
 	}
+	/* XXX save filehandle here */
 
 	ENCODE_SEQID_OP_TAIL(open->op_stateowner);
 }
diff -puN include/linux/nfsd/state.h~knfsd-replaying-fixes include/linux/nfsd/state.h
--- 25/include/linux/nfsd/state.h~knfsd-replaying-fixes	Mon Feb 23 16:33:45 2004
+++ 25-akpm/include/linux/nfsd/state.h	Mon Feb 23 16:33:45 2004
@@ -113,6 +113,8 @@ struct nfs4_replay {
 	unsigned int		rp_buflen;
 	char			*rp_buf;
 	unsigned		intrp_allocated;
+	int			rp_openfh_len;
+	char			rp_openfh[NFS4_FHSIZE];
 	char			rp_ibuf[NFSD4_REPLAY_ISIZE];
 };
 

_