
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 <asm/system.h>
 
+#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 */
_
