2022-02-24 01:11:19

by Trond Myklebust

[permalink] [raw]
Subject: [PATCH v7 20/21] NFS: Fix up forced readdirplus

From: Trond Myklebust <[email protected]>

Avoid clearing the entire readdir page cache if we're just doing forced
readdirplus for the 'ls -l' heuristic.

Signed-off-by: Trond Myklebust <[email protected]>
---
fs/nfs/dir.c | 49 ++++++++++++++++++++++++++----------------
include/linux/nfs_fs.h | 1 +
2 files changed, 31 insertions(+), 19 deletions(-)

diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 2007eebfb5cf..d41ea614edec 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -169,6 +169,7 @@ struct nfs_readdir_descriptor {
unsigned int cache_entry_index;
unsigned int buffer_fills;
unsigned int dtsize;
+ bool force_plus;
bool plus;
bool eob;
bool eof;
@@ -352,6 +353,16 @@ static bool nfs_readdir_page_cookie_match(struct page *page, u64 last_cookie,
return ret;
}

+static bool nfs_readdir_page_is_full(struct page *page)
+{
+ struct nfs_cache_array *array = kmap_atomic(page);
+ int ret;
+
+ ret = nfs_readdir_array_is_full(array);
+ kunmap_atomic(array);
+ return ret;
+}
+
static void nfs_readdir_page_unlock_and_put(struct page *page)
{
unlock_page(page);
@@ -359,7 +370,7 @@ static void nfs_readdir_page_unlock_and_put(struct page *page)
}

static struct page *nfs_readdir_page_get_locked(struct address_space *mapping,
- u64 last_cookie)
+ u64 last_cookie, bool clear)
{
pgoff_t index = nfs_readdir_page_cookie_hash(last_cookie);
struct page *page;
@@ -371,8 +382,10 @@ static struct page *nfs_readdir_page_get_locked(struct address_space *mapping,
change_attr = inode_peek_iversion_raw(mapping->host);
if (PageUptodate(page)) {
if (nfs_readdir_page_cookie_match(page, last_cookie,
- change_attr))
- return page;
+ change_attr)) {
+ if (!clear || !nfs_readdir_page_is_full(page))
+ return page;
+ }
nfs_readdir_clear_array(page);
}
nfs_readdir_page_init_array(page, last_cookie, change_attr);
@@ -393,13 +406,7 @@ static u64 nfs_readdir_page_last_cookie(struct page *page)

static bool nfs_readdir_page_needs_filling(struct page *page)
{
- struct nfs_cache_array *array;
- bool ret;
-
- array = kmap_atomic(page);
- ret = !nfs_readdir_array_is_full(array);
- kunmap_atomic(array);
- return ret;
+ return !nfs_readdir_page_is_full(page);
}

static void nfs_readdir_page_set_eof(struct page *page)
@@ -412,11 +419,11 @@ static void nfs_readdir_page_set_eof(struct page *page)
}

static struct page *nfs_readdir_page_get_next(struct address_space *mapping,
- u64 cookie)
+ u64 cookie, bool clear)
{
struct page *page;

- page = nfs_readdir_page_get_locked(mapping, cookie);
+ page = nfs_readdir_page_get_locked(mapping, cookie, clear);
if (page) {
if (nfs_readdir_page_last_cookie(page) == cookie)
return page;
@@ -808,7 +815,8 @@ static int nfs_readdir_page_filler(struct nfs_readdir_descriptor *desc,
*arrays = page = new;
} else {
new = nfs_readdir_page_get_next(mapping,
- entry->prev_cookie);
+ entry->prev_cookie,
+ desc->force_plus);
if (!new)
break;
if (page != *arrays)
@@ -937,8 +945,8 @@ nfs_readdir_page_unlock_and_put_cached(struct nfs_readdir_descriptor *desc)
static struct page *
nfs_readdir_page_get_cached(struct nfs_readdir_descriptor *desc)
{
- return nfs_readdir_page_get_locked(desc->file->f_mapping,
- desc->last_cookie);
+ return nfs_readdir_page_get_locked(
+ desc->file->f_mapping, desc->last_cookie, desc->force_plus);
}

/*
@@ -1124,9 +1132,7 @@ static void nfs_readdir_handle_cache_misses(struct inode *inode,
if (desc->ctx->pos == 0 ||
cache_misses <= NFS_READDIR_CACHE_MISS_THRESHOLD)
return;
- if (invalidate_mapping_pages(inode->i_mapping, 0, -1) == 0)
- return;
- trace_nfs_readdir_invalidate_cache_range(inode, 0, MAX_LFS_FILESIZE);
+ desc->force_plus = true;
}

/* The file offset position represents the dirent entry number. A
@@ -1170,6 +1176,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
desc->page_index = page_index;
desc->last_cookie = dir_ctx->last_cookie;
desc->attr_gencount = dir_ctx->attr_gencount;
+ desc->force_plus = dir_ctx->force_plus;
desc->eof = dir_ctx->eof;
nfs_set_dtsize(desc, dir_ctx->dtsize);
memcpy(desc->verf, dir_ctx->verf, sizeof(desc->verf));
@@ -1183,7 +1190,10 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
}

desc->plus = nfs_use_readdirplus(inode, ctx, cache_hits, cache_misses);
- nfs_readdir_handle_cache_misses(inode, desc, cache_misses);
+ if (desc->plus)
+ nfs_readdir_handle_cache_misses(inode, desc, cache_misses);
+ else
+ desc->force_plus = false;

do {
res = readdir_search_pagecache(desc);
@@ -1224,6 +1234,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
dir_ctx->last_cookie = desc->last_cookie;
dir_ctx->attr_gencount = desc->attr_gencount;
dir_ctx->page_index = desc->page_index;
+ dir_ctx->force_plus = desc->force_plus;
dir_ctx->eof = desc->eof;
dir_ctx->dtsize = desc->dtsize;
memcpy(dir_ctx->verf, desc->verf, sizeof(dir_ctx->verf));
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 42aad886d3c0..3f9625c7d0ef 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -109,6 +109,7 @@ struct nfs_open_dir_context {
__u64 last_cookie;
pgoff_t page_index;
unsigned int dtsize;
+ bool force_plus;
bool eof;
struct rcu_head rcu_head;
};
--
2.35.1