[pnfs] [PATCH 25/29] pnfs: use boundary in coalese page cache request

Benny Halevy bhalevy at panasas.com
Fri Dec 28 03:46:10 EST 2007


From: Andy Adamson <andros at umich.edu>

Add a new layout policy operation to test two struct nfs_page requests for
coalescing.

Add test function and boundary int to the nfs_pageio_descriptor structure.

Signed-off-by: Andy Adamson<andros at umich.edu>
Signed-off-by: Benny Halevy <bhalevy at panasas.com>
---
 fs/nfs/nfs4filelayout.c   |   21 +++++++++++++++++++++
 fs/nfs/nfs4proc.c         |    1 -
 fs/nfs/pagelist.c         |    9 +++++++--
 fs/nfs/pnfs.c             |   36 ++++++++++++++++++++++++++++++++++--
 fs/nfs/pnfs.h             |    4 +++-
 fs/nfs/read.c             |    2 +-
 fs/nfs/write.c            |    5 +++++
 include/linux/nfs4_pnfs.h |    3 +++
 include/linux/nfs_page.h  |    4 ++++
 include/linux/nfs_xdr.h   |    1 -
 10 files changed, 78 insertions(+), 8 deletions(-)

diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c
index e493f3a..73ba031 100644
--- a/fs/nfs/nfs4filelayout.c
+++ b/fs/nfs/nfs4filelayout.c
@@ -626,6 +626,26 @@ filelayout_gather_across_stripes(struct pnfs_mount_type *mountid)
 	return 0;
 }
 
+/*
+ * filelayout_pg_test(). Called by nfs_can_coalesce_requests()
+ * return 1 :  prev and req on same stripe.
+ * return 0 :  pref and req on different stripe.
+ */
+int
+filelayout_pg_test(int boundary, struct nfs_page *prev, struct nfs_page *req)
+{
+	u32 p_stripe, r_stripe;
+
+	if (boundary == 0)
+		return 1;
+	p_stripe = prev->wb_index << PAGE_CACHE_SHIFT;
+	do_div(p_stripe, boundary);
+	r_stripe = req->wb_index << PAGE_CACHE_SHIFT;
+	do_div(r_stripe, boundary);
+
+	return (p_stripe == r_stripe);
+}
+
 /* Use the NFSv4 page cache
 */
 int
