
DESC
pnfs-hooks
EDESC

---

 linux-2.6.14-pnfs-current-dhildebz/fs/nfs/inode.c           |   58 ++++++++
 linux-2.6.14-pnfs-current-dhildebz/fs/nfs/nfs4proc.c        |   32 +++-
 linux-2.6.14-pnfs-current-dhildebz/fs/nfs/pagelist.c        |   22 ++-
 linux-2.6.14-pnfs-current-dhildebz/fs/nfs/pnfs.c            |   85 +++++++++++-
 linux-2.6.14-pnfs-current-dhildebz/fs/nfs/pnfs.h            |    3 
 linux-2.6.14-pnfs-current-dhildebz/fs/nfs/read.c            |   24 ++-
 linux-2.6.14-pnfs-current-dhildebz/fs/nfs/write.c           |   38 +++--
 linux-2.6.14-pnfs-current-dhildebz/include/linux/nfs_page.h |    2 
 linux-2.6.14-pnfs-current-dhildebz/include/linux/nfs_xdr.h  |    2 
 9 files changed, 241 insertions(+), 25 deletions(-)

diff -puN fs/nfs/pnfs.c~client-pnfs-hooks fs/nfs/pnfs.c
--- linux-2.6.14-pnfs-current/fs/nfs/pnfs.c~client-pnfs-hooks	2006-01-13 17:39:50.266533000 -0500
+++ linux-2.6.14-pnfs-current-dhildebz/fs/nfs/pnfs.c	2006-01-18 19:58:05.151914000 -0500
@@ -46,6 +46,7 @@
 #include <linux/nfs_fs.h>
 #include <linux/nfs_mount.h>
 #include <linux/nfs_page.h>
+#include <linux/nfs4_pnfs.h>
 
 #include "nfs4_fs.h"
 #include "pnfs.h"
