2014-05-20 18:08:26

by Anna Schumaker

[permalink] [raw]
Subject: [RFC 00/12] PNFS Read and Write Cleanups

There is a lot of duplicate code in pnfs.c that can be cleaned up to
share more code. This patch set goes through each function one at a
time and merges read and write code together wherever possible. In the
end I'm passing around a few function pointers. Would it be better to
use a function pointer struct instead?

These patches still need a lot of testing and are not ready for merge
yet (hence the RFC). I just wanted to send out a preview of the changes
I've made so far.

Questions, comments and thoughts are appreciated!

Anna


Anna Schumaker (12):
nfs: Create a common pnfs_pageio_reset_mds() function
nfs: Create a common pnfs_generic_pg_init() function
nfs: Create a common pnfs_ld_handle_rw_error() function
nfs: Create a common pnfs_ld_rw_done()
nfs: Create a common pnfs_through_mds() function
nfs: merge pnfs_try_to_write_data() and pnfs_do_write()
nfs: merge pnfs_try_to_read_data() and pnfs_do_read()
nfs: create a common pnfs_do_rw() function
nfs: create a common pnfs_pgiohdr_free function
nfs: Split up generic_pg_pgios
nfs: pnfs can use nfs_generic_pgios_common() too!
nfs: Create a common pnfs_generic_rwpages() function

fs/nfs/blocklayout/blocklayout.c | 4 +-
fs/nfs/internal.h | 6 +-
fs/nfs/nfs4filelayout.c | 4 +-
fs/nfs/pagelist.c | 25 +++-
fs/nfs/pnfs.c | 297 ++++++++++++++-------------------------
fs/nfs/pnfs.h | 1 +
fs/nfs/read.c | 7 -
fs/nfs/write.c | 8 --
8 files changed, 138 insertions(+), 214 deletions(-)

--
1.9.2



2014-05-20 18:08:33

by Anna Schumaker

[permalink] [raw]
Subject: [RFC 09/12] nfs: create a common pnfs_pgiohdr_free function

This function is exactly the same for reads and writes.

Signed-off-by: Anna Schumaker <[email protected]>
---
fs/nfs/pnfs.c | 24 ++++++++----------------
1 file changed, 8 insertions(+), 16 deletions(-)

diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 69751d4..b6ebea8 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -1499,6 +1499,12 @@ pnfs_do_rw(struct nfs_pageio_descriptor *desc, struct nfs_pgio_header *hdr,
return ret;
}

+static void pnfs_pgiohdr_free(struct nfs_pgio_header *hdr)
+{
+ pnfs_put_lseg(hdr->lseg);
+ nfs_pgio_header_free(hdr);
+}
+
void
pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
struct nfs_page *req, u64 wb_size)
@@ -1541,13 +1547,6 @@ pnfs_do_write(struct nfs_pageio_descriptor *desc, struct nfs_pgio_header *hdr)
nfs_inc_stats(hdr->inode, NFSIOS_PNFS_WRITE);
}

-static void pnfs_writehdr_free(struct nfs_pgio_header *hdr)
-{
- pnfs_put_lseg(hdr->lseg);
- nfs_pgio_header_free(hdr);
-}
-EXPORT_SYMBOL_GPL(pnfs_writehdr_free);
-
int
pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc)
{
@@ -1561,7 +1560,7 @@ pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc)
desc->pg_lseg = NULL;
return -ENOMEM;
}
- nfs_pgheader_init(desc, hdr, pnfs_writehdr_free);
+ nfs_pgheader_init(desc, hdr, pnfs_pgiohdr_free);
hdr->lseg = pnfs_get_lseg(desc->pg_lseg);
ret = nfs_generic_pgio(desc, hdr);
if (ret != 0) {
@@ -1623,13 +1622,6 @@ pnfs_do_read(struct nfs_pageio_descriptor *desc, struct nfs_pgio_header *hdr)
nfs_inc_stats(hdr->inode, NFSIOS_PNFS_READ);
}

-static void pnfs_readhdr_free(struct nfs_pgio_header *hdr)
-{
- pnfs_put_lseg(hdr->lseg);
- nfs_pgio_header_free(hdr);
-}
-EXPORT_SYMBOL_GPL(pnfs_readhdr_free);
-
int
pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc)
{
@@ -1644,7 +1636,7 @@ pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc)
desc->pg_lseg = NULL;
return ret;
}
- nfs_pgheader_init(desc, hdr, pnfs_readhdr_free);
+ nfs_pgheader_init(desc, hdr, pnfs_pgiohdr_free);
hdr->lseg = pnfs_get_lseg(desc->pg_lseg);
ret = nfs_generic_pgio(desc, hdr);
if (ret != 0) {
--
1.9.2


2014-05-20 18:08:26

by Anna Schumaker

[permalink] [raw]
Subject: [RFC 02/12] nfs: Create a common pnfs_generic_pg_init() function

Most of this code can be shared. There are some differences with
calculating bsize, but that needs to be changed in the layout drivers
that call the read and write versions of this function.

Signed-off-by: Anna Schumaker <[email protected]>
---
fs/nfs/pnfs.c | 61 +++++++++++++++++++++++++++--------------------------------
1 file changed, 28 insertions(+), 33 deletions(-)

diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 8da7ff6..4d57003 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -1387,48 +1387,22 @@ void pnfs_pageio_reset_mds(struct nfs_pageio_descriptor *pgio)
}
EXPORT_SYMBOL_GPL(pnfs_pageio_reset_mds);