@@ -663,6 +683,7 @@ struct layoutdriver_io_operations filelayout_io_operations = {
 struct layoutdriver_policy_operations filelayout_policy_operations = {
 	.get_stripesize        = filelayout_get_stripesize,
 	.gather_across_stripes = filelayout_gather_across_stripes,
+	.pg_test               = filelayout_pg_test,
 	.use_pagecache         = filelayout_use_pagecache,
 	.layoutget_on_open     = filelayout_layoutget_on_open,
 	.get_read_threshold    = filelayout_get_io_threshold,
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 7b65623..ef958b4 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -5411,7 +5411,6 @@ const struct nfs_rpc_ops pnfs_v41_clientops = {
 	.wsize		= pnfs_wsize,
 	.rpages		= pnfs_rpages,
 	.wpages		= pnfs_wpages,
-	.boundary	= pnfs_getboundary,
 	.clear_acl_cache = nfs4_zap_acl_attr,
 	.pnfs_layoutget      = nfs4_proc_pnfs_layoutget,
 	.pnfs_layoutcommit_setup = nfs4_proc_pnfs_layoutcommit_setup,
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index 345bb9b..491cb10 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -251,7 +251,8 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
  * Return 'true' if this is the case, else return 'false'.
  */
 static int nfs_can_coalesce_requests(struct nfs_page *prev,
-				     struct nfs_page *req)
+				     struct nfs_page *req,
+				     struct nfs_pageio_descriptor *pgio)
 {
 	if (req->wb_context->cred != prev->wb_context->cred)
 		return 0;
@@ -265,6 +266,10 @@ static int nfs_can_coalesce_requests(struct nfs_page *prev,
 		return 0;
 	if (prev->wb_pgbase + prev->wb_bytes != PAGE_CACHE_SIZE)
 		return 0;
+#ifdef CONFIG_PNFS
+	if (pgio->pg_test && (pgio->pg_test(pgio->pg_boundary, prev, req) == 0))
+		return 0;
+#endif /* CONFIG_PNFS */
 	return 1;
 }
 
@@ -297,7 +302,7 @@ static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc,
 		if (newlen > desc->pg_bsize)
 			return 0;
 		prev = nfs_list_entry(desc->pg_list.prev);
-		if (!nfs_can_coalesce_requests(prev, req))
+		if (!nfs_can_coalesce_requests(prev, req, desc))
 			return 0;
 	} else
 		desc->pg_base = req->wb_pgbase;
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 50e075b..c15a805 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -640,15 +640,36 @@ check:
 		return 0;
 }
 
+void
+pnfs_set_pg_test(struct inode *inode, struct nfs_pageio_descriptor *pgio)
+{
+	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 (!pnfs_enabled_sb(NFS_SERVER(inode)) || !laytype)
+		return;
+	policy_ops = ld->ld_policy_ops;
+
+	if (policy_ops && policy_ops->pg_test) {
+		pgio->pg_test = policy_ops->pg_test;
+	} else {
+		pgio->pg_test = NULL;
+	}
+}
+
 /*
  * rsize is already set by caller to MDS rsize.
  */
 void
-pnfs_set_ds_size(struct inode *inode,
+pnfs_set_ds_rsize(struct inode *inode,
 		 struct nfs_open_context *ctx,
 		 struct list_head *pages,
 		 loff_t offset,
-		 size_t *rsize)
+		 size_t *rsize,
+		 struct nfs_pageio_descriptor *pgio)
 {
 	struct nfs_server *nfss = NFS_SERVER(inode);
 	struct page *page;
@@ -658,6 +679,9 @@ pnfs_set_ds_size(struct inode *inode,
 	dprintk("--> %s inode %p ctx %p pages %p offset %lu\n",
 		__func__, inode, ctx, pages, (unsigned long)offset);
 
+	pgio->pg_boundary = 0;
+	pgio->pg_test = 0;
+
 	if (!pnfs_enabled_sb(nfss))
 		return;
 
@@ -675,6 +699,14 @@ pnfs_set_ds_size(struct inode *inode,
 
 	if (status == 0 && count > 0 && !below_threshold(inode, count, 0))
 		*rsize = NFS_SERVER(inode)->ds_rsize;
+
+	/* boundary set => gather pages by stripe => need pg_test */
+	pgio->pg_boundary = pnfs_getboundary(inode);
+	if (pgio->pg_boundary)
+		pnfs_set_pg_test(inode, pgio);
+
+	dprintk("<-- %s pg_boundary %d, pg_test %p\n", __func__,
+			pgio->pg_boundary, pgio->pg_test);
 }
 
 
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
index aa17804..4309918 100644
--- a/fs/nfs/pnfs.h
+++ b/fs/nfs/pnfs.h
@@ -13,6 +13,8 @@
 #define FS_NFS_PNFS_H
 
 #ifdef CONFIG_PNFS
+#include <linux/nfs_page.h>
+
 int virtual_update_layout(struct inode *ino, struct nfs_open_context *ctx,
 	size_t count, loff_t pos, enum pnfs_iomode access_type);
 
@@ -52,7 +54,7 @@ int pnfs_wpages(struct inode *);
 void pnfs_readpage_result_norpc(struct rpc_task *task, void *calldata);
 void pnfs_writeback_done_norpc(struct rpc_task *, void *);
 void pnfs_commit_done_norpc(struct rpc_task *, void *);
-void pnfs_set_ds_size(struct inode *, struct nfs_open_context *, struct list_head *, loff_t, size_t *);
+void pnfs_set_ds_rsize(struct inode *, struct nfs_open_context *, struct list_head *, loff_t, size_t *, struct nfs_pageio_descriptor *);
 
 
 /*
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 177dc4d..be283b4 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -650,7 +650,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
 	} else
 		desc.ctx = get_nfs_open_context(nfs_file_open_context(filp));
 #ifdef CONFIG_PNFS
-	pnfs_set_ds_size(inode, desc.ctx, pages, filp->f_pos, &rsize);
+	pnfs_set_ds_rsize(inode, desc.ctx, pages, filp->f_pos, &rsize, &pgio);
 #endif /* CONFIG_PNFS */
 	if (rsize < PAGE_CACHE_SIZE)
 		nfs_pageio_init(&pgio, inode, nfs_pagein_multi, rsize, 0);
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 22cacde..31f2745 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -974,6 +974,11 @@ static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
 {
 	int wsize = NFS_SERVER(inode)->wsize;
 
+#ifdef CONFIG_PNFS
+	pgio->pg_boundary = 0;
+	pgio->pg_test = NULL;
+#endif /* CONFIG_PNFS */
+
 	if (wsize < PAGE_CACHE_SIZE)
 		nfs_pageio_init(pgio, inode, nfs_flush_multi, wsize, ioflags);
 	else
diff --git a/include/linux/nfs4_pnfs.h b/include/linux/nfs4_pnfs.h
index d760b91..529f522 100644
--- a/include/linux/nfs4_pnfs.h
+++ b/include/linux/nfs4_pnfs.h
@@ -87,6 +87,9 @@ struct layoutdriver_policy_operations {
 	/* Should the NFS req. gather algorithm cross stripe boundaries? */
 	int (*gather_across_stripes) (struct pnfs_mount_type *mountid);
 
+	/* test for nfs page cache coalescing */
+	int (*pg_test)(int, struct nfs_page *, struct nfs_page *);
+
 	/* Retreive the block size of the file system.  If gather_across_stripes == 1,
 	 * then the file system will gather requests into the block size.
 	 * TODO: Where will the layout driver get this info?  It is hard coded in PVFS2.
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h
index 681fda8..d957ab3 100644
--- a/include/linux/nfs_page.h
+++ b/include/linux/nfs_page.h
@@ -61,6 +61,10 @@ struct nfs_pageio_descriptor {
 	int			(*pg_doio)(struct inode *, struct list_head *, unsigned int, size_t, int);
 	int 			pg_ioflags;
 	int			pg_error;
+#ifdef CONFIG_PNFS
+	int			pg_boundary;
+	int			(*pg_test)(int, struct nfs_page *, struct nfs_page *);
+#endif /* CONFIG_PNFS */
 };
 
 #define NFS_WBACK_BUSY(req)	(test_bit(PG_BUSY,&(req)->wb_flags))
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index c40bf7e..320b8c0 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1169,7 +1169,6 @@ struct nfs_rpc_ops {
 	int	(*wsize) (struct inode *, unsigned int, struct nfs_write_data *);
 	int	(*rpages) (struct inode *);
 	int	(*wpages) (struct inode *);
-	u32	(*boundary) (struct inode *);
 	int	(*pnfs_layoutget)(struct nfs4_pnfs_layoutget *layout);
 	void	(*pnfs_layoutcommit_setup)(struct pnfs_layoutcommit_data *);
 	int	(*pnfs_layoutcommit)  (struct pnfs_layoutcommit_data *);
-- 
1.5.3.3



More information about the pNFS mailing list