Commit eb9f2a5a authored by Trond Myklebust's avatar Trond Myklebust Committed by Anna Schumaker

NFS: Support folios in nfs_generic_pgio()

Add support for multi-page folios in the generic NFS i/o engine.
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent 35c5db0e
...@@ -807,11 +807,10 @@ unsigned char nfs_umode_to_dtype(umode_t mode) ...@@ -807,11 +807,10 @@ unsigned char nfs_umode_to_dtype(umode_t mode)
* Determine the number of pages in an array of length 'len' and * Determine the number of pages in an array of length 'len' and
* with a base offset of 'base' * with a base offset of 'base'
*/ */
static inline static inline unsigned int nfs_page_array_len(unsigned int base, size_t len)
unsigned int nfs_page_array_len(unsigned int base, size_t len)
{ {
return ((unsigned long)len + (unsigned long)base + return ((unsigned long)len + (unsigned long)base + PAGE_SIZE - 1) >>
PAGE_SIZE - 1) >> PAGE_SHIFT; PAGE_SHIFT;
} }
/* /*
......
...@@ -31,6 +31,42 @@ ...@@ -31,6 +31,42 @@
static struct kmem_cache *nfs_page_cachep; static struct kmem_cache *nfs_page_cachep;
static const struct rpc_call_ops nfs_pgio_common_ops; static const struct rpc_call_ops nfs_pgio_common_ops;
struct nfs_page_iter_page {
const struct nfs_page *req;
size_t count;
};
static void nfs_page_iter_page_init(struct nfs_page_iter_page *i,
const struct nfs_page *req)
{
i->req = req;
i->count = 0;
}
static void nfs_page_iter_page_advance(struct nfs_page_iter_page *i, size_t sz)
{
const struct nfs_page *req = i->req;
size_t tmp = i->count + sz;
i->count = (tmp < req->wb_bytes) ? tmp : req->wb_bytes;
}
static struct page *nfs_page_iter_page_get(struct nfs_page_iter_page *i)
{
const struct nfs_page *req = i->req;
struct page *page;
if (i->count != req->wb_bytes) {
size_t base = i->count + req->wb_pgbase;
size_t len = PAGE_SIZE - offset_in_page(base);
page = nfs_page_to_page(req, base);
nfs_page_iter_page_advance(i, len);
return page;
}
return NULL;
}
static struct nfs_pgio_mirror * static struct nfs_pgio_mirror *
nfs_pgio_get_mirror(struct nfs_pageio_descriptor *desc, u32 idx) nfs_pgio_get_mirror(struct nfs_pageio_descriptor *desc, u32 idx)
{ {
...@@ -693,13 +729,14 @@ EXPORT_SYMBOL_GPL(nfs_pgio_header_free); ...@@ -693,13 +729,14 @@ EXPORT_SYMBOL_GPL(nfs_pgio_header_free);
/** /**
* nfs_pgio_rpcsetup - Set up arguments for a pageio call * nfs_pgio_rpcsetup - Set up arguments for a pageio call
* @hdr: The pageio hdr * @hdr: The pageio hdr
* @pgbase: base
* @count: Number of bytes to read * @count: Number of bytes to read
* @how: How to commit data (writes only) * @how: How to commit data (writes only)
* @cinfo: Commit information for the call (writes only) * @cinfo: Commit information for the call (writes only)
*/ */
static void nfs_pgio_rpcsetup(struct nfs_pgio_header *hdr, static void nfs_pgio_rpcsetup(struct nfs_pgio_header *hdr, unsigned int pgbase,
unsigned int count, unsigned int count, int how,
int how, struct nfs_commit_info *cinfo) struct nfs_commit_info *cinfo)
{ {
struct nfs_page *req = hdr->req; struct nfs_page *req = hdr->req;
...@@ -710,7 +747,7 @@ static void nfs_pgio_rpcsetup(struct nfs_pgio_header *hdr, ...@@ -710,7 +747,7 @@ static void nfs_pgio_rpcsetup(struct nfs_pgio_header *hdr,
hdr->args.offset = req_offset(req); hdr->args.offset = req_offset(req);
/* pnfs_set_layoutcommit needs this */ /* pnfs_set_layoutcommit needs this */
hdr->mds_offset = hdr->args.offset; hdr->mds_offset = hdr->args.offset;
hdr->args.pgbase = req->wb_pgbase; hdr->args.pgbase = pgbase;
hdr->args.pages = hdr->page_array.pagevec; hdr->args.pages = hdr->page_array.pagevec;
hdr->args.count = count; hdr->args.count = count;
hdr->args.context = get_nfs_open_context(nfs_req_openctx(req)); hdr->args.context = get_nfs_open_context(nfs_req_openctx(req));
...@@ -896,9 +933,10 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc, ...@@ -896,9 +933,10 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc,
struct nfs_commit_info cinfo; struct nfs_commit_info cinfo;
struct nfs_page_array *pg_array = &hdr->page_array; struct nfs_page_array *pg_array = &hdr->page_array;
unsigned int pagecount, pageused; unsigned int pagecount, pageused;
unsigned int pg_base = offset_in_page(mirror->pg_base);
gfp_t gfp_flags = nfs_io_gfp_mask(); gfp_t gfp_flags = nfs_io_gfp_mask();
pagecount = nfs_page_array_len(mirror->pg_base, mirror->pg_count); pagecount = nfs_page_array_len(pg_base, mirror->pg_count);
pg_array->npages = pagecount; pg_array->npages = pagecount;
if (pagecount <= ARRAY_SIZE(pg_array->page_array)) if (pagecount <= ARRAY_SIZE(pg_array->page_array))
...@@ -918,19 +956,26 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc, ...@@ -918,19 +956,26 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc,
last_page = NULL; last_page = NULL;
pageused = 0; pageused = 0;
while (!list_empty(head)) { while (!list_empty(head)) {
struct nfs_page_iter_page i;
struct page *page;
req = nfs_list_entry(head->next); req = nfs_list_entry(head->next);
nfs_list_move_request(req, &hdr->pages); nfs_list_move_request(req, &hdr->pages);
if (req->wb_pgbase == 0) if (req->wb_pgbase == 0)
last_page = NULL; last_page = NULL;
if (!last_page || last_page != req->wb_page) { nfs_page_iter_page_init(&i, req);
pageused++; while ((page = nfs_page_iter_page_get(&i)) != NULL) {
if (pageused > pagecount) if (last_page != page) {
break; pageused++;
*pages++ = last_page = req->wb_page; if (pageused > pagecount)
goto full;
*pages++ = last_page = page;
}
} }
} }
full:
if (WARN_ON_ONCE(pageused != pagecount)) { if (WARN_ON_ONCE(pageused != pagecount)) {
nfs_pgio_error(hdr); nfs_pgio_error(hdr);
desc->pg_error = -EINVAL; desc->pg_error = -EINVAL;
...@@ -942,7 +987,8 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc, ...@@ -942,7 +987,8 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc,
desc->pg_ioflags &= ~FLUSH_COND_STABLE; desc->pg_ioflags &= ~FLUSH_COND_STABLE;
/* Set up the argument struct */ /* Set up the argument struct */
nfs_pgio_rpcsetup(hdr, mirror->pg_count, desc->pg_ioflags, &cinfo); nfs_pgio_rpcsetup(hdr, pg_base, mirror->pg_count, desc->pg_ioflags,
&cinfo);
desc->pg_rpc_callops = &nfs_pgio_common_ops; desc->pg_rpc_callops = &nfs_pgio_common_ops;
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment