diff -urpN linux-2.4.18-patched/fs/nfsd/Makefile linux-2.4.18-patched-ssds-getfh/fs/nfsd/Makefile
--- linux-2.4.18-patched/fs/nfsd/Makefile	2003-11-04 16:15:09.000000000 -0500
+++ linux-2.4.18-patched-ssds-getfh/fs/nfsd/Makefile	2004-01-12 18:57:37.000000000 -0500
@@ -16,7 +16,7 @@ obj-y :=    nfssvc.o nfsctl.o nfsproc.o 
 	    stats.o
 
 obj-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o
-obj-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o nfs4idmap_syms.o
+obj-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o nfs4idmap_syms.o stateserver.o rw_svc.o rw_state.o
 
 obj-m := $(O_TARGET)
 
diff -urpN linux-2.4.18-patched/fs/nfsd/nfs4proc.c linux-2.4.18-patched-ssds-getfh/fs/nfsd/nfs4proc.c
--- linux-2.4.18-patched/fs/nfsd/nfs4proc.c	2003-11-04 16:15:09.000000000 -0500
+++ linux-2.4.18-patched-ssds-getfh/fs/nfsd/nfs4proc.c	2004-04-19 00:30:50.402002000 -0400
@@ -53,6 +53,11 @@
 #include <linux/nfsd/state.h>
 #include <linux/nfsd/xdr4.h>
 
+extern int calc_file_locations(struct svc_rqst *rqstp,struct nfsd4_open* open);
+extern int nfsd4_distribute_state(struct svc_rqst *rqstp,struct nfsd4_open* open, struct svc_fh *fhp);
+extern struct nfsd4_file_locations* get_file_locations(stateid_t* stateid);
+extern int nfsd4_remote_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open);
+
 #define NFSDDBG_FACILITY		NFSDDBG_PROC
 
 /* Note: The organization of the OPEN code seems a little strange; it
@@ -61,12 +66,12 @@
  * This is because the code has been organized in anticipation of a
  * subsequent patch which will implement more of the NFSv4 state model.
  */
