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

Call release_delegation on delegreturn (DELEG_RET).

Signed-off-by: Andy Adamson <andros@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/fs/nfsd/nfs4state.c        |   62 ++++++++++++++++++++++---------------
 25-akpm/include/linux/nfsd/state.h |    1 
 2 files changed, 39 insertions(+), 24 deletions(-)

diff -puN fs/nfsd/nfs4state.c~knfsd-add-checking-of-delegation-stateids-to-nfs4_preprocess_stateid_op fs/nfsd/nfs4state.c
--- 25/fs/nfsd/nfs4state.c~knfsd-add-checking-of-delegation-stateids-to-nfs4_preprocess_stateid_op	Fri Dec 17 15:08:45 2004
+++ 25-akpm/fs/nfsd/nfs4state.c	Fri Dec 17 15:08:45 2004
@@ -1943,7 +1943,7 @@ access_permit_write(unsigned long access
 }
 
 static
-int check_openmode(struct nfs4_stateid *stp, int flags)
+int nfs4_check_openmode(struct nfs4_stateid *stp, int flags)
 {
         int status = nfserr_openmode;
 
@@ -1976,7 +1976,9 @@ out:
 int
 nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int flags)
 {
-	struct nfs4_stateid *stp;
+	struct nfs4_stateid *stp = NULL;
+	struct nfs4_delegation *dp = NULL;
+	stateid_t *stidp;
 	int status;
 
 	dprintk("NFSD: preprocess_stateid_op: stateid = (%08x/%08x/%08x/%08x)\n",
@@ -1990,35 +1992,47 @@ nfs4_preprocess_stateid_op(struct svc_fh
 
 	/* BAD STATEID */
 	status = nfserr_bad_stateid;
-	if (!(stp = find_stateid(stateid, flags))) {
-		dprintk("NFSD: preprocess_stateid_op: no open stateid!\n");
-		goto out;
-	}
-	if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) {
-		dprintk("NFSD: preprocess_stateid_op: fh-stateid mismatch!\n");
-		stp->st_vfs_set = 0;
-		goto out;
-	}
-	if (!stp->st_stateowner->so_confirmed) {
-		dprintk("preprocess_stateid_op: lockowner not confirmed yet!\n");
-		goto out;
+	if (!stateid->si_fileid) { /* delegation stateid */
+		struct inode *ino = current_fh->fh_dentry->d_inode;
+
+		if(!(dp = find_delegation_stateid(ino, stateid))) {
+			dprintk("NFSD: delegation stateid not found\n");
+			goto out;
+		}
+		stidp = &dp->dl_stateid;
+	} else { /* open or lock stateid */
+		if (!(stp = find_stateid(stateid, flags))) {
+			dprintk("NFSD: open or lock stateid not found\n");
+			goto out;
+		}
+		if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp))
+			goto out;
+		if (!stp->st_stateowner->so_confirmed)
+			goto out;
+		stidp = &stp->st_stateid;
 	}
-	if (stateid->si_generation > stp->st_stateid.si_generation) {
-		dprintk("preprocess_stateid_op: future stateid?!\n");
+	if (stateid->si_generation > stidp->si_generation)
 		goto out;
-	}
 
 	/* OLD STATEID */
 	status = nfserr_old_stateid;
-	if (stateid->si_generation < stp->st_stateid.si_generation) {
-		dprintk("preprocess_stateid_op: old stateid!\n");
+	if (stateid->si_generation < stidp->si_generation)
 		goto out;
+	if (stp) {
+		if ((status = nfs4_check_openmode(stp,flags)))
+			goto out;
+		renew_client(stp->st_stateowner->so_client);
+	} else if (dp) {
+		if ((status = nfs4_check_delegmode(dp, flags)))
+			goto out;
+		renew_client(dp->dl_client);
+		if (flags & DELEG_RET) {
+			atomic_set(&dp->dl_state,NFS4_RECALL_COMPLETE);
+			spin_lock(&recall_lock);
+			release_delegation(dp);
+			spin_unlock(&recall_lock);
+		}
 	}
-	renew_client(stp->st_stateowner->so_client);
-
-        if((status = check_openmode(stp, flags)))
-		goto out;
-
 	status = nfs_ok;
 out:
 	return status;
diff -puN include/linux/nfsd/state.h~knfsd-add-checking-of-delegation-stateids-to-nfs4_preprocess_stateid_op include/linux/nfsd/state.h
--- 25/include/linux/nfsd/state.h~knfsd-add-checking-of-delegation-stateids-to-nfs4_preprocess_stateid_op	Fri Dec 17 15:08:45 2004
+++ 25-akpm/include/linux/nfsd/state.h	Fri Dec 17 15:08:45 2004
@@ -271,6 +271,7 @@ struct nfs4_stateid {
 #define RD_STATE	        0x00000010
 #define WR_STATE	        0x00000020
 #define CLOSE_STATE             0x00000040
+#define DELEG_RET               0x00000080
 
 #define seqid_mutating_err(err)                       \
 	(((err) != nfserr_stale_clientid) &&    \
_
