[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