-static int
+int
 do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
 {
 	struct svc_fh resfh;
 	int accmode, status;
-
+	dprintk("%s: Begin\n",__FUNCTION__);
 	fh_init(&resfh, NFS4_FHSIZE);
 	open->op_truncate = 0;
 
@@ -75,18 +80,21 @@ do_open_lookup(struct svc_rqst *rqstp, s
 		 * Note: create modes (UNCHECKED,GUARDED...) are the same
 		 * in NFSv4 as in v3.
 		 */
+		dprintk("%s: Debug 1\n",__FUNCTION__);
 		status = nfsd_create_v3(rqstp, current_fh, open->op_fname.data,
 					open->op_fname.len, &open->op_iattr,
 					&resfh, open->op_createmode,
 					(u32 *)open->op_verf, &open->op_truncate);
 	}
 	else {
+		dprintk("%s: Debug 2\n",__FUNCTION__);
 		status = nfsd_lookup(rqstp, current_fh,
 				     open->op_fname.data, open->op_fname.len, &resfh);
 		fh_unlock(current_fh);
 	}
 
 	if (!status) {
+		dprintk("%s: Debug 3\n",__FUNCTION__);
 		set_change_info(&open->op_cinfo, current_fh);
 		fh_dup2(current_fh, &resfh);
 
@@ -106,6 +114,7 @@ do_open_lookup(struct svc_rqst *rqstp, s
 	}
 
 	fh_put(&resfh);
+	dprintk("%s: End\n",__FUNCTION__);
 	return status;
 }
 
@@ -113,8 +122,11 @@ static inline int
 nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
 {
 	int status;
+#if NFSD_STATE_SERVER
+	struct timeval begin = { 0, 0 }, end = { 0, 0 };
+	do_gettimeofday(&begin);
+#endif
 	dprintk("NFSD: nfsd4_open filename %.*s\n",open->op_fname.len, open->op_fname.data);
-
 	/* This check required by spec. */
 	if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
 		return nfserr_inval;
@@ -123,6 +135,12 @@ nfsd4_open(struct svc_rqst *rqstp, struc
 	status = nfsd4_process_open1(open);
 	if (status)
 		return status;
+#if NFSD_STATE_SERVER
+	status = nfsd4_remote_lookup(rqstp, current_fh, open);
+	if (status)
+		return status;
+	rqstp->is_fake_fh = 1;
+#else 
 	/*
 	 * This block of code will (1) set CURRENT_FH to the file being opened,
 	 * creating it if necessary, (2) set open->op_cinfo, 
@@ -132,7 +150,7 @@ nfsd4_open(struct svc_rqst *rqstp, struc
 	status = do_open_lookup(rqstp, current_fh, open);
 	if (status)
 		return status;
-
+#endif
 	/*
 	 * nfsd4_process_open2() does the actual opening of the file.  If
 	 * successful, it (1) truncates the file if open->op_truncate was
@@ -141,6 +159,28 @@ nfsd4_open(struct svc_rqst *rqstp, struc
 	status = nfsd4_process_open2(rqstp, current_fh, open);
 	if (status)
 		return status;
+
+#if NFSD_STATE_SERVER
+	/* Determine the data server (s) to handle any requests btw the open and close.
+	 * This needs to be called before a get_attr request for the file location
+	 * data can be processed
+	 */
+	if ((status = calc_file_locations(rqstp,open)))
+	  return status;
+ 	
+	/* Send info to be distributed to data servers */
+	dprintk("nfsd4_open: Distributing file_locations\n");	
+	if ((status = nfsd4_distribute_state(rqstp,open,current_fh)))
+	  return status;
+     	dprintk("nfsd4_open: Distributing file_locations Done\n");
+	do_gettimeofday(&end);
+	if (end.tv_usec < begin.tv_usec) {
+	  end.tv_usec += 1000000; end.tv_sec--;
+	}
+	end.tv_sec  -= begin.tv_sec;
+	end.tv_usec -= begin.tv_usec;
+	dprintk("Sec:%ld usec: %ld\n",end.tv_sec,end.tv_usec);
+#endif
 	return 0;
 }
 
@@ -150,10 +190,12 @@ nfsd4_open(struct svc_rqst *rqstp, struc
 static inline int
 nfsd4_getfh(struct svc_fh *current_fh, struct svc_fh **getfh)
 {
+	dprintk("%s: Begin\n",__FUNCTION__);
 	if (!current_fh->fh_dentry)
 		return nfserr_nofilehandle;
 
 	*getfh = current_fh;
+	dprintk("%s: End\n",__FUNCTION__);
 	return nfs_ok;
 }
 
@@ -169,9 +211,12 @@ nfsd4_putfh(struct svc_rqst *rqstp, stru
 static inline int
 nfsd4_putrootfh(struct svc_rqst *rqstp, struct svc_fh *current_fh)
 {
+	int status;
+	dprintk("%s: Begin\n",__FUNCTION__);
 	fh_put(current_fh);
-	return exp_pseudoroot(rqstp->rq_client, current_fh,
+	status = exp_pseudoroot(rqstp->rq_client, current_fh,
 			      &rqstp->rq_chandle);
+	dprintk("%s: End\n",__FUNCTION__);
 }
 
 static inline int
@@ -300,21 +345,46 @@ nfsd4_create(struct svc_rqst *rqstp, str
 }
 
 static inline int
-nfsd4_getattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_getattr *getattr)
+nfsd4_getattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, stateid_t* current_stateid, struct nfsd4_getattr *getattr)
 {
 	int status;
-
-	status = fh_verify(rqstp, current_fh, 0, MAY_NOP);
-	if (status)
-		return status;
+	struct timeval begin = { 0, 0 }, end = { 0, 0 };
+	dprintk("%s: Begin\n",__FUNCTION__);
+	/* DH-TODO:Need to be only for state server */
+	if (!rqstp->is_fake_fh)
+	{	
+		status = fh_verify(rqstp, current_fh, 0, MAY_NOP);
+		if (status)
+			return status;
+	}
 
 	if (getattr->ga_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)
 		return nfserr_inval;
 
 	getattr->ga_bmval[0] &= NFSD_SUPPORTED_ATTRS_WORD0;
-	getattr->ga_bmval[1] &= NFSD_SUPPORTED_ATTRS_WORD1;
+	getattr->ga_bmval[1] &= (NFSD_SUPPORTED_ATTRS_WORD1 | FATTR4_WORD1_FILE_LOCATIONS);
 
 	getattr->ga_fhp = current_fh;
+
+        if (getattr->ga_bmval[1] & FATTR4_WORD1_FILE_LOCATIONS)
+	{
+		dprintk("%s: retrieving file_locations\n",__FUNCTION__);
+		do_gettimeofday(&begin);
+		getattr->ga_file_locations = get_file_locations(current_stateid);
+		if (getattr->ga_file_locations == NULL)
+			return nfserr_file_locations;
+		do_gettimeofday(&end);
+		/*	printk("%ld %ld %ld %ld\n",begin.tv_sec,begin.tv_usec,end.tv_sec,end.tv_usec); */
+		if (end.tv_usec < begin.tv_usec) 
+		{
+			end.tv_usec += 1000000; end.tv_sec--;
+		}
+		end.tv_sec  -= begin.tv_sec;
+		end.tv_usec -= begin.tv_usec;
+		/*	printk("%ld %ld\n",end.tv_sec,end.tv_usec); */
+		dprintk("%s: finished retrieving file_locations %p\n",__FUNCTION__,getattr->ga_file_locations);
+	}
+	dprintk("%s: End\n",__FUNCTION__);
 	return nfs_ok;
 }
 
@@ -473,7 +543,15 @@ nfsd4_setattr(struct svc_rqst *rqstp, st
 		nfsd4_lock_state();
 		if ((status = nfs4_preprocess_stateid_op(current_fh, 
 						&setattr->sa_stateid, 
-						CHECK_FH, &stp))) {
+		/* DH-TODO: need to make this dynamic (or send these 
+		 * to the data servers 
+		 */
+#if NFSD_STATE_SERVER
+						0, 
+#else
+							 CHECK_FH,
+#endif
+							 &stp))) {
 			dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n");
 			goto out;
 		}
@@ -614,10 +692,12 @@ nfsd4_proc_compound(struct svc_rqst *rqs
 {
 	struct nfsd4_op	*op;
 	struct svc_fh	current_fh;
+	stateid_t	current_stateid;
 	struct svc_fh	save_fh;
 	int		slack_space;    /* in words, not bytes! */
 	int		status;
 
+	dprintk("%s: Begin\n",__FUNCTION__);
 	fh_init(&current_fh, NFS4_FHSIZE);
 	fh_init(&save_fh, NFS4_FHSIZE);
 
@@ -639,6 +719,8 @@ nfsd4_proc_compound(struct svc_rqst *rqs
 	if (args->minorversion > NFSD_SUPPORTED_MINOR_VERSION)
 		goto out;
 
+	rqstp->is_fake_fh = 0;
+
 	status = nfs_ok;
 	while (!status && resp->opcnt < args->opcnt) {
 		op = &args->ops[resp->opcnt++];
@@ -678,7 +760,7 @@ nfsd4_proc_compound(struct svc_rqst *rqs
 			op->status = nfsd4_create(rqstp, &current_fh, &op->u.create);
 			break;
 		case OP_GETATTR:
-			op->status = nfsd4_getattr(rqstp, &current_fh, &op->u.getattr);
+			op->status = nfsd4_getattr(rqstp, &current_fh, &current_stateid,&op->u.getattr);
 			break;
 		case OP_GETFH:
 			op->status = nfsd4_getfh(&current_fh, &op->u.getfh);
@@ -699,6 +781,7 @@ nfsd4_proc_compound(struct svc_rqst *rqs
 			break;
 		case OP_OPEN:
 			op->status = nfsd4_open(rqstp, &current_fh, &op->u.open);
+			memcpy(&current_stateid,&op->u.open.op_stateid,sizeof(stateid_t));
 			break;
 		case OP_OPEN_CONFIRM:
 			op->status = nfsd4_open_confirm(rqstp, &current_fh, &op->u.open_confirm);
@@ -778,8 +861,12 @@ out:
 		kfree(tb->buf);
 		kfree(tb);
 	}
-	fh_put(&current_fh);
-	fh_put(&save_fh);
+	if (!rqstp->is_fake_fh)
+	{
+		fh_put(&current_fh);
+		fh_put(&save_fh);
+	}
+	dprintk("%s: End\n",__FUNCTION__);
 	return status;
 }
 
diff -urpN linux-2.4.18-patched/fs/nfsd/nfs4state.c linux-2.4.18-patched-ssds-getfh/fs/nfsd/nfs4state.c
--- linux-2.4.18-patched/fs/nfsd/nfs4state.c	2004-02-10 15:38:45.168256000 -0500
+++ linux-2.4.18-patched-ssds-getfh/fs/nfsd/nfs4state.c	2004-04-15 14:26:10.537000000 -0400
@@ -48,6 +48,9 @@
 #include <linux/nfsd/state.h>
 #include <linux/nfsd/xdr4.h>
 
+extern int nfsd4_recall_state(struct nfs4_stateid *ofp);
+
+
 #define NFSDDBG_FACILITY                NFSDDBG_PROC
 
 /* Globals */
@@ -106,10 +109,9 @@ opaque_hashval(const void *ptr, int nbyt
 
 /* forward declarations */
 static void release_stateowner(struct nfs4_stateowner *sop);
-static void release_stateid(struct nfs4_stateid *stp);
+void release_stateid(struct nfs4_stateid *stp);
 static void release_file(struct nfs4_file *fp);
 
-
 /* 
  * SETCLIENTID state 
  */
@@ -133,11 +135,11 @@ static void release_file(struct nfs4_fil
  * client_lru holds client queue ordered by nfs4_client.cl_time
  * for lease renewal.
  */
-static struct list_head	conf_id_hashtbl[CLIENT_HASH_SIZE];
-static struct list_head	conf_str_hashtbl[CLIENT_HASH_SIZE];
-static struct list_head	unconf_str_hashtbl[CLIENT_HASH_SIZE];
-static struct list_head	unconf_id_hashtbl[CLIENT_HASH_SIZE];
-static struct list_head client_lru;
+struct list_head	conf_id_hashtbl[CLIENT_HASH_SIZE];
+struct list_head	conf_str_hashtbl[CLIENT_HASH_SIZE];
+struct list_head	unconf_str_hashtbl[CLIENT_HASH_SIZE];
+struct list_head	unconf_id_hashtbl[CLIENT_HASH_SIZE];
+struct list_head client_lru;
 
 static inline void
 renew_client(struct nfs4_client *clp)
@@ -156,8 +158,11 @@ renew_client(struct nfs4_client *clp)
 static int
 STALE_CLIENTID(clientid_t *clid)
 {
+  /* DH-TODO: Maybe a good idea is to figure out how to handle this */
+#if NFSD_DATA_SERVER == 0
 	if (clid->cl_boot == boot_time)
-		return 0;
+#endif		
+	  return 0;
 	dprintk("NFSD stale clientid (%08x/%08x)\n", 
 			clid->cl_boot, clid->cl_id);
 	return 1;
@@ -194,12 +199,11 @@ free_client(struct nfs4_client *clp)
 	kfree(clp);
 }
 
-static void
+void
 expire_client(struct nfs4_client *clp)
 {
 	struct nfs4_stateowner *sop;
-
-	dprintk("NFSD: expire_client\n");
+	dprintk("%s Begin\n",__FUNCTION__);
 	list_del(&clp->cl_idhash);
 	list_del(&clp->cl_strhash);
 	list_del(&clp->cl_lru);
@@ -208,10 +212,11 @@ expire_client(struct nfs4_client *clp)
 		release_stateowner(sop);
 	}
 	free_client(clp);
+	dprintk("%s: End\n",__FUNCTION__);
 }
 
 static struct nfs4_client *
-create_client(struct xdr_netobj name) {
+create_client(struct xdr_netobj name,u8 expire) {
 	struct nfs4_client *clp;
 
 	if(!(clp = alloc_client(name)))
@@ -220,6 +225,7 @@ create_client(struct xdr_netobj name) {
 	INIT_LIST_HEAD(&clp->cl_strhash);
 	INIT_LIST_HEAD(&clp->cl_perclient);
 	INIT_LIST_HEAD(&clp->cl_lru);
+	clp->cl_expire = expire;
 out:
 	return clp;
 }
@@ -361,9 +367,8 @@ move_to_confirmed(struct nfs4_client *cl
  *
  */
 int
-nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
+nfsd4_setclientid_ip(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid,u32 ip_addr,u8 expire)
 {
-	u32 			ip_addr = rqstp->rq_addr.sin_addr.s_addr;
 	struct xdr_netobj 	clname = { 
 		.len = setclid->se_namelen,
 		.data = setclid->se_name,
@@ -373,6 +378,10 @@ nfsd4_setclientid(struct svc_rqst *rqstp
 	struct nfs4_client *	conf, * unconf, * new, * clp;
 	int 			status;
 	struct list_head *pos, *next;
+#if NFSD_DATA_SERVER
+	unsigned int idhashval;
+#endif
+	dprintk("%s: Begin\n",__FUNCTION__);
 	
 	status = nfserr_inval;
 	if (!check_name(clname))
@@ -396,6 +405,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp
 		 * clname match, confirmed, different principal
 		 * or different ip_address
 		 */
+		dprintk("%s: Case 0\n",__FUNCTION__);
 		status = nfserr_clid_inuse;
 		if (!cmp_creds(&clp->cl_cred,&rqstp->rq_cred)) {
 			printk("NFSD: setclientid: string in use by client"
@@ -432,16 +442,28 @@ nfsd4_setclientid(struct svc_rqst *rqstp
 		 * CASE 4:
 		 * placed first, because it is the normal case.
 		 */
+		dprintk("%s: Case 4\n",__FUNCTION__);
 		if (unconf)
 			expire_client(unconf);
-		if (!(new = create_client(clname)))
+		if (!(new = create_client(clname,expire)))
 			goto out;
 		copy_verf(new,clverifier);
 		new->cl_addr = ip_addr;
 		copy_cred(&new->cl_cred,&rqstp->rq_cred);
+#if NFSD_DATA_SERVER
+		dprintk("setting %d %d\n",setclid->se_clientid.cl_boot,setclid->se_clientid.cl_id);
+		new->cl_clientid.cl_boot = setclid->se_clientid.cl_boot; 
+		new->cl_clientid.cl_id = setclid->se_clientid.cl_id; 
+		strncpy(new->cl_confirm,setclid->se_confirm,NFS4_VERIFIER_SIZE);
+#else
 		gen_clid(new);
 		gen_confirm(new);
+#endif
 		add_to_unconfirmed(new, strhashval);
+#if NFSD_DATA_SERVER
+		idhashval = clientid_hashval(new->cl_clientid.cl_id);
+		move_to_confirmed(new, idhashval);
+#endif
 	} else if (cmp_verf(conf->cl_verifier, clverifier)) {
 		/*
 		 * CASE 1:
@@ -456,19 +478,28 @@ nfsd4_setclientid(struct svc_rqst *rqstp
 		 * nfs4_client,  but with the new callback info and a 
 		 * new cl_confirm
 		 */
+		dprintk("%s: Case 1\n",__FUNCTION__);
 		if ((unconf) && 
 		    cmp_verf(unconf->cl_verifier, conf->cl_verifier) &&
 		     cmp_clid(&unconf->cl_clientid, &conf->cl_clientid)) {
 				expire_client(unconf);
 		}
-		if (!(new = create_client(clname)))
+		if (!(new = create_client(clname,expire)))
 			goto out;
 		copy_verf(new,conf->cl_verifier);
 		new->cl_addr = ip_addr;
 		copy_cred(&new->cl_cred,&rqstp->rq_cred);
 		copy_clid(new, conf);
+#if NFSD_DATA_SERVER
+		strncpy(new->cl_confirm,setclid->se_confirm,NFS4_VERIFIER_SIZE);
+#else
 		gen_confirm(new);
-		add_to_unconfirmed(new,strhashval);
+#endif
+		add_to_unconfirmed(new, strhashval);
+#if NFSD_DATA_SERVER
+		idhashval = clientid_hashval(new->cl_clientid.cl_id);
+		move_to_confirmed(new, idhashval);
+#endif
 	} else if (!unconf) {
 		/*
 		 * CASE 2:
@@ -478,14 +509,26 @@ nfsd4_setclientid(struct svc_rqst *rqstp
 		 * using input clverifier, clname, and callback info
 		 * and generate a new cl_clientid and cl_confirm.
 		 */
-		if (!(new = create_client(clname)))
+		dprintk("%s: Case 2\n",__FUNCTION__);
+		if (!(new = create_client(clname,expire)))
 			goto out;
 		copy_verf(new,clverifier);
 		new->cl_addr = ip_addr;
 		copy_cred(&new->cl_cred,&rqstp->rq_cred);
+#if NFSD_DATA_SERVER
+		dprintk("setting %d %d\n",setclid->se_clientid.cl_boot,setclid->se_clientid.cl_id);
+		new->cl_clientid.cl_boot = setclid->se_clientid.cl_boot; 
+		new->cl_clientid.cl_id = setclid->se_clientid.cl_id; 
+		strncpy(new->cl_confirm,setclid->se_confirm,NFS4_VERIFIER_SIZE);
+#else
 		gen_clid(new);
 		gen_confirm(new);
+#endif
 		add_to_unconfirmed(new, strhashval);
+#if NFSD_DATA_SERVER
+		idhashval = clientid_hashval(new->cl_clientid.cl_id);
+		move_to_confirmed(new, idhashval);
+#endif
 	} else if (!cmp_clid(&conf->cl_clientid, &unconf->cl_clientid) &&
 	      !cmp_verf(conf->cl_confirm, unconf->cl_confirm)) {
 		/*	
@@ -504,31 +547,53 @@ nfsd4_setclientid(struct svc_rqst *rqstp
 		 * but with new callback info, new cl_clientid,
 		 * new cl_verifier and a new cl_confirm
 		 */
+		dprintk("%s: Case 3\n",__FUNCTION__);
 		expire_client(unconf);
-		if (!(new = create_client(clname)))
+		if (!(new = create_client(clname,expire)))
 			goto out;
 		copy_verf(new,clverifier);
 		new->cl_addr = ip_addr;
 		copy_cred(&new->cl_cred,&rqstp->rq_cred);
+#if NFSD_DATA_SERVER
+		dprintk("setting %d %d\n",setclid->se_clientid.cl_boot,setclid->se_clientid.cl_id);
+		new->cl_clientid.cl_boot = setclid->se_clientid.cl_boot; 
+		new->cl_clientid.cl_id = setclid->se_clientid.cl_id; 
+		strncpy(new->cl_confirm,setclid->se_confirm,NFS4_VERIFIER_SIZE);
+#else
 		gen_clid(new);
 		gen_confirm(new);
+#endif
 		add_to_unconfirmed(new, strhashval);
+#if NFSD_DATA_SERVER
+		idhashval = clientid_hashval(new->cl_clientid.cl_id);
+		move_to_confirmed(new, idhashval);
+#endif
 	} else {
 		/* No cases hit !!! */
+		printk("%s: No cases!!\n",__FUNCTION__);
+#if !NFSD_DATA_SERVER
 		status = nfserr_inval;
 		goto out;
-
+#endif
 	}
+#if !NFSD_DATA_SERVER
 	setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;
 	setclid->se_clientid.cl_id = new->cl_clientid.cl_id;
 	memcpy(&setclid->se_confirm, new->cl_confirm, sizeof(nfs4_verifier));
-	printk(KERN_INFO "NFSD: this client will not receive delegations\n");
+#endif
+	dprintk(KERN_INFO "NFSD: this client will not receive delegations\n");
 	status = nfs_ok;
 out:
 	up(&client_sema);
+	dprintk("%s: End\n",__FUNCTION__);
 	return status;
 }
 
+int
+nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
+{
+  return nfsd4_setclientid_ip(rqstp,setclid,rqstp->rq_addr.sin_addr.s_addr,1);
+}
 
 /*
  * RFC 3010 has a complex implmentation description of processing a 
@@ -538,9 +603,8 @@ out:
  * NOTE: callback information will be processed here in a future patch
  */
 int
-nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm)
+nfsd4_setclientid_confirm_ip(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm, u32 ip_addr)
 {
-	u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr;
 	unsigned int idhashval;
 	struct nfs4_client *clp, *conf = NULL, *unconf = NULL;
 	char * confirm = setclientid_confirm->sc_confirm; 
@@ -548,6 +612,7 @@ nfsd4_setclientid_confirm(struct svc_rqs
 	struct list_head *pos, *next;
 	int status;
 
+	dprintk("%s: Begin\n",__FUNCTION__);
 	status = nfserr_stale_clientid;
 	if (STALE_CLIENTID(clid))
 		goto out;
@@ -555,7 +620,6 @@ nfsd4_setclientid_confirm(struct svc_rqs
 	 * XXX The Duplicate Request Cache (DRC) has been checked (??)
 	 * We get here on a DRC miss.
 	 */
-
 	idhashval = clientid_hashval(clid->cl_id);
 	down(&client_sema);
 	list_for_each_safe(pos, next, &conf_id_hashtbl[idhashval]) {
@@ -602,6 +666,7 @@ nfsd4_setclientid_confirm(struct svc_rqs
 	    (cmp_verf(conf->cl_verifier, unconf->cl_verifier)) &&
 	    (cmp_name(&conf->cl_name,&unconf->cl_name))  &&
 	    (!cmp_verf(conf->cl_confirm, unconf->cl_confirm))) {
+		dprintk("%s: Case 1\n",__FUNCTION__);
 		if (!cmp_creds(&conf->cl_cred, &unconf->cl_cred)) 
 			status = nfserr_clid_inuse;
 		else {
@@ -620,6 +685,7 @@ nfsd4_setclientid_confirm(struct svc_rqs
 	    ((conf && unconf) && 
 	     (!cmp_verf(conf->cl_verifier, unconf->cl_verifier) ||
 	      !cmp_name(&conf->cl_name, &unconf->cl_name)))) {
+		dprintk("%s: Case 2\n",__FUNCTION__);
 		if (!cmp_creds(&conf->cl_cred,&rqstp->rq_cred)) {
 			status = nfserr_clid_inuse;
 		} else {
@@ -633,6 +699,7 @@ nfsd4_setclientid_confirm(struct svc_rqs
 	 * unconf->cl_confirm matches input confirm
 	 */ 
 	if (!conf && unconf && cmp_verf(unconf->cl_confirm, confirm)) {
+		dprintk("%s: Case 3\n",__FUNCTION__);
 		if (!cmp_creds(&unconf->cl_cred, &rqstp->rq_cred)) {
 			status = nfserr_clid_inuse;
 		} else {
@@ -649,18 +716,28 @@ nfsd4_setclientid_confirm(struct svc_rqs
 	 */
 	if ((!conf || (conf && !cmp_verf(conf->cl_confirm, confirm))) &&
 	    (!unconf || (unconf && !cmp_verf(unconf->cl_confirm, confirm)))) {
+		dprintk("%s: Case 4\n",__FUNCTION__);
 		status = nfserr_stale_clientid;
 		goto out;
 	}
+
 	/* check that we have hit one of the cases...*/
 	status = nfserr_inval;
 	goto out;
 out:
 	/* XXX if status == nfs_ok, probe callback path */
 	up(&client_sema);
+	dprintk("%s: End\n",__FUNCTION__);
 	return status;
 }
 
+int
+nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm)
+{
+
+  return nfsd4_setclientid_confirm_ip(rqstp,setclientid_confirm, rqstp->rq_addr.sin_addr.s_addr);
+}
+
 /* 
  * Open owner state (share locks)
  */
@@ -697,14 +774,23 @@ static struct list_head openstateid_hash
 
 /* OPEN Share state helper functions */
 static inline struct nfs4_file *
-alloc_init_file(unsigned int hashval, nfs4_ino_desc_t *ino) {
+alloc_init_file(unsigned int hashval, nfs4_ino_desc_t *ino,u32 file_id) {
 	struct nfs4_file *fp;
+	u32 id;
+	/* set the next id to the one sent from the state server if
+	   the file_id is not -1
+	*/
+	if (file_id == -1)
+	  id = current_fileid++;
+	else
+	  id = file_id;
+	dprintk("%s: Creating a new file: %d\n",__FUNCTION__,id);
 	if ((fp = kmalloc(sizeof(struct nfs4_file),GFP_KERNEL))) {
 		INIT_LIST_HEAD(&fp->fi_hash);
 		INIT_LIST_HEAD(&fp->fi_perfile);
 		list_add(&fp->fi_hash, &file_hashtbl[hashval]);
 		memcpy(&fp->fi_ino, ino, sizeof(nfs4_ino_desc_t));
-		fp->fi_id = current_fileid++;
+		fp->fi_id = id;
 		alloc_file++;
 		return fp;
 	}
@@ -729,7 +815,7 @@ release_all_files(void)
 	}
 }
 
-static inline struct nfs4_stateowner *
+inline struct nfs4_stateowner *
 alloc_stateowner(struct xdr_netobj *owner)
 {
 	struct nfs4_stateowner *sop;
@@ -757,13 +843,21 @@ free_stateowner(struct nfs4_stateowner *
 }
 
 static struct nfs4_stateowner *
-alloc_init_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_open *open) {
+alloc_init_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_open *open,u32 stateownerid) {
 	struct nfs4_stateowner *sop;
 	unsigned int idhashval;
-
+	u32 id;
+	/* set the next id to the one sent from the state server if
+	   the stateownerid is not -1
+	*/
+	if (stateownerid == -1)
+	  id = current_ownerid++;
+	else
+	  id = stateownerid;
 	if (!(sop = alloc_stateowner(&open->op_owner)))
 		return (struct nfs4_stateowner *)NULL;
-	idhashval = ownerid_hashval(current_ownerid);
+	dprintk("%s: Creating new stateowner id: %d\n",__FUNCTION__,id);
+	idhashval = ownerid_hashval(id);
 	INIT_LIST_HEAD(&sop->so_idhash);
 	INIT_LIST_HEAD(&sop->so_strhash);
 	INIT_LIST_HEAD(&sop->so_perclient);
@@ -772,7 +866,7 @@ alloc_init_stateowner(unsigned int strha
 	list_add(&sop->so_strhash, &ownerstr_hashtbl[strhashval]);
 	list_add(&sop->so_perclient, &clp->cl_perclient);
 	add_perclient++;
-	sop->so_id = current_ownerid++;
+	sop->so_id = id;
 	sop->so_client = clp;
 	sop->so_seqid = open->op_seqid;
 	sop->so_confirmed = 0;
@@ -784,7 +878,7 @@ static void
 release_stateowner(struct nfs4_stateowner *sop)
 {
 	struct nfs4_stateid *stp;
-
+	dprintk("release_lockowner: Start\n");
 	list_del_init(&sop->so_idhash);
 	list_del_init(&sop->so_strhash);
 	list_del_init(&sop->so_perclient);
@@ -795,12 +889,13 @@ release_stateowner(struct nfs4_stateowne
 		release_stateid(stp);
 	}
 	free_stateowner(sop);
+	dprintk("release_lockowner: End\n");
 }
 
 static inline void
 init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfs4_stateowner *sop, struct nfsd4_open *open) {
 	unsigned int hashval = openstateid_hashval(sop->so_id, fp->fi_id);
-
+	dprintk("%s: initializing stateid so_id:%d fi_id:%d\n",__FUNCTION__,sop->so_id, fp->fi_id);
 	INIT_LIST_HEAD(&stp->st_hash);
 	INIT_LIST_HEAD(&stp->st_peropenstate);
 	INIT_LIST_HEAD(&stp->st_perfile);
@@ -818,19 +913,22 @@ init_stateid(struct nfs4_stateid *stp, s
 	stp->st_share_deny = open->op_share_deny;
 }
 
-static void
+void
 release_stateid(struct nfs4_stateid *stp) {
 
 	list_del_init(&stp->st_hash);
 	list_del_perfile++;
 	list_del_init(&stp->st_perfile);
 	list_del_init(&stp->st_peropenstate);
+	/* DH-TODO: This needs to be dynamic to handle non parallel clients */
+#if !NFSD_STATE_SERVER
 	if(stp->st_vfs_set) {
 		nfsd_close(&stp->st_vfs_file);
 		vfsclose++;
 		dput(stp->st_vfs_file.f_dentry);
 		mntput(stp->st_vfs_file.f_vfsmnt);
 	}
+#endif
 	/* should use a slab cache */
 	kfree(stp);
 	stp = NULL;
@@ -900,12 +998,14 @@ verify_clientid(struct nfs4_client **cli
 
 	list_for_each_safe(pos, next, &conf_id_hashtbl[idhashval]) {
 		clp = list_entry(pos, struct nfs4_client, cl_idhash);
+		dprintk("%s: CurrID %d %d MatchID %d %d\n",__FUNCTION__,clp->cl_clientid.cl_boot,clp->cl_clientid.cl_id,clid->cl_boot,clid->cl_id);
 		if (!cmp_clid(&clp->cl_clientid, clid))
 			continue;
 		*client = clp;
 		return 1;
 	}
 	*client = NULL;
+	dprintk("%s: List empty for %d %d\n",__FUNCTION__,clid->cl_boot,clid->cl_id);
 	return 0;
 }
 
@@ -934,7 +1034,7 @@ test_share(struct nfs4_stateid *stp, str
 	return 1;
 }
 
-static inline void
+inline void
 nfs4_init_ino(nfs4_ino_desc_t *ino, struct svc_fh *fhp)
 {
 	struct inode *inode;
@@ -972,7 +1072,7 @@ nfs4_share_conflict(struct svc_fh *curre
 	return nfs_ok;
 }
 
-static inline int
+inline int
 nfs4_file_upgrade(struct file *filp, unsigned int share_access)
 {
 int status;
@@ -1012,22 +1112,20 @@ nfs4_file_downgrade(struct file *filp, u
  * 			create new owner
  */
 int
-nfsd4_process_open1(struct nfsd4_open *open)
+nfsd4_process_open1_id(struct nfsd4_open *open,u32 stateownerid)
 {
 	int status;
 	clientid_t *clientid = &open->op_clientid;
 	struct nfs4_client *clp = NULL;
 	unsigned int strhashval;
 	struct nfs4_stateowner *sop = NULL;
-	struct timeval tm = { 0, 0 };
-
-	do_gettimeofday(&tm);
-	dprintk("Time at beg %s %ld %ld\n",__FUNCTION__,tm.tv_sec,tm.tv_usec);
-
-
+	dprintk("%s: Begin\n",__FUNCTION__);
 	status = nfserr_inval;
 	if (!check_name(open->op_owner))
-		goto out;
+	{
+	  printk("%s: Check name failed %d\n",__FUNCTION__,open->op_owner.len);
+	  goto out;
+	}
 
 	status = nfserr_stale_clientid;
 	if (STALE_CLIENTID(&open->op_clientid))
@@ -1037,18 +1135,29 @@ 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;
+		/* this request is from the state server so ignore
+		   seqid checks
+		   DH-TODO: since the laundromat is disable, should go to
+		            out instead of renew
+		*/
+		if (open->op_seqid == -1)
+		{
+		  dprintk("%s: seqid's irrelevant\n",__FUNCTION__);
+		  status = nfs_ok;
+		  goto renew;
+		}
 		if (open->op_seqid == sop->so_seqid){
-			/* XXX retplay: for now, return bad seqid */
-			status = nfserr_bad_seqid;
-			goto out;
+		  /* XXX retplay: for now, return bad seqid */
+		  status = nfserr_bad_seqid;
+		  goto out;
 		}
 		if (sop->so_confirmed) {
-			if (open->op_seqid == sop->so_seqid + 1) { 
-				status = nfs_ok;
-				goto renew;
-			} 
-			status = nfserr_bad_seqid;
-			goto out;
+		  if (open->op_seqid == sop->so_seqid + 1) { 
+		    status = nfs_ok;
+		    goto renew;
+		  } 
+		  status = nfserr_bad_seqid;
+		  goto out;
 		}
 		/* If we get here, we received and OPEN for an unconfirmed
 		 * nfs4_stateowner. If seqid's are the same then this 
@@ -1069,24 +1178,32 @@ nfsd4_process_open1(struct nfsd4_open *o
 	*/
 	status = nfserr_expired;
 	if (!verify_clientid(&clp, clientid))
+	{
+	  dprintk("%s: Client id verification failed\n",__FUNCTION__);
 		goto out;
+	}
 instantiate_new_owner:
 	status = nfserr_resource;
-	if (!(sop = alloc_init_stateowner(strhashval, clp, open))) 
+	if (!(sop = alloc_init_stateowner(strhashval, clp, open,stateownerid))) 
 		goto out;
 	open->op_stateowner = sop;
 	status = nfs_ok;
 renew:
 	renew_client(sop->so_client);
 out:
-	do_gettimeofday(&tm);
-	dprintk("Time at end %s %ld %ld\n",__FUNCTION__,tm.tv_sec,tm.tv_usec);
 	up(&client_sema); /*XXX need finer grained locking */
+	dprintk("%s: End\n",__FUNCTION__);
 	return status;
 }
 
 int
-nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
+nfsd4_process_open1(struct nfsd4_open *open)
+{
+  return nfsd4_process_open1_id(open,-1);
+}
+
+int
+nfsd4_process_open2_id(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open,u32 file_id)
 {
 	struct iattr iattr;
 	struct nfs4_stateowner *sop = open->op_stateowner;
@@ -1096,11 +1213,7 @@ nfsd4_process_open2(struct svc_rqst *rqs
 	struct list_head *pos, *next;
 	struct nfs4_stateid *stq, *stp = NULL;
 	int status;
-	struct timeval tm = { 0, 0 };
-
-	do_gettimeofday(&tm);
-	dprintk("Time at beg %s %ld %ld\n",__FUNCTION__,tm.tv_sec,tm.tv_usec);
-
+	dprintk("%s: Begin\n",__FUNCTION__);
 	status = nfserr_resource;
 	if (!sop)
 		goto out;
@@ -1113,7 +1226,7 @@ nfsd4_process_open2(struct svc_rqst *rqs
 		/* Search for conflicting share reservations */
 		status = nfserr_share_denied;
 		list_for_each_safe(pos, next, &fp->fi_perfile) {
-		stq = list_entry(pos, struct nfs4_stateid, st_perfile);
+		  stq = list_entry(pos, struct nfs4_stateid, st_perfile);
 			if(stq->st_stateowner == sop) {
 				stp = stq;
 				continue;
@@ -1121,11 +1234,16 @@ nfsd4_process_open2(struct svc_rqst *rqs
 			if (!test_share(stq,open))	
 				goto out;
 		}
+		if (file_id != -1 && fp->fi_id != file_id)
+		{
+		  printk("%s: Updating file id from %d to %d\n",__FUNCTION__,fp->fi_id,file_id);
+		  fp->fi_id = file_id;
+		}
 	} else {
-	/* No nfs4_file found; allocate and init a new one */
-		status = nfserr_resource;
-		if ((fp = alloc_init_file(fi_hashval, &ino)) == NULL)
-			goto out;
+	  /* No nfs4_file found; allocate and init a new one */
+	  status = nfserr_resource;
+	  if ((fp = alloc_init_file(fi_hashval, &ino,file_id)) == NULL)
+	    goto out;
 	}
 
 	if (!stp) {
@@ -1135,7 +1253,8 @@ nfsd4_process_open2(struct svc_rqst *rqs
 		if ((stp = kmalloc(sizeof(struct nfs4_stateid),
 						GFP_KERNEL)) == NULL)
 			goto out;
-
+	/* DH-TODO: This needs to be dynamic to handle non parallel clients */
+#if !NFSD_STATE_SERVER
 		if (open->op_share_access && NFS4_SHARE_ACCESS_WRITE)
 			flags = MAY_WRITE;
 		else
@@ -1148,9 +1267,9 @@ nfsd4_process_open2(struct svc_rqst *rqs
 		vfsopen++;
 		dget(stp->st_vfs_file.f_dentry);
 		mntget(stp->st_vfs_file.f_vfsmnt);
-
-		init_stateid(stp, fp, sop, open);
 		stp->st_vfs_set = 1;
+#endif
+		init_stateid(stp, fp, sop, open);
 	} else {
 		/* This is an upgrade of an existing OPEN. 
 		 * OR the incoming share with the existing 
@@ -1182,9 +1301,6 @@ nfsd4_process_open2(struct svc_rqst *rqs
 
 	open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE;
 	status = nfs_ok;
-
-	do_gettimeofday(&tm);
-	dprintk("Time at end %s %ld %ld\n",__FUNCTION__,tm.tv_sec,tm.tv_usec);
 out:
 	/*
 	* To finish the open response, we just need to set the rflags.
@@ -1194,11 +1310,19 @@ out:
 		open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM;
 
 	up(&client_sema); /*XXX need finer grained locking */
+	dprintk("%s: End\n",__FUNCTION__);
 	return status;
 out_free:
 	kfree(stp);
 	goto out;
 }
+
+int
+nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
+{
+  return nfsd4_process_open2_id(rqstp,current_fh,open,-1);
+}
+
 static struct work_struct laundromat_work;
 static void laundromat_main(void *);
 static DECLARE_WORK(laundromat_work, laundromat_main, NULL);
@@ -1212,7 +1336,7 @@ nfsd4_renew(clientid_t *clid)
 	int status;
 
 	down(&client_sema);
-	printk("process_renew(%08x/%08x): starting\n", 
+	dprintk("process_renew(%08x/%08x): starting\n", 
 			clid->cl_boot, clid->cl_id);
 	status = nfserr_stale_clientid;
 	if (STALE_CLIENTID(clid))
@@ -1255,9 +1379,12 @@ nfs4_laundromat(void)
 
 	down(&client_sema);
 
-	/* dprintk("NFSD: laundromat service - starting, examining clients\n"); */
+	/*	dprintk("NFSD: laundromat service - starting, examining clients\n"); */
 	list_for_each_safe(pos, next, &client_lru) {
 		clp = list_entry(pos, struct nfs4_client, cl_lru);
+		/* clients created by the state server do not expire */
+		if (!clp->cl_expire)
+		  continue;
 		if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) {
 			t = clp->cl_time - cutoff;
 			if (return_val > t)
@@ -1266,6 +1393,11 @@ nfs4_laundromat(void)
 		}
 		dprintk("NFSD: purging unused client (clientid %08x)\n",
 			clp->cl_clientid.cl_id);
+		/* DH-TODO: Need to expire client on data servers
+#if NFSD_STATE_SERVER
+		nfsd4_recall_state(clp);
+#endif
+		*/
 		expire_client(clp);
 	}
 	if (return_val < NFSD_LAUNDROMAT_MINTIMEOUT)
@@ -1280,7 +1412,7 @@ laundromat_main(void *not_used)
 	time_t t;
 
 	t = nfs4_laundromat();
-	/* dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t); */
+	/*	dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t); */
 	schedule_delayed_work(&laundromat_work, t*HZ);
 }
 
@@ -1300,6 +1432,7 @@ find_stateid(stateid_t *stid)
 		   (local->st_stateid.si_fileid == f_id))
 			return local;
 	}
+	printk("%s Empty for %d %d\n",__FUNCTION__,st_id,f_id);
 	return NULL;
 }
 
@@ -1344,7 +1477,7 @@ nfs4_preprocess_stateid_op(struct svc_fh
 {
 	struct nfs4_stateid *stp;
 	int status;
-
+        u8 expire;
 	dprintk("NFSD: preprocess_stateid_op:stateid = (%08x/%08x/%08x/%08x)\n",
 		stateid->si_boot, stateid->si_stateownerid, 
 		stateid->si_fileid, stateid->si_generation); 
@@ -1352,35 +1485,41 @@ nfs4_preprocess_stateid_op(struct svc_fh
 	*stpp = NULL;
 
 	/* STALE STATEID */
+	if (!(stp = find_stateid(stateid))) {
+	  status = nfserr_bad_stateid;
+	  printk("NFSD: process stateid: no open stateid!\n");
+	  goto out;
+	}
+        expire = stp->st_stateowner->so_client->cl_expire;
 	status = nfserr_stale_stateid;
-	if (STALE_STATEID(stateid)) 
+	if (expire && STALE_STATEID(stateid)) 
 		goto out;
 
 	/* BAD STATEID */
-	status = nfserr_bad_stateid;
-	if (!(stp = find_stateid(stateid))) {
-		dprintk("NFSD: process stateid: no open stateid!\n");
-		goto out;
-	}
 	if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) {
-		dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
+		printk("NFSD: preprocess_stateid_op: fh-stateid mismatch!\n");
 		goto out;
 	}
 	if (!stp->st_stateowner->so_confirmed) {
-		dprintk("process_stateid: lockowner not confirmed yet!\n");
+		printk("process_stateid: lockowner not confirmed yet!\n");
 		goto out;
 	}
-	if (stateid->si_generation > stp->st_stateid.si_generation) {
-		dprintk("process_stateid: future stateid?!\n");
-		goto out;
-	}
-
-	/* OLD STATEID */
-	status = nfserr_old_stateid;
-	if (stateid->si_generation < stp->st_stateid.si_generation) {
-		dprintk("process_stateid: old stateid!\n");
-		goto out;
+	
+	if (expire)
+	{
+	  if (stateid->si_generation > stp->st_stateid.si_generation) {
+	    printk("process_stateid: future stateid?!\n");
+	    goto out;
+	  }
+	  
+	  /* OLD STATEID */
+	  status = nfserr_old_stateid;
+	  if (stateid->si_generation < stp->st_stateid.si_generation) {
+	    printk("process_stateid: old stateid!\n");
+	    goto out;
+	  }
 	}
+	
 	*stpp = stp;
 	status = nfs_ok;
 	renew_client(stp->st_stateowner->so_client);
@@ -1514,8 +1653,13 @@ nfsd4_open_confirm(struct svc_rqst *rqst
 	down(&client_sema); /* XXX need finer grained locking */
 
 	if ((status = nfs4_preprocess_seqid_op(current_fh, oc->oc_seqid,
-					&oc->oc_req_stateid,
-					CHECK_FH | CONFIRM,
+					       &oc->oc_req_stateid,
+/* DH-TODO: Need to make this dynamic */
+#if NFSD_STATE_SERVER
+					       CONFIRM,
+#else
+					       CHECK_FH | CONFIRM,
+#endif
 					&oc->oc_stateowner, &stp)))
 		goto out; 
 
@@ -1587,7 +1731,12 @@ nfsd4_close(struct svc_rqst *rqstp, stru
 	down(&client_sema); /* XXX need finer grained locking */
 	if ((status = nfs4_preprocess_seqid_op(current_fh, close->cl_seqid, 
 					&close->cl_stateid, 
+/* DH-TODO: Need to make this dynamic */
+#if NFSD_STATE_SERVER
+					       0,
+#else
 					CHECK_FH, 
+#endif
 					&close->cl_stateowner, &stp)))
 		goto out; 
 	/*
@@ -1597,6 +1746,15 @@ nfsd4_close(struct svc_rqst *rqstp, stru
 	update_stateid(&stp->st_stateid);
 	memcpy(&close->cl_stateid, &stp->st_stateid, sizeof(stateid_t));
 
+#if NFSD_STATE_SERVER
+	/* Send info to be distributed to rw servers */
+	/* DH-TODO: This code no longer checks for replay, is it necessary */
+	dprintk("nfsd4_close: Recalling file_locations\n");	
+	if ((status = nfsd4_recall_state(stp)))
+	  goto out;
+     	dprintk("nfsd4_close: Recalling file_locations Done\n");
+#endif
+
 	/* release_open_state() calls nfsd_close() if needed */
 	release_open_state(stp);
 out:
@@ -1644,6 +1802,7 @@ __nfs4_state_shutdown(void)
 {
 	int i;
 	struct nfs4_client *clp = NULL;
+	dprintk("__nfs4_state_shutdown: Start\n");
 
 	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
 		while (!list_empty(&conf_id_hashtbl[i])) {
@@ -1669,6 +1828,7 @@ __nfs4_state_shutdown(void)
 			alloc_sowner, free_sowner);
 	dprintk("NFSD: vfsopen %d vfsclose %d\n",
 			vfsopen, vfsclose);
+	dprintk("__nfs4_state_shutdown: End\n");
 }
 
 void
diff -urpN linux-2.4.18-patched/fs/nfsd/nfs4xdr.c linux-2.4.18-patched-ssds-getfh/fs/nfsd/nfs4xdr.c
--- linux-2.4.18-patched/fs/nfsd/nfs4xdr.c	2003-11-04 16:15:09.000000000 -0500
+++ linux-2.4.18-patched-ssds-getfh/fs/nfsd/nfs4xdr.c	2004-04-15 14:26:28.081000000 -0400
@@ -54,8 +54,10 @@
 #include <linux/sunrpc/name_lookup.h>
 #include <linux/nfsd/nfsd.h>
 #include <linux/nfsd/state.h>
+#include <linux/nfsd/stateserver.h>
 #include <linux/nfsd/xdr4.h>
 
+
 #define NFSDDBG_FACILITY		NFSDDBG_XDR
 
 /*
@@ -1147,13 +1149,13 @@ static u32 nfs4_ftypes[16] = {
  * replaced with the number of words written.
  */
 int
-nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
-		   struct dentry *dentry, u32 *buffer, int *countp, u32 *bmval)
+nfsd4_encode_fattr_fl(struct svc_fh *fhp, struct svc_export *exp,
+		   struct dentry *dentry, u32 *buffer, int *countp, u32 *bmval, struct nfsd4_getattr* getattr)
 {
 	u32 bmval0 = bmval[0];
 	u32 bmval1 = bmval[1];
-	struct name_ent *owner = NULL;
-	struct name_ent *group = NULL;
+	struct name_ent owner;
+	struct name_ent group;
 	struct svc_fh tempfh;
 	struct statfs statfs;
 	struct inode *inode = dentry->d_inode;
@@ -1163,6 +1165,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
 	u64 dummy64;
 	u32 *p = buffer;
 	int status;
+	dprintk("%s: Begin\n",__FUNCTION__);
 
 	BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1);
 	BUG_ON(bmval0 & ~NFSD_SUPPORTED_ATTRS_WORD0);
@@ -1183,14 +1186,10 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
 		fhp = &tempfh;
 	}
 	if (bmval1 & FATTR4_WORD1_OWNER) {
-		status = name_get_user(inode->i_uid, &owner);
-		if (status)
-			goto out_nfserr;
+		strcpy(owner.name,"nobody");
 	}
 	if (bmval1 & FATTR4_WORD1_OWNER_GROUP) {
-		status = name_get_group(inode->i_gid, &group);
-		if (status)
-			goto out_nfserr;
+		strcpy(group.name,"nobody");
 	}
 
 	if ((buflen -= 16) < 0)
@@ -1391,20 +1390,22 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
 		WRITE32(inode->i_nlink);
 	}
 	if (bmval1 & FATTR4_WORD1_OWNER) {
-		int namelen  = strlen(owner->name);
+		dprintk("returning owner %s\n",owner.name);
+		int namelen  = strlen(owner.name);
 		buflen -= (XDR_QUADLEN(namelen) << 2) + 4;
 		if (buflen < 0)
 			goto out_resource;
 		WRITE32(namelen);
-		WRITEMEM(owner->name, namelen);
+		WRITEMEM(owner.name, namelen);
 	}
 	if (bmval1 & FATTR4_WORD1_OWNER_GROUP) {
-		int namelen = strlen(group->name);
+		dprintk("returning group %s\n",group.name);
+		int namelen = strlen(group.name);
 		buflen -= (XDR_QUADLEN(namelen) << 2) + 4;
 		if (buflen < 0)
 			goto out_resource;
 		WRITE32(namelen);
-		WRITEMEM(group->name, namelen);
+		WRITEMEM(group.name, namelen);
 	}
 	if (bmval1 & FATTR4_WORD1_RAWDEV) {
 		if ((buflen -= 8) < 0)
@@ -1467,20 +1468,59 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
 		/* WRITE32(stat.mtime.tv_nsec); */
 		WRITE32(0);
 	}
+       	if (bmval1 & FATTR4_WORD1_FILE_LOCATIONS) {      
+   	        int i=0;
+		struct nfsd4_file_locations* loc; 
+		dprintk("%s: start encode of file_locations\n",__FUNCTION__);
+		if (getattr == NULL)
+		{
+			printk("%s: Error encoding file locations.getattr is NULL\n",__FUNCTION__);
+			status = nfserr_file_locations;
+			goto out_nfserr;
+		}
+
+		loc = getattr->ga_file_locations;
+
+		if (loc == NULL)
+		{
+		  printk("%s: Error encoding file locations. Loc is NULL\n",__FUNCTION__);
+		  status = nfserr_file_locations;
+		  goto out_nfserr;
+		}
+
+		buflen -= loc->locationslen;
+		if (buflen < 0)
+			goto out_resource;
+		WRITE32(loc->locationslen);  /* length of array */
+		dprintk("%s: filelocations len %d\n",__FUNCTION__, loc->locationslen);
+		for (i=0; i < loc->locationslen ;i++)
+		{
+			buflen -= (XDR_QUADLEN(loc->locations[i]->serverlen) << 2) + 4;
+			if (buflen < 0)
+				goto out_resource;
+			WRITE32(loc->locations[i]->serverlen);  /* server len */
+			WRITEMEM(loc->locations[i]->server,loc->locations[i]->serverlen);  /* server name */
+			dprintk("%s: filelocations %d %s\n",__FUNCTION__,loc->locations[i]->serverlen,loc->locations[i]->server);
+                } 
+	} 
 
 	*attrlenp = htonl((char *)p - (char *)attrlenp - 4);
 	*countp = p - buffer;
 	status = nfs_ok;
 
 out:
+	dprintk("%s: Begin of the End\n",__FUNCTION__);
 	if (fhp == &tempfh)
 	{
 		fh_put(&tempfh);
 	}
+	/*
 	if (owner)
 		name_put(owner);
 	if (group)
 		name_put(group);
+	*/
+	dprintk("%s: End\n",__FUNCTION__);
 	return status;
 out_nfserr:
 	status = nfserrno(status);
@@ -1494,6 +1534,13 @@ out_serverfault:
 	goto out;
 }
 
+int
+nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
+		   struct dentry *dentry, u32 *buffer, int *countp, u32 *bmval)
+{
+	return nfsd4_encode_fattr_fl(fhp,exp,dentry,buffer,countp,bmval,NULL);
+}
+
 static int
 nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen,
 		    loff_t offset, ino_t ino, unsigned int d_type)
@@ -1680,8 +1727,8 @@ nfsd4_encode_getattr(struct nfsd4_compou
 		return nfserr;
 
 	buflen = resp->end - resp->p - (COMPOUND_ERR_SLACK_SPACE >> 2);
-	nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry,
-				    resp->p, &buflen, getattr->ga_bmval);
+	nfserr = nfsd4_encode_fattr_fl(fhp, fhp->fh_export, fhp->fh_dentry,
+				    resp->p, &buflen, getattr->ga_bmval, getattr);
 
 	if (!nfserr)
 		resp->p += buflen;
@@ -2083,7 +2130,7 @@ nfsd4_encode_operation(struct nfsd4_comp
 {
 	u32 *statp;
 	ENCODE_HEAD;
-
+	dprintk("%s: Begin\n",__FUNCTION__);
 	RESERVE_SPACE(8);
 	WRITE32(op->opnum);
 	statp = p++;                  /* to be backfilled at the end */
@@ -2173,6 +2220,7 @@ nfsd4_encode_operation(struct nfsd4_comp
 	 * since it is already in network byte order.
 	 */
 	*statp = op->status;
+	dprintk("%s: End\n",__FUNCTION__);
 }
 
 /*
diff -urpN linux-2.4.18-patched/fs/nfsd/nfsfh.c linux-2.4.18-patched-ssds-getfh/fs/nfsd/nfsfh.c
--- linux-2.4.18-patched/fs/nfsd/nfsfh.c	2004-02-10 15:39:22.757256000 -0500
+++ linux-2.4.18-patched-ssds-getfh/fs/nfsd/nfsfh.c	2004-03-10 17:20:42.820256000 -0500
@@ -143,11 +143,12 @@ static struct dentry *nfsd_iget(struct s
 	inode = iget(sb, ino);
 	if (inode == NULL)
 		return ERR_PTR(-ENOMEM);
-	if (is_bad_inode(inode)
-	    || (generation && inode->i_generation != generation)
-		) {
+	if (is_bad_inode(inode))
+	  /* DH: gpfs patch */
+	{
 		/* we didn't find the right inode.. */
-		dprintk("fh_verify: Inode %lu, Bad count: %d %d or version  %u %u\n",
+	        dprintk("%s: Error with inode %lu, i_nlink: %d i_count: %d or   inode generation: %u generation: %u\n",
+			__FUNCTION__,
 			inode->i_ino,
 			inode->i_nlink, atomic_read(&inode->i_count),
 			inode->i_generation,
@@ -165,18 +166,57 @@ static struct dentry *nfsd_iget(struct s
 		if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED)) {
 			dget_locked(result);
 			result->d_vfs_flags |= DCACHE_REFERENCED;
+			/* DH - GPFS patch */
+			if (result->d_inode != inode)
+			{
+			  dput(result);
+			  goto build_dentry;
+			}
+			if (inode->i_op && inode->i_op->revalidate &&
+			    inode->i_op->revalidate(result))
+			{
+			  iput(inode);
+			  dput(result);
+			  return ERR_PTR(-ESTALE);
+			}
+			if (generation && inode->i_generation != generation)
+			{
+			  /* we didn't find the right inode.. */
+			  iput(inode);
+			  dput(result);
+			  return ERR_PTR(-ESTALE);
+			}  
+			/* end patch */
 			spin_unlock(&dcache_lock);
 			iput(inode);
 			return result;
 		}
 	}
 	spin_unlock(&dcache_lock);
+
+build_dentry:
 	result = d_alloc_root(inode);
 	if (result == NULL) {
 		iput(inode);
 		return ERR_PTR(-ENOMEM);
 	}
 	result->d_flags |= DCACHE_NFSD_DISCONNECTED;
+	/* gpfs patch */
+	if (inode->i_op && inode->i_op->revalidate &&
+	    inode->i_op->revalidate(result))
+	{
+		iput(inode);
+		dput(result);
+		return ERR_PTR(-ESTALE);
+	}
+	if (generation && inode->i_generation != generation)
+	{
+		/* we didn't find the right inode.. */
+		iput(inode);
+		dput(result);
+		return ERR_PTR(-ESTALE);
+	}
+	/* end patch */
 	return result;
 }
 
@@ -390,7 +430,7 @@ static struct dentry *splice(struct dent
  * we try to find the parent, and the parent of that and so-on until a
  * connection if made.
  */
-static struct dentry *
+struct dentry *
 find_fh_dentry(struct super_block *sb, __u32 *datap, int len, int fhtype, int needpath)
 {
 	struct dentry *dentry, *result = NULL;
@@ -538,12 +578,9 @@ fh_verify(struct svc_rqst *rqstp, struct
 	struct dentry	*dentry;
 	struct inode	*inode;
 	u32		error = 0;
-	struct timeval tm = { 0, 0 };
-
-	do_gettimeofday(&tm);
-	dprintk("Time at beg %s %ld %ld\n",__FUNCTION__,tm.tv_sec,tm.tv_usec);
 
-	dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
+	dprintk("%s: Hex File Handle (%s)\n", __FUNCTION__,SVCFH_fmt(fhp));
+	dprintk("%s: File Handle (%s)\n",__FUNCTION__,NFS4FH_fmt(fhp));
 
 	/* keep this filehandle for possible reference  when encoding attributes */
 	rqstp->rq_reffh = fh;
@@ -597,12 +634,13 @@ fh_verify(struct svc_rqst *rqstp, struct
 		}
 		error = nfserr_dropit;
 		if (IS_ERR(exp) && PTR_ERR(exp) == -EAGAIN)
+		{
+		  printk("Could not find export!\n");
 			goto out;
-
+		}
 		error = nfserr_stale;
 		if (!exp || IS_ERR(exp))
 			goto out;
-
 		/* Check if the request originated from a secure port. */
 		error = nfserr_perm;
 		if (!rqstp->rq_secure && EX_SECURE(exp)) {
@@ -612,14 +650,12 @@ fh_verify(struct svc_rqst *rqstp, struct
 			       ntohs(rqstp->rq_addr.sin_port));
 			goto out;
 		}
-
 		/*
 		 * Look up the dentry using the NFS file handle.
 		 */
 		error = nfserr_stale;
 		if (rqstp->rq_vers > 2)
 			error = nfserr_badhandle;
-
 		if (fh->fh_version == 1) {
 			/* if fileid_type != 0, and super_operations 
 			 * provide fh_to_dentry lookup,
@@ -654,7 +690,18 @@ fh_verify(struct svc_rqst *rqstp, struct
 			       dentry->d_parent->d_name.name, dentry->d_name.name);
 		}
 #endif
-
+		/* GPFS patch begin: need to revalidate the inode */
+		inode = dentry->d_inode;
+		if (inode && inode->i_op && inode->i_op->revalidate)
+		{
+		  if (inode->i_op->revalidate(dentry)) 
+		  {
+		    dentry = ERR_PTR(-ESTALE);
+		    error = nfserr_stale;
+		    goto out;
+		  }
+		}
+		/* end patch */
 		fhp->fh_dentry = dentry;
 		fhp->fh_export = exp;
 		nfsd_nr_verified++;
@@ -680,7 +727,6 @@ fh_verify(struct svc_rqst *rqstp, struct
 	 * spec says this is incorrect (implementation notes for the
 	 * write call).
 	 */
-
 	/* Type can be negative to e.g. exclude directories from linking */
 	if (type > 0 && (inode->i_mode & S_IFMT) != type) {
 		error = (type == S_IFDIR)? nfserr_notdir : nfserr_isdir;
@@ -690,7 +736,6 @@ fh_verify(struct svc_rqst *rqstp, struct
 		error = (type == -S_IFDIR)? nfserr_notdir : nfserr_isdir;
 		goto out;
 	}
-
 	/*
 	 * Security: Check that the export is valid for dentry <gam3@acm.org>
 	 */
@@ -726,7 +771,6 @@ fh_verify(struct svc_rqst *rqstp, struct
 			}
 		}
 	}
-
 	/* Finally, check access permissions. */
 	if (!error) {
 		error = nfsd_permission(exp, dentry, access);
@@ -738,9 +782,6 @@ fh_verify(struct svc_rqst *rqstp, struct
 	}
 #endif
 out:
-
-	do_gettimeofday(&tm);
-	dprintk("Time at end %s %ld %ld\n",__FUNCTION__,tm.tv_sec,tm.tv_usec);
 	if (exp && IS_ERR(exp))
 		exp_put(exp);
 	if (error == nfserr_stale)
diff -urpN linux-2.4.18-patched/fs/nfsd/nfssvc.c linux-2.4.18-patched-ssds-getfh/fs/nfsd/nfssvc.c
--- linux-2.4.18-patched/fs/nfsd/nfssvc.c	2003-11-04 16:15:09.000000000 -0500
+++ linux-2.4.18-patched-ssds-getfh/fs/nfsd/nfssvc.c	2004-04-28 18:37:56.492721000 -0400
@@ -30,8 +30,13 @@
 #include <linux/nfsd/nfsd.h>
 #include <linux/nfsd/stats.h>
 #include <linux/nfsd/cache.h>
+#include <linux/nfsd/nfsd4_rw.h>
 #include <linux/lockd/bind.h>
 
+extern void nfs4_state_server_shutdown(void);
+extern void nfs4_state_server_init(void);
+
+
 #define NFSDDBG_FACILITY	NFSDDBG_SVC
 
 /* these signals will be delivered to an nfsd thread 
@@ -83,7 +88,19 @@ nfsd_svc(unsigned short port, int nrserv
 	struct list_head *victim;
 	
 	lock_kernel();
-	dprintk("nfsd: creating service\n");
+
+#if NFSD_DATA_SERVER
+	/* Start the read/write thread, if not already running 
+	   This is called every time the user executes 'rpc.nfsd'
+	   and so is used to create and destroy nfsd.
+	 */
+	if (nrservs) {
+	  printk("nfsd: Starting data server thread\n");
+	  if ((error = nfs4_data_server_start()))
+	    goto out;
+	}
+#endif
+	printk("nfsd: creating service\n");
 	error = -EINVAL;
 	if (nrservs <= 0)
 		nrservs = 0;
@@ -93,6 +110,12 @@ nfsd_svc(unsigned short port, int nrserv
 	/* Readahead param cache - will no-op if it already exists */
 	error =	nfsd_racache_init(2*nrservs);
 	nfs4_state_init();
+
+#if NFSD_STATE_SERVER
+	printk("nfsd_svc: calling nfs4_stateserver_init()\n");
+	nfs4_state_server_init(); 
+#endif
+
 	if (error<0)
 		goto out;
 	if (!nfsd_serv) {
@@ -135,6 +158,12 @@ nfsd_svc(unsigned short port, int nrserv
 		nfsd_serv = NULL;
 		nfsd_racache_shutdown();
 		nfs4_state_shutdown();
+#if NFSD_STATE_SERVER
+                printk("nfsd_svc: calling state_server_shutdown\n");
+		nfs4_state_server_shutdown();
+#elif NFSD_DATA_SERVER
+		nfs4_data_server_shutdown();
+#endif
 	}
  out:
 	unlock_kernel();
@@ -257,6 +286,13 @@ nfsd(struct svc_rqst *rqstp)
 		nfsd_serv = NULL;
 	        nfsd_racache_shutdown();	/* release read-ahead cache */
 		nfs4_state_shutdown();
+#if NFSD_STATE_SERVER
+                printk("%s: calling state_server_shutdown\n",__FUNCTION__);
+		nfs4_state_server_shutdown();
+#elif NFSD_DATA_SERVER
+                printk("%s: calling nfs4_data_server_shutdown\n",__FUNCTION__);
+		nfs4_data_server_shutdown();
+#endif
 	}
 	list_del(&me.list);
 	nfsdstats.th_cnt --;
diff -urpN linux-2.4.18-patched/fs/nfsd/rw_state.c linux-2.4.18-patched-ssds-getfh/fs/nfsd/rw_state.c
--- linux-2.4.18-patched/fs/nfsd/rw_state.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.4.18-patched-ssds-getfh/fs/nfsd/rw_state.c	2004-04-15 14:26:21.283001000 -0400
@@ -0,0 +1,202 @@
+/*
+ *  fs/nfs4fs/rw_state.c
+ *
+ *  Copyright (c) 2003 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Dean Hildebrand <dhildebz@umich.edu>
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the University nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/fs.h>
+#include <linux/sunrpc/sched.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/svc.h>
+#include <linux/sunrpc/svcsock.h>
+#include <linux/nfsd/cache.h>	/* need RC_NOCACHE */
+#include <linux/inet.h>
+
+#include <linux/nfs4_acl.h>
+#include <linux/nfsd/nfsd4_rw.h>
+#include <linux/nfsd/xdr4.h>
+
+#define NFSDDBG_FACILITY                NFSDDBG_PROC
+extern struct nfs4_stateid * find_stateid(stateid_t *stid);
+extern int nfsd4_setclientid_ip(struct svc_rqst *rqstp, 
+		struct nfsd4_setclientid *setclid,u32 ipaddr,u8 expire);
+extern int nfsd4_setclientid_confirm_ip(struct svc_rqst *rqstp, 
+		struct nfsd4_setclientid_confirm *setclientid_confirm,u32 ipaddr);
+extern int nfsd4_process_open1_id(struct nfsd4_open *open,u32 stateownerid);
+
+extern int nfsd4_process_open2_id(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open,u32 file_id);
+extern void release_open_state(struct nfs4_stateid *stp);
+
+/* 
+ * Create client state structure.
+ */
+static int
+rw_create_client(struct svc_rqst *rqstp, u32 ip_addr, unsigned int namelen,char* name,char* verifier,char* confirm,clientid_t* clientid)
+{
+  struct nfsd4_setclientid setclid;
+  int status;
+  dprintk("%s: Begin\n",__FUNCTION__);
+  setclid.se_namelen = namelen;
+  setclid.se_name = name;
+  setclid.se_clientid.cl_boot = clientid->cl_boot;
+  setclid.se_clientid.cl_id = clientid->cl_id;
+  strncpy(setclid.se_verf,verifier,NFS4_VERIFIER_SIZE);
+  strncpy(setclid.se_confirm,confirm,NFS4_VERIFIER_SIZE);
+  if ((status = nfsd4_setclientid_ip(rqstp,&setclid,ip_addr,0)) != nfs_ok)
+    goto out;
+  
+  /* confirm client */
+  /*
+  struct nfsd4_setclientid_confirm setclientid_confirm;
+  strncpy(setclientid_confirm.sc_confirm,confirm,NFS4_VERIFIER_SIZE);
+  setclientid_confirm.sc_clientid.cl_boot = clientid->cl_boot;
+  setclientid_confirm.sc_clientid.cl_id = clientid->cl_id;
+  if ((status = nfsd4_setclientid_confirm_ip(rqstp,&setclientid_confirm,ip_addr)) != nfs_ok)
+    goto out;
+  */
+ out:
+  dprintk("%s: End\n",__FUNCTION__);
+  return status;
+}
+
+/*
+ * Modeled after nfsd4_open1().  Essentially it checks for the existence of a 
+ * stateowner and creates one if necessary
+ */
+static int
+rw_process_open(struct svc_rqst *rqstp,clientid_t* clid,unsigned int namelen,char* name,stateid_t* stateid,u32 share_access, u32 share_deny,struct svc_fh* fhp)
+{
+  int status;
+  struct nfsd4_open open;
+  dprintk("%s: Begin\n",__FUNCTION__);
+  open.op_clientid.cl_boot = clid->cl_boot; /* clientid_t* */
+  open.op_clientid.cl_id = clid->cl_id; /* clientid_t* */
+  open.op_owner.len = namelen;
+  open.op_owner.data = name;
+  open.op_seqid = -1; /* indicate seqid's are irrelevant for this open1 call */
+  open.op_share_access = share_access;
+  open.op_share_deny = share_deny;
+  open.op_truncate = 0; /* DH-TODO: disable for now */
+
+  if ((status = nfsd4_process_open1_id(&open,stateid->si_stateownerid)) != nfs_ok)
+    goto out;
+
+  /* open.op_stateowner is now set */
+  if ((status = nfsd4_process_open2_id(rqstp, fhp, &open,stateid->si_fileid)) != nfs_ok)
+    goto out;
+  
+  open.op_stateowner->so_confirmed = 1;
+
+ out:
+  dprintk("%s: End\n",__FUNCTION__);
+  return status;
+}
+
+
+/* Create file state for this data server. 
+ */
+int
+rw_create_state(struct svc_rqst *rqstp,struct rw_receive_args* argp)
+{
+  /* 
+     Step 1: Create a client id structure.  Based on client's ip addr 
+     Step 2: Create stateowner if needed.
+     Step 3: Create open file state and open file
+  */
+  int status;
+  dprintk("%s: Begin\n",__FUNCTION__);
+  if ((status = rw_create_client(rqstp,
+				 argp->ip_addr,
+                                 argp->cl_namelen,
+                                 argp->cl_name,
+                                 argp->verifier,
+				 argp->confirm,
+                                 &argp->client)))
+  {
+    printk("rw_create_state: rw_create_client failed!\n");
+    return status;
+  }
+    
+  if ((status = rw_process_open(rqstp,
+				&argp->client,
+				argp->cl_namelen,
+				argp->cl_name,
+				&argp->stateid,
+				argp->share_access,
+				argp->share_deny,
+				&argp->fhp)))
+  {
+    printk("rw_create_state: rw_process_open failed!\n");
+    return status;
+  }
+
+  dprintk("%s: End\n",__FUNCTION__);
+  return 0;
+}
+
+/* Invalidate the state by calling release_openfile 
+*/
+int
+rw_inval_state(int stateowner_id, int file_id)
+{
+  int status ;
+  struct nfs4_stateid* st_id;
+  stateid_t st;
+
+  dprintk("%s: Begin\n",__FUNCTION__);  
+  /* Find file to invalidate */
+  st.si_stateownerid = stateowner_id;
+  st.si_fileid = file_id;
+  if (!(st_id = find_stateid(&st)))
+    goto no_openfile;
+
+  dprintk("rw_inval_state: Releasing open file\n");
+  release_open_state(st_id);
+
+  status = 0;
+ out:
+  dprintk("%s: End\n",__FUNCTION__);
+  return status;
+
+no_openfile:
+  printk("rw_inval_state: File not found with stateowner id %d and file id %d\n",stateowner_id,file_id);
+  status = 1;
+  goto out;
+}
diff -urpN linux-2.4.18-patched/fs/nfsd/rw_svc.c linux-2.4.18-patched-ssds-getfh/fs/nfsd/rw_svc.c
--- linux-2.4.18-patched/fs/nfsd/rw_svc.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.4.18-patched-ssds-getfh/fs/nfsd/rw_svc.c	2004-04-18 20:52:31.112001000 -0400
@@ -0,0 +1,627 @@
+/*
+ *  fs/nfs4fs/rw_svc.c
+ *
+ *  Copyright (c) 2003 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Dean Hildebrand <dhildebz@umich.edu>
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the University nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/fs.h>
+#include <linux/sunrpc/sched.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/svc.h>
+#include <linux/sunrpc/svcsock.h>
+#include <linux/nfsd/cache.h>	/* need RC_NOCACHE */
+#include <linux/inet.h>
+#include <linux/kdev_t.h>
+
+#include <linux/nfsd/nfsd4_rw.h>
+#include <linux/nfs4_acl.h>
+
+
+
+#define NFSDDBG_FACILITY                NFSDDBG_PROC
+#define RW_VERSION		1
+#define RW_BUFSIZE		(1024 + NFSSVC_MAXBLKSIZE)
+#define RW_XDRSIZE		sizeof(struct rw_receive_args)
+
+#define ALLOWED_SIGS    (sigmask(SIGKILL))
+#define SHUTDOWN_SIGS   (sigmask(SIGKILL) | sigmask(SIGHUP) | sigmask(SIGINT) | sigmask(SIGQUIT))
+
+static DECLARE_MUTEX_LOCKED(rw_start);
+static DECLARE_WAIT_QUEUE_HEAD(rw_exit);
+
+static void	rw_main(struct svc_rqst *);
+static int	rw_decode_null(struct svc_rqst *, u32 *, void *);
+static int	rw_proc_null(struct svc_rqst *, void *, void *);
+static int	rw_encode_null(struct svc_rqst *, u32 *, void *);
+static int	rw_decode_receive_state(struct svc_rqst *, u32 *, struct rw_receive_args *);
+static int	rw_proc_receive_state(struct svc_rqst *, struct rw_receive_args *, struct rw_reps *);
+static int	rw_encode_receive_state(struct svc_rqst *, u32 *, struct rw_reps *);
+static int	rw_decode_inval_state(struct svc_rqst *, u32 *, struct rw_inval_args *);
+static int	rw_proc_inval_state(struct svc_rqst *, struct rw_inval_args *, struct rw_reps *);
+static int	rw_encode_inval_state(struct svc_rqst *, u32 *, struct rw_reps *);
+static int	rw_decode_lookup(struct svc_rqst *, u32 *, struct rw_lookup_args *);
+static int	rw_proc_lookup(struct svc_rqst *, struct rw_lookup_args *, struct rw_lookup_reps *);
+static int	rw_encode_lookup(struct svc_rqst *, u32 *, struct rw_lookup_reps *);
+
+extern int      do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open);
+
+/*
+ * RPC state tables etc., for the callback service.
+ *
+ * XXX: The 1024's here are total overkill; fix later...
+ */
+#define PROC(proc)			\
+{	(svc_procfunc) rw_proc_##proc,	\
+	(kxdrproc_t) rw_decode_##proc,	\
+	(kxdrproc_t) rw_encode_##proc,	\
+	NULL,				\
+	1024,			       	\
+	1024,				\
+	0,				\
+	RC_NOCACHE			\
+}
+
+static struct svc_procedure rw_v1_procedures[] = {
+	PROC(null),
+	PROC(receive_state),
+	PROC(inval_state),
+	PROC(lookup)
+};
+
+static struct svc_version nfs4_rw_version1 = {
+		.vs_vers	= 1,
+		.vs_nproc	= 4,
+		.vs_proc	= rw_v1_procedures,
+		.vs_dispatch	= NULL,
+		.vs_xdrsize     = RW_XDRSIZE
+};
+
+static struct svc_version *rw_version[] = {
+	NULL,
+	&nfs4_rw_version1,
+};
+
+static struct svc_stat	rwsvc_stats;
+static struct svc_serv* rw_serv;
+static pid_t  rwsvc_pid;
+static struct task_struct *rw_task = NULL;
+
+#define RW_NRVERS (sizeof(rw_version) / sizeof(rw_version[0]))
+static struct svc_program rw_svc_program = {
+ .pg_prog   = RW_PROGRAM,           /* program number      */
+ .pg_lovers = 1,                         /* lowest version no.  */
+ .pg_hivers = RW_NRVERS - 1,     /* highest version no. */
+ .pg_nvers  = RW_NRVERS,         /* number of versions  */
+ .pg_vers   = rw_version,   /* version array       */
+ .pg_name   = "nfsd",              /* service name        */
+ .pg_class  = "nfsd",
+ .pg_stats  = &rwsvc_stats      /* rpc statistics      */
+ };
+
+#define READ32(q)			\
+	(q) = ntohl(*p++)
+#define READ64(q)			\
+	(q) = (u64)ntohl(*p++) << 32;	\
+	(q) |= (u64)ntohl(*p++)
+#define READMEM(q, nbytes)		\
+	memcpy(q, p, nbytes);           \
+	(p) += (nbytes+3) >> 2
+#define COPYMEM(q, nbytes)		\
+	memcpy((q), p, (nbytes));	\
+	p += XDR_QUADLEN(nbytes)
+#define WRITE32(q)	*p++ = htonl(q)
+#define WRITE64(n)               do {                           \
+        *p++ = htonl((u32)((n) >> 32));                         \
+        *p++ = htonl((u32)(n));                                 \
+} while (0)
+#define WRITEMEM(ptr,nbytes)     do {                           \
+        *(p + XDR_QUADLEN(nbytes) -1) = 0;                      \
+        memcpy(p, ptr, nbytes);                                 \
+        p += XDR_QUADLEN(nbytes);                               \
+} while (0)
+
+
+
+/* convenient shorthand for the XDR routines... */
+#define CHECK(condition)                        \
+        do {                                    \
+                if (!(condition)) {             \
+                        printk("xdr error in read/write server: line %d\n", __LINE__); \
+                        goto xdr_error;         \
+                }                               \
+        } while (0)
+
+/*
+ * Create service procedure to handle incoming messages from the metaserver.
+ */
+int
+nfs4_data_server_start(void)
+{
+	int status = -EINVAL;
+	printk("create_rwserver: Begin\n");	
+
+	/* are we running? */
+	if (rwsvc_pid)
+		goto out;
+
+	/*
+	 * Try to create an RPC service for the callback.
+	 */
+	printk("create_rwserver: Creating Service\n");	
+	status = -ENOMEM;
+	if (!(rw_serv = svc_create(&rw_svc_program, RW_BUFSIZE))) {
+		printk(KERN_WARNING "nfs4: couldn't create read/write service\n");
+		goto out;
+	}
+	printk("create_rwserver: Creating Socket\n");	
+	if ((status = svc_makesock(rw_serv, IPPROTO_TCP, RW_BASE_PORT))) {
+		printk(KERN_WARNING "nfs4: couldn't create rw socket\n");
+		goto out_serv;
+	}
+
+	/*
+	 * Fork the rw server thread, and wait for it to start.
+	 */
+	printk("create_rwserver: Creating Thread\n");	
+	if ((status = svc_create_thread(rw_main, rw_serv))) {
+		printk(KERN_WARNING "nfs4: couldn't create rw thread\n");
+		goto out_serv;
+	}
+
+	status = 0;
+out:
+	printk("create_rwserver: End\n");	
+	return status;
+out_serv:
+	svc_destroy(rw_serv);
+	goto out;
+}
+
+/*
+ * This is currently not called to destroy the process.  
+ * killproc is being used instead.
+ */
+void
+nfs4_destroy_rw(void)
+{
+	int warned = 0;
+
+	printk("nfs4_destroy_rw: Begin\n");
+	if (!rwsvc_pid) {
+	  if (warned++ == 0)
+	    printk(KERN_WARNING "nfs4_destroy_rw: no rw server running.\n"); 
+	    return;
+	}
+	warned = 0;
+	/*	kill_proc(rwsvc_pid, SIGKILL, 1); */
+	if (send_sig(SIGKILL, rw_task, 1)) {
+	  printk(KERN_WARNING "nfsd: couldn't kill thread!\n");
+	}
+	rwsvc_pid = 0;
+	printk("nfs4_destroy_rw: End\n");
+}
+
+/* 
+ * This is called in ctl.c file upon module unload 
+ */
+void
+nfs4_data_server_shutdown(void)
+{
+	if (rw_serv) {
+		svc_destroy(rw_serv);
+		rw_serv = NULL;
+	}
+
+	nfs4_destroy_rw();
+}
+
+/*
+ * This is the kernel thread which handles incoming requests from the
+ * metaserver.  Essentially a continual loop waiting for requests.
+ */
+static void
+rw_main(struct svc_rqst *rqstp)
+{
+	struct svc_serv *serv = rqstp->rq_server;
+	int err;
+	sigset_t shutdown_mask, allowed_mask;
+
+	printk("%s: Begin\n",__FUNCTION__);	
+
+	MOD_INC_USE_COUNT;
+	lock_kernel();
+	daemonize();
+	current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
+
+	siginitsetinv(&shutdown_mask, SHUTDOWN_SIGS);
+	siginitsetinv(&allowed_mask, ALLOWED_SIGS);
+
+	rw_task = current;
+	up(&rw_start);	
+	unlock_kernel();
+	/*
+	 * Let our maker know we're running.
+	 */
+	rwsvc_pid = current->pid;
+
+	sprintf(current->comm, "nfs4_rw");
+	printk("%s: Entering processing 'for' loop\n",__FUNCTION__);	
+	for (;;) {
+		spin_lock_irq(&current->sigmask_lock);
+		siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
+		recalc_sigpending(current);
+		spin_unlock_irq(&current->sigmask_lock);
+
+		/*
+		 * Find a socket with data available and call its
+		 * recvfrom routine.
+		 */
+		while ((err = svc_recv(serv, rqstp,
+				       60*60*HZ)) == -EAGAIN)
+			;
+		if (err < 0)
+			break;
+
+		/*
+		 * Process requests with signals blocked.
+		 */
+		spin_lock_irq(&current->sigmask_lock);
+		siginitsetinv(&current->blocked, ALLOWED_SIGS);
+		recalc_sigpending(current);
+		spin_unlock_irq(&current->sigmask_lock);
+		dprintk("%s: processing request\n",__FUNCTION__);	
+		svc_process(serv, rqstp);
+	}
+
+	printk("rw_main: Data server request loop exited\n");	
+	if (err != -EINTR)
+		printk(KERN_WARNING "nfs4: read/write thread terminating on error %d\n", err);
+	else {
+	  unsigned int	signo;
+		for (signo = 1; signo <= _NSIG; signo++)
+			if (sigismember(&current->pending.signal, signo) &&
+			    !sigismember(&current->blocked, signo))
+				break;
+		printk(KERN_WARNING "nfs4: read/write thread terminating on signal %d\n", signo);
+	}
+
+	wake_up(&rw_exit);	
+	svc_exit_thread(rqstp);
+	MOD_DEC_USE_COUNT;
+	printk("%s: End\n",__FUNCTION__);	
+}
+
+
+
+/*
+ * Finally, the routines to do XDR encode/decode, and top-level
+ * processing, for NULL, receive state and revoke state.
+ */
+static int
+rw_decode_null(struct svc_rqst *rqstp, u32 *p, void *dummy)
+{
+	dprintk("%s: Begin\n",__FUNCTION__);
+	return 0;
+}
+
+static int
+rw_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
+{
+	dprintk("%s: Begin\n",__FUNCTION__);
+	return 0;
+}
+
+static int
+rw_encode_null(struct svc_rqst *rqstp, u32 *p, void *dummy)
+{
+	dprintk("%s: Begin\n",__FUNCTION__);
+	return xdr_ressize_check(rqstp, p);
+}
+
+/* Handle receiving new state information for a file to be read/write by
+ *  a NFSv4 client.
+ */
+static int
+rw_decode_receive_state(struct svc_rqst *rqstp, u32 *p, struct rw_receive_args *argp)
+{
+	u32 len, xdrlen;
+	int status;
+
+	dprintk("rw_decode_receive_state: Begin\n");
+	/*	end = rqstp->rq_arg.head[0].iov_base + rqstp->rq_arg.head[0].iov_len; */
+	/*
+	struct page ** pagelist = rqstp->rq_arg.pages;
+	int pagelen = rqstp->rq_arg.page_len;
+	*/
+
+	/* Get tag length. */
+	len = ntohl(*p++);
+	dprintk("First val sent from metaserver: %d\n",len);
+	xdrlen = XDR_QUADLEN(len);
+	
+	/* Read tag, minor version, array length */
+	/*	CHECK(p + xdrlen + 2 <= end); */
+	p += xdrlen;
+	READ32(argp->minorversion);
+	dprintk("Minor Version: %d\n",argp->minorversion);
+
+	READ32(argp->cl_namelen);
+	dprintk("Client name len: %d\n",argp->cl_namelen);
+	READMEM(argp->cl_name,argp->cl_namelen);
+	dprintk("Client Name: %s\n",argp->cl_name);
+	READMEM(argp->verifier,NFS4_VERIFIER_SIZE);
+	dprintk("Verifier: %s\n",argp->verifier);
+	READMEM(argp->confirm,NFS4_VERIFIER_SIZE);
+	dprintk("Confirm: %s\n",argp->confirm);
+	READ32(argp->ip_addr);
+	dprintk("ipaddr: %d\n",argp->ip_addr);
+	READ32(argp->client.cl_boot);
+	dprintk("client boot: %d\n",argp->client.cl_boot);
+	READ32(argp->client.cl_id);
+	dprintk("client id: %d\n",argp->client.cl_id);
+	READ32(argp->share_access);
+	dprintk("Share Access: %d\n",argp->share_access);
+	READ32(argp->share_deny);
+	dprintk("Deny Access: %d\n",argp->share_deny);
+	READ32(argp->stateid.si_boot);
+	dprintk("client boot: %d\n",argp->stateid.si_boot);
+	READ32(argp->stateid.si_stateownerid);
+	dprintk("Stateowner id: %d\n",argp->stateid.si_stateownerid);
+	READ32(argp->stateid.si_fileid);
+	dprintk("File id: %d\n",argp->stateid.si_fileid);
+
+	/* Decode filehandle.  If an error occurs, do not go to
+	 * xdr_error since it will then return status code 4
+	 * indicating a retry is requested.  Simply set the status
+	 * and return an error code to the state server 
+	 */
+	READ32(argp->fhp.fh_handle.fh_size);
+	READMEM(&argp->fhp.fh_handle.fh_base,argp->fhp.fh_handle.fh_size);
+	argp->fhp.fh_dentry = NULL;
+	argp->fhp.fh_export = NULL;
+	dprintk("NFSv4 File Handle (%s)\n",NFS4FH_fmt(&argp->fhp));
+	argp->fh_read_status = fh_verify(rqstp,&argp->fhp,0, MAY_NOP);
+
+	/* A 1 in rpcland is successful.  Very annoying. */
+	status = 1;
+	dprintk("rw_decode_receive_state: End\n");
+	return status;
+}
+
+static int
+rw_proc_receive_state(struct svc_rqst *rqstp, struct rw_receive_args *argp, struct rw_reps *repp)
+{
+	int rpc_status;
+	dprintk("rw_proc_receive_state Begin\n");
+
+	rpc_status = rpc_success;
+
+	/* Determine if filehandle was properly decode and read */
+	if (argp->fh_read_status != nfs_ok)
+	{
+	  printk("%s: Failed to decode filehandle from state server %d\n",__FUNCTION__,ntohl(argp->fh_read_status));
+	  repp->status = argp->fh_read_status;
+	  goto out;
+	}
+
+	repp->status = rw_create_state(rqstp,argp);
+out:
+	dprintk("rw_proc_receive_state: nfs status: %d rpc status %d End\n",ntohl(repp->status),rpc_status);
+	return rpc_status;
+}
+
+/* Send a response (a status) back to the state server after creating state */
+static int
+rw_encode_receive_state(struct svc_rqst *rqstp, u32 *p, struct rw_reps *repp)
+{
+	dprintk("rw_encode_receive_state: Begin\n");
+
+	dprintk("rw_encode_receive_state: Returning status: %d\n",ntohl(repp->status));
+	*p++ = repp->status; /* pre-xdr'd */
+
+	dprintk("rw_encode_receive_state: End\n");
+	return xdr_ressize_check(rqstp,p);
+}
+
+/* inval_state functions handle incoming requests to invalidate state
+ * previously placed on this data server.  
+ */
+static int
+rw_decode_inval_state(struct svc_rqst *rqstp, u32 *p, struct rw_inval_args *argp)
+{
+	u32 len, xdrlen;
+	int status;
+	/* u32 *end = rqstp->rq_arg.head[0].iov_base + rqstp->rq_arg.head[0].iov_len; */
+	/*
+	struct page ** pagelist = rqstp->rq_arg.pages;
+	int pagelen = rqstp->rq_arg.page_len;
+	*/
+	dprintk("rw_decode_inval_state: Begin\n");
+	/* Get tag length. */
+	len = ntohl(*p++);
+	dprintk("First val sent from metaserver: %d\n",len);
+	xdrlen = XDR_QUADLEN(len);
+	
+	/* Read tag, minor version, array length */
+	/* CHECK(p + xdrlen + 2 <= end); */
+	p += xdrlen;
+	READ32(argp->minorversion);
+	dprintk("Minor Version: %d\n",argp->minorversion);
+
+	READ32(argp->stateowner_id);
+	dprintk("Lockowner id: %d\n",argp->stateowner_id);
+	READ32(argp->file_id);
+	dprintk("File id: %d\n",argp->file_id);
+
+	status = 1;
+	dprintk("rw_decode_inval_state: End\n");
+	return status;
+}
+
+/* Call procedure with decoded args to actually invalidate the state */
+static int
+rw_proc_inval_state(struct svc_rqst *rqstp, struct rw_inval_args *argp, struct rw_reps *repp)
+{
+	int rpc_status, nfs_status;
+	dprintk("rw_proc_inval_state Begin\n");
+
+	rpc_status = rpc_success;
+	nfs_status = NFS_OK;
+
+	nfs_status = rw_inval_state(argp->stateowner_id,
+				    argp->file_id);
+	  
+	repp->status = nfs_status;
+
+	dprintk("rw_proc_inval_state: End\n");
+	return rpc_status;
+}
+
+/* Send a respose (a status) to the state server for invalidating state */
+static int
+rw_encode_inval_state(struct svc_rqst *rqstp, u32 * p, struct rw_reps *repp)
+{
+	dprintk("rw_encode_inval_state: Begin\n");
+
+	dprintk("rw_encode_inval_state: Returning status: %d\n",repp->status);
+	*p++ = ntohl(repp->status);
+
+	dprintk("rw_encode_inval_state: End\n");
+	return xdr_ressize_check(rqstp,p);
+}
+
+static int
+rw_decode_lookup(struct svc_rqst *rqstp, u32 *p, struct rw_lookup_args *argp)
+{
+  int len,xdrlen,junk;
+  struct nfsd4_open* open = &argp->open;
+
+	dprintk("%s: Begin\n",__FUNCTION__);
+	memset(open->op_bmval, 0, sizeof(open->op_bmval));
+	open->op_iattr.ia_valid = 0;
+
+	/* Get tag length. */
+	len = ntohl(*p++);
+	dprintk("First val sent from metaserver: %d\n",len);
+	xdrlen = XDR_QUADLEN(len);	
+	p += xdrlen;
+	READ32(junk);
+	READ32(open->op_create);
+	switch (open->op_create) {
+	case NFS4_OPEN_NOCREATE:
+	  break;
+	case NFS4_OPEN_CREATE:
+	  READ32(open->op_createmode);
+	  switch (open->op_createmode) {
+	  case NFS4_CREATE_UNCHECKED:
+	  case NFS4_CREATE_GUARDED:
+	    READ32(open->op_iattr.ia_mode);
+	    break;
+	  case NFS4_CREATE_EXCLUSIVE:
+	    COPYMEM(open->op_verf, 8);
+	    break;
+	  }
+	  break;
+	}
+
+	/* open_claim */
+	READ32(open->op_claim_type);
+	READ32(open->op_fname.len);
+	open->op_fname.data = kmalloc(open->op_fname.len * sizeof(u8), GFP_KERNEL);
+	READMEM(open->op_fname.data, open->op_fname.len);
+	READ32(argp->fhp.fh_handle.fh_size);
+	READMEM(&argp->fhp.fh_handle.fh_base,argp->fhp.fh_handle.fh_size);
+	argp->fhp.fh_dentry = NULL;
+	argp->fhp.fh_export = NULL;
+	dprintk("NFSv4 File Handle (%s)\n",NFS4FH_fmt(&argp->fhp));
+	argp->fh_read_status = fh_verify(rqstp,&argp->fhp,0, MAY_NOP);
+	dprintk("%s: End\n",__FUNCTION__);
+	return 1;
+}
+
+static int 
+rw_proc_lookup(struct svc_rqst *rqstp, struct rw_lookup_args *argp, struct rw_lookup_reps *repp)
+{
+  int nfs_status,rpc_status;
+  dprintk("%s: Begin\n",__FUNCTION__);
+  rpc_status = rpc_success;
+  nfs_status = nfs_ok;
+
+  if (argp->fh_read_status != nfs_ok)
+  {
+    printk("%s: Failed to decode filehandle from state server %d\n",__FUNCTION__,ntohl(argp->fh_read_status));
+    repp->status = argp->fh_read_status;
+    goto out;
+  }
+
+  nfs_status = do_open_lookup(rqstp, &argp->fhp, &argp->open);
+  dprintk("%s: End\n",__FUNCTION__);
+  repp->status = nfs_status;
+  if (nfs_status)
+  {
+    dprintk("%s: Error with do_open_lookup %d\n",__FUNCTION__,nfs_status);
+	goto out;
+  }
+  repp->fhp = &argp->fhp;
+
+ out:
+  kfree(argp->open.op_fname.data);
+  return rpc_status;
+}
+
+static int
+rw_encode_lookup(struct svc_rqst *rqstp, u32 *p, struct rw_lookup_reps *repp)
+{
+	int len;
+	struct inode *inode = repp->fhp->fh_dentry->d_inode;
+	dprintk("%s: Begin\n",__FUNCTION__);
+	dprintk("Returning Handle (%s)\n",NFS4FH_fmt(repp->fhp));
+ 	*p++ = repp->status;
+ 	WRITE32((u32) MAJOR(inode->i_sb->s_dev));
+ 	WRITE32((u32) MINOR(inode->i_sb->s_dev));
+ 	WRITE64((u64) inode->i_ino);
+ 	WRITE32(inode->i_generation);
+	len = repp->fhp->fh_handle.fh_size;
+	WRITE32(len);
+	WRITEMEM(&repp->fhp->fh_handle.fh_base, len);
+
+	dprintk("%s: End\n",__FUNCTION__);
+	return xdr_ressize_check(rqstp, p);
+}
diff -urpN linux-2.4.18-patched/fs/nfsd/stateserver.c linux-2.4.18-patched-ssds-getfh/fs/nfsd/stateserver.c
--- linux-2.4.18-patched/fs/nfsd/stateserver.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.4.18-patched-ssds-getfh/fs/nfsd/stateserver.c	2004-04-19 12:42:17.156000000 -0400
@@ -0,0 +1,1082 @@
+/*
+ *  linux/fs/nfsd/stateserver.c
+ *
+ *  Copyright (c) 2001 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Dean Hildebrand <dhildebz@umich.edu>
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the University nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <linux/param.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+
+#include <linux/sunrpc/svc.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/nfsd/nfsd.h>
+#include <linux/nfsd/cache.h>
+#include <linux/mount.h>
+#include <linux/workqueue.h>
+#include <linux/inet.h>
+#include <linux/nfs4.h>
+#include <linux/nfsd/state.h>
+#include <linux/nfsd/stateserver.h>
+#include <linux/nfsd/xdr4.h>
+
+
+#define NFSDDBG_FACILITY                NFSDDBG_PROC
+
+static struct semaphore state_server_sem;
+
+void
+nfs4_lock_state_server(void)
+{
+	down(&state_server_sem);
+}
+
+void
+nfs4_unlock_state_server(void)
+{
+	up(&state_server_sem);
+}
+
+#define CLIENT_DATA_HASH_BITS		4
+#define CLIENT_DATA_HASH_SIZE		(1 << CLIENT_DATA_HASH_BITS)
+#define CLIENT_DATA_HASH_MASK		(CLIENT_DATA_HASH_SIZE - 1)
+
+#define clientdatamap_hashval(owner_id,file_id) \
+	(((owner_id) + (file_id)) & CLIENT_DATA_HASH_MASK)
+
+/* List of available data servers */
+static struct list_head data_server_list;
+/* Mapping of clients to data servers */
+static struct list_head cd_map[CLIENT_DATA_HASH_SIZE];
+
+static void dealloc_file_locations(struct nfsd4_file_locations* file_locations);
+
+/* Lookup a assocation between a client/file and a data server(s).
+ */
+static inline struct nfs4_client_data_map*
+lookup_dataserver(unsigned int hashval, stateid_t* stateid)
+{
+	struct nfs4_client_data_map *cd;
+	struct list_head *pos, *next;
+	dprintk("lookup_dataserver: Begin\n");
+	dprintk("lookup_dataserver: hashval:%d stateowner id:%d file id:%d\n",hashval,stateid->si_stateownerid,stateid->si_fileid);
+	list_for_each_safe(pos,next, &cd_map[hashval]) {
+	  cd = list_entry(pos,struct nfs4_client_data_map,hash_val);
+	  if (cd->ownerid == stateid->si_stateownerid &&
+	      cd->fileid == stateid->si_fileid)
+	  {
+	    dprintk("lookup_dataserver: Found End\n");
+	    return cd;
+	  }
+	}
+	dprintk("lookup_dataserver: Empty End\n");
+	return NULL;
+}
+
+/* Remove association between a client/file with a set of data_servers.
+ * Since we do not have access to the clientid or lockowner in this association,
+ * there may be more than a single open refering to this assocation.  We must
+ * not clean it up until the reference counter reaches 0.
+ */
+static inline void
+dequeue_data_client_map(unsigned int hashval, stateid_t* st)
+{
+	struct nfs4_client_data_map *cd;
+        struct nfs4_data_server_ref_list* ds;
+
+	dprintk("dequeue_data_client_map: Begin\n");
+	cd = lookup_dataserver(hashval,st);
+	if (cd == NULL) 
+	  return;
+	/* Only remove association if there are no other outstanding
+	 * open requests whose state has not been cleaned up.
+	 */
+	if (cd->num_references == 1)
+	{
+	  list_del(&cd->hash_val);
+	  dealloc_file_locations(cd->file_locations);
+	  while (!list_empty(&cd->data_servers))
+	  {
+	    ds = list_entry(cd->data_servers.next,struct nfs4_data_server_ref_list,hash_val);
+	    list_del(&ds->hash_val);
+		kfree(ds);
+	  }
+	  kfree(cd);
+	}
+	else
+	{
+	  cd->num_references--;
+	}
+
+	dprintk("dequeue_data_client_map: End\n");
+}
+
+/* Setup rpc message and connect to data server */
+static int
+data_transmit(struct rpc_message* msg,struct rpc_clnt* clnt)
+{
+        int status;
+	dprintk("data_transmit: Begin\n");
+
+	msg->rpc_cred = rpcauth_lookupcred(clnt->cl_auth,0);
+
+	if ((status = rpc_call_sync(clnt, msg, 0))) {
+		printk(KERN_WARNING "data_transmit: rpc_execute failed! %d\n",status);
+		status = nfserrno(status);
+		return status;
+	}
+	dprintk("data_transmit: End\n");
+	return 0;
+}
+
+/*
+ * This is the size of both the request and repsonse buffer, including
+ * XDR baggage and RPC header.
+ *
+ * XXX: 1024 is total overkill, figure out right amount later!
+ */
+#define DATA_BUFSIZE		1024
+#define DATA_MINOR_VERSION	0
+#define DATA_NULL                 0
+
+/*
+ * Callback arg/result structs.
+ */
+
+struct nfsd4_dist_state_args {
+  struct svc_fh *fhp;
+  stateid_t* stateid;
+  u32 share_access;
+  u32 share_deny;
+  struct nfs4_client* client;
+};
+
+struct nfsd4_inval_state_args {
+  stateid_t* stateid;
+};
+
+struct nfsd4_data_res {
+  	int data_status; 
+};
+
+struct data_dist_state {
+	struct rpc_task		task;     /* must be first */
+	struct nfsd4_dist_state_args	arg;
+	struct nfsd4_data_res	res;
+};
+
+struct data_inval_state {
+	struct rpc_task		task;     /* must be first */
+	struct nfsd4_inval_state_args	arg;
+	struct nfsd4_data_res	res;
+};
+
+struct nfsd4_rem_lookup_args {
+  struct nfsd4_open* open;
+  struct svc_fh *fhp;
+};
+struct nfsd4_rem_lookup_res {
+  	int data_status; 
+	kdev_t dev;
+	unsigned long ino;
+	__u32 gen;
+	struct knfsd_fh fh;
+};
+struct data_rem_lookup {
+	struct rpc_task		task;     /* must be first */
+	struct nfsd4_rem_lookup_args	arg;
+	struct nfsd4_rem_lookup_res	res;
+};
+
+static int data_enc_null(struct rpc_rqst *req, u32 *p, void *dummy);
+static int data_enc_distribute_state(struct rpc_rqst *req, u32 *p, struct nfsd4_dist_state_args *data_args);
+static int data_enc_inval_state(struct rpc_rqst *req, u32 *p, struct nfsd4_inval_state_args *data_args);
+static int data_dec_null(struct rpc_rqst *req, u32 *p, void *dummy);
+static int data_dec_distribute_state(struct rpc_rqst *req, u32 *p, struct nfsd4_data_res *data_res);
+static int data_dec_inval_state(struct rpc_rqst *req, u32 *p, struct nfsd4_data_res *data_res);
+static int create_data_client(struct nfs4_data_server* data_server,int remote);
+
+static int data_enc_rem_lookup(struct rpc_rqst *req, u32 *p, struct nfsd4_rem_lookup_args *data_args);
+static int data_dec_rem_lookup(struct rpc_rqst *req, u32 *p, struct nfsd4_rem_lookup_res *data_res);
+/*
+ * RPC procedure tables
+ */
+static struct rpc_procinfo data_procedures[] = {
+	{ DATA_NULL, (kxdrproc_t)data_enc_null, (kxdrproc_t)data_dec_null, 0, 0,0 },
+	{ DATA_DIST_STATE, (kxdrproc_t)data_enc_distribute_state, (kxdrproc_t)data_dec_distribute_state, DATA_BUFSIZE, 0,0 },
+	{ DATA_INVAL_STATE, (kxdrproc_t)data_enc_inval_state, (kxdrproc_t)data_dec_inval_state, DATA_BUFSIZE, 0,0 },
+	{ 3, (kxdrproc_t)data_enc_rem_lookup, (kxdrproc_t)data_dec_rem_lookup, DATA_BUFSIZE, 0,0 }
+};
+
+static struct rpc_version data_version1 = {
+	1,
+	sizeof(data_procedures) / sizeof(data_procedures[0]),
+	data_procedures
+};
+
+static struct rpc_version *data_version[] = {
+	NULL,
+	&data_version1
+};
+static struct rpc_program              pnfs_program;
+static struct rpc_stat                 data_rpcstat = {
+        .program                = &pnfs_program
+};
+
+static struct rpc_program              pnfs_program = {
+        .name                   = "nfs4_data",
+        .number                 = DATA_PROGRAM,
+        .nrvers                 = sizeof(data_version) / sizeof(data_version[0]),
+        .version                = data_version,
+        .stats                  = &data_rpcstat,
+};
+
+#define READ32(x)         (x) = ntohl(*p++)
+#define READ64(x)         do {                  \
+        (x) = (u64)ntohl(*p++) << 32;           \
+        (x) |= ntohl(*p++);                     \
+} while (0)
+#define WRITE32(q)		\
+	*p++ = htonl(q)
+#define WRITE64(q)		\
+	*p++ = htonl((u32)(q >> 32));  \
+	*p++ = htonl((u32)q)
+#define WRITEMEM(q, nbytes)	 \
+	if(((XDR_QUADLEN(nbytes) << 2) - nbytes) > 0) \
+		memset((u8 *)p+nbytes,0,((XDR_QUADLEN(nbytes) << 2) - nbytes)); \
+	memcpy(p, (q), (nbytes)); \
+	p += XDR_QUADLEN(nbytes)  
+#define READMEM(q, nbytes)              \
+        memcpy(q, p, nbytes);           \
+        (p) += (nbytes+3) >> 2
+
+
+static int data_enc_rem_lookup(struct rpc_rqst *rqstp, u32 *p, struct nfsd4_rem_lookup_args *data_args)
+{
+  struct nfsd4_open* open = data_args->open;
+  struct svc_fh *fhp = data_args->fhp;
+  int len;
+
+        dprintk("%s: Begin\n",__FUNCTION__);	
+	*p++ = 0;            /* tag -- ignored */
+	*p++ = htonl(DATA_MINOR_VERSION);
+	WRITE32(open->op_create);
+	switch (open->op_create) {
+	case NFS4_OPEN_NOCREATE:
+		break;
+	case NFS4_OPEN_CREATE:
+	  WRITE32(open->op_createmode);
+	  switch (open->op_createmode) {
+	  case NFS4_CREATE_UNCHECKED:
+	  case NFS4_CREATE_GUARDED:
+	    WRITE32(open->op_iattr.ia_mode);
+	    break;
+	  case NFS4_CREATE_EXCLUSIVE:
+	    WRITEMEM(open->op_verf, 8);
+	    break;
+	  }
+	  break;
+	}
+	/* open_claim */
+	WRITE32(open->op_claim_type);
+	WRITE32(open->op_fname.len);
+	WRITEMEM(open->op_fname.data, open->op_fname.len);
+	len = fhp->fh_handle.fh_size;
+	WRITE32(len);
+	WRITEMEM(&fhp->fh_handle.fh_base, len);
+	rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p);
+	dprintk("%s: End\n",__FUNCTION__);
+	return 0;
+}
+
+static int data_dec_rem_lookup(struct rpc_rqst *req, u32 *p, struct nfsd4_rem_lookup_res *data_res)
+{
+	uint32_t dummy32;
+
+  dprintk("%s: Begin\n",__FUNCTION__);
+  /*
+   * data_status: NFS4ERR_BADHANDLE (10001) -> Error decoding handle
+   * data_status: NFS4ERR_STALE (70) -> Error decoding handle
+   */
+  data_res->data_status = *p++;
+  dprintk("%s: Status: %d\n",__FUNCTION__,ntohl(data_res->data_status));
+	READ32(dummy32);
+	data_res->dev = (dummy32 << MINORBITS);
+	READ32(dummy32);
+	data_res->dev |= (dummy32 & MINORMASK);
+
+  READ64(data_res->ino);
+  READ32(data_res->gen);
+  READ32(data_res->fh.fh_size);
+  READMEM(&data_res->fh.fh_base,data_res->fh.fh_size);
+ 
+  dprintk("%s End\n",__FUNCTION__);
+  return 0;
+}
+
+int nfsd4_remote_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
+{	
+  struct rpc_message msg;
+  struct rpc_clnt *clnt;
+  struct data_rem_lookup data_msg;
+	struct inode* inode;
+  int status;
+  struct nfs4_data_server* data_server = NULL;
+  struct svc_fh resfh;
+  dprintk("%s: Begin\n",__FUNCTION__);
+
+  /* Get data server */
+  data_server = list_entry((&data_server_list)->next,struct nfs4_data_server,hash_val);
+  list_move_tail(&data_server->hash_val,&data_server_list);
+  clnt = data_server->data_client;
+
+	  rpc_init_task(&data_msg.task, clnt, NULL, 0);
+	  data_msg.task.tk_calldata = &data_msg;
+	  /* DH-TODO: forget for now data_msg.task.tk_release = data_recall_release;	*/
+	  msg.rpc_proc = &data_procedures[3];
+	  msg.rpc_argp = &data_msg.arg;
+	  msg.rpc_resp = &data_msg.res;
+
+	  data_msg.arg.fhp = current_fh;
+	  data_msg.arg.open = open;
+	  
+	  if ((status = data_transmit(&msg,clnt)))
+	  {
+	    /* Keep trying the other data servers on error */
+	    printk("%s: Failed data transmition status: %d\n",__FUNCTION__,status);
+	    goto out;
+	  }
+	  /* Determine if file handle was correctly parsed by data server */
+	  if (data_msg.res.data_status != nfs_ok)
+	  {
+	    printk("%s: Failed to recall state %d\n",__FUNCTION__,ntohl(data_msg.res.data_status));
+	    status = data_msg.res.data_status;
+	    goto out;
+	  }
+	  /*DH-TODO: Need to set result values in a better way*/
+	  resfh.fh_dentry = (struct dentry*)kmalloc(sizeof(struct dentry),GFP_KERNEL);
+	  resfh.fh_dentry->d_inode = (struct inode*)kmalloc(sizeof(struct inode),GFP_KERNEL);
+	  resfh.fh_dentry->d_inode->i_sb = (struct super_block*)kmalloc(sizeof(struct super_block),GFP_KERNEL);
+	inode = resfh.fh_dentry->d_inode;
+	inode->i_sb->s_dev = data_msg.res.dev; 
+	inode->i_ino = data_msg.res.ino; 
+	inode->i_generation = data_msg.res.gen; 
+	inode->i_mode = S_IFREG;
+	resfh.fh_handle.fh_size = data_msg.res.fh.fh_size;
+	memcpy(&resfh.fh_handle.fh_base,&data_msg.res.fh.fh_base,data_msg.res.fh.fh_size);
+	fh_dup2(current_fh, &resfh);
+	status = 0;
+ out:
+	dprintk("%s: End\n",__FUNCTION__);
+	return status;
+}
+
+/*
+ * Encode arguments to send state to the data servers
+ */
+static int
+data_enc_distribute_state(struct rpc_rqst *rqstp, u32 *p, struct nfsd4_dist_state_args *data_args)
+{
+	struct nfs4_client* client = data_args->client;
+	struct svc_fh *fhp = data_args->fhp;
+	stateid_t* stateid = data_args->stateid;
+	int len;
+
+        dprintk("data_enc_send_state: Begin\n");	
+	*p++ = 0;            /* tag -- ignored */
+	*p++ = htonl(DATA_MINOR_VERSION);
+
+	*p++ = htonl(client->cl_name.len);
+	WRITEMEM(client->cl_name.data,client->cl_name.len);
+	WRITEMEM(client->cl_verifier,NFS4_VERIFIER_SIZE);
+	WRITEMEM(client->cl_confirm,NFS4_VERIFIER_SIZE);
+	*p++ = htonl(client->cl_addr);
+	*p++ = htonl(client->cl_clientid.cl_boot);
+	*p++ = htonl(client->cl_clientid.cl_id);
+	*p++ = htonl(data_args->share_access);
+	*p++ = htonl(data_args->share_deny);
+	*p++ = htonl(stateid->si_boot);
+	*p++ = htonl(stateid->si_stateownerid);
+	*p++ = htonl(stateid->si_fileid);
+	len = fhp->fh_handle.fh_size;
+	WRITE32(len);
+	WRITEMEM(&fhp->fh_handle.fh_base, len);
+
+	dprintk("Client name length %d\n",client->cl_name.len);
+	dprintk("Client Name %s\n",client->cl_name.data);
+	dprintk("Client verifier %s\n",client->cl_verifier);
+	dprintk("Client confirm %s\n",client->cl_confirm);
+	dprintk("Client address %d\n",client->cl_addr);
+	dprintk("Client id boot %d\n",client->cl_clientid.cl_boot);
+	dprintk("Client id %d\n",client->cl_clientid.cl_id);
+	dprintk("Share access %d\n",data_args->share_access);
+	dprintk("Share deny %d\n",data_args->share_deny);
+	dprintk("State boot %d\n",stateid->si_boot);
+	dprintk("Stateowner id %d\n",stateid->si_stateownerid);
+	dprintk("File id %d \n",stateid->si_fileid);
+	dprintk("File Handle len %d \n",len);
+	dprintk("Hex File Handle(%s)\n",SVCFH_fmt(fhp));
+	dprintk("NFSv4 File Handle(%s)\n",NFS4FH_fmt(fhp));
+	rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p);
+
+	dprintk("data_enc_send_state: End\n");
+	return 0;
+}
+
+/*
+ * Receives response from data server in sending state.
+ * @return value: 0 -> successful
+ * @return value: 4 -> retry
+*/
+static int
+data_dec_distribute_state(struct rpc_rqst *rqstp, u32 *p, struct nfsd4_data_res *data_res)
+{
+  dprintk("data_dec_send_state: Begin\n");
+  /*
+   * data_status: NFS4ERR_BADHANDLE (10001) -> Error decoding handle
+   * data_status: NFS4ERR_STALE (70) -> Error decoding handle
+   */
+  data_res->data_status = *p++;       
+  dprintk("data_dec_send_state: Status: %d\n",ntohl(data_res->data_status));
+  dprintk("data_dec_send_state: End\n");
+  return 0;	
+}
+
+/* Encode the arguments to request state invalidation
+ */
+static int
+data_enc_inval_state(struct rpc_rqst *rqstp, u32 *p, struct nfsd4_inval_state_args *data_args)
+{
+  stateid_t* stateid = data_args->stateid;
+
+  dprintk("data_enc_inval_sate: Begin\n");
+  *p++ = 0;            /* tag -- ignored */
+  *p++ = htonl(DATA_MINOR_VERSION);
+  *p++ = htonl(stateid->si_stateownerid);
+  *p++ = htonl(stateid->si_fileid);
+  
+  dprintk("State owner id %d\n",stateid->si_stateownerid);
+  dprintk("File id %d \n",stateid->si_fileid);
+  
+  rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p);
+  
+  dprintk("data_enc_inval_sate: End\n");
+  
+  return 0;
+}
+
+/*
+ * Receives response from data server to inval state
+*/
+static int
+data_dec_inval_state(struct rpc_rqst *rqstp, u32 *p, struct nfsd4_data_res *data_res)
+{
+  dprintk("data_dec_invalstate: Begin\n");
+  data_res->data_status = *p++;       
+  dprintk("data_dec_inval_state: Status: %d\n",ntohl(data_res->data_status));
+  
+  dprintk("data_dec_inval_state: End\n");
+  return 0;	  
+}
+
+
+/* Create a connection to the data servers
+ * DH-TODO: Need to create error codes
+ * If remoteHost is true, then a rpc connection is created and
+ * the data will be distributed to it.  Otherwise, no data is distributed
+ * to this data server but it will be sent to clients as a data server.
+ */
+static int 
+create_data_client(struct nfs4_data_server* data_server,int remoteHost)
+{
+        struct sockaddr_in	addr;
+	static struct rpc_timeout	timeparms;
+	struct rpc_xprt *	xprt;
+	struct rpc_clnt *	clnt;
+	/* currently unused 
+	struct rpc_message	msg = { DATA_NULL, NULL, NULL, NULL };
+	int status;
+	*/
+
+ 	printk("%s: Begin\n",__FUNCTION__);
+
+	if (!remoteHost)
+	{
+	  data_server->data_client = NULL;
+	  goto add_data_server;
+	}
+	printk("%s: transport to %s %s\n",__FUNCTION__,data_server->data_name,data_server->data_location.server);
+	  /* Initialize address */
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(data_server->data_port);
+	addr.sin_addr.s_addr = in_aton(data_server->data_location.server);
+	  
+	/* Initialize timeout */
+	timeparms.to_initval = 600 * HZ / 10;
+	timeparms.to_retries = 5;
+	timeparms.to_maxval = RPC_MAX_TCP_TIMEOUT;
+	timeparms.to_exponential = 1;
+	
+	  /* Create RPC transport */
+	if (!(xprt = xprt_create_proto(IPPROTO_TCP, &addr, &timeparms))) {
+	  printk("%s: ERROR -- couldn't create READ/WRITE transport!\n",__FUNCTION__);
+	  goto out_err;
+	}
+
+	/* Create RPC client */
+	if (!(clnt = rpc_create_client(xprt, data_server->data_name, &pnfs_program,1 , RPC_AUTH_NULL))) {
+	  printk("%s: ERROR -- Couldn't create client!\n",__FUNCTION__);
+	  goto out_xprt;
+	}
+	
+	clnt->cl_intr = 1;
+	clnt->cl_softrtry = 1;
+	clnt->cl_chatty = 1;
+	data_server->data_client = clnt;
+	
+	  /* Code if we wanted to test connection
+	     msg.rpc_cred = rpcauth_lookupcred(clnt,RPC_AUTH_UNIX,0);
+	     if ((status = rpc_call_sync(clnt, &msg, 0))) {
+	    printk(KERN_WARNING "nfsd: synchronous DATA_NULL failed!\n");
+	    goto out_rpciod;
+	    }
+	  */
+add_data_server:
+	printk("%s: Inserting item into list\n",__FUNCTION__);
+	list_add(&data_server->hash_val,&data_server_list);
+	printk("%s: End\n",__FUNCTION__);	
+	return 0;
+
+out_xprt:
+	xprt_destroy(xprt);
+out_err:
+	return 1;
+}
+
+/* Null functions to test connections */
+static int
+data_enc_null(struct rpc_rqst *rqstp, u32 *p, void *dummy)
+{
+	dprintk("data_enc_null: Begin\n");
+	rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p);
+	return 0;
+}
+
+static int
+data_dec_null(struct rpc_rqst *rqstp, u32 *p, void *dummy)
+{
+	dprintk("data_dec_null: Begin\n");
+	return 0;
+}
+
+/* This function is set as the function to release resources
+ * in the rpc connection.  I currently don't believe sunrpc
+ * calls this function though....
+ */
+static void
+data_send_release(struct rpc_task *task)
+{
+        struct data_dist_state *data;
+	dprintk("data_send_release: Begin\n");
+	data = (struct data_dist_state *)task->tk_calldata;
+	kfree(data);
+	dprintk("data_send_release: End\n");
+}
+
+static void
+data_recall_release(struct rpc_task *task)
+{
+        struct data_inval_state *data;
+	dprintk("data_recall_release: Begin\n");
+	data = (struct data_inval_state *)task->tk_calldata;
+	kfree(data);
+	dprintk("data_recall_release: End\n");
+}
+
+
+/* Prepare data for distributing state */
+static int
+data_call_distribute(struct svc_fh *fhp,struct nfsd4_open* open)
+{
+	struct rpc_message msg;
+	struct rpc_clnt *clnt;
+	u32 hashval; 
+	int status;
+	struct nfs4_client_data_map* cd_map_item = NULL;
+	struct nfs4_data_server_ref_list* ds_entry = NULL;
+	struct data_dist_state data_msg;
+	stateid_t* stateid = &open->op_stateid;
+	struct list_head *pos, *next;
+
+	dprintk("%s: Begin\n",__FUNCTION__);
+
+	hashval = clientdatamap_hashval(stateid->si_stateownerid,stateid->si_fileid);
+	if (!(cd_map_item = lookup_dataserver(hashval,stateid)))
+	{
+	  printk("%s: Could not find a rpc client for owner %d fileid %d\n",__FUNCTION__,stateid->si_stateownerid,stateid->si_fileid);
+	  status = 1; /* error */
+	  goto out;
+	}
+
+
+	list_for_each_safe(pos,next,&cd_map_item->data_servers)	
+	{
+	  ds_entry = list_entry(pos,struct nfs4_data_server_ref_list, hash_val);
+	  clnt = ds_entry->data_server->data_client;
+	  dprintk("%s: Distributing data to %s\n",__FUNCTION__,ds_entry->data_server->data_location.server);
+	  if (clnt == NULL)
+	  {
+	    /* The data server is the state server itself */
+	    dprintk("%s: data server is state server - continuing...\n",__FUNCTION__);
+	    status = 0;
+	    continue;
+	  }
+	  rpc_init_task(&data_msg.task, clnt, NULL, 0);
+	  data_msg.task.tk_calldata = &data_msg;
+	  data_msg.task.tk_release = data_send_release;	
+	  msg.rpc_proc = &data_procedures[DATA_DIST_STATE];
+	  msg.rpc_argp = &data_msg.arg;
+	  msg.rpc_resp = &data_msg.res;
+	
+	  /* set transmit values */
+	  data_msg.arg.share_access = open->op_share_access;
+	  data_msg.arg.share_deny = open->op_share_deny;
+	  data_msg.arg.fhp = fhp;
+	  data_msg.arg.client = open->op_stateowner->so_client;
+	  data_msg.arg.stateid = stateid;
+
+	  if ((status = data_transmit(&msg,clnt)))
+	  {
+	    /* DH-TODO: It would be best to keep trying the other data 
+	     * servers on transmission error.  It may just be that we lost a 
+	     * data server and it should be taken out of the data server list.  
+	     * For now quit everything.
+	     */
+	    printk("%s: Failed data transmition\n",__FUNCTION__);
+	    goto cleanup;
+	  }
+
+	  /* Determine if file handle was correctly parsed by data server */
+	  if (data_msg.res.data_status != nfs_ok)
+	  {
+	    printk("%s: Failed to send state %d\n",__FUNCTION__,ntohl(data_msg.res.data_status));
+	    /*	    status =  nfserr_file_locations; */
+	    status = data_msg.res.data_status;
+	    goto cleanup;
+	  }
+	}
+	status = 0;
+out:
+	dprintk("%s: End\n",__FUNCTION__);
+	return status;
+cleanup:
+	dequeue_data_client_map(hashval, stateid);
+	goto out;
+}
+
+/* Prepare data for recalling state */
+static int
+data_call_recall(stateid_t* stateid,u32 client_ipaddr)
+{
+	struct rpc_message msg;
+	struct rpc_clnt *clnt;
+	struct data_inval_state data_msg;
+	int status;
+	struct nfs4_client_data_map* cd_map_item = NULL;
+	u32 hashval;
+	struct nfs4_data_server_ref_list* ds_entry = NULL;
+	struct list_head *pos, *next;
+
+	dprintk("data_call_recall: Begin\n");
+	hashval = clientdatamap_hashval(stateid->si_stateownerid,stateid->si_fileid);
+	if (!(cd_map_item = lookup_dataserver(hashval,stateid)))
+	{
+	  printk("data_call_recall: Could not find a rpc client for owner %d fileid %d\n",stateid->si_stateownerid,stateid->si_fileid);
+	  status = 1;
+	  goto out;
+	}
+
+	dprintk("data_call_recall: Recalling from servers...\n");
+	/* Go through each data server assign to this file and client
+	 * and send a recall message to it
+	 */
+	list_for_each_safe(pos,next,&cd_map_item->data_servers)	{
+	  ds_entry = list_entry(pos,struct nfs4_data_server_ref_list, hash_val);
+	  clnt = ds_entry->data_server->data_client;
+	  if (clnt == NULL)
+	  {
+	    /* The data server is the state server itself */
+	    dprintk("data_call_recall: data server is state server - continuing...\n");
+	    status = 0;
+	    continue;
+	  }
+
+	  dprintk("data_call_recall: Recalling data from %s\n",ds_entry->data_server->data_location.server);
+	  /*
+	  if (!(data_msg = NFS4_ALLOC(sizeof(struct data_inval_state)))) 
+	  {
+		printk("data_call_recall: couldn't alloc data_inval_state!\n");
+		status = NFS4ERR_RESOURCE;
+		goto out;
+	  }
+	  */
+	  rpc_init_task(&data_msg.task, clnt, NULL, 0);
+	  data_msg.task.tk_calldata = &data_msg;
+	  data_msg.task.tk_release = data_recall_release;	
+	  msg.rpc_proc = &data_procedures[DATA_INVAL_STATE];
+	  msg.rpc_argp = &data_msg.arg;
+	  msg.rpc_resp = &data_msg.res;
+
+	  data_msg.arg.stateid = stateid;
+	  
+	  if ((status = data_transmit(&msg,clnt)))
+	  {
+	    /* Keep trying the other data servers on error */
+	    printk("data_call_recall: Failed data transmition status: %d\n",status);
+	    /*	    kfree(data_msg); */
+	    goto out;
+	  }
+	  /* Determine if file handle was correctly parsed by data server */
+	  if (data_msg.res.data_status != nfs_ok)
+	  {
+	    printk("%s: Failed to recall state %d\n",__FUNCTION__,ntohl(data_msg.res.data_status));
+	    status = nfserr_file_locations;
+	  }
+	}
+
+	status = 0;
+ out:
+	dprintk("data_call_recall: End\n");
+	return status;
+}
+
+/*
+ * Main function for sending the state to the clients.  
+ */
+int 
+nfsd4_distribute_state(struct svc_rqst *rqstp,struct nfsd4_open* open, struct svc_fh *fhp)
+{
+  dprintk("nfsd4_distribute_state\n");
+  return data_call_distribute(fhp,open);
+}
+
+/*
+ * Main function for recalling the state from the clients.  
+ * DH-TODO: Handle array of openfiles in a single rpc request to data servers... maybe
+ */
+int 
+nfsd4_recall_state(struct nfs4_stateid *ofp)
+{
+  u32 client_ipaddr = ofp->st_stateowner->so_client->cl_addr;
+  stateid_t* st = &ofp->st_stateid;
+  int status;
+  u32 clientdatahash;
+
+  dprintk("nfsd4_recall_state: Begin\n");
+
+  if ((status = data_call_recall(st,client_ipaddr)))
+  {
+    return status;
+  }
+
+  dprintk("nfsd4_recall_state: Removing mapping from table (ownerid %d) (fileid %d)\n",st->si_stateownerid,st->si_fileid);
+  clientdatahash = clientdatamap_hashval(st->si_stateownerid,st->si_fileid);
+  dequeue_data_client_map(clientdatahash,st);
+
+  dprintk("nfsd4_recall_state: End\n");
+  return 0;
+
+}
+
+/* Retrieve file locations data based upon ip_addr
+ * Calc_file_locations must be called *before* this function.
+ * ie: You must open the file before you can ask for the data servers
+ * that contain the state for the file.
+ */
+struct nfsd4_file_locations*
+get_file_locations(stateid_t* current_stateid)
+{
+  u32 clientdatahash;
+  struct nfs4_client_data_map* cd_item;
+
+  dprintk("get_file_locations: Begin\n");
+
+  clientdatahash = clientdatamap_hashval(current_stateid->si_stateownerid,current_stateid->si_fileid);
+  cd_item = lookup_dataserver(clientdatahash,current_stateid);
+  dprintk("get_file_locations: End\n");
+  if (cd_item != NULL)
+    return cd_item->file_locations;
+  else
+    return NULL;
+}
+
+/* Free the memory of a file_locations element sent to a client */
+static void
+dealloc_file_locations(struct nfsd4_file_locations* file_locations)
+{
+  dprintk("dealloc_file_locations: Begin\n");
+  if (!file_locations)
+    return;
+
+  kfree(file_locations->locations);
+  kfree(file_locations);
+  dprintk("dealloc_file_locations: End\n");
+}
+
+/* Create file_locations data structures for a given data_server.
+ * Must have allready called the file_loadbalance_algorithm function
+ * to determine which data servers map to which client/file.
+ * This function is a re-hashing of the existent data server information
+ * into the file_location information.  A little inefficient but much cleaner
+ * and easier to encode.
+ */
+static int
+alloc_file_locations(struct nfs4_client_data_map* cd_item)
+{
+  struct nfsd4_file_locations* ga_file_locations = NULL;
+  struct nfs4_data_server_ref_list* ds_entry = NULL;
+  struct list_head *pos, *next;
+  int i = 0;
+
+  ga_file_locations = (struct nfsd4_file_locations*)kmalloc(sizeof(struct nfsd4_fs_locations*),GFP_KERNEL);
+  if (!ga_file_locations)
+    goto out_mem4;
+
+  ga_file_locations->locationslen = cd_item->data_servers_len;
+  ga_file_locations->locations = (struct nfsd4_file_location**)kmalloc(ga_file_locations->locationslen * sizeof(struct nfsd4_file_location*),GFP_KERNEL); 
+  if (!ga_file_locations->locations)
+    goto out_mem3;
+
+  list_for_each_safe(pos,next,&cd_item->data_servers)
+  {
+    ds_entry = list_entry(pos,struct nfs4_data_server_ref_list, hash_val);
+    ga_file_locations->locations[i] = &ds_entry->data_server->data_location;
+    i++;
+  }
+
+  cd_item->file_locations = ga_file_locations;
+  return 0;
+
+  /* Free partial memory allocated */
+ out_mem3:
+  kfree(ga_file_locations);
+ out_mem4:
+  return 1;
+}
+
+/* Load balancing algorithm.  Determines which data servers to give to which clients
+ * for which files.  Returns the number of data servers chosen.
+ * DH-TODO: Need to create a better algorithm than round robin.
+ */
+static int
+file_loadbalance_algorithm(struct nfs4_client_data_map* cd_item)
+{
+  struct nfs4_data_server* data_server = NULL;
+  struct nfs4_data_server_ref_list* entry = NULL;
+
+  dprintk("file_loadbalance_algorithm: Begin\n");
+
+  if (list_empty(&data_server_list))
+    return 1;
+
+  /* Get data server */
+  data_server = list_entry((&data_server_list)->next,struct nfs4_data_server,hash_val);
+
+  /* Put the data server on the end of the list (Round Robin)*/
+  dprintk("file_loadbalance_algorithm: Moving data server %s %s to end of list\n",data_server->data_name, data_server->data_location.server);
+  list_move_tail(&data_server->hash_val,&data_server_list);
+  if (!(entry = kmalloc(sizeof(struct nfs4_data_server_ref_list),GFP_KERNEL)))
+  {
+    printk("ERROR:file_loadbalance_algorithm: Could not alloc nfs4_data_server_ref_list structure.\n");
+    return 1;
+  }
+
+  entry->data_server = data_server;
+  
+  /* Put data server in mapping list */
+  INIT_LIST_HEAD(&cd_item->data_servers);
+  list_add(&entry->hash_val,&cd_item->data_servers);
+  cd_item->data_servers_len = 1;  /* send 1 back */
+  dprintk("file_loadbalance_algorithm: End\n");
+
+  return 0;
+}
+
+/* Determine which data servers (locations) for a given file are to be
+ * sent back to the client.  Called from nfsd4_open in vfs.c
+ */
+int
+calc_file_locations(struct svc_rqst *rqstp,struct nfsd4_open* open)
+{
+  int status = nfserr_file_locations;
+  u32 clientdatahash;
+  struct nfs4_client_data_map* cd_item;
+  stateid_t* st = &open->op_stateid;
+
+  dprintk("calc_file_locations: Begin\n");    
+
+  /* Associate data server information with the state owner id.
+   */
+  nfs4_lock_state_server();
+  clientdatahash = clientdatamap_hashval(st->si_stateownerid,st->si_fileid);
+  cd_item = lookup_dataserver(clientdatahash,st);
+  /* This should be null if everything is working correctly.  If it is not,
+   * then something failed b/c the client is trying to open the file 
+   * that has allready been opened.  OPEN must have failed or the
+   * client is simply opening the file multiple times with a different
+   * owner id each time.
+   */
+  if (cd_item == NULL)
+  {
+    if (!(cd_item = kmalloc(sizeof(struct nfs4_client_data_map),GFP_KERNEL)))
+    {
+      printk("ERROR:calc_file_locations: Could not alloc client data map strcture for clid %d file id %d\n",st->si_stateownerid,st->si_fileid);
+      goto out;
+    }
+
+    /* Determine data servers to handle i/o requests */
+    if ((file_loadbalance_algorithm(cd_item)))
+    {
+      printk("ERROR:calc_file_locations: Could locate a data server.\n");
+      kfree(cd_item);
+      goto out;
+    }
+
+    /* Generate file location structure. 
+    */
+    if ((alloc_file_locations(cd_item)))
+    {
+      printk("ERROR:calc_file_locations: Could not alloc file locations structure.\n");
+      kfree(cd_item);
+      goto out;
+    }
+
+    dprintk("calc_file_locations: Inserting map of owner %d file %d\n",st->si_stateownerid,st->si_fileid);
+    cd_item->ownerid = st->si_stateownerid;
+    cd_item->fileid = st->si_fileid;
+    cd_item->num_references = 1;
+    /* Insert into list of data server <-> client associations */
+    list_add(&cd_item->hash_val,&cd_map[clientdatahash]);
+  }
+  else
+  {
+    /* Need to record the fact that another *set* of state is being created for
+     * this client ip_addr.  Most likely with a new lockowner id
+     */
+    dprintk("calc_file_locations: Found data_server client inode map.  Incrementing reference counter\n");
+    cd_item->num_references++;
+  }
+
+  status = nfs_ok;
+out:
+  nfs4_unlock_state_server();  
+  dprintk("calc_file_locations: End \n");
+  return status;
+}
+
+
+/* Shutdown connections to data servers */
+void
+nfs4_state_server_shutdown(void)
+{
+  struct nfs4_data_server* data_server;
+
+  printk("nfs4_state_server_shutdown: Begin\n");
+  while (!list_empty(&data_server_list)) 
+  {
+    data_server = list_entry((&data_server_list)->next,struct nfs4_data_server,hash_val);
+    /* This caused an error so comment out
+    rpc_shutdown_client(data_server->data_client);
+    */
+    list_del(&data_server->hash_val);
+    kfree(data_server->data_location.server);
+    kfree(data_server);
+  }
+  printk("nfs4_state_server_shutdown: End\n");
+}
+
+
+/* Called to initialize data server list structures */
+void
+nfs4_state_server_init(void)
+{
+  struct nfs4_data_server* data_server,*data_server2,*data_server3,*data_server4;
+  int i;
+  printk("nfs4_state_server_init: Start\n");
+
+  init_MUTEX(&state_server_sem);
+
+  INIT_LIST_HEAD(&data_server_list);
+  for (i = 0; i < CLIENT_DATA_HASH_SIZE; i++) 
+  {
+    INIT_LIST_HEAD(&cd_map[i]);
+  }
+  
+  data_server = (struct nfs4_data_server*)kmalloc(sizeof(struct nfs4_data_server),GFP_KERNEL);
+  strcpy(data_server->data_name,"iota6g.citi.umich.edu");
+  data_server->data_location.serverlen = 15;
+  data_server->data_location.server = (char*)kmalloc(data_server->data_location.serverlen * sizeof(char),GFP_KERNEL);
+  strcpy(data_server->data_location.server,"141.211.133.211");
+  data_server->data_port = DATA_PORT;
+  
+  /* Create Connection to data_server */
+  create_data_client(data_server,1); 
+  
+  data_server2 = (struct nfs4_data_server*)kmalloc(sizeof(struct nfs4_data_server),GFP_KERNEL);
+  strcpy(data_server2->data_name,"iota7g.citi.umich.edu");
+  data_server2->data_location.serverlen = 15;
+  data_server2->data_location.server = (char*)kmalloc(data_server2->data_location.serverlen * sizeof(char),GFP_KERNEL);
+  strcpy(data_server2->data_location.server,"141.211.133.213");
+  data_server2->data_port = DATA_PORT;
+ 
+  create_data_client(data_server2,1); 
+  
+  data_server3 = (struct nfs4_data_server*)kmalloc(sizeof(struct nfs4_data_server),GFP_KERNEL);
+  strcpy(data_server3->data_name,"iota8g.citi.umich.edu");
+  data_server3->data_location.serverlen = 15;
+  data_server3->data_location.server = (char*)kmalloc(data_server3->data_location.serverlen * sizeof(char),GFP_KERNEL);
+  strcpy(data_server3->data_location.server,"141.211.133.215");
+  data_server3->data_port = DATA_PORT;
+
+  create_data_client(data_server3,1); 
+
+  data_server4 = (struct nfs4_data_server*)kmalloc(sizeof(struct nfs4_data_server),GFP_KERNEL);
+  strcpy(data_server4->data_name,"iota5g.citi.umich.edu");
+  data_server4->data_location.serverlen = 15;
+  data_server4->data_location.server = (char*)kmalloc(data_server4->data_location.serverlen * sizeof(char),GFP_KERNEL);
+  strcpy(data_server4->data_location.server,"141.211.133.209");
+  data_server3->data_port = DATA_PORT;
+
+  create_data_client(data_server4,0); 
+
+  printk("nfs4_state_server_init: End\n");
+}
diff -urpN linux-2.4.18-patched/fs/nfsd/vfs.c linux-2.4.18-patched-ssds-getfh/fs/nfsd/vfs.c
--- linux-2.4.18-patched/fs/nfsd/vfs.c	2004-02-10 15:36:59.612257000 -0500
+++ linux-2.4.18-patched-ssds-getfh/fs/nfsd/vfs.c	2004-05-04 11:01:32.140650000 -0400
@@ -466,10 +466,6 @@ nfsd_open(struct svc_rqst *rqstp, struct
 	struct dentry	*dentry;
 	struct inode	*inode;
 	int		err;
-	struct timeval tm = { 0, 0 };
-
-	do_gettimeofday(&tm);
-	dprintk("Time at beg %s %ld %ld\n",__FUNCTION__,tm.tv_sec,tm.tv_usec);
 
 	/*
 	 * If we get here, then the client has already done an "open", and (hopefully)
@@ -507,7 +503,7 @@ nfsd_open(struct svc_rqst *rqstp, struct
 	atomic_set(&filp->f_count, 1);
 	filp->f_dentry = dentry;
 	filp->f_vfsmnt = fhp->fh_export->ex_mnt;
-	if (access & MAY_WRITE) {
+	if (access & MAY_WRITE && !(access & MAY_READ)) {
 		filp->f_flags = O_WRONLY|O_LARGEFILE;
 		filp->f_mode = FMODE_WRITE;
 		DQUOT_INIT(inode);
@@ -530,9 +526,6 @@ nfsd_open(struct svc_rqst *rqstp, struct
 			atomic_dec(&filp->f_count);
 		}
 	}
-
-	do_gettimeofday(&tm);
-	dprintk("Time at end %s %ld %ld\n",__FUNCTION__,tm.tv_sec,tm.tv_usec);
 out_nfserr:
 	if (err)
 		err = nfserrno(err);
@@ -709,32 +702,28 @@ out:
  * N.B. After this call fhp needs an fh_put
  */
 int
-nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
+nfsd4_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
 				struct iovec *vec, int vlen,
-	   			unsigned long cnt, int *stablep)
+	   			unsigned long cnt, int *stablep,struct file* file)
 {
 	struct svc_export	*exp;
-	struct file		file;
 	struct dentry		*dentry;
 	struct inode		*inode;
 	mm_segment_t		oldfs;
 	int			err = 0;
 	int			stable = *stablep;
 
-	err = nfsd_open(rqstp, fhp, S_IFREG, MAY_WRITE, &file);
-	if (err)
-		goto out;
 	if (!cnt)
-		goto out_close;
+		goto out;
 	err = nfserr_perm;
 
 #ifdef MSNFS
 	if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
-		(!lock_may_write(file.f_dentry->d_inode, offset, cnt)))
-		goto out_close;
+		(!lock_may_write(file->f_dentry->d_inode, offset, cnt)))
+		goto out;
 #endif
 
-	dentry = file.f_dentry;
+	dentry = file->f_dentry;
 	inode = dentry->d_inode;
 	exp   = fhp->fh_export;
 
@@ -747,7 +736,7 @@ nfsd_write(struct svc_rqst *rqstp, struc
 	 * flushing the data to disk is handled separately below.
 	 */
 
-	if (file.f_op->fsync == 0) {/* COMMIT3 cannot work */
+	if (file->f_op->fsync == 0) {/* COMMIT3 cannot work */
 	       stable = 2;
 	       *stablep = 2; /* FILE_SYNC */
 	}
@@ -755,11 +744,11 @@ nfsd_write(struct svc_rqst *rqstp, struc
 	if (!EX_ISSYNC(exp))
 		stable = 0;
 	if (stable && !EX_WGATHER(exp))
-		file.f_flags |= O_SYNC;
+		file->f_flags |= O_SYNC;
 
 	/* Write the data. */
 	oldfs = get_fs(); set_fs(KERNEL_DS);
-	err = vfs_writev(&file, vec, vlen, &offset);
+	err = vfs_writev(file, vec, vlen, &offset);
 	if (err >= 0)
 		nfsdstats.io_write += cnt;
 	set_fs(oldfs);
@@ -803,7 +792,7 @@ nfsd_write(struct svc_rqst *rqstp, struc
 
 			if (inode->i_state & I_DIRTY) {
 				dprintk("nfsd: write sync %d\n", current->pid);
-				nfsd_sync(&file);
+				nfsd_sync(file);
 			}
 #if 0
 			wake_up(&inode->i_wait);
@@ -818,13 +807,29 @@ nfsd_write(struct svc_rqst *rqstp, struc
 		err = 0;
 	else 
 		err = nfserrno(err);
-out_close:
+out:
+	return err;
+}
+
+int
+nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
+				struct iovec *vec, int vlen,
+	   			unsigned long cnt, int *stablep)
+{
+	struct file		file;
+        int			err = 0;
+
+	err = nfsd_open(rqstp, fhp, S_IFREG, MAY_WRITE, &file);
+	if (err)
+	  goto out;
+	nfsd4_vfs_write(rqstp,fhp,offset,vec,vlen,cnt,stablep,&file);
 	nfsd_close(&file);
 out:
 	return err;
 }
 
 
+
 #ifdef CONFIG_NFSD_V3
 /*
  * Commit all pending writes to stable storage.
@@ -1531,6 +1536,7 @@ nfsd_permission(struct svc_export *exp, 
 
 	if (acc == MAY_NOP)
 		return 0;
+#if 0
 	dprintk("nfsd: permission 0x%x%s%s%s%s%s%s%s mode 0%o%s%s%s\n",
 		acc,
 		(acc & MAY_READ)?	" read"  : "",
@@ -1546,6 +1552,7 @@ nfsd_permission(struct svc_export *exp, 
 		IS_RDONLY(inode)?	" ro" : "");
 	dprintk("      owner %d/%d user %d/%d\n",
 		inode->i_uid, inode->i_gid, current->fsuid, current->fsgid);
+#endif
 
 	/* Normally we reject any write/sattr etc access on a read-only file
 	 * system.  But if it is IRIX doing check on write-access for a 
@@ -1590,7 +1597,6 @@ nfsd_permission(struct svc_export *exp, 
 		return 0;
 
 	err = permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC));
-	dprintk("Result of permission %d\n",err);
 
 	/* Allow read access to binaries even when mode 111 */
 	if (err == -EACCES && S_ISREG(inode->i_mode) &&
diff -urpN linux-2.4.18-patched/include/linux/nfs4.h linux-2.4.18-patched-ssds-getfh/include/linux/nfs4.h
--- linux-2.4.18-patched/include/linux/nfs4.h	2003-11-04 16:15:09.000000000 -0500
+++ linux-2.4.18-patched-ssds-getfh/include/linux/nfs4.h	2004-01-12 18:40:38.000000000 -0500
@@ -243,6 +243,7 @@ enum open_delegation_type4 {
 #define FATTR4_WORD1_TIME_METADATA      (1 << 20)
 #define FATTR4_WORD1_TIME_MODIFY        (1 << 21)
 #define FATTR4_WORD1_TIME_MODIFY_SET    (1 << 22)
+#define FATTR4_WORD1_FILE_LOCATIONS     (1 << 23)
 
 #define NFSPROC4_NULL 0
 #define NFSPROC4_COMPOUND 1
diff -urpN linux-2.4.18-patched/include/linux/nfsd/nfsd4_rw.h linux-2.4.18-patched-ssds-getfh/include/linux/nfsd/nfsd4_rw.h
--- linux-2.4.18-patched/include/linux/nfsd/nfsd4_rw.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.4.18-patched-ssds-getfh/include/linux/nfsd/nfsd4_rw.h	2004-04-18 23:09:55.862000000 -0400
@@ -0,0 +1,58 @@
+#ifndef _NFSD4_RW_H
+#define _NFSD4_RW_H
+
+#include <linux/nfsd/nfsd.h> 
+#include <linux/nfsd/nfsfh.h>
+#include <linux/nfsd/state.h>
+#include <linux/nfsd/xdr4.h>
+
+#define RW_PROGRAM              20000001
+#define RW_BASE_PORT		31000
+
+/*
+ * These are the definitions for the callback XDR.
+ */
+struct rw_receive_args {
+  u32 minorversion;
+  u32 share_access;
+  u32 share_deny;
+  char verifier[NFS4_VERIFIER_SIZE];
+  char confirm[NFS4_VERIFIER_SIZE];
+  u32 ip_addr;
+  u32 cl_namelen;
+  char cl_name[NFS4_OPAQUE_LIMIT];
+  stateid_t stateid;
+  struct svc_fh fhp;
+  u32 fh_read_status;
+  clientid_t client;
+ };
+
+struct rw_inval_args {
+  u32 minorversion;
+  u32 stateowner_id;
+  u32 file_id;
+ };
+
+struct rw_lookup_args {
+  struct nfsd4_open open;
+  struct svc_fh fhp;
+  u32 fh_read_status;
+};
+
+struct rw_lookup_reps {
+  u32		status;
+  struct svc_fh* fhp;
+};
+
+struct rw_reps {
+	u32		status;
+};
+
+
+extern int nfs4_data_server_start(void);
+extern void nfs4_data_server_shutdown(void);
+extern int rw_create_state(struct svc_rqst *rqstp,struct rw_receive_args* argp);
+extern int rw_inval_state(int stateowner_id, int file_id);
+extern void rw_svc_shutdown(void);
+
+#endif   /* NFSD4_RW_H */
diff -urpN linux-2.4.18-patched/include/linux/nfsd/nfsd.h linux-2.4.18-patched-ssds-getfh/include/linux/nfsd/nfsd.h
--- linux-2.4.18-patched/include/linux/nfsd/nfsd.h	2004-03-15 15:49:05.856257000 -0500
+++ linux-2.4.18-patched-ssds-getfh/include/linux/nfsd/nfsd.h	2004-06-03 23:00:55.128667000 -0400
@@ -192,7 +192,6 @@ void		nfsd_lockd_shutdown(void);
 #define	nfserr_openmode		__constant_htonl(NFSERR_OPENMODE)
 #define nfserr_file_locations   __constant_htonl(NFS4ERR_FILE_LOCATIONS)
 
-
 /* error codes for internal use */
 /* if a request fails due to kmalloc failure, it gets dropped.
  *  Client should resend eventually
@@ -257,6 +256,15 @@ extern struct timeval	nfssvc_boot;
  | FATTR4_WORD0_MAXFILESIZE     | FATTR4_WORD0_MAXLINK      | FATTR4_WORD0_MAXNAME          \
  | FATTR4_WORD0_MAXREAD         | FATTR4_WORD0_MAXWRITE)
 
+#if NFSD_STATE_SERVER
+#define NFSD_SUPPORTED_ATTRS_WORD1                                                          \
+(FATTR4_WORD1_MODE              | FATTR4_WORD1_NO_TRUNC     | FATTR4_WORD1_NUMLINKS         \
+ | FATTR4_WORD1_OWNER	        | FATTR4_WORD1_OWNER_GROUP  | FATTR4_WORD1_RAWDEV           \
+ | FATTR4_WORD1_SPACE_AVAIL     | FATTR4_WORD1_SPACE_FREE   | FATTR4_WORD1_SPACE_TOTAL      \
+ | FATTR4_WORD1_SPACE_USED      | FATTR4_WORD1_TIME_ACCESS  | FATTR4_WORD1_TIME_ACCESS_SET  \
+ | FATTR4_WORD1_TIME_CREATE     | FATTR4_WORD1_TIME_DELTA   | FATTR4_WORD1_TIME_METADATA    \
+ | FATTR4_WORD1_TIME_MODIFY     | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_FILE_LOCATIONS)
+#else
 #define NFSD_SUPPORTED_ATTRS_WORD1                                                          \
 (FATTR4_WORD1_MODE              | FATTR4_WORD1_NO_TRUNC     | FATTR4_WORD1_NUMLINKS         \
  | FATTR4_WORD1_OWNER	        | FATTR4_WORD1_OWNER_GROUP  | FATTR4_WORD1_RAWDEV           \
@@ -264,6 +272,7 @@ extern struct timeval	nfssvc_boot;
  | FATTR4_WORD1_SPACE_USED      | FATTR4_WORD1_TIME_ACCESS  | FATTR4_WORD1_TIME_ACCESS_SET  \
  | FATTR4_WORD1_TIME_CREATE     | FATTR4_WORD1_TIME_DELTA   | FATTR4_WORD1_TIME_METADATA    \
  | FATTR4_WORD1_TIME_MODIFY     | FATTR4_WORD1_TIME_MODIFY_SET)
+#endif
 
 /* These will return ERR_INVAL if specified in GETATTR or READDIR. */
 #define NFSD_WRITEONLY_ATTRS_WORD1							    \
@@ -275,6 +284,12 @@ extern struct timeval	nfssvc_boot;
 (FATTR4_WORD1_MODE              | FATTR4_WORD1_OWNER         | FATTR4_WORD1_OWNER_GROUP     \
  | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_METADATA | FATTR4_WORD1_TIME_MODIFY_SET)
 
+/* Only 1 of these can be defined. To have a state and a data server, only define
+   the state server
+*/
+#define NFSD_STATE_SERVER 0
+#define NFSD_DATA_SERVER 0
+
 #endif /* CONFIG_NFSD_V4 */
 
 #endif /* __KERNEL__ */
diff -urpN linux-2.4.18-patched/include/linux/nfsd/state.h linux-2.4.18-patched-ssds-getfh/include/linux/nfsd/state.h
--- linux-2.4.18-patched/include/linux/nfsd/state.h	2004-03-15 15:49:05.858257000 -0500
+++ linux-2.4.18-patched-ssds-getfh/include/linux/nfsd/state.h	2004-05-16 20:00:40.600099000 -0400
@@ -87,6 +87,7 @@ struct nfs4_client {
 	struct svc_cred		cl_cred; 	/* setclientid principal */
 	clientid_t		cl_clientid;	/* generated by server */
 	nfs4_verifier		cl_confirm;	/* generated by server */
+        u8                      cl_expire;      /* 1->expire,0->doesn't expire */
 };
 
 static inline void
@@ -149,6 +150,7 @@ struct nfs4_stateid {
 	int                           st_vfs_set;
 	unsigned int                  st_share_access;
 	unsigned int                  st_share_deny;
+  int local_file;
 };
 
 /* flags for preprocess_seqid_op() */
diff -urpN linux-2.4.18-patched/include/linux/nfsd/stateserver.h linux-2.4.18-patched-ssds-getfh/include/linux/nfsd/stateserver.h
--- linux-2.4.18-patched/include/linux/nfsd/stateserver.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.4.18-patched-ssds-getfh/include/linux/nfsd/stateserver.h	2004-04-15 16:11:09.415000000 -0400
@@ -0,0 +1,45 @@
+#ifndef _STATESERVER_H
+#define _STATESERVER_H
+
+#define DATA_NULL 			0
+#define DATA_DIST_STATE			1
+#define DATA_INVAL_STATE		2
+
+#define DATA_PROGRAM              20000001
+#define DATA_PORT		  31000
+#define MAX_DATA_NAME_LEN	  100
+
+struct nfsd4_file_location {
+  u32       serverlen;
+  char*     server;
+};
+
+struct nfsd4_file_locations {
+  u32                          locationslen;
+  struct nfsd4_file_location**    locations;
+};
+
+struct nfs4_data_server {
+	char					data_name[MAX_DATA_NAME_LEN];
+        struct nfsd4_file_location              data_location;
+	unsigned short				data_port;
+	struct rpc_clnt *			data_client;
+        struct list_head                        hash_val; /* list of conns */
+};
+
+struct nfs4_data_server_ref_list {
+  struct nfs4_data_server*                      data_server;
+  struct list_head                              hash_val; /* list of data servers per client */
+};
+
+struct nfs4_client_data_map {
+  u32                                           ownerid; /* key */
+  u32                                           fileid; /* key */
+  int                                           num_references; /* clean up when == 0 */
+  struct nfsd4_file_locations*                  file_locations;
+  int                                           data_servers_len;
+  struct list_head                              data_servers; /* list of data servers to the client */
+  struct list_head                              hash_val; /* list of client data maps */
+};
+
+#endif   /* STATESERVER_H */
diff -urpN linux-2.4.18-patched/include/linux/nfsd/xdr4.h linux-2.4.18-patched-ssds-getfh/include/linux/nfsd/xdr4.h
--- linux-2.4.18-patched/include/linux/nfsd/xdr4.h	2003-11-04 16:15:09.000000000 -0500
+++ linux-2.4.18-patched-ssds-getfh/include/linux/nfsd/xdr4.h	2004-01-12 18:40:38.000000000 -0500
@@ -103,6 +103,7 @@ struct nfsd4_create {
 struct nfsd4_getattr {
 	u32		ga_bmval[2];        /* request */
 	struct svc_fh	*ga_fhp;            /* response */
+        struct nfsd4_file_locations* ga_file_locations;
 };
 
 struct nfsd4_link {
diff -urpN linux-2.4.18-patched/include/linux/nfs.h linux-2.4.18-patched-ssds-getfh/include/linux/nfs.h
--- linux-2.4.18-patched/include/linux/nfs.h	2004-04-14 22:44:40.796001000 -0400
+++ linux-2.4.18-patched-ssds-getfh/include/linux/nfs.h	2004-01-12 18:40:38.000000000 -0500
@@ -113,7 +113,6 @@
 	NFSERR_CB_PATH_DOWN = 10048,   /*       v4 */
 	NFSERR_REPLAY_ME = 10049,	/*       v4 */
 	NFS4ERR_FILE_LOCATIONS	= 10050,
-	NFS4ERR_OPEN_REDIRECT	= 10051,
 };
 
 /* NFSv2 file types - beware, these are not the same in NFSv3 */
