Commit fd88e181 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nfs-for-6.10-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs

Pull NFS client fixes from Trond Myklebust:
 "Bugfixes:
   - NFSv4.2: Fix a memory leak in nfs4_set_security_label
   - NFSv2/v3: abort nfs_atomic_open_v23 if the name is too long.
   - NFS: Add appropriate memory barriers to the sillyrename code
   - Propagate readlink errors in nfs_symlink_filler
   - NFS: don't invalidate dentries on transient errors
   - NFS: fix unnecessary synchronous writes in random write workloads
   - NFSv4.1: enforce rootpath check when deciding whether or not to trunk

  Other:
   - Change email address for Trond Myklebust due to email server concerns"

* tag 'nfs-for-6.10-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  NFS: add barriers when testing for NFS_FSDATA_BLOCKED
  SUNRPC: return proper error from gss_wrap_req_priv
  NFSv4.1 enforce rootpath check in fs_location query
  NFS: abort nfs_atomic_open_v23 if name is too long.
  nfs: don't invalidate dentries on transient errors
  nfs: Avoid flushing many pages with NFS_FILE_SYNC
  nfs: propagate readlink errors in nfs_symlink_filler
  MAINTAINERS: Change email address for Trond Myklebust
  NFSv4: Fix memory leak in nfs4_set_security_label
