mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-10 15:58:47 +00:00
NFS: Reduce number of RPC calls when doing uncached readdir
If we're doing uncached readdir, allocate multiple pages in order to try to avoid duplicate RPC calls for the same getdents() call. Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> Reviewed-by: Benjamin Coddington <bcodding@redhat.com> Tested-by: Benjamin Coddington <bcodding@redhat.com> Tested-by: Dave Wysochanski <dwysocha@redhat.com>
This commit is contained in:
parent
762567b7c7
commit
35df59d3ef
105
fs/nfs/dir.c
105
fs/nfs/dir.c
@ -199,6 +199,23 @@ void nfs_readdir_clear_array(struct page *page)
|
||||
kunmap_atomic(array);
|
||||
}
|
||||
|
||||
static struct page *
|
||||
nfs_readdir_page_array_alloc(u64 last_cookie, gfp_t gfp_flags)
|
||||
{
|
||||
struct page *page = alloc_page(gfp_flags);
|
||||
if (page)
|
||||
nfs_readdir_page_init_array(page, last_cookie);
|
||||
return page;
|
||||
}
|
||||
|
||||
static void nfs_readdir_page_array_free(struct page *page)
|
||||
{
|
||||
if (page) {
|
||||
nfs_readdir_clear_array(page);
|
||||
put_page(page);
|
||||
}
|
||||
}
|
||||
|
||||
static void nfs_readdir_array_set_eof(struct nfs_cache_array *array)
|
||||
{
|
||||
array->page_is_eof = 1;
|
||||
@ -694,12 +711,14 @@ out:
|
||||
static int nfs_readdir_page_filler(struct nfs_readdir_descriptor *desc,
|
||||
struct nfs_entry *entry,
|
||||
struct page **xdr_pages,
|
||||
struct page *fillme, unsigned int buflen)
|
||||
unsigned int buflen,
|
||||
struct page **arrays,
|
||||
size_t narrays)
|
||||
{
|
||||
struct address_space *mapping = desc->file->f_mapping;
|
||||
struct xdr_stream stream;
|
||||
struct xdr_buf buf;
|
||||
struct page *scratch, *new, *page = fillme;
|
||||
struct page *scratch, *new, *page = *arrays;
|
||||
int status;
|
||||
|
||||
scratch = alloc_page(GFP_KERNEL);
|
||||
@ -725,15 +744,25 @@ static int nfs_readdir_page_filler(struct nfs_readdir_descriptor *desc,
|
||||
if (status != -ENOSPC)
|
||||
continue;
|
||||
|
||||
if (page->mapping != mapping)
|
||||
break;
|
||||
new = nfs_readdir_page_get_next(mapping, page->index + 1,
|
||||
entry->prev_cookie);
|
||||
if (!new)
|
||||
break;
|
||||
if (page != fillme)
|
||||
nfs_readdir_page_unlock_and_put(page);
|
||||
page = new;
|
||||
if (page->mapping != mapping) {
|
||||
if (!--narrays)
|
||||
break;
|
||||
new = nfs_readdir_page_array_alloc(entry->prev_cookie,
|
||||
GFP_KERNEL);
|
||||
if (!new)
|
||||
break;
|
||||
arrays++;
|
||||
*arrays = page = new;
|
||||
} else {
|
||||
new = nfs_readdir_page_get_next(mapping,
|
||||
page->index + 1,
|
||||
entry->prev_cookie);
|
||||
if (!new)
|
||||
break;
|
||||
if (page != *arrays)
|
||||
nfs_readdir_page_unlock_and_put(page);
|
||||
page = new;
|
||||
}
|
||||
status = nfs_readdir_add_to_array(entry, page);
|
||||
} while (!status && !entry->eof);
|
||||
|
||||
@ -750,7 +779,7 @@ static int nfs_readdir_page_filler(struct nfs_readdir_descriptor *desc,
|
||||
break;
|
||||
}
|
||||
|
||||
if (page != fillme)
|
||||
if (page != *arrays)
|
||||
nfs_readdir_page_unlock_and_put(page);
|
||||
|
||||
put_page(scratch);
|
||||
@ -790,10 +819,11 @@ out_freepages:
|
||||
}
|
||||
|
||||
static int nfs_readdir_xdr_to_array(struct nfs_readdir_descriptor *desc,
|
||||
struct page *page, __be32 *verf_arg,
|
||||
__be32 *verf_res)
|
||||
__be32 *verf_arg, __be32 *verf_res,
|
||||
struct page **arrays, size_t narrays)
|
||||
{
|
||||
struct page **pages;
|
||||
struct page *page = *arrays;
|
||||
struct nfs_entry *entry;
|
||||
size_t array_size;
|
||||
struct inode *inode = file_inode(desc->file);
|
||||
@ -835,7 +865,8 @@ static int nfs_readdir_xdr_to_array(struct nfs_readdir_descriptor *desc,
|
||||
break;
|
||||
}
|
||||
|
||||
status = nfs_readdir_page_filler(desc, entry, pages, page, pglen);
|
||||
status = nfs_readdir_page_filler(desc, entry, pages, pglen,
|
||||
arrays, narrays);
|
||||
} while (!status && nfs_readdir_page_needs_filling(page));
|
||||
|
||||
nfs_readdir_free_pages(pages, array_size);
|
||||
@ -884,8 +915,8 @@ static int find_and_lock_cache_page(struct nfs_readdir_descriptor *desc)
|
||||
if (!desc->page)
|
||||
return -ENOMEM;
|
||||
if (nfs_readdir_page_needs_filling(desc->page)) {
|
||||
res = nfs_readdir_xdr_to_array(desc, desc->page,
|
||||
nfsi->cookieverf, verf);
|
||||
res = nfs_readdir_xdr_to_array(desc, nfsi->cookieverf, verf,
|
||||
&desc->page, 1);
|
||||
if (res < 0) {
|
||||
nfs_readdir_page_unlock_and_put_cached(desc);
|
||||
if (res == -EBADCOOKIE || res == -ENOTSYNC) {
|
||||
@ -976,37 +1007,39 @@ static void nfs_do_filldir(struct nfs_readdir_descriptor *desc)
|
||||
*/
|
||||
static int uncached_readdir(struct nfs_readdir_descriptor *desc)
|
||||
{
|
||||
struct page *page = NULL;
|
||||
struct page **arrays;
|
||||
size_t i, sz = 512;
|
||||
__be32 verf[NFS_DIR_VERIFIER_SIZE];
|
||||
int status;
|
||||
int status = -ENOMEM;
|
||||
|
||||
dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for cookie %Lu\n",
|
||||
dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for cookie %llu\n",
|
||||
(unsigned long long)desc->dir_cookie);
|
||||
|
||||
page = alloc_page(GFP_HIGHUSER);
|
||||
if (!page) {
|
||||
status = -ENOMEM;
|
||||
arrays = kcalloc(sz, sizeof(*arrays), GFP_KERNEL);
|
||||
if (!arrays)
|
||||
goto out;
|
||||
arrays[0] = nfs_readdir_page_array_alloc(desc->dir_cookie, GFP_KERNEL);
|
||||
if (!arrays[0])
|
||||
goto out;
|
||||
}
|
||||
|
||||
desc->page_index = 0;
|
||||
desc->last_cookie = desc->dir_cookie;
|
||||
desc->page = page;
|
||||
desc->duped = 0;
|
||||
|
||||
nfs_readdir_page_init_array(page, desc->dir_cookie);
|
||||
status = nfs_readdir_xdr_to_array(desc, page, desc->verf, verf);
|
||||
if (status < 0)
|
||||
goto out_release;
|
||||
status = nfs_readdir_xdr_to_array(desc, desc->verf, verf, arrays, sz);
|
||||
|
||||
nfs_do_filldir(desc);
|
||||
for (i = 0; !desc->eof && i < sz && arrays[i]; i++) {
|
||||
desc->page = arrays[i];
|
||||
nfs_do_filldir(desc);
|
||||
}
|
||||
desc->page = NULL;
|
||||
|
||||
out_release:
|
||||
nfs_readdir_clear_array(desc->page);
|
||||
nfs_readdir_page_put(desc);
|
||||
out:
|
||||
dfprintk(DIRCACHE, "NFS: %s: returns %d\n",
|
||||
__func__, status);
|
||||
|
||||
for (i = 0; i < sz && arrays[i]; i++)
|
||||
nfs_readdir_page_array_free(arrays[i]);
|
||||
out:
|
||||
kfree(arrays);
|
||||
dfprintk(DIRCACHE, "NFS: %s: returns %d\n", __func__, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user