@@ -60,6 +61,8 @@ extern int nfs_fsync(struct file *file, 
 extern int nfs4_pnfs_getdevicelist(struct nfs_server *server, struct pnfs_devicelist* devlist);
 extern int nfs4_pnfs_getdeviceinfo(struct nfs_server *server, u32 dev_id, struct pnfs_device *res);
 
+struct pnfs_client_operations pnfs_ops;
+
 /* Locking:
  *
  * pnfs_spinlock:
@@ -72,7 +75,6 @@ static spinlock_t	pnfs_spinlock = SPIN_L
  */
 static struct list_head	pnfs_modules_tbl;
 static int is_pnfs_initialized = 0;
-static struct pnfs_client_operations pnfs_ops;
 
 /*
  * struct pnfs_module - One per pNFS device module.
@@ -887,5 +889,86 @@ pnfs_getdeviceinfo(struct super_block *s
 	return rc;
 }
 
+/* Callback operations for layout drivers.
+ */
+struct pnfs_client_operations pnfs_ops = {
+        .nfs_fsync = nfs_fsync,
+	.nfs_getdevicelist = pnfs_getdevicelist,
+	.nfs_getdeviceinfo = pnfs_getdeviceinfo,
+};
+
+unsigned int
+pnfs_getboundary(struct inode* inode)
+{
+	struct pnfs_layout_type *laytype;
+	struct layoutdriver_policy_operations *policy_ops;
+	struct pnfs_layoutdriver_type *ld;
+
+	laytype = NFS_I(inode)->current_layout;
+	ld = NFS_SERVER(inode)->pnfs_curr_ld;
+	if (!laytype || !ld)
+		return 0;
+	policy_ops = ld->ld_policy_ops;
+
+	/* The default is to not gather across stripes */
+	if (policy_ops && policy_ops->gather_across_stripes)
+	{
+		if (policy_ops->gather_across_stripes(laytype->mountid))
+		{
+			return 0;
+		}
+	}
+	if (policy_ops && policy_ops->get_stripesize)
+	{
+		return policy_ops->get_stripesize(laytype, inode);
+	}
+
+	return 0; /* Gather up to wsize/rsize */
+}
+
+/* Return number of pages the layout driver can handle
+ * in a single request.
+ * blocksize must be a multiple of the page cache size.
+ */
+unsigned int
+pnfs_getpages(struct inode* inode, int iswrite)
+{
+	struct pnfs_mount_type *mounttype;
+	struct layoutdriver_policy_operations *policy_ops;
+	struct pnfs_layoutdriver_type *ld;
+	ssize_t bsize = 0;
+	unsigned int npages;
+	struct nfs_server *server = NFS_SERVER(inode);
+
+	mounttype = server->pnfs_mountid;
+	ld = server->pnfs_curr_ld;
+	if (!mounttype || !ld)
+		goto outnfs;
+	policy_ops = ld->ld_policy_ops;
+
+	if (policy_ops && policy_ops->get_blocksize)
+	{
+		bsize = policy_ops->get_blocksize(mounttype);
+	}
+
+	if (bsize == 0)
+	{
+		goto outnfs;
+	}
+
+	/* Convert the block size into a number of pages */
+	npages = (bsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+
+out:
+	return npages;
+outnfs:
+	/* Return the number of NFS write or read pages */
+	if (iswrite)
+		npages = server->wpages;
+	else
+		npages = server->rpages;
+	goto out;
+}
+
 EXPORT_SYMBOL(pnfs_unregister_layoutdriver);
 EXPORT_SYMBOL(pnfs_register_layoutdriver);
diff -puN fs/nfs/inode.c~client-pnfs-hooks fs/nfs/inode.c
--- linux-2.6.14-pnfs-current/fs/nfs/inode.c~client-pnfs-hooks	2006-01-13 17:39:50.277533000 -0500
+++ linux-2.6.14-pnfs-current-dhildebz/fs/nfs/inode.c	2006-01-13 17:39:50.346511000 -0500
@@ -35,6 +35,7 @@
 #include <linux/mount.h>
 #include <linux/nfs_idmap.h>
 #include <linux/vfs.h>
+#include <linux/nfs4_pnfs.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -125,6 +126,29 @@ struct rpc_program		nfsacl_program = {
 };
 #endif  /* CONFIG_NFS_V3_ACL */
 
+struct rpc_clnt*
+create_nfs_rpcclient(struct rpc_xprt *xprt,
+		     char* server_name,
+		     u32 version,
+		     rpc_authflavor_t authflavor,
+		     int *err)
+{
+	struct rpc_clnt* clnt = rpc_create_client(xprt,
+						  server_name,
+						  &nfs_program,
+						  version,
+						  authflavor);
+	if (IS_ERR(clnt)) {
+		*err = PTR_ERR(clnt);
+		printk("%s: error rpc_create_client\n", __FUNCTION__);
+		return NULL;
+	}
+	clnt->cl_intr = 1;
+	clnt->cl_softrtry = 1;
+	clnt->cl_chatty = 1;
+	return clnt;
+}
+
 static inline unsigned long
 nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
 {
@@ -146,6 +170,7 @@ nfs_write_inode(struct inode *inode, int
 static void
 nfs_delete_inode(struct inode * inode)
 {
+	struct pnfs_layout_type* laytype;
 	dprintk("NFS: delete_inode(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino);
 
 	truncate_inode_pages(&inode->i_data, 0);
@@ -158,6 +183,16 @@ nfs_delete_inode(struct inode * inode)
 		printk(KERN_ERR "nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
 	}
 
+#if defined(CONFIG_NFS_V4)
+	/* TODO: I think we should be returning the layout at this point */
+	laytype = NFS_I(inode)->current_layout;
+	if (laytype && NFS_SERVER(inode)->pnfs_curr_ld->ld_io_ops->free_layout) {
+		dprintk ("%s: removing layout\n", __FUNCTION__);
+		NFS_SERVER(inode)->pnfs_curr_ld->ld_io_ops->free_layout(laytype, inode);
+		NFS_I(inode)->current_layout = NULL;
+	}
+#endif
+
 	clear_inode(inode);
 }
 
@@ -1446,8 +1481,12 @@ static int nfs_update_inode(struct inode
 	nfsi->last_updated = jiffies;
 
 	/* Are we racing with known updates of the metadata on the server? */
+#if 1 //??? date change on DS makes it rewrite all data
+	data_unstable = 1;
+#else
 	data_unstable = ! (nfs_verify_change_attribute(inode, verifier) ||
 		(nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE));
+#endif
 
 	/* Check if our cached file size is stale */
  	new_isize = nfs_size_to_loff_t(fattr->size);
@@ -1738,11 +1777,23 @@ static struct super_operations nfs4_sops
 static void nfs4_clear_inode(struct inode *inode)
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
+	struct pnfs_layout_type *laytype;
 
 	/* If we are holding a delegation, return it! */
 	nfs_inode_return_delegation(inode);
 	/* First call standard NFS clear_inode() code */
 	nfs_clear_inode(inode);
+
+#if defined(CONFIG_NFS_V4)
+	laytype = NFS_I(inode)->current_layout;
+	if (laytype && NFS_SERVER(inode)->pnfs_curr_ld->ld_io_ops->free_layout) {
+		/* TODO: I think we should be returning the layout at this point */
+		dprintk ("%s: removing layout\n", __FUNCTION__);
+		NFS_SERVER(inode)->pnfs_curr_ld->ld_io_ops->free_layout(laytype, inode);
+		NFS_I(inode)->current_layout = NULL;
+	}
+#endif
+
 	/* Now clear out any remaining state */
 	while (!list_empty(&nfsi->open_states)) {
 		struct nfs4_state *state;
@@ -2060,6 +2111,7 @@ static struct file_system_type nfs4_fs_t
 		init_rwsem(&nfsi->rwsem); \
 		nfsi->pnfs_dirty = 0; \
 		nfsi->nfs_dirty = 0; \
+		nfsi->current_layout = NULL; \
 	} while(0)
 #define register_nfs4fs() register_filesystem(&nfs4_fs_type)
 #define unregister_nfs4fs() unregister_filesystem(&nfs4_fs_type)
@@ -2097,6 +2149,9 @@ static struct inode *nfs_alloc_inode(str
 #endif
 #ifdef CONFIG_NFS_V4
 	nfsi->nfs4_acl = NULL;
+	nfsi->current_layout = NULL;
+	nfsi->pnfs_dirty = 0;
+	nfsi->nfs_dirty = 0;
 #endif /* CONFIG_NFS_V4 */
 	return &nfsi->vfs_inode;
 }
@@ -2217,6 +2272,9 @@ static void __exit exit_nfs_fs(void)
 	unregister_nfs4fs();
 }
 
+/* Required for the pNFS file layout driver */
+EXPORT_SYMBOL(create_nfs_rpcclient);
+
 /* Not quite true; I just maintain it */
 MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
 MODULE_LICENSE("GPL");
diff -puN fs/nfs/nfs4proc.c~client-pnfs-hooks fs/nfs/nfs4proc.c
--- linux-2.6.14-pnfs-current/fs/nfs/nfs4proc.c~client-pnfs-hooks	2006-01-13 17:39:50.290533000 -0500
+++ linux-2.6.14-pnfs-current-dhildebz/fs/nfs/nfs4proc.c	2006-01-13 17:39:50.360497000 -0500
@@ -1479,7 +1479,11 @@ static int _nfs4_proc_read(struct nfs_re
 			(long long) rdata->args.offset);
 
 	nfs_fattr_init(fattr);
-	status = rpc_call_sync(server->client, &msg, flags);
+	if (rdata->pnfs_client)
+		status = rpc_call_sync(rdata->pnfs_client, &msg, flags);
+	else
+		status = rpc_call_sync(server->client, &msg, flags);
+
 	if (!status)
 		renew_lease(server, timestamp);
 	dprintk("NFS reply read: %d\n", status);
@@ -1610,7 +1614,10 @@ static int _nfs4_proc_write(struct nfs_w
 			(long long) wdata->args.offset);
 
 	nfs_fattr_init(fattr);
-	status = rpc_call_sync(server->client, &msg, rpcflags);
+	if (wdata->pnfs_client)
+		status = rpc_call_sync(wdata->pnfs_client, &msg, rpcflags);
+	else
+		status = rpc_call_sync(server->client, &msg, rpcflags);
 	dprintk("NFS reply write: %d\n", status);
 	return status;
 }
@@ -2269,6 +2276,10 @@ nfs4_read_done(struct rpc_task *task)
 		rpc_restart_call(task);
 		return;
 	}
+
+	/* Reset rpc client.  Is this necessary? */
+	data->pnfs_client = NULL;
+
 	if (task->tk_status > 0)
 		renew_lease(NFS_SERVER(inode), data->timestamp);
 	/* Call back common NFS readpage processing */
@@ -2294,7 +2305,11 @@ nfs4_proc_read_setup(struct nfs_read_dat
 	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);
+	/* Use the pNFS chosen rpc client if it exists */
+	if (data->pnfs_client)
+		rpc_init_task(task, data->pnfs_client, nfs4_read_done, flags);
+	else
+		rpc_init_task(task, NFS_CLIENT(inode), nfs4_read_done, flags);
 	rpc_call_setup(task, &msg, 0);
 }
 
@@ -2308,6 +2323,7 @@ nfs4_write_done(struct rpc_task *task)
 		rpc_restart_call(task);
 		return;
 	}
