diff -urpN linux-2.6.1-patched/fs/nfs/inode.c linux-2.6.1-client/fs/nfs/inode.c --- linux-2.6.1-patched/fs/nfs/inode.c 2004-02-06 16:15:00.628256000 -0500 +++ linux-2.6.1-client/fs/nfs/inode.c 2004-02-24 10:51:17.560256000 -0500 @@ -107,6 +107,8 @@ struct rpc_program nfs_program = { .pipe_dir_name = "/nfs", }; +struct list_head ds_conn_pool[DS_POOL_HASH_SIZE]; /* rpc connections to data servers */ + static inline unsigned long nfs_fattr_to_ino_t(struct nfs_fattr *fattr) { @@ -759,7 +761,10 @@ nfs_fhget(struct super_block *sb, struct inode->i_mtime = fattr->mtime; inode->i_ctime = fattr->ctime; if (fattr->valid & NFS_ATTR_FATTR_V4) + { + dprintk("Setting change attr to %Ld\n",fattr->change_attr); nfsi->change_attr = fattr->change_attr; + } inode->i_size = nfs_size_to_loff_t(fattr->size); inode->i_nlink = fattr->nlink; inode->i_uid = fattr->uid; @@ -1291,6 +1296,7 @@ static int nfs_update_inode(struct inode * lookup validation will know that the inode is bad. * (But we fall through to invalidate the caches.) */ + dprintk("__nfs_refresh_inode: nfs_invaliate_inode\n"); nfs_invalidate_inode(inode); out_err: return -EIO; @@ -1828,6 +1834,7 @@ static struct inode *nfs_alloc_inode(str return NULL; nfsi->flags = 0; nfsi->mm_cred = NULL; + nfsi->file_locations = NULL; #ifdef CONFIG_NFS_V4_ACL nfsi->acl = NFS4_ACL_NOT_CACHED; nfsi->default_acl = NFS4_ACL_NOT_CACHED; @@ -1877,12 +1884,38 @@ void nfs_destroy_inodecache(void) printk(KERN_INFO "nfs_inode_cache: not all structures were freed\n"); } +/* Shutdown connection to data servers in connection pool + */ +static void +nfs4_shutdown_data_server_conns(void) +{ + struct list_head *pos, *next; + struct nfs4_data_server *local = NULL; + int i; + dprintk("nfs4_shutdown_data_server_conns: Begin\n"); + + for (i=0; i < DS_POOL_HASH_SIZE;i++) + { + list_for_each_safe(pos, next, &ds_conn_pool[i]) + { + local = list_entry(pos, struct nfs4_data_server,ds_ip_num); + if (local->ds_data_client != NULL) + { + dprintk("nfs4_shutdown_data_server_conns: About to shutdown data server\n"); + rpc_shutdown_client(local->ds_data_client); + dprintk("nfs4_shutdown_data_server_conns: Finished shutdown data server connection\n"); + } + } + } + dprintk("nfs4_shutdown_data_server_conns: End\n"); +} + /* * Initialize NFS */ static int __init init_nfs_fs(void) { - int err; + int err,i; err = nfs_init_nfspagecache(); if (err) @@ -1900,6 +1933,10 @@ static int __init init_nfs_fs(void) if (err) goto out1; + /* Initialize the data server connection pool */ + for (i = 0; i < DS_POOL_HASH_SIZE; i++) + INIT_LIST_HEAD(&(ds_conn_pool[i])); + #ifdef CONFIG_PROC_FS rpc_proc_register(&nfs_rpcstat); #endif @@ -1928,6 +1965,7 @@ static void __exit exit_nfs_fs(void) nfs_destroy_readpagecache(); nfs_destroy_inodecache(); nfs_destroy_nfspagecache(); + nfs4_shutdown_data_server_conns(); #ifdef CONFIG_PROC_FS rpc_proc_unregister("nfs"); #endif Binary files linux-2.6.1-patched/fs/nfs/.inode.c.swp and linux-2.6.1-client/fs/nfs/.inode.c.swp differ diff -urpN linux-2.6.1-patched/fs/nfs/nfs4proc.c linux-2.6.1-client/fs/nfs/nfs4proc.c --- linux-2.6.1-patched/fs/nfs/nfs4proc.c 2004-02-06 16:15:00.684257000 -0500 +++ linux-2.6.1-client/fs/nfs/nfs4proc.c 2004-03-09 18:43:04.356256000 -0500 @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -56,8 +57,31 @@ static int nfs4_async_handle_error(struct rpc_task *, struct nfs_server *); extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); extern struct rpc_procinfo nfs4_procedures[]; +extern struct rpc_program nfs_program; + extern nfs4_stateid zero_stateid; +extern struct list_head ds_conn_pool[]; + +/* search for dataserver in ds_conn_pool */ +static struct rpc_clnt* +find_dataserver_client(unsigned int hashval, int ip) +{ + struct list_head *pos, *next; + struct nfs4_data_server *local = NULL; + dprintk("find_dataserver_client: Begin\n"); + list_for_each_safe(pos, next, &ds_conn_pool[hashval]) + { + local = list_entry(pos, struct nfs4_data_server,ds_ip_num); + dprintk("find_dataserver_client: Current entry %d\n",local->ds_ip); + if (local->ds_ip != ip) + continue; + dprintk("find_dataserver_client: Found Client End\n"); + return local->ds_data_client; + } + dprintk("find_dataserver_client: Returning Null End\n"); + return NULL; +} /* * This is our standard bitmap for GETATTR requests. @@ -202,10 +226,224 @@ nfs4_open_reclaim(struct nfs4_state_owne nfs_refresh_inode(inode, &fattr); return status; } +/* Selects a server to read/write from. If a file location has been + * returned to the client from the server then it reads the data + * from a returned data server. The current algorithm for choosing + * from a list of data servers is Round Robin. If the file_locations + * list is empty, then it reads from the server in the super_block + * (the server that was mounted) + */ +static struct rpc_clnt* +get_data_server(struct inode* inode) +{ + struct nfs_inode* nfsi = NFS_I(inode); + struct nfs4_file_locations* fileLocList = nfsi->file_locations; + u32 last_server,index; + dprintk("get_data_server: Begin\n"); + + if (fileLocList != NULL && fileLocList->locationslen > 0) + { +/* + last_server = fileLocList->last_location; + index = last_server + 1; + index = index % fileLocList->locationslen; + fileLocList->last_location = index; + dprintk("get_data_server:Returning index %d server %s\n",index,fileLocList->locations[index]->data_client->cl_server); + dprintk("get_data_server: End\n"); + return fileLocList->locations[index]->data_client; +*/ + + return fileLocList->locations[0]->data_client; + } + else + { + dprintk("get_data_server: Returning metaserver\n"); + dprintk("get_data_server: End\n"); + return NFS_CLIENT(inode); + } +} + +/* free memory for the file_locations structures created in do_open decode function */ +void +nfs4_free_file_locations(struct nfs4_file_locations* file_locations) +{ + int locationslen=0,i=0; + dprintk("nfs4_free_file_locations: Begin\n"); + if (file_locations != NULL && file_locations->locationslen != 0) + { + dprintk("nfs4_free_file_locations Freeing Memory %d\n",file_locations->locationslen); + locationslen = file_locations->locationslen; + for (i=0; i < locationslen;i++) + { + kfree(file_locations->locations[i]->server); + kfree(file_locations->locations[i]); + } + kfree(file_locations->locations); + kfree(file_locations); + } + else + { + kfree(file_locations); + } + dprintk("nfs4_free_file_locations: End\n"); +} + +/* + This method sets the current set of read/write servers for this + client to access in the inode. The close method should clear the list of + fs_locations in the inode. The close method might not be best as + it seems that close is not always the last command called on a file. + Need to look into this more.... +*/ +static struct rpc_clnt* +nfs4_create_data_server_conn(struct nfs_server *sb, char* server) +{ + rpc_authflavor_t authflavour; + struct rpc_xprt *xprt = NULL; + struct rpc_clnt *clnt = NULL; + static struct rpc_timeout timeparms; + int proto; + struct sockaddr_in server_addr; + u32 ipbinary; + u32 version; + unsigned int cl_softrtry = 1;/* soft timeouts */ + unsigned int cl_intr = 1;/* interruptible */ + unsigned int cl_chatty = 1;/* be verbose */ + dprintk("nfs4_create_data_server_conn: Begin\n"); + + /* Assume the hostname is a ip address */ + ipbinary = in_aton(server); + if (sb->addr.sin_addr.s_addr == ipbinary) + { + /* The data server is the state server. + * Return the client in the sb and return + */ + dprintk("nfs4_create_data_server_conn: State server %s equals data server. Returning rpc client in superblock\n",sb->hostname); + clnt = sb->client; + goto out; + } + + /* store data about original client to create a copy */ + proto = sb->client->cl_xprt->prot; + memcpy(&timeparms,&sb->client->cl_xprt->timeout,sizeof(struct rpc_timeout)); + authflavour = RPC_AUTH_UNIX; + version = sb->rpc_ops->version; + cl_intr = sb->client->cl_intr; + cl_softrtry = sb->client->cl_softrtry; + cl_chatty = sb->client->cl_chatty; + + server_addr.sin_family = AF_INET; + memcpy(&server_addr.sin_addr.s_addr,&ipbinary ,4); + server_addr.sin_port = htons(NFS_PORT); + + /* Now create transport and client */ + dprintk("nfs4_create_data_server_conn: About to try and create proto to server %s\n",server); + xprt = xprt_create_proto(proto,&server_addr, &timeparms); + if (xprt == NULL) { + printk(KERN_WARNING "NFS: cannot create RPC transport.\n"); + goto out_fail; + } + + dprintk("nfs4_create_data_server_conn: About to try and create rpc client\n"); + dprintk("nfs4_create_data_server_conn: flav: %d ver: %d name: %s\n",authflavour,version,nfs_program.name); + clnt = rpc_create_client(xprt,server , &nfs_program,version, authflavour); + + if (clnt == NULL) { + printk(KERN_WARNING "NFS: cannot create RPC client.\n"); + xprt_destroy(xprt); + goto out_fail; + } + + clnt->cl_intr = cl_intr; + clnt->cl_softrtry = cl_softrtry; + clnt->cl_chatty = cl_chatty; + +out: + dprintk("nfs4_create_data_server_conn: End\n"); + return clnt; + +out_fail: + return NULL; +} + +/* + This method sets the current set of read/write servers for this + client to access. + The close method should clear the list of fs_locations on destruction + of the inode. +*/ +static int +nfs4_refresh_file_locations(struct inode* inode, struct nfs4_file_locations* floc) +{ + struct rpc_clnt* clnt = NULL; + int i,ll; + struct nfs4_file_location* loc = NULL; + u32 ip; + unsigned int ip_hash; + struct nfs4_data_server* ds = NULL; + dprintk("nfs4_refresh_file_locations: Begin\n"); + + /* this means we do not need to set the file location */ + if (inode == NULL || floc == NULL) + return 0; /* no action needed */ + + if (NFS_I(inode)->file_locations != NULL) + { + nfs4_free_file_locations(NFS_I(inode)->file_locations); + } + NFS_I(inode)->file_locations = floc; + + ll = floc->locationslen; + /* Create a connection to the data server if one does not allready exist */ + if (ll <= 0) + goto no_exist; + for (i=0;i < ll;i++) + { + loc = floc->locations[i]; + + /* Search current data server pool for an existing connection */ + ip = in_aton(loc->server); + ip_hash = dataserver_hashval(ip); + dprintk("nfs4_refresh_file_locations: server: %s ipnum %d ip_hash %d\n",loc->server,ip,ip_hash); + if ((clnt = find_dataserver_client(ip_hash, ip))) + { + dprintk("nfs4_refresh_file_locations: Updating data client from data server pool at index %d\n",i); + loc->data_client = clnt; + } + else + { + dprintk("nfs4_refresh_file_locations: Updating data client index %d\n",i); + if (!(clnt = nfs4_create_data_server_conn(NFS_SERVER(inode),loc->server))) + goto cleanup_err; + loc->data_client = clnt; + ds = kmalloc(sizeof(struct nfs4_data_server),GFP_KERNEL); + if (!ds) + goto cleanup_client_err; + ds->ds_ip = ip; + ds->ds_data_client = clnt; + list_add_tail(&ds->ds_ip_num, &ds_conn_pool[ip_hash]); + } + } + dprintk("nfs4_refresh_file_locations: End\n"); + return 0; +cleanup_client_err: + rpc_shutdown_client(clnt); +cleanup_err: + nfs4_free_file_locations(floc); + return 1; /* fail */ +no_exist: + printk("nfs4_refresh_file_locations: No File Locations Exist!!"); + return 1;/* fail */ +} + /* * Returns an nfs4_state + an referenced inode */ +/* Modified getattr part of compound to ask for the file_locations data. A + new connection is then created to this server (should this be done now or + on the read/write command? and the data is set in the inode. +*/ struct nfs4_state * nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *sattr, struct rpc_cred *cred) { @@ -220,6 +458,7 @@ nfs4_do_open(struct inode *dir, struct q }; struct nfs_fattr f_attr = { .valid = 0, + .file_locations = (struct nfs4_file_locations*)kmalloc(sizeof(struct nfs4_file_locations),GFP_KERNEL), }; struct nfs_openargs o_arg = { .fh = NFS_FH(dir), @@ -241,7 +480,7 @@ nfs4_do_open(struct inode *dir, struct q .rpc_resp = &o_res, .rpc_cred = cred, }; - + dprintk("%s: Start\n",__FUNCTION__); retry: status = -ENOMEM; if (!(sp = nfs4_get_state_owner(NFS_SERVER(dir), cred))) { @@ -261,10 +500,19 @@ retry: o_arg.id = sp->so_id; o_arg.clientid = NFS_SERVER(dir)->nfs4_state->cl_clientid, + /* Initialize file locations data to know whether + * we receceived the attribute + */ + f_attr.file_locations->locationslen = 0; + + dprintk("nfs4_do_open: call sync Begin\n"); status = rpc_call_sync(server->client, &msg, 0); nfs4_increment_seqid(status, sp); if (status) + { + nfs4_free_file_locations(f_attr.file_locations); goto out_up; + } process_cinfo(&d_cinfo, &d_attr); nfs_refresh_inode(dir, &d_attr); @@ -276,6 +524,16 @@ retry: if (!state) goto out_up; + /* This means the server does not support this attribute */ + if (f_attr.file_locations->locationslen == 0) + { + kfree(f_attr.file_locations); + } + /* Reset the new Read Write server + */ + else if ((status = nfs4_refresh_file_locations(inode,f_attr.file_locations))) + goto out_up; + if(o_res.rflags & NFS4_OPEN_RESULT_CONFIRM) { struct nfs_open_confirmargs oc_arg = { .fh = &o_res.fh, @@ -325,6 +583,7 @@ out_up: goto retry; BUG_ON(status < -1000 || status > 0); out: + dprintk("%s: End\n",__FUNCTION__); return ERR_PTR(status); } @@ -392,11 +651,16 @@ nfs4_do_close(struct inode *inode, struc .rpc_argp = &arg, .rpc_resp = &res, }; + struct nfs_inode* nfsi = NFS_I(inode); + struct nfs4_file_locations* fileLocList = nfsi->file_locations; + memcpy(&arg.stateid, &state->stateid, sizeof(arg.stateid)); /* Serialization for the sequence id */ arg.seqid = sp->so_seqid, status = rpc_call_sync(NFS_SERVER(inode)->client, &msg, 0); + nfs4_free_file_locations(fileLocList); + nfsi->file_locations = NULL; /* hmm. we are done with the inode, and in the process of freeing * the state_owner. we keep this around to process errors @@ -558,9 +822,7 @@ nfs4_proc_getattr(struct inode *inode, s .rpc_argp = NFS_FH(inode), .rpc_resp = &res, }; - fattr->valid = 0; - return rpc_call_sync(NFS_CLIENT(inode), &msg, 0); } @@ -954,6 +1216,7 @@ nfs4_proc_read(struct nfs_read_data *rda }; unsigned long timestamp = jiffies; int status; + struct rpc_clnt* data_server; dprintk("NFS call read %d @ %Ld\n", rdata->args.count, (long long) rdata->args.offset); @@ -961,7 +1224,7 @@ nfs4_proc_read(struct nfs_read_data *rda /* * Try first to use O_RDONLY, then O_RDWR stateid. */ - if (filp) { +if (filp) { struct nfs4_state *state; state = (struct nfs4_state *)filp->private_data; nfs4_copy_stateid(&rdata->args.stateid, state, rdata->lockowner); @@ -972,7 +1235,8 @@ nfs4_proc_read(struct nfs_read_data *rda } fattr->valid = 0; - status = rpc_call_sync(server->client, &msg, flags); + data_server = get_data_server(inode); + status = rpc_call_sync(data_server, &msg, flags); if (!status) renew_lease(server, timestamp); dprintk("NFS reply read: %d\n", status); @@ -985,13 +1249,13 @@ nfs4_proc_write(struct nfs_write_data *w int rpcflags = wdata->flags; struct inode *inode = wdata->inode; struct nfs_fattr *fattr = wdata->res.fattr; - struct nfs_server *server = NFS_SERVER(inode); struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE], .rpc_argp = &wdata->args, .rpc_resp = &wdata->res, }; int status; + struct rpc_clnt* data_server; dprintk("NFS call write %d @ %Ld\n", wdata->args.count, (long long) wdata->args.offset); @@ -1010,7 +1274,12 @@ nfs4_proc_write(struct nfs_write_data *w } fattr->valid = 0; - status = rpc_call_sync(server->client, &msg, rpcflags); + /* This function is the initial point for all write requests. + * If a file location has been returned to the client from the server, + * then it writes the data to the returned data server + */ + data_server = get_data_server(inode); + status = rpc_call_sync(data_server, &msg, rpcflags); dprintk("NFS reply write: %d\n", status); return status; } @@ -1462,15 +1731,21 @@ nfs4_read_done(struct rpc_task *task) { struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata; struct inode *inode = data->inode; + dprintk("%s: Begin\n",__FUNCTION__); if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { task->tk_action = nfs4_restart_read; return; } + /* DH-TODO: Disable updating piggybacked ack since read commands + * no longer being sent to state server + * Need to handle non-file_loc scenario if (task->tk_status > 0) renew_lease(NFS_SERVER(inode), data->timestamp); + */ /* Call back common NFS readpage processing */ nfs_readpage_result(task); + dprintk("%s: End\n",__FUNCTION__); } static void @@ -1486,7 +1761,8 @@ nfs4_proc_read_setup(struct nfs_read_dat struct inode *inode = data->inode; struct nfs_page *req = nfs_list_entry(data->pages.next); int flags; - + struct rpc_clnt* data_server; + data->args.fh = NFS_FH(inode); data->args.offset = req_offset(req); data->args.pgbase = req->wb_pgbase; @@ -1506,9 +1782,11 @@ nfs4_proc_read_setup(struct nfs_read_dat /* N.B. Do we need to test? Never called for swapfile inode */ flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); - /* Finalize the task. */ - rpc_init_task(task, NFS_CLIENT(inode), nfs4_read_done, flags); + /* Determine which server to send request to */ + data_server = get_data_server(inode); + rpc_init_task(task, data_server, nfs4_read_done, flags); task->tk_calldata = data; + /* Release requests */ task->tk_release = nfs_readdata_release; @@ -1534,17 +1812,24 @@ nfs4_write_done(struct rpc_task *task) { struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata; struct inode *inode = data->inode; - + dprintk("%s: Begin\n",__FUNCTION__); if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { task->tk_action = nfs4_restart_write; return; } + /* DH-TODO: Disable updating piggybacked ack since read commands + * no longer being sent to state server + * Need to handle non-file_loc scenario if (task->tk_status >= 0) renew_lease(NFS_SERVER(inode), data->timestamp); + */ + /* Call back common NFS writeback processing */ nfs_writeback_done(task); + dprintk("%s: End\n",__FUNCTION__); } + static void nfs4_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how) { @@ -1559,7 +1844,8 @@ nfs4_proc_write_setup(struct nfs_write_d struct nfs_page *req = nfs_list_entry(data->pages.next); int stable; int flags; - + struct rpc_clnt* data_server; + if (how & FLUSH_STABLE) { if (!NFS_I(inode)->ncommit) stable = NFS_FILE_SYNC; @@ -1588,8 +1874,13 @@ nfs4_proc_write_setup(struct nfs_write_d /* Set the initial flags for the task. */ flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; - /* Finalize the task. */ - rpc_init_task(task, NFS_CLIENT(inode), nfs4_write_done, flags); + /* This function is the initial point for all write requests. + * If a file location has been returned to the client from the server, + * then it writes the data to the returned data server + */ + /* Determine which server to send request to */ + data_server = get_data_server(inode); + rpc_init_task(task, data_server, nfs4_write_done, flags); task->tk_calldata = data; /* Release requests */ task->tk_release = nfs_writedata_release; @@ -1623,7 +1914,9 @@ nfs4_proc_commit_setup(struct nfs_write_ }; struct inode *inode = data->inode; int flags; - + struct nfs_inode* nfsi = NFS_I(inode); + struct nfs4_file_locations* fileLocList = nfsi->file_locations; + data->args.fh = NFS_FH(data->inode); data->args.offset = start; data->args.count = len; @@ -1635,7 +1928,16 @@ nfs4_proc_commit_setup(struct nfs_write_ flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; /* Finalize the task. */ - rpc_init_task(task, NFS_CLIENT(inode), nfs4_commit_done, flags); + if (fileLocList!= NULL && fileLocList->locationslen > 0) + { + dprintk("nfs4_proc_commit_setup: Comitting to server %s\n",fileLocList->locations[0]->data_client->cl_server); + rpc_init_task(task, fileLocList->locations[0]->data_client, nfs4_commit_done, flags); + } + else + { + dprintk("nfs4_proc_commit_setup: Committing to metaserver\n"); + rpc_init_task(task, NFS_CLIENT(inode), nfs4_commit_done, flags); + } task->tk_calldata = data; /* Release requests */ task->tk_release = nfs_commit_release; @@ -2135,9 +2437,8 @@ nfs4_proc_setlk(struct nfs4_state *state lsp = nfs4_find_lock_state(state, request->fl_owner); if (lsp == NULL) { struct nfs4_state_owner *owner = state->owner; - struct nfs_open_to_lock otl = { - .lock_owner.clientid = server->nfs4_state->cl_clientid, - }; + struct nfs_open_to_lock otl; + otl.lock_owner.clientid = server->nfs4_state->cl_clientid, status = -ENOMEM; lsp = nfs4_alloc_lock_state(state, request->fl_owner); if (!lsp) diff -urpN linux-2.6.1-patched/fs/nfs/nfs4xdr.c linux-2.6.1-client/fs/nfs/nfs4xdr.c --- linux-2.6.1-patched/fs/nfs/nfs4xdr.c 2004-02-17 15:41:38.579260000 -0500 +++ linux-2.6.1-client/fs/nfs/nfs4xdr.c 2004-03-12 17:33:37.740256000 -0500 @@ -724,6 +724,13 @@ encode_getfattr(struct xdr_stream *xdr) nfs4_fattr_bitmap[1]); } +static inline int +encode_open_getfattr(struct xdr_stream *xdr) +{ + return encode_getattr_two(xdr, nfs4_fattr_bitmap[0], + nfs4_fattr_bitmap[1] | FATTR4_WORD1_FILE_LOCATIONS); +} + /* * Request the change attribute in order to check attribute+cache consistency */ @@ -1601,7 +1608,7 @@ nfs4_xdr_enc_open(struct rpc_rqst *req, status = encode_open(&xdr, args); if (status) goto out; - status = encode_getfattr(&xdr); + status = encode_open_getfattr(&xdr); if (status) goto out; status = encode_getfh(&xdr); @@ -2392,7 +2399,7 @@ decode_getfattr(struct xdr_stream *xdr, unsigned int type; int fmode = 0; int status; - + struct nfs4_file_locations *file_locations = NULL; status = decode_op_hdr(xdr, OP_GETATTR); if (status) return status; @@ -2410,7 +2417,7 @@ decode_getfattr(struct xdr_stream *xdr, READ32(attrlen); if ((bmval0 & ~nfs4_fattr_bitmap[0]) || - (bmval1 & ~nfs4_fattr_bitmap[1])) { + (bmval1 & ~(nfs4_fattr_bitmap[1] | FATTR4_WORD1_FILE_LOCATIONS))) { dprintk("read_attrs: server returned bad attributes!\n"); goto xdr_error; } @@ -2554,9 +2561,56 @@ decode_getfattr(struct xdr_stream *xdr, READTIME(nfp->mtime); dprintk("read_attrs: mtime=%ld\n", (long)nfp->mtime.tv_sec); } + if (bmval1 & FATTR4_WORD1_FILE_LOCATIONS) { + int i = 0; + uint32_t file_locations_serverlen=0; + file_locations = nfp->file_locations; + dprintk("Starting decoding file_locations\n"); + + /* For now there is always 1 data server */ + READ_BUF(4); + len += 4; + READ32(file_locations->locationslen); + dprintk("read_attrs: file_locations locationslen= %d\n",file_locations->locationslen); + if (file_locations->locationslen <= 0) + { + printk("read_attrs: Server does either not support or have any available data locations.\n"); + goto xdr_error; + } + file_locations->last_location = 0; /* init value */ + file_locations->locations = (struct nfs4_file_location**)kmalloc(file_locations->locationslen*sizeof(struct nfs4_file_location*),GFP_KERNEL); + if (!file_locations->locations) + goto xdr_error; + for (i=0; i < file_locations->locationslen;i++) + { + file_locations->locations[i] = (struct nfs4_file_location*)kmalloc(sizeof(struct nfs4_file_location),GFP_KERNEL); + if (!file_locations->locations[i]) + goto xdr_error; + + READ_BUF(4); + len += 4; + READ32(file_locations->locations[i]->serverlen); + file_locations_serverlen = file_locations->locations[i]->serverlen; + dprintk("read_attrs file_location server name length: %d\n",file_locations_serverlen); + if (file_locations_serverlen > XDR_MAX_NETOBJ) { + printk("read_attrs: serverlen too long!\n"); + return 1; + } + READ_BUF(file_locations_serverlen); + len += (XDR_QUADLEN(file_locations_serverlen) << 2); + file_locations->locations[i]->server = (char*)kmalloc((file_locations_serverlen + 1) * sizeof(char),GFP_KERNEL); + if (!file_locations->locations[i]->server) + goto xdr_error; + + strncpy(file_locations->locations[i]->server, (char*)p,file_locations_serverlen); + file_locations->locations[i]->server[file_locations_serverlen] = '\0'; + dprintk("read_attrs file_locations server= %s\n",file_locations->locations[i]->server); + + file_locations->locations[i]->data_client = NULL; /* initialize */ + } + } if (len != attrlen) goto xdr_error; - DECODE_TAIL; } diff -urpN linux-2.6.1-patched/include/linux/nfs4.h linux-2.6.1-client/include/linux/nfs4.h --- linux-2.6.1-patched/include/linux/nfs4.h 2004-03-05 14:54:33.043261000 -0500 +++ linux-2.6.1-client/include/linux/nfs4.h 2004-03-05 14:56:00.929256000 -0500 @@ -326,6 +326,7 @@ enum lock_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.6.1-patched/include/linux/nfs_fs.h linux-2.6.1-client/include/linux/nfs_fs.h --- linux-2.6.1-patched/include/linux/nfs_fs.h 2004-02-06 16:15:00.905257000 -0500 +++ linux-2.6.1-client/include/linux/nfs_fs.h 2004-02-24 10:51:17.589259000 -0500 @@ -172,8 +172,21 @@ struct nfs_inode { struct posix_acl *default_acl; #endif /* CONFIG_NFS_V4_ACL */ struct inode vfs_inode; + struct nfs4_file_locations* file_locations; }; +struct nfs4_data_server { + struct list_head ds_ip_num; /* hash by ip addr num */ + u32 ds_ip; + struct rpc_clnt* ds_data_client; +}; + +#define DS_POOL_HASH_BITS 4 +#define DS_POOL_HASH_SIZE (1 << DS_POOL_HASH_BITS) +#define DS_POOL_HASH_MASK (DS_POOL_HASH_SIZE - 1) + +#define dataserver_hashval(id) ((id) & DS_POOL_HASH_MASK) + /* * Legal inode flag values */ diff -urpN linux-2.6.1-patched/include/linux/nfs_xdr.h linux-2.6.1-client/include/linux/nfs_xdr.h --- linux-2.6.1-patched/include/linux/nfs_xdr.h 2004-02-06 16:15:00.973256000 -0500 +++ linux-2.6.1-client/include/linux/nfs_xdr.h 2004-02-24 10:51:17.593257000 -0500 @@ -3,6 +3,19 @@ #include +struct nfs4_file_location { + u32 serverlen; + char* server; + struct rpc_clnt* data_client; +}; + +struct nfs4_file_locations { + u32 algorithm_id; /* Indicate load balancing algorithm for this file */ + u32 last_location; /* The last read/write request used the last_location index in locations */ + u32 locationslen; + struct nfs4_file_location** locations; +}; + struct nfs_fattr { unsigned short valid; /* which fields are valid */ __u64 pre_size; /* pre_op_attr.size */ @@ -41,6 +54,7 @@ struct nfs_fattr { unsigned long timestamp; #ifdef CONFIG_NFS_V4 struct nfs4_acl *acl; /* NFSv4 ACL */ + struct nfs4_file_locations * file_locations; /* response */ #endif /* CONFIG_NFS_V4 */ };