-void
-pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
-{
- u64 rd_size = req->wb_bytes;
-
- WARN_ON_ONCE(pgio->pg_lseg != NULL);
-
- if (pgio->pg_dreq == NULL)
- rd_size = i_size_read(pgio->pg_inode) - req_offset(req);
- else
- rd_size = nfs_dreq_bytes_left(pgio->pg_dreq);
-
- pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
- req->wb_context,
- req_offset(req),
- rd_size,
- IOMODE_READ,
- GFP_KERNEL);
- /* If no lseg, fall back to read through mds */
- if (pgio->pg_lseg == NULL)
- pnfs_pageio_reset_mds(pgio);
-
-}
-EXPORT_SYMBOL_GPL(pnfs_generic_pg_init_read);
-
-void
-pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
- struct nfs_page *req, u64 wb_size)
+static void pnfs_generic_pg_init(struct nfs_pageio_descriptor *pgio,
+ struct nfs_page *req, u64 bsize,
+ enum pnfs_iomode iomode, gfp_t gfp_flags)
{
WARN_ON_ONCE(pgio->pg_lseg != NULL);

pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
req->wb_context,
req_offset(req),
- wb_size,
- IOMODE_RW,
- GFP_NOFS);
- /* If no lseg, fall back to write through mds */
+ bsize,
+ iomode,
+ gfp_flags);
+ /* If no lseg, fall back to IO through mds */
if (pgio->pg_lseg == NULL)
pnfs_pageio_reset_mds(pgio);
}
-EXPORT_SYMBOL_GPL(pnfs_generic_pg_init_write);

/*
* Return 0 if @req cannot be coalesced into @pgio, otherwise return the number
@@ -1472,6 +1446,14 @@ pnfs_generic_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
}
EXPORT_SYMBOL_GPL(pnfs_generic_pg_test);

+void
+pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
+ struct nfs_page *req, u64 wb_size)
+{
+ pnfs_generic_pg_init(pgio, req, wb_size, IOMODE_RW, GFP_NOFS);
+}
+EXPORT_SYMBOL_GPL(pnfs_generic_pg_init_write);
+
int pnfs_write_done_resend_to_mds(struct nfs_pgio_header *hdr)
{
struct nfs_pageio_descriptor pgio;
@@ -1590,6 +1572,19 @@ pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc)
}
EXPORT_SYMBOL_GPL(pnfs_generic_pg_writepages);

+void
+pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
+{
+ u64 rd_size;
+ if (pgio->pg_dreq == NULL)
+ rd_size = i_size_read(pgio->pg_inode) - req_offset(req);
+ else
+ rd_size = nfs_dreq_bytes_left(pgio->pg_dreq);
+
+ pnfs_generic_pg_init(pgio, req, rd_size, IOMODE_READ, GFP_KERNEL);
+}
+EXPORT_SYMBOL_GPL(pnfs_generic_pg_init_read);
+
int pnfs_read_done_resend_to_mds(struct nfs_pgio_header *hdr)
{
struct nfs_pageio_descriptor pgio;
--
1.9.2


2014-05-20 18:08:29

by Anna Schumaker

[permalink] [raw]
Subject: [RFC 05/12] nfs: Create a common pnfs_through_mds() function

Signed-off-by: Anna Schumaker <[email protected]>
---
fs/nfs/pnfs.c | 40 ++++++++++++++--------------------------
1 file changed, 14 insertions(+), 26 deletions(-)

diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 5976b87..a0eee54 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -1469,6 +1469,18 @@ static void pnfs_ld_rw_done(struct nfs_pgio_header *hdr,
hdr->mds_ops->rpc_release(hdr);
}

+static void
+pnfs_through_mds(struct nfs_pageio_descriptor *desc,
+ struct nfs_pgio_header *hdr)
+{
+ if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) {
+ list_splice_tail_init(&hdr->pages, &desc->pg_list);
+ pnfs_pageio_reset_mds(desc);
+ desc->pg_recoalesce = 1;
+ }
+ nfs_generic_pgio_reset(hdr);
+}
+
void
pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
struct nfs_page *req, u64 wb_size)
@@ -1498,18 +1510,6 @@ void pnfs_ld_write_done(struct nfs_pgio_header *hdr)
}
EXPORT_SYMBOL_GPL(pnfs_ld_write_done);

-static void
-pnfs_write_through_mds(struct nfs_pageio_descriptor *desc,
- struct nfs_pgio_header *hdr)
-{
- if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) {
- list_splice_tail_init(&hdr->pages, &desc->pg_list);
- pnfs_pageio_reset_mds(desc);
- desc->pg_recoalesce = 1;
- }
- nfs_generic_pgio_reset(hdr);
-}
-
static enum pnfs_try_status
pnfs_try_to_write_data(struct nfs_pgio_header *hdr,
const struct rpc_call_ops *call_ops,
@@ -1542,7 +1542,7 @@ pnfs_do_write(struct nfs_pageio_descriptor *desc,
desc->pg_lseg = NULL;
trypnfs = pnfs_try_to_write_data(hdr, call_ops, lseg, how);
if (trypnfs == PNFS_NOT_ATTEMPTED)
- pnfs_write_through_mds(desc, hdr);
+ pnfs_through_mds(desc, hdr);
pnfs_put_lseg(lseg);
}

@@ -1612,18 +1612,6 @@ void pnfs_ld_read_done(struct nfs_pgio_header *hdr)
}
EXPORT_SYMBOL_GPL(pnfs_ld_read_done);

-static void
-pnfs_read_through_mds(struct nfs_pageio_descriptor *desc,
- struct nfs_pgio_header *hdr)
-{
- if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) {
- list_splice_tail_init(&hdr->pages, &desc->pg_list);
- pnfs_pageio_reset_mds(desc);
- desc->pg_recoalesce = 1;
- }
- nfs_generic_pgio_reset(hdr);
-}
-
/*
* Call the appropriate parallel I/O subsystem read function.
*/
@@ -1658,7 +1646,7 @@ pnfs_do_read(struct nfs_pageio_descriptor *desc, struct nfs_pgio_header *hdr)
desc->pg_lseg = NULL;
trypnfs = pnfs_try_to_read_data(hdr, call_ops, lseg);
if (trypnfs == PNFS_NOT_ATTEMPTED)
- pnfs_read_through_mds(desc, hdr);
+ pnfs_through_mds(desc, hdr);
pnfs_put_lseg(lseg);
}

