Integrate the Linux cache into the read calls. This allows the layout driver to utilize the Linux read cache (read gather) algorithm. --- linux-2.6.14-pnfs-current-dhildebz/fs/nfs/pnfs.c | 69 ++++++++++++++++++++ linux-2.6.14-pnfs-current-dhildebz/fs/nfs/pnfs.h | 2 linux-2.6.14-pnfs-current-dhildebz/fs/nfs/read.c | 76 +++++++++++++---------- 3 files changed, 117 insertions(+), 30 deletions(-) diff -puN fs/nfs/pnfs.c~client-readcache fs/nfs/pnfs.c --- linux-2.6.14-pnfs-current/fs/nfs/pnfs.c~client-readcache 2006-01-12 13:21:38.895683000 -0500 +++ linux-2.6.14-pnfs-current-dhildebz/fs/nfs/pnfs.c 2006-01-12 13:21:38.925683000 -0500 @@ -522,6 +522,75 @@ pnfs_writepages(struct nfs_write_data* w * If no I/O device driver exists, or one does match the returned * fstype, then call regular NFS processing. */ +int +pnfs_readpages(struct nfs_read_data *rdata) +{ + struct nfs_readargs *args = &rdata->args; + struct inode *inode = rdata->inode; + int numpages, status = -EIO, pgcount=0, temp; + struct nfs_server* nfss = NFS_SERVER(inode); + struct nfs_inode* nfsi = NFS_I(inode); + + dprintk("%s: Reading ino:%lu %u@%llu\n", __FUNCTION__, inode->i_ino, args->count, args->offset); + + /* Step 1: Retrieve and set layout if not allready cached */ + if ((status = virtual_update_layout(inode, + args->context, + args->count, + args->offset, + FMODE_WRITE))) + { + goto out; + } + /* find out the number of pages + * TODO: Is this necessary? Does the layout driver need the # of pages? + */ + pgcount = args->pgbase + args->count; + temp = pgcount % PAGE_CACHE_SIZE; + numpages = pgcount / PAGE_CACHE_SIZE; + if (temp != 0) + { + numpages++; + } + dprintk("%s: Using %d pages\n",__FUNCTION__, numpages); + /* Step 2: Execute the read with the layout driver + */ + dprintk("%s: Calling layout driver read\n",__FUNCTION__); + if (nfss->pnfs_curr_ld->ld_io_ops && nfss->pnfs_curr_ld->ld_io_ops->read_pagelist) + { + status = nfss->pnfs_curr_ld->ld_io_ops->read_pagelist(nfsi->current_layout, + inode, + args->pages, + args->pgbase, + numpages, + (loff_t)args->offset, + args->count, + (void*)rdata); + } + else + { + status = -EIO; + goto out; + } + + /* Step 3: Finish reading the page list */ + dprintk("%s: Calling writeback_done\n",__FUNCTION__); + /* TODO: NFS is async and so can't free the data structure yet. + * Should this be a policy decision? + */ + if (!IS_SYNC(inode) && nfss->pnfs_curr_ld->id != LAYOUT_NFSV4_FILES) + rdata->complete(rdata, status); + + out: + dprintk("%s: End Status %d\n",__FUNCTION__, status); + return status; +} + +/* + * Call the appropriate parallel I/O subsystem read function. + * If no I/O device driver exists, or one does match the returned + * fstype, then call regular NFS processing. + */ ssize_t pnfs_file_read(struct file* filp, char __user *buf, size_t count, loff_t* pos) { diff -puN fs/nfs/read.c~client-readcache fs/nfs/read.c --- linux-2.6.14-pnfs-current/fs/nfs/read.c~client-readcache 2006-01-12 13:21:38.905683000 -0500 +++ linux-2.6.14-pnfs-current-dhildebz/fs/nfs/read.c 2006-01-12 13:22:43.282819000 -0500 @@ -31,6 +31,8 @@ #include +#include "pnfs.h" + #define NFSDBG_FACILITY NFSDBG_PAGECACHE static int nfs_pagein_one(struct list_head *, struct inode *); @@ -120,7 +122,14 @@ static int nfs_readpage_sync(struct nfs_ rdata->args.count); lock_kernel(); - result = NFS_PROTO(inode)->read(rdata); + if (!use_pnfs_io(inode, count)) + { + result = NFS_PROTO(inode)->read(rdata); + } + else + { + result = pnfs_readpages(rdata); + } unlock_kernel(); /* @@ -194,9 +203,24 @@ static void nfs_readpage_release(struct } /* + * Start an async read operation + */ +static void nfs_execute_read(struct nfs_read_data *data) +{ + struct rpc_clnt *clnt = NFS_CLIENT(data->inode); + sigset_t oldset; + + rpc_clnt_sigmask(clnt, &oldset); + lock_kernel(); + rpc_execute(&data->task); + unlock_kernel(); + rpc_clnt_sigunmask(clnt, &oldset); +} + +/* * Set up the NFS read request struct */ -static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, +static void nfs_read_call(struct nfs_page *req, struct nfs_read_data *data, unsigned int count, unsigned int offset) { struct inode *inode; @@ -217,19 +241,29 @@ static void nfs_read_rpcsetup(struct nfs data->res.eof = 0; nfs_fattr_init(&data->fattr); - NFS_PROTO(inode)->read_setup(data); + /* Only create an rpc request if utilizing NFSv4 I/O */ + if (!use_pnfs_io(inode, count)) + { + NFS_PROTO(inode)->read_setup(data); + data->task.tk_cookie = (unsigned long)inode; + data->task.tk_calldata = data; + /* Release requests */ + /* This is only called for RPC, not pNFS */ + data->task.tk_release = nfs_readdata_release; - data->task.tk_cookie = (unsigned long)inode; - data->task.tk_calldata = data; - /* Release requests */ - data->task.tk_release = nfs_readdata_release; - - dprintk("NFS: %4d initiated read call (req %s/%Ld, %u bytes @ offset %Lu)\n", + dprintk("NFS: %4d initiated read call (req %s/%Ld, %u bytes @ offset %Lu)\n", data->task.tk_pid, inode->i_sb->s_id, (long long)NFS_FILEID(inode), count, (unsigned long long)data->args.offset); + nfs_execute_read(data); + } + else + { + dprintk("%s Utilizing pNFS I/O\n",__FUNCTION__); + pnfs_readpages(data); + } } static void @@ -246,21 +280,6 @@ nfs_async_read_error(struct list_head *h } /* - * Start an async read operation - */ -static void nfs_execute_read(struct nfs_read_data *data) -{ - struct rpc_clnt *clnt = NFS_CLIENT(data->inode); - sigset_t oldset; - - rpc_clnt_sigmask(clnt, &oldset); - lock_kernel(); - rpc_execute(&data->task); - unlock_kernel(); - rpc_clnt_sigunmask(clnt, &oldset); -} - -/* * Generate multiple requests to fill a single page. * * We optimize to reduce the number of read operations on the wire. If we @@ -310,14 +329,13 @@ static int nfs_pagein_multi(struct list_ data->complete = nfs_readpage_result_partial; if (nbytes > rsize) { - nfs_read_rpcsetup(req, data, rsize, offset); + nfs_read_call(req, data, rsize, offset); offset += rsize; nbytes -= rsize; } else { - nfs_read_rpcsetup(req, data, nbytes, offset); + nfs_read_call(req, data, nbytes, offset); nbytes = 0; } - nfs_execute_read(data); } while (nbytes != 0); return 0; @@ -361,9 +379,7 @@ static int nfs_pagein_one(struct list_he req = nfs_list_entry(data->pages.next); data->complete = nfs_readpage_result_full; - nfs_read_rpcsetup(req, data, count, 0); - - nfs_execute_read(data); + nfs_read_call(req, data, count, 0); return 0; out_bad: nfs_async_read_error(head); diff -puN fs/nfs/pnfs.h~client-readcache fs/nfs/pnfs.h --- linux-2.6.14-pnfs-current/fs/nfs/pnfs.h~client-readcache 2006-01-12 13:22:19.965192000 -0500 +++ linux-2.6.14-pnfs-current-dhildebz/fs/nfs/pnfs.h 2006-01-12 13:22:30.464649000 -0500 @@ -19,4 +19,6 @@ ssize_t pnfs_file_read(struct file* filp int use_pnfs_io(struct inode *inode,unsigned int count); int pnfs_writepages(struct nfs_write_data *wdata); void pnfs_writeback_done(struct nfs_write_data *data, int status); +int pnfs_readpages(struct nfs_read_data *rdata); + #endif /* FS_NFS_PNFS_H */ _