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

We take a reference on the stateowner, and copy the clientid, instead of just
hoping no one destroys the stateowner before we reference it in
nfsd4_encode_lock_denied.

Signed-off-by: J. Bruce Fields <bfields@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       |    5 ++++-
 25-akpm/fs/nfsd/nfs4xdr.c         |    3 ++-
 25-akpm/include/linux/nfsd/xdr4.h |    1 +
 3 files changed, 7 insertions(+), 2 deletions(-)

diff -puN fs/nfsd/nfs4state.c~nfsd4-fix-race-in-xdr-encoding-of-lock_denied-response fs/nfsd/nfs4state.c
--- 25/fs/nfsd/nfs4state.c~nfsd4-fix-race-in-xdr-encoding-of-lock_denied-response	2004-09-23 22:13:19.666249192 -0700
+++ 25-akpm/fs/nfsd/nfs4state.c	2004-09-23 22:13:19.675247824 -0700
@@ -1949,8 +1949,11 @@ nfs4_set_lock_denied(struct file_lock *f
 	unsigned int hval = lockownerid_hashval(sop->so_id);
 
 	deny->ld_sop = NULL;
-	if (nfs4_verify_lock_stateowner(sop, hval))
+	if (nfs4_verify_lock_stateowner(sop, hval)) {
+		kref_get(&sop->so_ref);
 		deny->ld_sop = sop;
+		deny->ld_clientid = sop->so_client->cl_clientid;
+	}
 	deny->ld_start = fl->fl_start;
 	deny->ld_length = ~(u64)0;
 	if (fl->fl_end != ~(u64)0)
diff -puN fs/nfsd/nfs4xdr.c~nfsd4-fix-race-in-xdr-encoding-of-lock_denied-response fs/nfsd/nfs4xdr.c
--- 25/fs/nfsd/nfs4xdr.c~nfsd4-fix-race-in-xdr-encoding-of-lock_denied-response	2004-09-23 22:13:19.668248888 -0700
+++ 25-akpm/fs/nfsd/nfs4xdr.c	2004-09-23 22:13:19.677247520 -0700
@@ -1994,9 +1994,10 @@ nfsd4_encode_lock_denied(struct nfsd4_co
 	WRITE64(ld->ld_length);
 	WRITE32(ld->ld_type);
 	if (ld->ld_sop) {
-		WRITEMEM(&ld->ld_sop->so_client->cl_clientid, 8);
+		WRITEMEM(&ld->ld_clientid, 8);
 		WRITE32(ld->ld_sop->so_owner.len);
 		WRITEMEM(ld->ld_sop->so_owner.data, ld->ld_sop->so_owner.len);
+		kref_put(&ld->ld_sop->so_ref, nfs4_free_stateowner);
 	}  else {  /* non - nfsv4 lock in conflict, no clientid nor owner */
 		WRITE64((u64)0); /* clientid */
 		WRITE32(0); /* length of owner name */
diff -puN include/linux/nfsd/xdr4.h~nfsd4-fix-race-in-xdr-encoding-of-lock_denied-response include/linux/nfsd/xdr4.h
--- 25/include/linux/nfsd/xdr4.h~nfsd4-fix-race-in-xdr-encoding-of-lock_denied-response	2004-09-23 22:13:19.670248584 -0700
+++ 25-akpm/include/linux/nfsd/xdr4.h	2004-09-23 22:13:19.678247368 -0700
@@ -116,6 +116,7 @@ struct nfsd4_link {
 };
 
 struct nfsd4_lock_denied {
+	clientid_t	ld_clientid;
 	struct nfs4_stateowner   *ld_sop;
 	u64             ld_start;
 	u64             ld_length;
_