--
1.9.2


2014-05-20 18:08:27

by Anna Schumaker

[permalink] [raw]
Subject: [RFC 04/12] nfs: Create a common pnfs_ld_rw_done()

The read and write paths run mostly the same code, so it makes sense to
combine them.

Signed-off-by: Anna Schumaker <[email protected]>
---
fs/nfs/pnfs.c | 26 ++++++++++++++------------
1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 4eaf74a..5976b87 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -1457,6 +1457,18 @@ static void pnfs_ld_handle_rw_error(struct nfs_pgio_header *hdr,
hdr->task.tk_status = resend_to_mds(hdr);
}

+static void pnfs_ld_rw_done(struct nfs_pgio_header *hdr,
+ void (*cb)(struct nfs_pgio_header *),
+ int (*resend_to_mds)(struct nfs_pgio_header *))
+{
+ if (!hdr->pnfs_error) {
+ cb(hdr);
+ hdr->mds_ops->rpc_call_done(&hdr->task, hdr);
+ } else
+ pnfs_ld_handle_rw_error(hdr, resend_to_mds);
+ hdr->mds_ops->rpc_release(hdr);
+}
+
void
pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
struct nfs_page *req, u64 wb_size)
@@ -1482,12 +1494,7 @@ EXPORT_SYMBOL_GPL(pnfs_write_done_resend_to_mds);
void pnfs_ld_write_done(struct nfs_pgio_header *hdr)
{
trace_nfs4_pnfs_write(hdr, hdr->pnfs_error);
- if (!hdr->pnfs_error) {
- pnfs_set_layoutcommit(hdr);
- hdr->mds_ops->rpc_call_done(&hdr->task, hdr);
- } else
- pnfs_ld_handle_rw_error(hdr, pnfs_write_done_resend_to_mds);
- hdr->mds_ops->rpc_release(hdr);
+ pnfs_ld_rw_done(hdr, pnfs_set_layoutcommit, pnfs_write_done_resend_to_mds);
}
EXPORT_SYMBOL_GPL(pnfs_ld_write_done);

@@ -1601,12 +1608,7 @@ EXPORT_SYMBOL_GPL(pnfs_read_done_resend_to_mds);
void pnfs_ld_read_done(struct nfs_pgio_header *hdr)
{
trace_nfs4_pnfs_read(hdr, hdr->pnfs_error);
- if (likely(!hdr->pnfs_error)) {
- __nfs4_read_done_cb(hdr);
- hdr->mds_ops->rpc_call_done(&hdr->task, hdr);
- } else
- pnfs_ld_handle_rw_error(hdr, pnfs_read_done_resend_to_mds);
- hdr->mds_ops->rpc_release(hdr);
+ pnfs_ld_rw_done(hdr, __nfs4_read_done_cb, pnfs_read_done_resend_to_mds);
}
EXPORT_SYMBOL_GPL(pnfs_ld_read_done);

--
1.9.2


2014-05-20 18:08:30

by Anna Schumaker

[permalink] [raw]
Subject: [RFC 06/12] nfs: merge pnfs_try_to_write_data() and pnfs_do_write()

This makes these functions look neater in preparation for combining with
their read equivalents.

Signed-off-by: Anna Schumaker <[email protected]>
---
fs/nfs/pnfs.c | 28 +++++++---------------------
1 file changed, 7 insertions(+), 21 deletions(-)

diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index a0eee54..355cd41 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -1511,38 +1511,24 @@ void pnfs_ld_write_done(struct nfs_pgio_header *hdr)
EXPORT_SYMBOL_GPL(pnfs_ld_write_done);

static enum pnfs_try_status
-pnfs_try_to_write_data(struct nfs_pgio_header *hdr,
- const struct rpc_call_ops *call_ops,
- struct pnfs_layout_segment *lseg,
- int how)
+pnfs_try_to_write_data(struct nfs_pgio_header *hdr, int how)
{
- struct inode *inode = hdr->inode;
- enum pnfs_try_status trypnfs;
- struct nfs_server *nfss = NFS_SERVER(inode);
-
- hdr->mds_ops = call_ops;
-
- dprintk("%s: Writing ino:%lu %u@%llu (how %d)\n", __func__,
- inode->i_ino, hdr->args.count, hdr->args.offset, how);
- trypnfs = nfss->pnfs_curr_ld->write_pagelist(hdr, how);
- if (trypnfs != PNFS_NOT_ATTEMPTED)
- nfs_inc_stats(inode, NFSIOS_PNFS_WRITE);
- dprintk("%s End (trypnfs:%d)\n", __func__, trypnfs);
- return trypnfs;
+ return NFS_SERVER(hdr->inode)->pnfs_curr_ld->write_pagelist(hdr, how);
}

static void
pnfs_do_write(struct nfs_pageio_descriptor *desc,
struct nfs_pgio_header *hdr, int how)
{
- const struct rpc_call_ops *call_ops = desc->pg_rpc_callops;
struct pnfs_layout_segment *lseg = desc->pg_lseg;
- enum pnfs_try_status trypnfs;

+ hdr->mds_ops = desc->pg_rpc_callops;
desc->pg_lseg = NULL;
- trypnfs = pnfs_try_to_write_data(hdr, call_ops, lseg, how);
- if (trypnfs == PNFS_NOT_ATTEMPTED)
+
+ if (pnfs_try_to_write_data(hdr, how) == PNFS_NOT_ATTEMPTED)
pnfs_through_mds(desc, hdr);
+ else
+ nfs_inc_stats(hdr->inode, NFSIOS_PNFS_WRITE);
pnfs_put_lseg(lseg);
}

