Merge tag 'nfs-for-5.7-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client updates from Trond Myklebust: "Highlights include: Stable fixes: - Fix a page leak in nfs_destroy_unlinked_subrequests() - Fix use-after-free issues in nfs_pageio_add_request() - Fix new mount code constant_table array definitions - finish_automount() requires us to hold 2 refs to the mount record Features: - Improve the accuracy of telldir/seekdir by using 64-bit cookies when possible. - Allow one RDMA active connection and several zombie connections to prevent blocking if the remote server is unresponsive. - Limit the size of the NFS access cache by default - Reduce the number of references to credentials that are taken by NFS - pNFS files and flexfiles drivers now support per-layout segment COMMIT lists. - Enable partial-file layout segments in the pNFS/flexfiles driver. - Add support for CB_RECALL_ANY to the pNFS flexfiles layout type - pNFS/flexfiles Report NFS4ERR_DELAY and NFS4ERR_GRACE errors from the DS using the layouterror mechanism. Bugfixes and cleanups: - SUNRPC: Fix krb5p regressions - Don't specify NFS version in "UDP not supported" error - nfsroot: set tcp as the default transport protocol - pnfs: Return valid stateids in nfs_layout_find_inode_by_stateid() - alloc_nfs_open_context() must use the file cred when available - Fix locking when dereferencing the delegation cred - Fix memory leaks in O_DIRECT when nfs_get_lock_context() fails - Various clean ups of the NFS O_DIRECT commit code - Clean up RDMA connect/disconnect - Replace zero-length arrays with C99-style flexible arrays" * tag 'nfs-for-5.7-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (86 commits) NFS: Clean up process of marking inode stale. SUNRPC: Don't start a timer on an already queued rpc task NFS/pnfs: Reference the layout cred in pnfs_prepare_layoutreturn() NFS/pnfs: Fix dereference of layout cred in pnfs_layoutcommit_inode() NFS: Beware when dereferencing the delegation cred NFS: Add a module parameter to set nfs_mountpoint_expiry_timeout NFS: finish_automount() requires us to hold 2 refs to the mount record NFS: Fix a few constant_table array definitions NFS: Try to join page groups before an O_DIRECT retransmission NFS: Refactor nfs_lock_and_join_requests() NFS: Reverse the submission order of requests in __nfs_pageio_add_request() NFS: Clean up nfs_lock_and_join_requests() NFS: Remove the redundant function nfs_pgio_has_mirroring() NFS: Fix memory leaks in nfs_pageio_stop_mirroring() NFS: Fix a request reference leak in nfs_direct_write_clear_reqs() NFS: Fix use-after-free issues in nfs_pageio_add_request() NFS: Fix races nfs_page_group_destroy() vs nfs_destroy_unlinked_subrequests() NFS: Fix a page leak in nfs_destroy_unlinked_subrequests() NFS: Remove unused FLUSH_SYNC support in nfs_initiate_pgio() pNFS/flexfiles: Specify the layout segment range in LAYOUTGET ...
This commit is contained in:
79
fs/nfs/dir.c
79
fs/nfs/dir.c
@@ -141,10 +141,9 @@ struct nfs_cache_array {
|
||||
int size;
|
||||
int eof_index;
|
||||
u64 last_cookie;
|
||||
struct nfs_cache_array_entry array[0];
|
||||
struct nfs_cache_array_entry array[];
|
||||
};
|
||||
|
||||
typedef int (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, bool);
|
||||
typedef struct {
|
||||
struct file *file;
|
||||
struct page *page;
|
||||
@@ -153,7 +152,7 @@ typedef struct {
|
||||
u64 *dir_cookie;
|
||||
u64 last_cookie;
|
||||
loff_t current_index;
|
||||
decode_dirent_t decode;
|
||||
loff_t prev_index;
|
||||
|
||||
unsigned long dir_verifier;
|
||||
unsigned long timestamp;
|
||||
@@ -240,6 +239,25 @@ out:
|
||||
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
|
||||
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
|
||||
!nfs_readdir_inode_mapping_valid(nfsi)) {
|
||||
ctx->duped = 0;
|
||||
ctx->attr_gencount = nfsi->attr_gencount;
|
||||
} else if (new_pos < desc->ctx->pos) {
|
||||
} else if (new_pos < desc->prev_index) {
|
||||
if (ctx->duped > 0
|
||||
&& ctx->dup_cookie == *desc->dir_cookie) {
|
||||
if (printk_ratelimit()) {
|
||||
@@ -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->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;
|
||||
return 0;
|
||||
}
|
||||
@@ -376,9 +398,10 @@ error:
|
||||
static int xdr_decode(nfs_readdir_descriptor_t *desc,
|
||||
struct nfs_entry *entry, struct xdr_stream *xdr)
|
||||
{
|
||||
struct inode *inode = file_inode(desc->file);
|
||||
int error;
|
||||
|
||||
error = desc->decode(xdr, entry, desc->plus);
|
||||
error = NFS_PROTO(inode)->decode_dirent(xdr, entry, desc->plus);
|
||||
if (error)
|
||||
return error;
|
||||
entry->fattr->time_start = desc->timestamp;
|
||||
@@ -756,6 +779,7 @@ int readdir_search_pagecache(nfs_readdir_descriptor_t *desc)
|
||||
|
||||
if (desc->page_index == 0) {
|
||||
desc->current_index = 0;
|
||||
desc->prev_index = 0;
|
||||
desc->last_cookie = 0;
|
||||
}
|
||||
do {
|
||||
@@ -786,11 +810,14 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc)
|
||||
desc->eof = true;
|
||||
break;
|
||||
}
|
||||
desc->ctx->pos++;
|
||||
if (i < (array->size-1))
|
||||
*desc->dir_cookie = array->array[i+1].cookie;
|
||||
else
|
||||
*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)
|
||||
ctx->duped = 1;
|
||||
}
|
||||
@@ -860,9 +887,14 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
|
||||
{
|
||||
struct dentry *dentry = file_dentry(file);
|
||||
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;
|
||||
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;
|
||||
|
||||
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)
|
||||
* to either find the entry with the appropriate number or
|
||||
* 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))
|
||||
res = nfs_revalidate_mapping(inode, file->f_mapping);
|
||||
if (res < 0)
|
||||
@@ -954,7 +978,10 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int whence)
|
||||
}
|
||||
if (offset != filp->f_pos) {
|
||||
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;
|
||||
}
|
||||
inode_unlock(inode);
|
||||
@@ -2282,7 +2309,7 @@ static DEFINE_SPINLOCK(nfs_access_lru_lock);
|
||||
static LIST_HEAD(nfs_access_lru_list);
|
||||
static atomic_long_t nfs_access_nr_entries;
|
||||
|
||||
static unsigned long nfs_access_max_cachesize = ULONG_MAX;
|
||||
static unsigned long nfs_access_max_cachesize = 4*1024*1024;
|
||||
module_param(nfs_access_max_cachesize, ulong, 0644);
|
||||
MODULE_PARM_DESC(nfs_access_max_cachesize, "NFS access maximum total cache length");
|
||||
|
||||
@@ -2642,9 +2669,10 @@ static int nfs_do_access(struct inode *inode, const struct cred *cred, int mask)
|
||||
status = NFS_PROTO(inode)->access(inode, &cache);
|
||||
if (status != 0) {
|
||||
if (status == -ESTALE) {
|
||||
nfs_zap_caches(inode);
|
||||
if (!S_ISDIR(inode->i_mode))
|
||||
set_bit(NFS_INO_STALE, &NFS_I(inode)->flags);
|
||||
nfs_set_inode_stale(inode);
|
||||
else
|
||||
nfs_zap_caches(inode);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
@@ -2732,14 +2760,7 @@ force_lookup:
|
||||
if (!NFS_PROTO(inode)->access)
|
||||
goto out_notsup;
|
||||
|
||||
/* Always try fast lookups first */
|
||||
rcu_read_lock();
|
||||
res = nfs_do_access(inode, cred, mask|MAY_NOT_BLOCK);
|
||||
rcu_read_unlock();
|
||||
if (res == -ECHILD && !(mask & MAY_NOT_BLOCK)) {
|
||||
/* Fast lookup failed, try the slow way */
|
||||
res = nfs_do_access(inode, cred, mask);
|
||||
}
|
||||
res = nfs_do_access(inode, cred, mask);
|
||||
out:
|
||||
if (!res && (mask & MAY_EXEC))
|
||||
res = nfs_execute_ok(inode, mask);
|
||||
|
Reference in New Issue
Block a user