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 #include +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(¤t_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, ¤t_fh, &op->u.create); break; case OP_GETATTR: - op->status = nfsd4_getattr(rqstp, ¤t_fh, &op->u.getattr); + op->status = nfsd4_getattr(rqstp, ¤t_fh, ¤t_stateid,&op->u.getattr); break; case OP_GETFH: op->status = nfsd4_getfh(¤t_fh, &op->u.getfh); @@ -699,6 +781,7 @@ nfsd4_proc_compound(struct svc_rqst *rqs break; case OP_OPEN: op->status = nfsd4_open(rqstp, ¤t_fh, &op->u.open); + memcpy(¤t_stateid,&op->u.open.op_stateid,sizeof(stateid_t)); break; case OP_OPEN_CONFIRM: op->status = nfsd4_open_confirm(rqstp, ¤t_fh, &op->u.open_confirm); @@ -778,8 +861,12 @@ out: kfree(tb->buf); kfree(tb); } - fh_put(¤t_fh); - fh_put(&save_fh); + if (!rqstp->is_fake_fh) + { + fh_put(¤t_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 #include +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 #include #include +#include #include + #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 */ @@ -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 #include #include +#include #include +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 + * + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* need RC_NOCACHE */ +#include + +#include +#include +#include + +#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 + * + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* need RC_NOCACHE */ +#include +#include + +#include +#include + + + +#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(¤t->sigmask_lock); + siginitsetinv(¤t->blocked, SHUTDOWN_SIGS); + recalc_sigpending(current); + spin_unlock_irq(¤t->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(¤t->sigmask_lock); + siginitsetinv(¤t->blocked, ALLOWED_SIGS); + recalc_sigpending(current); + spin_unlock_irq(¤t->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(¤t->pending.signal, signo) && + !sigismember(¤t->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 + * + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#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 +#include +#include +#include + +#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 */