--
1.9.2


2014-05-21 14:23:21

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [RFC 00/12] PNFS Read and Write Cleanups

On Tue, May 20, 2014 at 02:08:07PM -0400, Anna Schumaker wrote:
> There is a lot of duplicate code in pnfs.c that can be cleaned up to
> share more code. This patch set goes through each function one at a
> time and merges read and write code together wherever possible. In the
> end I'm passing around a few function pointers. Would it be better to
> use a function pointer struct instead?

No chance to share this with the r/w ops for the classic code?

Aso I think it would be even better if a lot of this code could be
mergedinto the classic code path, it seems like we'd mostly need
pnfs_get/put_lseg in common code for this. pnfs_get_lseg is so trivial
that it's not a problem, and the put could be done by simply giving each
lseg a free function pointer.


2014-05-20 18:08:26

by Anna Schumaker

[permalink] [raw]
Subject: [RFC 01/12] nfs: Create a common pnfs_pageio_reset_mds() function

bsize never changes once it is set in the pageio descriptor, so we don't
need to add extra code to reset it. I also moved this function into
pnfs.c because it is only called from pnfs.

Signed-off-by: Anna Schumaker <[email protected]>
---
fs/nfs/blocklayout/blocklayout.c | 4 ++--
fs/nfs/internal.h | 2 --
fs/nfs/nfs4filelayout.c | 4 ++--
fs/nfs/pagelist.c | 1 +
fs/nfs/pnfs.c | 14 ++++++++++----
fs/nfs/pnfs.h | 1 +
fs/nfs/read.c | 7 -------
fs/nfs/write.c | 8 --------
8 files changed, 16 insertions(+), 25 deletions(-)

diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c
index 04ac32b..eb0f5a7 100644
--- a/fs/nfs/blocklayout/blocklayout.c
+++ b/fs/nfs/blocklayout/blocklayout.c
@@ -1183,7 +1183,7 @@ bl_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
{
if (pgio->pg_dreq != NULL &&
!is_aligned_req(req, SECTOR_SIZE))
- nfs_pageio_reset_read_mds(pgio);
+ pnfs_pageio_reset_mds(pgio);
else
pnfs_generic_pg_init_read(pgio, req);
}
@@ -1231,7 +1231,7 @@ bl_pg_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
{
if (pgio->pg_dreq != NULL &&
!is_aligned_req(req, PAGE_CACHE_SIZE)) {
- nfs_pageio_reset_write_mds(pgio);
+ pnfs_pageio_reset_mds(pgio);
} else {
u64 wb_size;
if (pgio->pg_dreq == NULL)
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index e0e2b6d..5b64177 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -406,7 +406,6 @@ extern void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio,
struct inode *inode, bool force_mds,
const struct nfs_pgio_completion_ops *compl_ops);
extern void nfs_read_prepare(struct rpc_task *task, void *calldata);
-extern void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio);

/* super.c */
void nfs_clone_super(struct super_block *, struct nfs_mount_info *);
@@ -423,7 +422,6 @@ int nfs_remount(struct super_block *sb, int *flags, char *raw_data);
extern void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
struct inode *inode, int ioflags, bool force_mds,
const struct nfs_pgio_completion_ops *compl_ops);
-extern void nfs_pageio_reset_write_mds(struct nfs_pageio_descriptor *pgio);
extern void nfs_commit_free(struct nfs_commit_data *p);
extern void nfs_write_prepare(struct rpc_task *task, void *calldata);
extern void nfs_commit_prepare(struct rpc_task *task, void *calldata);
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c
index 37e0b65..9586cfa 100644
--- a/fs/nfs/nfs4filelayout.c
+++ b/fs/nfs/nfs4filelayout.c
@@ -957,7 +957,7 @@ filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio,
GFP_KERNEL);
/* If no lseg, fall back to read through mds */
if (pgio->pg_lseg == NULL)
- nfs_pageio_reset_read_mds(pgio);
+ pnfs_pageio_reset_mds(pgio);
}

static void
@@ -986,7 +986,7 @@ filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio,
}
return;
out_mds:
- nfs_pageio_reset_write_mds(pgio);
+ pnfs_pageio_reset_mds(pgio);
}

static const struct nfs_pageio_ops filelayout_pg_read_ops = {
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index 0fcd34a..d1670a2 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -1040,3 +1040,4 @@ const struct nfs_pageio_ops nfs_pgio_rw_ops = {
.pg_test = nfs_generic_pg_test,
.pg_doio = nfs_generic_pg_pgios,
};
+EXPORT_SYMBOL_GPL(nfs_pgio_rw_ops);
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 79792a4..8da7ff6 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -1381,6 +1381,12 @@ out_forget_reply:
goto out;
}

+void pnfs_pageio_reset_mds(struct nfs_pageio_descriptor *pgio)
+{
+ pgio->pg_ops = &nfs_pgio_rw_ops;
+}
+EXPORT_SYMBOL_GPL(pnfs_pageio_reset_mds);
+
void
pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
{
@@ -1401,7 +1407,7 @@ pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *r
GFP_KERNEL);
/* If no lseg, fall back to read through mds */
if (pgio->pg_lseg == NULL)
- nfs_pageio_reset_read_mds(pgio);
+ pnfs_pageio_reset_mds(pgio);

}
EXPORT_SYMBOL_GPL(pnfs_generic_pg_init_read);
@@ -1420,7 +1426,7 @@ pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
GFP_NOFS);
/* If no lseg, fall back to write through mds */
if (pgio->pg_lseg == NULL)
- nfs_pageio_reset_write_mds(pgio);
+ pnfs_pageio_reset_mds(pgio);
}
EXPORT_SYMBOL_GPL(pnfs_generic_pg_init_write);

