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)
* Determine the number of pages in an array of length 'len' and
* with a base offset of 'base'
*/
static inline
unsigned int nfs_page_array_len(unsigned int base, size_t len)
static inline unsigned int nfs_page_array_len(unsigned int base, size_t len)
{
return ((unsigned long)len + (unsigned long)base +
PAGE_SIZE - 1) >> PAGE_SHIFT;
return ((unsigned long)len + (unsigned long)base + PAGE_SIZE - 1) >>
PAGE_SHIFT;
}
/*
......
......@@ -31,6 +31,42 @@
static struct kmem_cache *nfs_page_cachep;
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 *
nfs_pgio_get_mirror(struct nfs_pageio_descriptor *desc, u32 idx)
{
......@@ -693,13 +729,14 @@ EXPORT_SYMBOL_GPL(nfs_pgio_header_free);
/**
* nfs_pgio_rpcsetup - Set up arguments for a pageio call
* @hdr: The pageio hdr
* @pgbase: base
* @count: Number of bytes to read
* @how: How to commit data (writes only)
* @cinfo: Commit information for the call (writes only)
*/
static void nfs_pgio_rpcsetup(struct nfs_pgio_header *hdr,
unsigned int count,
int how, struct nfs_commit_info *cinfo)
static void nfs_pgio_rpcsetup(struct nfs_pgio_header *hdr, unsigned int pgbase,
unsigned int count, int how,
struct nfs_commit_info *cinfo)
{
struct nfs_page *req = hdr->req;
......@@ -710,7 +747,7 @@ static void nfs_pgio_rpcsetup(struct nfs_pgio_header *hdr,
hdr->args.offset = req_offset(req);
/* pnfs_set_layoutcommit needs this */
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.count = count;
hdr->args.context = get_nfs_open_context(nfs_req_openctx(req));
......@@ -896,9 +933,10 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc,
struct nfs_commit_info cinfo;
struct nfs_page_array *pg_array = &hdr->page_array;
unsigned int pagecount, pageused;
unsigned int pg_base = offset_in_page(mirror->pg_base);
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;
if (pagecount <= ARRAY_SIZE(pg_array->page_array))
......@@ -918,19 +956,26 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc,
last_page = NULL;
pageused = 0;
while (!list_empty(head)) {
struct nfs_page_iter_page i;
struct page *page;
req = nfs_list_entry(head->next);
nfs_list_move_request(req, &hdr->pages);
if (req->wb_pgbase == 0)
last_page = NULL;
if (!last_page || last_page != req->wb_page) {
nfs_page_iter_page_init(&i, req);
while ((page = nfs_page_iter_page_get(&i)) != NULL) {
if (last_page != page) {
pageused++;
if (pageused > pagecount)
break;
*pages++ = last_page = req->wb_page;
goto full;
*pages++ = last_page = page;
}
}
}
full:
if (WARN_ON_ONCE(pageused != pagecount)) {
nfs_pgio_error(hdr);
desc->pg_error = -EINVAL;
......@@ -942,7 +987,8 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc,
desc->pg_ioflags &= ~FLUSH_COND_STABLE;
/* 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;
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