+
 	if (task->tk_status >= 0) {
 		renew_lease(NFS_SERVER(inode), data->timestamp);
 		nfs_post_op_update_inode(inode, data->res.fattr);
@@ -2348,7 +2364,11 @@ nfs4_proc_write_setup(struct nfs_write_d
 	flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
 
 	/* Finalize the task. */
-	rpc_init_task(task, NFS_CLIENT(inode), nfs4_write_done, flags);
+	/* Use the pNFS chosen rpc client if it exists */
+	if (data->pnfs_client)
+		rpc_init_task(task, data->pnfs_client, nfs4_write_done, flags);
+	else
+		rpc_init_task(task, NFS_CLIENT(inode), nfs4_write_done, flags);
 	rpc_call_setup(task, &msg, 0);
 }
 
@@ -2362,6 +2382,10 @@ nfs4_commit_done(struct rpc_task *task)
 		rpc_restart_call(task);
 		return;
 	}
+
+	/* Reset rpc client.  Is this necessary? */
+	data->pnfs_client = NULL;
+
 	if (task->tk_status >= 0)
 		nfs_post_op_update_inode(inode, data->res.fattr);
 	/* Call back common NFS writeback processing */
diff -puN fs/nfs/pagelist.c~client-pnfs-hooks fs/nfs/pagelist.c
--- linux-2.6.14-pnfs-current/fs/nfs/pagelist.c~client-pnfs-hooks	2006-01-13 17:39:50.296533000 -0500
+++ linux-2.6.14-pnfs-current-dhildebz/fs/nfs/pagelist.c	2006-01-13 17:39:50.408449000 -0500
@@ -19,6 +19,10 @@
 #include <linux/nfs_fs.h>
 #include <linux/nfs_mount.h>
 
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? a : b)
+#endif
+
 #define NFS_PARANOIA 1
 
 static kmem_cache_t *nfs_page_cachep;