@@ -1510,7 +1516,7 @@ pnfs_write_through_mds(struct nfs_pageio_descriptor *desc,
{
if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) {
list_splice_tail_init(&hdr->pages, &desc->pg_list);
- nfs_pageio_reset_write_mds(desc);
+ pnfs_pageio_reset_mds(desc);
desc->pg_recoalesce = 1;
}
nfs_generic_pgio_reset(hdr);
@@ -1627,7 +1633,7 @@ pnfs_read_through_mds(struct nfs_pageio_descriptor *desc,
{
if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) {
list_splice_tail_init(&hdr->pages, &desc->pg_list);
- nfs_pageio_reset_read_mds(desc);
+ pnfs_pageio_reset_mds(desc);
desc->pg_recoalesce = 1;
}
nfs_generic_pgio_reset(hdr);
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
index 552b2e9..52310df 100644
--- a/fs/nfs/pnfs.h
+++ b/fs/nfs/pnfs.h
@@ -186,6 +186,7 @@ void pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *, struct nfs_page *
int pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc);
void pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
struct nfs_page *req, u64 wb_size);
+void pnfs_pageio_reset_mds(struct nfs_pageio_descriptor *pgio);
int pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc);
size_t pnfs_generic_pg_test(struct nfs_pageio_descriptor *pgio,
struct nfs_page *prev, struct nfs_page *req);
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index b1532b7..c9217e6 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -68,13 +68,6 @@ void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio,
}
EXPORT_SYMBOL_GPL(nfs_pageio_init_read);

-void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio)
-{
- pgio->pg_ops = &nfs_pgio_rw_ops;
- pgio->pg_bsize = NFS_SERVER(pgio->pg_inode)->rsize;
-}
-EXPORT_SYMBOL_GPL(nfs_pageio_reset_read_mds);
-
int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
struct page *page)
{
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 1baca45..2929648 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -1063,14 +1063,6 @@ void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
}
EXPORT_SYMBOL_GPL(nfs_pageio_init_write);

-void nfs_pageio_reset_write_mds(struct nfs_pageio_descriptor *pgio)
-{
- pgio->pg_ops = &nfs_pgio_rw_ops;
- pgio->pg_bsize = NFS_SERVER(pgio->pg_inode)->wsize;
-}
-EXPORT_SYMBOL_GPL(nfs_pageio_reset_write_mds);
-
-
void nfs_commit_prepare(struct rpc_task *task, void *calldata)
{
struct nfs_commit_data *data = calldata;
--
1.9.2


2014-05-20 18:08:35

by Anna Schumaker

[permalink] [raw]
Subject: [RFC 11/12] nfs: pnfs can use nfs_generic_pgios_common() too!

We just need to take a few extra steps in case of an error.

Signed-off-by: Anna Schumaker <[email protected]>
---
fs/nfs/pnfs.c | 41 ++++++++---------------------------------
1 file changed, 8 insertions(+), 33 deletions(-)

diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index b6ebea8..df07832 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -1540,34 +1540,22 @@ pnfs_try_to_write_data(struct nfs_pgio_header *hdr, int how)
return NFS_SERVER(hdr->inode)->pnfs_curr_ld->write_pagelist(hdr, how);
}

-static void
+static int
pnfs_do_write(struct nfs_pageio_descriptor *desc, struct nfs_pgio_header *hdr)
{
if (pnfs_do_rw(desc, hdr, pnfs_try_to_write_data))
nfs_inc_stats(hdr->inode, NFSIOS_PNFS_WRITE);
+ return 0;
}

int
pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc)
{
- struct nfs_pgio_header *hdr;
- int ret;
-
- hdr = nfs_pgio_header_alloc(desc->pg_rw_ops);
- if (!hdr) {
- desc->pg_completion_ops->error_cleanup(&desc->pg_list);
- pnfs_put_lseg(desc->pg_lseg);
- desc->pg_lseg = NULL;
- return -ENOMEM;
- }
- nfs_pgheader_init(desc, hdr, pnfs_pgiohdr_free);
- hdr->lseg = pnfs_get_lseg(desc->pg_lseg);
- ret = nfs_generic_pgio(desc, hdr);
+ int ret = nfs_generic_pgios_common(desc, pnfs_pgiohdr_free, pnfs_do_write);
if (ret != 0) {
pnfs_put_lseg(desc->pg_lseg);
desc->pg_lseg = NULL;
- } else
- pnfs_do_write(desc, hdr);
+ }
return ret;
}
EXPORT_SYMBOL_GPL(pnfs_generic_pg_writepages);
@@ -1615,35 +1603,22 @@ pnfs_try_to_read_data(struct nfs_pgio_header *hdr, int how)
return NFS_SERVER(hdr->inode)->pnfs_curr_ld->read_pagelist(hdr);
}

-static void
+static int
pnfs_do_read(struct nfs_pageio_descriptor *desc, struct nfs_pgio_header *hdr)
{
if (pnfs_do_rw(desc, hdr, pnfs_try_to_read_data))
nfs_inc_stats(hdr->inode, NFSIOS_PNFS_READ);
+ return 0;
}

