From: trondmy@kernel.org
To: linux-nfs@vger.kernel.org
Subject: [PATCH v5 21/22] NFS: Reduce number of RPC calls when doing uncached readdir
Date: Tue, 10 Nov 2020 16:37:40 -0500 [thread overview]
Message-ID: <20201110213741.860745-22-trondmy@kernel.org> (raw)
In-Reply-To: <20201110213741.860745-21-trondmy@kernel.org>
From: Trond Myklebust <trond.myklebust@hammerspace.com>
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>
---
fs/nfs/dir.c | 105 +++++++++++++++++++++++++++++++++------------------
1 file changed, 69 insertions(+), 36 deletions(-)
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index b6c3501e8f61..93c6f22cdc62 100644
--- a/fs/nfs/dir.c
+++ b/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 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry,
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 @@ static struct page **nfs_readdir_alloc_pages(size_t npages)
}
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;
}
--
2.28.0
next prev parent reply other threads:[~2020-11-10 21:48 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-11-10 21:37 [PATCH v5 00/22] Readdir enhancements trondmy
2020-11-10 21:37 ` [PATCH v5 01/22] NFS: Remove unnecessary inode locking in nfs_llseek_dir() trondmy
2020-11-10 21:37 ` [PATCH v5 02/22] NFS: Remove unnecessary inode lock in nfs_fsync_dir() trondmy
2020-11-10 21:37 ` [PATCH v5 03/22] NFSv4.2: condition READDIR's mask for security label based on LSM state trondmy
2020-11-10 21:37 ` [PATCH v5 04/22] NFS: Ensure contents of struct nfs_open_dir_context are consistent trondmy
2020-11-10 21:37 ` [PATCH v5 05/22] NFS: Clean up readdir struct nfs_cache_array trondmy
2020-11-10 21:37 ` [PATCH v5 06/22] NFS: Clean up nfs_readdir_page_filler() trondmy
2020-11-10 21:37 ` [PATCH v5 07/22] NFS: Clean up directory array handling trondmy
2020-11-10 21:37 ` [PATCH v5 08/22] NFS: Don't discard readdir results trondmy
2020-11-10 21:37 ` [PATCH v5 09/22] NFS: Remove unnecessary kmap in nfs_readdir_xdr_to_array() trondmy
2020-11-10 21:37 ` [PATCH v5 10/22] NFS: Replace kmap() with kmap_atomic() in nfs_readdir_search_array() trondmy
2020-11-10 21:37 ` [PATCH v5 11/22] NFS: Simplify struct nfs_cache_array_entry trondmy
2020-11-10 21:37 ` [PATCH v5 12/22] NFS: Support larger readdir buffers trondmy
2020-11-10 21:37 ` [PATCH v5 13/22] NFS: More readdir cleanups trondmy
2020-11-10 21:37 ` [PATCH v5 14/22] NFS: nfs_do_filldir() does not return a value trondmy
2020-11-10 21:37 ` [PATCH v5 15/22] NFS: Reduce readdir stack usage trondmy
2020-11-10 21:37 ` [PATCH v5 16/22] NFS: Cleanup to remove nfs_readdir_descriptor_t typedef trondmy
2020-11-10 21:37 ` [PATCH v5 17/22] NFS: Allow the NFS generic code to pass in a verifier to readdir trondmy
2020-11-10 21:37 ` [PATCH v5 18/22] NFS: Handle NFS4ERR_NOT_SAME and NFSERR_BADCOOKIE from readdir calls trondmy
2020-11-10 21:37 ` [PATCH v5 19/22] NFS: Improve handling of directory verifiers trondmy
2020-11-10 21:37 ` [PATCH v5 20/22] NFS: Optimisations for monotonically increasing readdir cookies trondmy
2020-11-10 21:37 ` trondmy [this message]
2020-11-10 21:37 ` [PATCH v5 22/22] NFS: Do uncached readdir when we're seeking a cookie in an empty page cache trondmy
2020-11-11 22:15 ` [PATCH v5 00/22] Readdir enhancements David Wysochanski
2020-11-12 11:41 ` David Wysochanski
2020-11-12 15:34 ` Guy Keren
2020-11-12 16:54 ` Trond Myklebust
2020-11-12 16:51 ` Trond Myklebust
2020-11-12 18:26 ` Trond Myklebust
2020-11-12 18:39 ` Benjamin Coddington
2020-11-12 18:49 ` Benjamin Coddington
2020-11-12 19:04 ` Trond Myklebust
2020-11-12 19:09 ` Benjamin Coddington
2020-11-12 20:23 ` Benjamin Coddington
2020-11-13 11:09 ` Mkrtchyan, Tigran
2020-11-14 13:32 ` David Wysochanski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20201110213741.860745-22-trondmy@kernel.org \
--to=trondmy@kernel.org \
--cc=linux-nfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).