parents 3572597c 99bc9f2e
......@@ -15825,7 +15825,7 @@ F: drivers/nfc/virtual_ncidev.c
F: tools/testing/selftests/nci/
NFS, SUNRPC, AND LOCKD CLIENTS
M: Trond Myklebust <trond.myklebust@hammerspace.com>
M: Trond Myklebust <trondmy@kernel.org>
M: Anna Schumaker <anna@kernel.org>
L: linux-nfs@vger.kernel.org
S: Maintained
......
......@@ -1627,7 +1627,16 @@ nfs_lookup_revalidate_done(struct inode *dir, struct dentry *dentry,
switch (error) {
case 1:
break;
case 0:
case -ETIMEDOUT:
if (inode && (IS_ROOT(dentry) ||
NFS_SERVER(inode)->flags & NFS_MOUNT_SOFTREVAL))
error = 1;
break;
case -ESTALE:
case -ENOENT:
error = 0;
fallthrough;
default:
/*
* We can't d_drop the root of a disconnected tree:
* its d_hash is on the s_anon list and d_drop() would hide
......@@ -1682,18 +1691,8 @@ static int nfs_lookup_revalidate_dentry(struct inode *dir,
dir_verifier = nfs_save_change_attribute(dir);
ret = NFS_PROTO(dir)->lookup(dir, dentry, fhandle, fattr);
if (ret < 0) {
switch (ret) {
case -ESTALE:
case -ENOENT:
ret = 0;
break;
case -ETIMEDOUT:
if (NFS_SERVER(inode)->flags & NFS_MOUNT_SOFTREVAL)
ret = 1;
}
if (ret < 0)
goto out;
}
/* Request help from readdirplus */
nfs_lookup_advise_force_readdirplus(dir, flags);
......@@ -1737,7 +1736,7 @@ nfs_do_lookup_revalidate(struct inode *dir, struct dentry *dentry,
unsigned int flags)
{
struct inode *inode;
int error;
int error = 0;
nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE);
inode = d_inode(dentry);
......@@ -1782,7 +1781,7 @@ nfs_do_lookup_revalidate(struct inode *dir, struct dentry *dentry,
out_bad:
if (flags & LOOKUP_RCU)
return -ECHILD;
return nfs_lookup_revalidate_done(dir, dentry, inode, 0);
return nfs_lookup_revalidate_done(dir, dentry, inode, error);
}
static int
......@@ -1804,9 +1803,10 @@ __nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags,
if (parent != READ_ONCE(dentry->d_parent))
return -ECHILD;
} else {
/* Wait for unlink to complete */
/* Wait for unlink to complete - see unblock_revalidate() */
wait_var_event(&dentry->d_fsdata,
dentry->d_fsdata != NFS_FSDATA_BLOCKED);
smp_load_acquire(&dentry->d_fsdata)
!= NFS_FSDATA_BLOCKED);
parent = dget_parent(dentry);
ret = reval(d_inode(parent), dentry, flags);
dput(parent);
......@@ -1819,6 +1819,29 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
return __nfs_lookup_revalidate(dentry, flags, nfs_do_lookup_revalidate);
}
static void block_revalidate(struct dentry *dentry)
{
/* old devname - just in case */
kfree(dentry->d_fsdata);
/* Any new reference that could lead to an open
* will take ->d_lock in lookup_open() -> d_lookup().
* Holding this lock ensures we cannot race with
* __nfs_lookup_revalidate() and removes and need
* for further barriers.
*/
lockdep_assert_held(&dentry->d_lock);
dentry->d_fsdata = NFS_FSDATA_BLOCKED;
}
static void unblock_revalidate(struct dentry *dentry)
{
/* store_release ensures wait_var_event() sees the update */
smp_store_release(&dentry->d_fsdata, NULL);
wake_up_var(&dentry->d_fsdata);
}
/*
* A weaker form of d_revalidate for revalidating just the d_inode(dentry)
* when we don't really care about the dentry name. This is called when a
......@@ -2255,6 +2278,9 @@ int nfs_atomic_open_v23(struct inode *dir, struct dentry *dentry,
*/
int error = 0;
if (dentry->d_name.len > NFS_SERVER(dir)->namelen)
return -ENAMETOOLONG;
if (open_flags & O_CREAT) {
file->f_mode |= FMODE_CREATED;
error = nfs_do_create(dir, dentry, mode, open_flags);
......@@ -2549,15 +2575,12 @@ int nfs_unlink(struct inode *dir, struct dentry *dentry)
spin_unlock(&dentry->d_lock);
goto out;
}
/* old devname */
kfree(dentry->d_fsdata);
dentry->d_fsdata = NFS_FSDATA_BLOCKED;
block_revalidate(dentry);
spin_unlock(&dentry->d_lock);
error = nfs_safe_remove(dentry);
nfs_dentry_remove_handle_error(dir, dentry, error);
dentry->d_fsdata = NULL;
wake_up_var(&dentry->d_fsdata);
unblock_revalidate(dentry);
out:
trace_nfs_unlink_exit(dir, dentry, error);
return error;
......@@ -2664,8 +2687,7 @@ nfs_unblock_rename(struct rpc_task *task, struct nfs_renamedata *data)
{
struct dentry *new_dentry = data->new_dentry;
new_dentry->d_fsdata = NULL;
wake_up_var(&new_dentry->d_fsdata);
unblock_revalidate(new_dentry);
}
/*
......@@ -2727,11 +2749,6 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
if (WARN_ON(new_dentry->d_flags & DCACHE_NFSFS_RENAMED) ||
WARN_ON(new_dentry->d_fsdata == NFS_FSDATA_BLOCKED))
goto out;
if (new_dentry->d_fsdata) {
/* old devname */
kfree(new_dentry->d_fsdata);
new_dentry->d_fsdata = NULL;
}
spin_lock(&new_dentry->d_lock);
if (d_count(new_dentry) > 2) {
......@@ -2753,7 +2770,7 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
new_dentry = dentry;
new_inode = NULL;
} else {
new_dentry->d_fsdata = NFS_FSDATA_BLOCKED;
block_revalidate(new_dentry);
must_unblock = true;
spin_unlock(&new_dentry->d_lock);
}
......@@ -2765,6 +2782,8 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry,
must_unblock ? nfs_unblock_rename : NULL);
if (IS_ERR(task)) {
if (must_unblock)
unblock_revalidate(new_dentry);
error = PTR_ERR(task);
goto out;
}
......
......@@ -4023,6 +4023,23 @@ static void test_fs_location_for_trunking(struct nfs4_fs_location *location,
}
}
static bool _is_same_nfs4_pathname(struct nfs4_pathname *path1,
struct nfs4_pathname *path2)
{
int i;
if (path1->ncomponents != path2->ncomponents)
return false;
for (i = 0; i < path1->ncomponents; i++) {
if (path1->components[i].len != path2->components[i].len)
return false;
if (memcmp(path1->components[i].data, path2->components[i].data,
path1->components[i].len))
return false;
}
return true;
}
static int _nfs4_discover_trunking(struct nfs_server *server,
struct nfs_fh *fhandle)
{
......@@ -4056,9 +4073,13 @@ static int _nfs4_discover_trunking(struct nfs_server *server,
if (status)
goto out_free_3;
for (i = 0; i < locations->nlocations; i++)
for (i = 0; i < locations->nlocations; i++) {
if (!_is_same_nfs4_pathname(&locations->fs_path,
&locations->locations[i].rootpath))
continue;
test_fs_location_for_trunking(&locations->locations[i], clp,
server);
}
out_free_3:
kfree(locations->fattr);
out_free_2:
......@@ -6268,6 +6289,7 @@ nfs4_set_security_label(struct inode *inode, const void *buf, size_t buflen)
if (status == 0)
nfs_setsecurity(inode, fattr);
nfs_free_fattr(fattr);
return status;
}
#endif /* CONFIG_NFS_V4_SECURITY_LABEL */
......
......@@ -1545,6 +1545,11 @@ void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index)
continue;
} else if (index == prev->wb_index + 1)
continue;
/*
* We will submit more requests after these. Indicate
* this to the underlying layers.
*/
desc->pg_moreio = 1;
nfs_pageio_complete(desc);
break;
}
......
......@@ -41,7 +41,7 @@ static int nfs_symlink_filler(struct file *file, struct folio *folio)
error:
folio_set_error(folio);
folio_unlock(folio);
return -EIO;
return error;
}
static const char *nfs_get_link(struct dentry *dentry,
......
......@@ -1875,8 +1875,10 @@ gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base;
maj_stat = gss_wrap(ctx->gc_gss_ctx, offset, snd_buf, inpages);
/* slack space should prevent this ever happening: */
if (unlikely(snd_buf->len > snd_buf->buflen))
if (unlikely(snd_buf->len > snd_buf->buflen)) {
status = -EIO;
goto wrap_failed;
}
/* We're assuming that when GSS_S_CONTEXT_EXPIRED, the encryption was
* done anyway, so it's safe to put the request on the wire: */
if (maj_stat == GSS_S_CONTEXT_EXPIRED)
......
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