int
pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc)
{
- struct nfs_pgio_header *hdr;
- int ret;
-
- hdr = nfs_pgio_header_alloc(desc->pg_rw_ops);
- if (!hdr) {
- desc->pg_completion_ops->error_cleanup(&desc->pg_list);
- ret = -ENOMEM;
- pnfs_put_lseg(desc->pg_lseg);
- desc->pg_lseg = NULL;
- return ret;
- }
- nfs_pgheader_init(desc, hdr, pnfs_pgiohdr_free);
- hdr->lseg = pnfs_get_lseg(desc->pg_lseg);
- ret = nfs_generic_pgio(desc, hdr);
+ int ret = nfs_generic_pgios_common(desc, pnfs_pgiohdr_free, pnfs_do_read);
if (ret != 0) {
pnfs_put_lseg(desc->pg_lseg);
desc->pg_lseg = NULL;
- } else
- pnfs_do_read(desc, hdr);
+ }
return ret;
}
EXPORT_SYMBOL_GPL(pnfs_generic_pg_readpages);
--
1.9.2


2014-05-20 18:08:27

by Anna Schumaker

[permalink] [raw]
Subject: [RFC 03/12] nfs: Create a common pnfs_ld_handle_rw_error() function

I use a simple function pointer to handle the difference between the
read and write paths.

Signed-off-by: Anna Schumaker <[email protected]>
---
fs/nfs/pnfs.c | 38 +++++++++++++-------------------------
1 file changed, 13 insertions(+), 25 deletions(-)

diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 4d57003..4eaf74a 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -1446,6 +1446,17 @@ pnfs_generic_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
}
EXPORT_SYMBOL_GPL(pnfs_generic_pg_test);

+static void pnfs_ld_handle_rw_error(struct nfs_pgio_header *hdr,
+ int (*resend_to_mds)(struct nfs_pgio_header *))
+{
+ if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags &
+ PNFS_LAYOUTRET_ON_ERROR) {
+ pnfs_return_layout(hdr->inode);
+ }
+ if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags))
+ hdr->task.tk_status = resend_to_mds(hdr);
+}
+
void
pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
struct nfs_page *req, u64 wb_size)
@@ -1465,18 +1476,6 @@ int pnfs_write_done_resend_to_mds(struct nfs_pgio_header *hdr)
}
EXPORT_SYMBOL_GPL(pnfs_write_done_resend_to_mds);

-static void pnfs_ld_handle_write_error(struct nfs_pgio_header *hdr)
-{
-
- dprintk("pnfs write error = %d\n", hdr->pnfs_error);
- if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags &
- PNFS_LAYOUTRET_ON_ERROR) {
- pnfs_return_layout(hdr->inode);
- }
- if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags))
- hdr->task.tk_status = pnfs_write_done_resend_to_mds(hdr);
-}
-
/*
* Called by non rpc-based layout drivers
*/
@@ -1487,7 +1486,7 @@ void pnfs_ld_write_done(struct nfs_pgio_header *hdr)
pnfs_set_layoutcommit(hdr);
hdr->mds_ops->rpc_call_done(&hdr->task, hdr);
} else
- pnfs_ld_handle_write_error(hdr);
+ pnfs_ld_handle_rw_error(hdr, pnfs_write_done_resend_to_mds);
hdr->mds_ops->rpc_release(hdr);
}
EXPORT_SYMBOL_GPL(pnfs_ld_write_done);
@@ -1596,17 +1595,6 @@ int pnfs_read_done_resend_to_mds(struct nfs_pgio_header *hdr)
}
EXPORT_SYMBOL_GPL(pnfs_read_done_resend_to_mds);

-static void pnfs_ld_handle_read_error(struct nfs_pgio_header *hdr)
-{
- dprintk("pnfs read error = %d\n", hdr->pnfs_error);
- if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags &
- PNFS_LAYOUTRET_ON_ERROR) {
- pnfs_return_layout(hdr->inode);
- }
- if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags))
- hdr->task.tk_status = pnfs_read_done_resend_to_mds(hdr);
-}
-
/*
* Called by non rpc-based layout drivers
*/
@@ -1617,7 +1605,7 @@ void pnfs_ld_read_done(struct nfs_pgio_header *hdr)
__nfs4_read_done_cb(hdr);
hdr->mds_ops->rpc_call_done(&hdr->task, hdr);
} else
- pnfs_ld_handle_read_error(hdr);
+ pnfs_ld_handle_rw_error(hdr, pnfs_read_done_resend_to_mds);
hdr->mds_ops->rpc_release(hdr);
}
EXPORT_SYMBOL_GPL(pnfs_ld_read_done);
--
1.9.2


2014-05-20 18:08:31

by Anna Schumaker

[permalink] [raw]
Subject: [RFC 07/12] nfs: merge pnfs_try_to_read_data() and pnfs_do_read()

This makes these functions look neater in preparation for combining with
their write equivilents.

Signed-off-by: Anna Schumaker <[email protected]>
---
fs/nfs/pnfs.c | 28 +++++++---------------------
1 file changed, 7 insertions(+), 21 deletions(-)

diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 355cd41..293e970 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -1602,37 +1602,23 @@ EXPORT_SYMBOL_GPL(pnfs_ld_read_done);
* Call the appropriate parallel I/O subsystem read function.
*/
static enum pnfs_try_status
-pnfs_try_to_read_data(struct nfs_pgio_header *hdr,
- const struct rpc_call_ops *call_ops,
- struct pnfs_layout_segment *lseg)
+pnfs_try_to_read_data(struct nfs_pgio_header *hdr)
{
- struct inode *inode = hdr->inode;
- struct nfs_server *nfss = NFS_SERVER(inode);
- enum pnfs_try_status trypnfs;
-
- hdr->mds_ops = call_ops;
-
- dprintk("%s: Reading ino:%lu %u@%llu\n",
- __func__, inode->i_ino, hdr->args.count, hdr->args.offset);
-
- trypnfs = nfss->pnfs_curr_ld->read_pagelist(hdr);
- if (trypnfs != PNFS_NOT_ATTEMPTED)
- nfs_inc_stats(inode, NFSIOS_PNFS_READ);
- dprintk("%s End (trypnfs:%d)\n", __func__, trypnfs);
- return trypnfs;
+ return NFS_SERVER(hdr->inode)->pnfs_curr_ld->read_pagelist(hdr);
}

