Commit b0365ccb authored by Trond Myklebust's avatar Trond Myklebust

NFS: Fix up forced readdirplus

Avoid clearing the entire readdir page cache if we're just doing forced
readdirplus for the 'ls -l' heuristic.
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
parent f648022f
...@@ -170,6 +170,7 @@ struct nfs_readdir_descriptor { ...@@ -170,6 +170,7 @@ struct nfs_readdir_descriptor {
unsigned int cache_entry_index; unsigned int cache_entry_index;
unsigned int buffer_fills; unsigned int buffer_fills;
unsigned int dtsize; unsigned int dtsize;
bool clear_cache;
bool plus; bool plus;
bool eob; bool eob;
bool eof; bool eof;
...@@ -227,6 +228,13 @@ static void nfs_readdir_clear_array(struct page *page) ...@@ -227,6 +228,13 @@ static void nfs_readdir_clear_array(struct page *page)
kunmap_atomic(array); kunmap_atomic(array);
} }
static void nfs_readdir_page_reinit_array(struct page *page, u64 last_cookie,
u64 change_attr)
{
nfs_readdir_clear_array(page);
nfs_readdir_page_init_array(page, last_cookie, change_attr);
}
static struct page * static struct page *
nfs_readdir_page_array_alloc(u64 last_cookie, gfp_t gfp_flags) nfs_readdir_page_array_alloc(u64 last_cookie, gfp_t gfp_flags)
{ {
...@@ -428,12 +436,11 @@ static struct page *nfs_readdir_page_get_next(struct address_space *mapping, ...@@ -428,12 +436,11 @@ static struct page *nfs_readdir_page_get_next(struct address_space *mapping,
struct page *page; struct page *page;
page = nfs_readdir_page_get_locked(mapping, cookie, change_attr); page = nfs_readdir_page_get_locked(mapping, cookie, change_attr);
if (page) { if (!page)
if (nfs_readdir_page_last_cookie(page) == cookie) return NULL;
return page; if (nfs_readdir_page_last_cookie(page) != cookie)
nfs_readdir_page_unlock_and_put(page); nfs_readdir_page_reinit_array(page, cookie, change_attr);
} return page;
return NULL;
} }
static inline static inline
...@@ -960,9 +967,15 @@ nfs_readdir_page_get_cached(struct nfs_readdir_descriptor *desc) ...@@ -960,9 +967,15 @@ nfs_readdir_page_get_cached(struct nfs_readdir_descriptor *desc)
{ {
struct address_space *mapping = desc->file->f_mapping; struct address_space *mapping = desc->file->f_mapping;
u64 change_attr = inode_peek_iversion_raw(mapping->host); u64 change_attr = inode_peek_iversion_raw(mapping->host);
u64 cookie = desc->last_cookie;
struct page *page;
return nfs_readdir_page_get_locked(mapping, desc->last_cookie, page = nfs_readdir_page_get_locked(mapping, cookie, change_attr);
change_attr); if (!page)
return NULL;
if (desc->clear_cache && !nfs_readdir_page_needs_filling(page))
nfs_readdir_page_reinit_array(page, cookie, change_attr);
return page;
} }
/* /*
...@@ -1013,6 +1026,7 @@ static int find_and_lock_cache_page(struct nfs_readdir_descriptor *desc) ...@@ -1013,6 +1026,7 @@ static int find_and_lock_cache_page(struct nfs_readdir_descriptor *desc)
trace_nfs_readdir_invalidate_cache_range( trace_nfs_readdir_invalidate_cache_range(
inode, 1, MAX_LFS_FILESIZE); inode, 1, MAX_LFS_FILESIZE);
} }
desc->clear_cache = false;
} }
res = nfs_readdir_search_array(desc); res = nfs_readdir_search_array(desc);
if (res == 0) if (res == 0)
...@@ -1147,16 +1161,17 @@ static int uncached_readdir(struct nfs_readdir_descriptor *desc) ...@@ -1147,16 +1161,17 @@ static int uncached_readdir(struct nfs_readdir_descriptor *desc)
#define NFS_READDIR_CACHE_MISS_THRESHOLD (16UL) #define NFS_READDIR_CACHE_MISS_THRESHOLD (16UL)
static void nfs_readdir_handle_cache_misses(struct inode *inode, static bool nfs_readdir_handle_cache_misses(struct inode *inode,
struct nfs_readdir_descriptor *desc, struct nfs_readdir_descriptor *desc,
unsigned int cache_misses) unsigned int cache_misses,
bool force_clear)
{ {
if (desc->ctx->pos == 0 || if (desc->ctx->pos == 0 || !desc->plus)
cache_misses <= NFS_READDIR_CACHE_MISS_THRESHOLD) return false;
return; if (cache_misses <= NFS_READDIR_CACHE_MISS_THRESHOLD && !force_clear)
if (invalidate_mapping_pages(inode->i_mapping, 0, -1) == 0) return false;
return; trace_nfs_readdir_force_readdirplus(inode);
trace_nfs_readdir_invalidate_cache_range(inode, 0, MAX_LFS_FILESIZE); return true;
} }
/* The file offset position represents the dirent entry number. A /* The file offset position represents the dirent entry number. A
...@@ -1171,6 +1186,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx) ...@@ -1171,6 +1186,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
struct nfs_open_dir_context *dir_ctx = file->private_data; struct nfs_open_dir_context *dir_ctx = file->private_data;
struct nfs_readdir_descriptor *desc; struct nfs_readdir_descriptor *desc;
unsigned int cache_hits, cache_misses; unsigned int cache_hits, cache_misses;
bool force_clear;
int res; int res;
dfprintk(FILE, "NFS: readdir(%pD2) starting at cookie %llu\n", dfprintk(FILE, "NFS: readdir(%pD2) starting at cookie %llu\n",
...@@ -1203,6 +1219,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx) ...@@ -1203,6 +1219,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
memcpy(desc->verf, dir_ctx->verf, sizeof(desc->verf)); memcpy(desc->verf, dir_ctx->verf, sizeof(desc->verf));
cache_hits = atomic_xchg(&dir_ctx->cache_hits, 0); cache_hits = atomic_xchg(&dir_ctx->cache_hits, 0);
cache_misses = atomic_xchg(&dir_ctx->cache_misses, 0); cache_misses = atomic_xchg(&dir_ctx->cache_misses, 0);
force_clear = dir_ctx->force_clear;
spin_unlock(&file->f_lock); spin_unlock(&file->f_lock);
if (desc->eof) { if (desc->eof) {
...@@ -1211,7 +1228,9 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx) ...@@ -1211,7 +1228,9 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
} }
desc->plus = nfs_use_readdirplus(inode, ctx, cache_hits, cache_misses); desc->plus = nfs_use_readdirplus(inode, ctx, cache_hits, cache_misses);
nfs_readdir_handle_cache_misses(inode, desc, cache_misses); force_clear = nfs_readdir_handle_cache_misses(inode, desc, cache_misses,
force_clear);
desc->clear_cache = force_clear;
do { do {
res = readdir_search_pagecache(desc); res = readdir_search_pagecache(desc);
...@@ -1240,6 +1259,8 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx) ...@@ -1240,6 +1259,8 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
nfs_do_filldir(desc, nfsi->cookieverf); nfs_do_filldir(desc, nfsi->cookieverf);
nfs_readdir_page_unlock_and_put_cached(desc); nfs_readdir_page_unlock_and_put_cached(desc);
if (desc->page_index == desc->page_index_max)
desc->clear_cache = force_clear;
} while (!desc->eob && !desc->eof); } while (!desc->eob && !desc->eof);
spin_lock(&file->f_lock); spin_lock(&file->f_lock);
...@@ -1247,6 +1268,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx) ...@@ -1247,6 +1268,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
dir_ctx->last_cookie = desc->last_cookie; dir_ctx->last_cookie = desc->last_cookie;
dir_ctx->attr_gencount = desc->attr_gencount; dir_ctx->attr_gencount = desc->attr_gencount;
dir_ctx->page_index = desc->page_index; dir_ctx->page_index = desc->page_index;
dir_ctx->force_clear = force_clear;
dir_ctx->eof = desc->eof; dir_ctx->eof = desc->eof;
dir_ctx->dtsize = desc->dtsize; dir_ctx->dtsize = desc->dtsize;
memcpy(dir_ctx->verf, desc->verf, sizeof(dir_ctx->verf)); memcpy(dir_ctx->verf, desc->verf, sizeof(dir_ctx->verf));
......
...@@ -160,6 +160,7 @@ DEFINE_NFS_INODE_EVENT(nfs_fsync_enter); ...@@ -160,6 +160,7 @@ DEFINE_NFS_INODE_EVENT(nfs_fsync_enter);
DEFINE_NFS_INODE_EVENT_DONE(nfs_fsync_exit); DEFINE_NFS_INODE_EVENT_DONE(nfs_fsync_exit);
DEFINE_NFS_INODE_EVENT(nfs_access_enter); DEFINE_NFS_INODE_EVENT(nfs_access_enter);
DEFINE_NFS_INODE_EVENT_DONE(nfs_set_cache_invalid); DEFINE_NFS_INODE_EVENT_DONE(nfs_set_cache_invalid);
DEFINE_NFS_INODE_EVENT(nfs_readdir_force_readdirplus);
DEFINE_NFS_INODE_EVENT_DONE(nfs_readdir_cache_fill_done); DEFINE_NFS_INODE_EVENT_DONE(nfs_readdir_cache_fill_done);
DEFINE_NFS_INODE_EVENT_DONE(nfs_readdir_uncached_done); DEFINE_NFS_INODE_EVENT_DONE(nfs_readdir_uncached_done);
......
...@@ -109,6 +109,7 @@ struct nfs_open_dir_context { ...@@ -109,6 +109,7 @@ struct nfs_open_dir_context {
__u64 last_cookie; __u64 last_cookie;
pgoff_t page_index; pgoff_t page_index;
unsigned int dtsize; unsigned int dtsize;
bool force_clear;
bool eof; bool eof;
struct rcu_head rcu_head; struct rcu_head rcu_head;
}; };
......
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