@@ -221,18 +225,32 @@ out:
  * @head: source list
  * @dst: destination list
  * @nmax: maximum number of requests to coalesce
+ * @boundary: byte boundary multiple that must not be crossed by this request
  *
  * Moves a maximum of 'nmax' elements from one list to another.
  * The elements are checked to ensure that they form a contiguous set
  * of pages, and that the RPC credentials are the same.
  */
 int
-nfs_coalesce_requests(struct list_head *head, struct list_head *dst,
-		      unsigned int nmax)
+nfs_coalesce_requests(struct list_head *head,
+		      struct list_head *dst,
+		      unsigned int nmax,
+		      unsigned int boundary)
 {
 	struct nfs_page		*req = NULL;
 	unsigned int		npages = 0;
 
+	if (boundary && !list_empty(head)) {
+		/* Boundary can be thought of as a stripe unit, we don't want requests
+		 * that span multiple stripes; boundary is given in bytes and is a
+		 * multiple of the PAGE_CACHE_SIZE.
+		 */
+		req = nfs_list_entry(head->next);
+		nmax = MIN(nmax, ((boundary - ((req->wb_index << PAGE_CACHE_SHIFT) %
+					       boundary)) >> PAGE_CACHE_SHIFT));
+		req = NULL;
+	}
+
 	while (!list_empty(head)) {
 		struct nfs_page	*prev = req;
 
diff -puN fs/nfs/read.c~client-pnfs-hooks fs/nfs/read.c
--- linux-2.6.14-pnfs-current/fs/nfs/read.c~client-pnfs-hooks	2006-01-13 17:39:50.303533000 -0500
+++ linux-2.6.14-pnfs-current-dhildebz/fs/nfs/read.c	2006-01-18 20:09:24.756831000 -0500
@@ -28,6 +28,7 @@
 #include <linux/nfs_fs.h>
 #include <linux/nfs_page.h>
 #include <linux/smp_lock.h>
+#include <linux/module.h>
 
 #include <asm/system.h>
 
@@ -205,9 +206,9 @@ static void nfs_readpage_release(struct 
 /*
  * Start an async read operation
  */
-static void nfs_execute_read(struct nfs_read_data *data)
+void nfs_execute_read(struct nfs_read_data *data)
 {
-	struct rpc_clnt *clnt = NFS_CLIENT(data->inode);
+	struct rpc_clnt *clnt = data->task.tk_client;
 	sigset_t oldset;
 
 	rpc_clnt_sigmask(clnt, &oldset);
@@ -387,15 +388,20 @@ out_bad:
 }
 
 static int
-nfs_pagein_list(struct list_head *head, int rpages)
+nfs_pagein_list(struct list_head *head, int rpages, struct inode *inode)
 {
 	LIST_HEAD(one_request);
 	struct nfs_page		*req;
 	int			error = 0;
 	unsigned int		pages = 0;
+	unsigned int            boundary = 0;
+
+#if defined(CONFIG_NFS_V4)
+	boundary = pnfs_getboundary(inode);
+#endif
 
 	while (!list_empty(head)) {
-		pages += nfs_coalesce_requests(head, &one_request, rpages);
+		pages += nfs_coalesce_requests(head, &one_request, rpages, boundary);
 		req = nfs_list_entry(one_request.next);
 		error = nfs_pagein_one(&one_request, req->wb_context->dentry->d_inode);
 		if (error < 0)
@@ -600,7 +606,12 @@ int nfs_readpages(struct file *filp, str
 				filp->private_data);
 	ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc);
 	if (!list_empty(&head)) {
-		int err = nfs_pagein_list(&head, server->rpages);
+#if defined(CONFIG_NFS_V4)
+		unsigned int rpages = pnfs_getpages(inode, 0);
+#else
+		unsigned int rpages = server->rpages;
+#endif
+		int err = nfs_pagein_list(&head, rpages, inode);
 		if (!ret)
 			ret = err;
 	}
@@ -633,3 +644,6 @@ void nfs_destroy_readpagecache(void)
 	if (kmem_cache_destroy(nfs_rdata_cachep))
 		printk(KERN_INFO "nfs_read_data: not all structures were freed\n");
 }
+
+EXPORT_SYMBOL(nfs_execute_read);
+EXPORT_SYMBOL(nfs_readdata_release);
diff -puN fs/nfs/write.c~client-pnfs-hooks fs/nfs/write.c
--- linux-2.6.14-pnfs-current/fs/nfs/write.c~client-pnfs-hooks	2006-01-13 17:39:50.311534000 -0500
+++ linux-2.6.14-pnfs-current-dhildebz/fs/nfs/write.c	2006-01-18 20:05:12.649483000 -0500
@@ -61,6 +61,7 @@
 #include <linux/nfs_page.h>
 #include <asm/uaccess.h>
 #include <linux/smp_lock.h>
+#include <linux/module.h>
 
 #include "delegation.h"
 #include "pnfs.h"
@@ -85,6 +86,7 @@ static int nfs_wait_on_requests(struct i
 static int nfs_flush_inode(struct inode *inode, unsigned long idx_start,
 			   unsigned int npages, int how);
 extern int pnfs_commit(struct inode* inode, struct list_head *head, int sync, struct nfs_write_data *data);
+extern unsigned int pnfs_getboundary(struct inode* inode);
 
 static kmem_cache_t *nfs_wdata_cachep;
 mempool_t *nfs_wdata_mempool;
@@ -842,7 +844,7 @@ out:
 	nfs_clear_page_writeback(req);
 }
 
-static inline int flush_task_priority(int how)
+inline int nfs_flush_task_priority(int how)
 {
 	switch (how & (FLUSH_HIGHPRI|FLUSH_LOWPRI)) {
 		case FLUSH_HIGHPRI:
@@ -853,9 +855,9 @@ static inline int flush_task_priority(in
 	return RPC_PRIORITY_NORMAL;
 }
 
-static void nfs_execute_write(struct nfs_write_data *data)
+void nfs_execute_write(struct nfs_write_data *data)
 {
-	struct rpc_clnt *clnt = NFS_CLIENT(data->inode);
+	struct rpc_clnt *clnt = data->task.tk_client;
 	sigset_t oldset;
 	rpc_clnt_sigmask(clnt, &oldset);
 	lock_kernel();
@@ -897,7 +899,7 @@ void nfs_write_call(struct nfs_page *req
 	if (!use_pnfs_io(inode, count))
 	{
 		NFS_PROTO(inode)->write_setup(data, how);
-		data->task.tk_priority = flush_task_priority(how);
+		data->task.tk_priority = nfs_flush_task_priority(how);
 		data->task.tk_cookie = (unsigned long)inode;
 		data->task.tk_calldata = data;
 		/* Release requests */
@@ -1041,15 +1043,19 @@ static int nfs_flush_one(struct list_hea
 }
 
 static int
-nfs_flush_list(struct list_head *head, int wpages, int how)
+nfs_flush_list(struct list_head *head, int wpages, int how, struct inode *inode)
 {
 	LIST_HEAD(one_request);
 	struct nfs_page		*req;
 	int			error = 0;
 	unsigned int		pages = 0;
+	unsigned int            boundary = 0;
 
+#if defined(CONFIG_NFS_V4)
+	boundary = pnfs_getboundary(inode);
+#endif
 	while (!list_empty(head)) {
-		pages += nfs_coalesce_requests(head, &one_request, wpages);
+		pages += nfs_coalesce_requests(head, &one_request, wpages, boundary);
 		req = nfs_list_entry(one_request.next);
 		error = nfs_flush_one(&one_request, req->wb_context->dentry->d_inode, how);
 		if (error < 0)
@@ -1239,7 +1245,7 @@ static void nfs_commit_release(struct rp
 /*
  * Set up the argument/result storage required for the RPC call.
  */
-static void nfs_commit_rpcsetup(struct nfs_write_data *data,
+void nfs_commit_rpcsetup(struct nfs_write_data *data,
 				int how)
 {
 	data->args.fh     = NFS_FH(data->inode);
@@ -1253,7 +1259,7 @@ static void nfs_commit_rpcsetup(struct n
 	
 	NFS_PROTO(data->inode)->commit_setup(data, how);
 
-	data->task.tk_priority = flush_task_priority(how);
+	data->task.tk_priority = nfs_flush_task_priority(how);
 	data->task.tk_cookie = (unsigned long)data->inode;
 	data->task.tk_calldata = data;
 	/* Release requests */
@@ -1294,7 +1300,7 @@ static void pnfs_layoutcommit_rpcsetup(s
 
 	NFS_PROTO(data->inode)->pnfs_layoutcommit_setup(data, how);
 
-	data->task.tk_priority = flush_task_priority(how);
+	data->task.tk_priority = nfs_flush_task_priority(how);
 	data->task.tk_cookie = (unsigned long)data->inode;
 	data->task.tk_calldata = data;
 	/* Release requests */
@@ -1435,13 +1441,17 @@ static int nfs_flush_inode(struct inode 
 	spin_unlock(&nfsi->req_lock);
 	if (res) {
 		struct nfs_server *server = NFS_SERVER(inode);
-
+#if defined(CONFIG_NFS_V4)
+		unsigned int wpages = pnfs_getpages(inode, 1);
+#else
+		unsigned int wpages = server->wpages;
+#endif
 		/* For single writes, FLUSH_STABLE is more efficient */
-		if (res == nfsi->npages && nfsi->npages <= server->wpages) {
+		if (res == nfsi->npages && nfsi->npages <= wpages) {
 			if (res > 1 || nfs_list_entry(head.next)->wb_bytes <= server->wsize)
 				how |= FLUSH_STABLE;
 		}
-		error = nfs_flush_list(&head, server->wpages, how);
+		error = nfs_flush_list(&head, wpages, how, inode);
 	}
 	if (error < 0)
 		return error;
@@ -1525,3 +1535,7 @@ void nfs_destroy_writepagecache(void)
 		printk(KERN_INFO "nfs_write_data: not all structures were freed\n");
 }
 
+EXPORT_SYMBOL(nfs_execute_write);
+EXPORT_SYMBOL(nfs_writedata_release);
+EXPORT_SYMBOL(nfs_flush_task_priority);
+EXPORT_SYMBOL(nfs_commit_rpcsetup);
diff -puN include/linux/nfs_page.h~client-pnfs-hooks include/linux/nfs_page.h
--- linux-2.6.14-pnfs-current/include/linux/nfs_page.h~client-pnfs-hooks	2006-01-13 17:39:50.315533000 -0500
+++ linux-2.6.14-pnfs-current-dhildebz/include/linux/nfs_page.h	2006-01-13 17:39:50.428429000 -0500
@@ -66,7 +66,7 @@ extern  int nfs_scan_lock_dirty(struct n
 extern	int nfs_scan_list(struct list_head *, struct list_head *,
 			  unsigned long, unsigned int);
 extern	int nfs_coalesce_requests(struct list_head *, struct list_head *,
-				  unsigned int);
+				  unsigned int, unsigned int);
 extern  int nfs_wait_on_request(struct nfs_page *);
 extern	void nfs_unlock_request(struct nfs_page *req);
 extern  int nfs_set_page_writeback_locked(struct nfs_page *req);
diff -puN include/linux/nfs_xdr.h~client-pnfs-hooks include/linux/nfs_xdr.h
--- linux-2.6.14-pnfs-current/include/linux/nfs_xdr.h~client-pnfs-hooks	2006-01-13 17:39:50.321533000 -0500
+++ linux-2.6.14-pnfs-current-dhildebz/include/linux/nfs_xdr.h	2006-01-13 17:39:50.434423000 -0500
@@ -693,6 +693,7 @@ struct nfs_read_data {
 	struct nfs_readres  res;
 #ifdef CONFIG_NFS_V4
 	unsigned long		timestamp;	/* For lease renewal */
+	struct rpc_clnt         *pnfs_client;   /* Holds pNFS device across async calls */
 #endif
 	void (*complete) (struct nfs_read_data *, int);
 };
@@ -713,6 +714,7 @@ struct nfs_write_data {
 	struct pnfs_layoutcommit_res lc_res;
 #ifdef CONFIG_NFS_V4
 	unsigned long		timestamp;	/* For lease renewal */
+	struct rpc_clnt         *pnfs_client;   /* Holds pNFS device across async calls */
 #endif
 	void (*complete) (struct nfs_write_data *, int);
 	unsigned int            ispartial;
diff -puN fs/nfs/pnfs.h~client-pnfs-hooks fs/nfs/pnfs.h
--- linux-2.6.14-pnfs-current/fs/nfs/pnfs.h~client-pnfs-hooks	2006-01-13 17:39:50.326531000 -0500
+++ linux-2.6.14-pnfs-current-dhildebz/fs/nfs/pnfs.h	2006-01-18 20:05:56.513667000 -0500
@@ -21,4 +21,7 @@ int pnfs_writepages(struct nfs_write_dat
 void pnfs_writeback_done(struct nfs_write_data *data, int status);
 int pnfs_readpages(struct nfs_read_data *rdata);
 int pnfs_fsync(struct file *file, struct dentry *dentry, int datasync);
+unsigned int pnfs_getboundary(struct inode* inode);
+unsigned int pnfs_getpages(struct inode* inode, int iswrite);
+
 #endif /* FS_NFS_PNFS_H */
_
