Merge tag 'nfs-for-3.15-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client updates from Trond Myklebust: "Highlights include: - Stable fix for a use after free issue in the NFSv4.1 open code - Fix the SUNRPC bi-directional RPC code to account for TCP segmentation - Optimise usage of readdirplus when confronted with 'ls -l' situations - Soft mount bugfixes - NFS over RDMA bugfixes - NFSv4 close locking fixes - Various NFSv4.x client state management optimisations - Rename/unlink code cleanups" * tag 'nfs-for-3.15-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (28 commits) nfs: pass string length to pr_notice message about readdir loops NFSv4: Fix a use-after-free problem in open() SUNRPC: rpc_restart_call/rpc_restart_call_prepare should clear task->tk_status SUNRPC: Don't let rpc_delay() clobber non-timeout errors SUNRPC: Ensure call_connect_status() deals correctly with SOFTCONN tasks SUNRPC: Ensure call_status() deals correctly with SOFTCONN tasks NFSv4: Ensure we respect soft mount timeouts during trunking discovery NFSv4: Schedule recovery if nfs40_walk_client_list() is interrupted NFS: advertise only supported callback netids SUNRPC: remove KERN_INFO from dprintk() call sites SUNRPC: Fix large reads on NFS/RDMA NFS: Clean up: revert increase in READDIR RPC buffer max size SUNRPC: Ensure that call_bind times out correctly SUNRPC: Ensure that call_connect times out correctly nfs: emit a fsnotify_nameremove call in sillyrename codepath nfs: remove synchronous rename code nfs: convert nfs_rename to use async_rename infrastructure nfs: make nfs_async_rename non-static nfs: abstract out code needed to complete a sillyrename NFSv4: Clear the open state flags if the new stateid does not match ...
This commit is contained in:
62
fs/nfs/dir.c
62
fs/nfs/dir.c
@@ -69,21 +69,28 @@ const struct address_space_operations nfs_dir_aops = {
|
||||
|
||||
static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir, struct rpc_cred *cred)
|
||||
{
|
||||
struct nfs_inode *nfsi = NFS_I(dir);
|
||||
struct nfs_open_dir_context *ctx;
|
||||
ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
|
||||
if (ctx != NULL) {
|
||||
ctx->duped = 0;
|
||||
ctx->attr_gencount = NFS_I(dir)->attr_gencount;
|
||||
ctx->attr_gencount = nfsi->attr_gencount;
|
||||
ctx->dir_cookie = 0;
|
||||
ctx->dup_cookie = 0;
|
||||
ctx->cred = get_rpccred(cred);
|
||||
spin_lock(&dir->i_lock);
|
||||
list_add(&ctx->list, &nfsi->open_files);
|
||||
spin_unlock(&dir->i_lock);
|
||||
return ctx;
|
||||
}
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
static void put_nfs_open_dir_context(struct nfs_open_dir_context *ctx)
|
||||
static void put_nfs_open_dir_context(struct inode *dir, struct nfs_open_dir_context *ctx)
|
||||
{
|
||||
spin_lock(&dir->i_lock);
|
||||
list_del(&ctx->list);
|
||||
spin_unlock(&dir->i_lock);
|
||||
put_rpccred(ctx->cred);
|
||||
kfree(ctx);
|
||||
}
|
||||
@@ -126,7 +133,7 @@ out:
|
||||
static int
|
||||
nfs_closedir(struct inode *inode, struct file *filp)
|
||||
{
|
||||
put_nfs_open_dir_context(filp->private_data);
|
||||
put_nfs_open_dir_context(filp->f_path.dentry->d_inode, filp->private_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -306,10 +313,9 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des
|
||||
if (printk_ratelimit()) {
|
||||
pr_notice("NFS: directory %pD2 contains a readdir loop."
|
||||
"Please contact your server vendor. "
|
||||
"The file: %s has duplicate cookie %llu\n",
|
||||
desc->file,
|
||||
array->array[i].string.name,
|
||||
*desc->dir_cookie);
|
||||
"The file: %.*s has duplicate cookie %llu\n",
|
||||
desc->file, array->array[i].string.len,
|
||||
array->array[i].string.name, *desc->dir_cookie);
|
||||
}
|
||||
status = -ELOOP;
|
||||
goto out;
|
||||
@@ -437,6 +443,22 @@ void nfs_advise_use_readdirplus(struct inode *dir)
|
||||
set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(dir)->flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is mainly for use by nfs_getattr().
|
||||
*
|
||||
* If this is an 'ls -l', we want to force use of readdirplus.
|
||||
* Do this by checking if there is an active file descriptor
|
||||
* and calling nfs_advise_use_readdirplus, then forcing a
|
||||
* cache flush.
|
||||
*/
|
||||
void nfs_force_use_readdirplus(struct inode *dir)
|
||||
{
|
||||
if (!list_empty(&NFS_I(dir)->open_files)) {
|
||||
nfs_advise_use_readdirplus(dir);
|
||||
nfs_zap_mapping(dir, dir->i_mapping);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
|
||||
{
|
||||
@@ -815,6 +837,17 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc)
|
||||
goto out;
|
||||
}
|
||||
|
||||
static bool nfs_dir_mapping_need_revalidate(struct inode *dir)
|
||||
{
|
||||
struct nfs_inode *nfsi = NFS_I(dir);
|
||||
|
||||
if (nfs_attribute_cache_expired(dir))
|
||||
return true;
|
||||
if (nfsi->cache_validity & NFS_INO_INVALID_DATA)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* The file offset position represents the dirent entry number. A
|
||||
last cookie cache takes care of the common case of reading the
|
||||
whole directory.
|
||||
@@ -847,7 +880,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
|
||||
desc->plus = nfs_use_readdirplus(inode, ctx) ? 1 : 0;
|
||||
|
||||
nfs_block_sillyrename(dentry);
|
||||
if (ctx->pos == 0 || nfs_attribute_cache_expired(inode))
|
||||
if (ctx->pos == 0 || nfs_dir_mapping_need_revalidate(inode))
|
||||
res = nfs_revalidate_mapping(inode, file->f_mapping);
|
||||
if (res < 0)
|
||||
goto out;
|
||||
@@ -1911,6 +1944,7 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *old_inode = old_dentry->d_inode;
|
||||
struct inode *new_inode = new_dentry->d_inode;
|
||||
struct dentry *dentry = NULL, *rehash = NULL;
|
||||
struct rpc_task *task;
|
||||
int error = -EBUSY;
|
||||
|
||||
dfprintk(VFS, "NFS: rename(%pd2 -> %pd2, ct=%d)\n",
|
||||
@@ -1958,8 +1992,16 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
if (new_inode != NULL)
|
||||
NFS_PROTO(new_inode)->return_delegation(new_inode);
|
||||
|
||||
error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name,
|
||||
new_dir, &new_dentry->d_name);
|
||||
task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry, NULL);
|
||||
if (IS_ERR(task)) {
|
||||
error = PTR_ERR(task);
|
||||
goto out;
|
||||
}
|
||||
|
||||
error = rpc_wait_for_completion_task(task);
|
||||
if (error == 0)
|
||||
error = task->tk_status;
|
||||
rpc_put_task(task);
|
||||
nfs_mark_for_revalidate(old_inode);
|
||||
out:
|
||||
if (rehash)
|
||||
|
Reference in New Issue
Block a user