static void
pnfs_do_read(struct nfs_pageio_descriptor *desc, struct nfs_pgio_header *hdr)
{
- const struct rpc_call_ops *call_ops = desc->pg_rpc_callops;
struct pnfs_layout_segment *lseg = desc->pg_lseg;
- enum pnfs_try_status trypnfs;

+ hdr->mds_ops = desc->pg_rpc_callops;
desc->pg_lseg = NULL;
- trypnfs = pnfs_try_to_read_data(hdr, call_ops, lseg);
- if (trypnfs == PNFS_NOT_ATTEMPTED)
+
+ if (pnfs_try_to_read_data(hdr) == PNFS_NOT_ATTEMPTED)
pnfs_through_mds(desc, hdr);
+ else
+ nfs_inc_stats(hdr->inode, NFSIOS_PNFS_READ);
pnfs_put_lseg(lseg);
}

--
1.9.2


2014-05-20 18:08:36

by Anna Schumaker

[permalink] [raw]
Subject: [RFC 12/12] nfs: Create a common pnfs_generic_rwpages() function

This code is almost identical, so it might as well be combined.

Signed-off-by: Anna Schumaker <[email protected]>
---
fs/nfs/pnfs.c | 26 ++++++++++++++------------
1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index df07832..6f1fd5e 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -1505,6 +1505,18 @@ static void pnfs_pgiohdr_free(struct nfs_pgio_header *hdr)
nfs_pgio_header_free(hdr);
}

+static int pnfs_generic_pg_rwpages(struct nfs_pageio_descriptor *desc,
+ int (*do_pgio)(struct nfs_pageio_descriptor *,
+ struct nfs_pgio_header *))
+{
+ int ret = nfs_generic_pgios_common(desc, pnfs_pgiohdr_free, do_pgio);
+ if (ret != 0) {
+ pnfs_put_lseg(desc->pg_lseg);
+ desc->pg_lseg = NULL;
+ }
+ return ret;
+}
+
void
pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
struct nfs_page *req, u64 wb_size)
@@ -1551,12 +1563,7 @@ pnfs_do_write(struct nfs_pageio_descriptor *desc, struct nfs_pgio_header *hdr)
int
pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc)
{
- int ret = nfs_generic_pgios_common(desc, pnfs_pgiohdr_free, pnfs_do_write);
- if (ret != 0) {
- pnfs_put_lseg(desc->pg_lseg);
- desc->pg_lseg = NULL;
- }
- return ret;
+ return pnfs_generic_pg_rwpages(desc, pnfs_do_write);
}
EXPORT_SYMBOL_GPL(pnfs_generic_pg_writepages);

@@ -1614,12 +1621,7 @@ pnfs_do_read(struct nfs_pageio_descriptor *desc, struct nfs_pgio_header *hdr)
int
pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc)
{
- int ret = nfs_generic_pgios_common(desc, pnfs_pgiohdr_free, pnfs_do_read);
- if (ret != 0) {
- pnfs_put_lseg(desc->pg_lseg);
- desc->pg_lseg = NULL;
- }
- return ret;
+ return pnfs_generic_pg_rwpages(desc, pnfs_do_read);
}
EXPORT_SYMBOL_GPL(pnfs_generic_pg_readpages);

--
1.9.2


2014-05-20 18:08:32

by Anna Schumaker

[permalink] [raw]
Subject: [RFC 08/12] nfs: create a common pnfs_do_rw() function

The read and write code looks almost identical, so use a simple function
pointer to decide between read_pagelist() and write_pagelist().

Signed-off-by: Anna Schumaker <[email protected]>
---
fs/nfs/pnfs.c | 45 +++++++++++++++++++++++----------------------
1 file changed, 23 insertions(+), 22 deletions(-)

diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 293e970..69751d4 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -1481,6 +1481,24 @@ pnfs_through_mds(struct nfs_pageio_descriptor *desc,
nfs_generic_pgio_reset(hdr);
}

+static bool
+pnfs_do_rw(struct nfs_pageio_descriptor *desc, struct nfs_pgio_header *hdr,
+ enum pnfs_try_status (*try_rw)(struct nfs_pgio_header *, int))
+{
+ struct pnfs_layout_segment *lseg = desc->pg_lseg;
+ bool ret = true;
+
+ hdr->mds_ops = desc->pg_rpc_callops;
+ desc->pg_lseg = NULL;
+
+ if (try_rw(hdr, desc->pg_ioflags) == PNFS_NOT_ATTEMPTED) {
+ pnfs_through_mds(desc, hdr);
+ ret = false;
+ }
+ pnfs_put_lseg(lseg);
+ return ret;
+}
+
void
pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
struct nfs_page *req, u64 wb_size)
@@ -1517,19 +1535,10 @@ pnfs_try_to_write_data(struct nfs_pgio_header *hdr, int how)
}

