Commit 59e356a9 authored by Trond Myklebust's avatar Trond Myklebust

NFS: Use the 64-bit server readdir cookies when possible

When we're running as a 64-bit architecture and are not running in
32-bit compatibility mode, it is better to use the 64-bit readdir
cookies that supplied by the server. Doing so improves the accuracy
of telldir()/seekdir(), particularly when the directory is changing,
for instance, when doing 'rm -rf'.

We still fall back to using the 32-bit offsets on 32-bit architectures
and when in compatibility mode.
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
parent fb33c651
...@@ -144,7 +144,6 @@ struct nfs_cache_array { ...@@ -144,7 +144,6 @@ struct nfs_cache_array {
struct nfs_cache_array_entry array[0]; struct nfs_cache_array_entry array[0];
}; };
typedef int (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, bool);
typedef struct { typedef struct {
struct file *file; struct file *file;
struct page *page; struct page *page;
...@@ -153,7 +152,7 @@ typedef struct { ...@@ -153,7 +152,7 @@ typedef struct {
u64 *dir_cookie; u64 *dir_cookie;
u64 last_cookie; u64 last_cookie;
loff_t current_index; loff_t current_index;
decode_dirent_t decode; loff_t prev_index;
unsigned long dir_verifier; unsigned long dir_verifier;
unsigned long timestamp; unsigned long timestamp;
...@@ -240,6 +239,25 @@ int nfs_readdir_add_to_array(struct nfs_entry *entry, struct page *page) ...@@ -240,6 +239,25 @@ int nfs_readdir_add_to_array(struct nfs_entry *entry, struct page *page)
return ret; return ret;
} }
static inline
int is_32bit_api(void)
{
#ifdef CONFIG_COMPAT
return in_compat_syscall();
#else
return (BITS_PER_LONG == 32);
#endif
}
static
bool nfs_readdir_use_cookie(const struct file *filp)
{
if ((filp->f_mode & FMODE_32BITHASH) ||
(!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
return false;
return true;
}
static static
int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descriptor_t *desc) int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descriptor_t *desc)
{ {
...@@ -289,7 +307,7 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des ...@@ -289,7 +307,7 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des
!nfs_readdir_inode_mapping_valid(nfsi)) { !nfs_readdir_inode_mapping_valid(nfsi)) {
ctx->duped = 0; ctx->duped = 0;
ctx->attr_gencount = nfsi->attr_gencount; ctx->attr_gencount = nfsi->attr_gencount;
} else if (new_pos < desc->ctx->pos) { } else if (new_pos < desc->prev_index) {
if (ctx->duped > 0 if (ctx->duped > 0
&& ctx->dup_cookie == *desc->dir_cookie) { && ctx->dup_cookie == *desc->dir_cookie) {
if (printk_ratelimit()) { if (printk_ratelimit()) {
...@@ -305,7 +323,11 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des ...@@ -305,7 +323,11 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des
ctx->dup_cookie = *desc->dir_cookie; ctx->dup_cookie = *desc->dir_cookie;
ctx->duped = -1; ctx->duped = -1;
} }
desc->ctx->pos = new_pos; if (nfs_readdir_use_cookie(desc->file))
desc->ctx->pos = *desc->dir_cookie;
else
desc->ctx->pos = new_pos;
desc->prev_index = new_pos;
desc->cache_entry_index = i; desc->cache_entry_index = i;
return 0; return 0;
} }
...@@ -376,9 +398,10 @@ int nfs_readdir_xdr_filler(struct page **pages, nfs_readdir_descriptor_t *desc, ...@@ -376,9 +398,10 @@ int nfs_readdir_xdr_filler(struct page **pages, nfs_readdir_descriptor_t *desc,
static int xdr_decode(nfs_readdir_descriptor_t *desc, static int xdr_decode(nfs_readdir_descriptor_t *desc,
struct nfs_entry *entry, struct xdr_stream *xdr) struct nfs_entry *entry, struct xdr_stream *xdr)
{ {
struct inode *inode = file_inode(desc->file);
int error; int error;
error = desc->decode(xdr, entry, desc->plus); error = NFS_PROTO(inode)->decode_dirent(xdr, entry, desc->plus);
if (error) if (error)
return error; return error;
entry->fattr->time_start = desc->timestamp; entry->fattr->time_start = desc->timestamp;
...@@ -756,6 +779,7 @@ int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) ...@@ -756,6 +779,7 @@ int readdir_search_pagecache(nfs_readdir_descriptor_t *desc)
if (desc->page_index == 0) { if (desc->page_index == 0) {
desc->current_index = 0; desc->current_index = 0;
desc->prev_index = 0;
desc->last_cookie = 0; desc->last_cookie = 0;
} }
do { do {
...@@ -786,11 +810,14 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc) ...@@ -786,11 +810,14 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc)
desc->eof = true; desc->eof = true;
break; break;
} }
desc->ctx->pos++;
if (i < (array->size-1)) if (i < (array->size-1))
*desc->dir_cookie = array->array[i+1].cookie; *desc->dir_cookie = array->array[i+1].cookie;
else else
*desc->dir_cookie = array->last_cookie; *desc->dir_cookie = array->last_cookie;
if (nfs_readdir_use_cookie(file))
desc->ctx->pos = *desc->dir_cookie;
else
desc->ctx->pos++;
if (ctx->duped != 0) if (ctx->duped != 0)
ctx->duped = 1; ctx->duped = 1;
} }
...@@ -860,9 +887,14 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx) ...@@ -860,9 +887,14 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
{ {
struct dentry *dentry = file_dentry(file); struct dentry *dentry = file_dentry(file);
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
nfs_readdir_descriptor_t my_desc,
*desc = &my_desc;
struct nfs_open_dir_context *dir_ctx = file->private_data; struct nfs_open_dir_context *dir_ctx = file->private_data;
nfs_readdir_descriptor_t my_desc = {
.file = file,
.ctx = ctx,
.dir_cookie = &dir_ctx->dir_cookie,
.plus = nfs_use_readdirplus(inode, ctx),
},
*desc = &my_desc;
int res = 0; int res = 0;
dfprintk(FILE, "NFS: readdir(%pD2) starting at cookie %llu\n", dfprintk(FILE, "NFS: readdir(%pD2) starting at cookie %llu\n",
...@@ -875,14 +907,6 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx) ...@@ -875,14 +907,6 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
* to either find the entry with the appropriate number or * to either find the entry with the appropriate number or
* revalidate the cookie. * revalidate the cookie.
*/ */
memset(desc, 0, sizeof(*desc));
desc->file = file;
desc->ctx = ctx;
desc->dir_cookie = &dir_ctx->dir_cookie;
desc->decode = NFS_PROTO(inode)->decode_dirent;
desc->plus = nfs_use_readdirplus(inode, ctx);
if (ctx->pos == 0 || nfs_attribute_cache_expired(inode)) if (ctx->pos == 0 || nfs_attribute_cache_expired(inode))
res = nfs_revalidate_mapping(inode, file->f_mapping); res = nfs_revalidate_mapping(inode, file->f_mapping);
if (res < 0) if (res < 0)
...@@ -954,7 +978,10 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int whence) ...@@ -954,7 +978,10 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int whence)
} }
if (offset != filp->f_pos) { if (offset != filp->f_pos) {
filp->f_pos = offset; filp->f_pos = offset;
dir_ctx->dir_cookie = 0; if (nfs_readdir_use_cookie(filp))
dir_ctx->dir_cookie = offset;
else
dir_ctx->dir_cookie = 0;
dir_ctx->duped = 0; dir_ctx->duped = 0;
} }
inode_unlock(inode); inode_unlock(inode);
......
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