static void
-pnfs_do_write(struct nfs_pageio_descriptor *desc,
- struct nfs_pgio_header *hdr, int how)
+pnfs_do_write(struct nfs_pageio_descriptor *desc, struct nfs_pgio_header *hdr)
{
- struct pnfs_layout_segment *lseg = desc->pg_lseg;
-
- hdr->mds_ops = desc->pg_rpc_callops;
- desc->pg_lseg = NULL;
-
- if (pnfs_try_to_write_data(hdr, how) == PNFS_NOT_ATTEMPTED)
- pnfs_through_mds(desc, hdr);
- else
+ if (pnfs_do_rw(desc, hdr, pnfs_try_to_write_data))
nfs_inc_stats(hdr->inode, NFSIOS_PNFS_WRITE);
- pnfs_put_lseg(lseg);
}

static void pnfs_writehdr_free(struct nfs_pgio_header *hdr)
@@ -1559,7 +1568,7 @@ pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc)
pnfs_put_lseg(desc->pg_lseg);
desc->pg_lseg = NULL;
} else
- pnfs_do_write(desc, hdr, desc->pg_ioflags);
+ pnfs_do_write(desc, hdr);
return ret;
}
EXPORT_SYMBOL_GPL(pnfs_generic_pg_writepages);
@@ -1602,7 +1611,7 @@ EXPORT_SYMBOL_GPL(pnfs_ld_read_done);
* Call the appropriate parallel I/O subsystem read function.
*/
static enum pnfs_try_status
-pnfs_try_to_read_data(struct nfs_pgio_header *hdr)
+pnfs_try_to_read_data(struct nfs_pgio_header *hdr, int how)
{
return NFS_SERVER(hdr->inode)->pnfs_curr_ld->read_pagelist(hdr);
}
@@ -1610,16 +1619,8 @@ pnfs_try_to_read_data(struct nfs_pgio_header *hdr)
static void
pnfs_do_read(struct nfs_pageio_descriptor *desc, struct nfs_pgio_header *hdr)
{
- struct pnfs_layout_segment *lseg = desc->pg_lseg;
-
- hdr->mds_ops = desc->pg_rpc_callops;
- desc->pg_lseg = NULL;
-
- if (pnfs_try_to_read_data(hdr) == PNFS_NOT_ATTEMPTED)
- pnfs_through_mds(desc, hdr);
- else
+ if (pnfs_do_rw(desc, hdr, pnfs_try_to_read_data))
nfs_inc_stats(hdr->inode, NFSIOS_PNFS_READ);
- pnfs_put_lseg(lseg);
}

static void pnfs_readhdr_free(struct nfs_pgio_header *hdr)
--
1.9.2


2014-05-20 18:08:34

by Anna Schumaker

[permalink] [raw]
Subject: [RFC 10/12] nfs: Split up generic_pg_pgios

pnfs will need a way to use a different function to initiate IO and to
free the pgio_header. The common function now expects a function
pointer for each.

Signed-off-by: Anna Schumaker <[email protected]>
---
fs/nfs/internal.h | 4 ++++
fs/nfs/pagelist.c | 24 +++++++++++++++++++-----
2 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 5b64177..3a5abf0 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -242,6 +242,10 @@ struct nfs_pgio_header *nfs_pgio_header_alloc(const struct nfs_rw_ops *);
void nfs_pgio_header_free(struct nfs_pgio_header *);
int nfs_generic_pgio(struct nfs_pageio_descriptor *, struct nfs_pgio_header *);
void nfs_generic_pgio_reset(struct nfs_pgio_header *);
+int nfs_generic_pgios_common(struct nfs_pageio_descriptor *,
+ void (*)(struct nfs_pgio_header *),
+ int (*)(struct nfs_pageio_descriptor *,
+ struct nfs_pgio_header *));
int nfs_initiate_pgio(struct rpc_clnt *, struct nfs_pgio_header *,
const struct rpc_call_ops *, int, int);

diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index d1670a2..fc01c5b 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -722,8 +722,18 @@ void nfs_generic_pgio_reset(struct nfs_pgio_header *hdr)
}
EXPORT_SYMBOL_GPL(nfs_generic_pgio_reset);

+static int nfs_do_pgio(struct nfs_pageio_descriptor *desc,
+ struct nfs_pgio_header *hdr)
+{
+ return nfs_initiate_pgio(NFS_CLIENT(hdr->inode),
+ hdr, desc->pg_rpc_callops,
+ desc->pg_ioflags, 0);
+}

-static int nfs_generic_pg_pgios(struct nfs_pageio_descriptor *desc)
+int nfs_generic_pgios_common(struct nfs_pageio_descriptor *desc,
+ void (*free_header)(struct nfs_pgio_header *),
+ int (*do_pgio)(struct nfs_pageio_descriptor *,
+ struct nfs_pgio_header *))
{
struct nfs_pgio_header *hdr;
int ret;
@@ -733,14 +743,18 @@ static int nfs_generic_pg_pgios(struct nfs_pageio_descriptor *desc)
desc->pg_completion_ops->error_cleanup(&desc->pg_list);
return -ENOMEM;
}
- nfs_pgheader_init(desc, hdr, nfs_pgio_header_free);
+ nfs_pgheader_init(desc, hdr, free_header);
ret = nfs_generic_pgio(desc, hdr);
if (ret == 0)
- ret = nfs_initiate_pgio(NFS_CLIENT(hdr->inode),
- hdr, desc->pg_rpc_callops,
- desc->pg_ioflags, 0);
+ ret = do_pgio(desc, hdr);
return ret;
}
+EXPORT_SYMBOL_GPL(nfs_generic_pgios_common);
+
+static int nfs_generic_pg_pgios(struct nfs_pageio_descriptor *desc)
+{
+ return nfs_generic_pgios_common(desc, nfs_pgio_header_free, nfs_do_pgio);
+}

static bool nfs_match_open_context(const struct nfs_open_context *ctx1,
const struct nfs_open_context *ctx2)
--
1.9.2