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 ...@@ -15825,7 +15825,7 @@ F: drivers/nfc/virtual_ncidev.c
F: tools/testing/selftests/nci/ F: tools/testing/selftests/nci/
NFS, SUNRPC, AND LOCKD CLIENTS NFS, SUNRPC, AND LOCKD CLIENTS
M: Trond Myklebust <trond.myklebust@hammerspace.com> M: Trond Myklebust <trondmy@kernel.org>
M: Anna Schumaker <anna@kernel.org> M: Anna Schumaker <anna@kernel.org>
L: linux-nfs@vger.kernel.org L: linux-nfs@vger.kernel.org
S: Maintained S: Maintained
......
...@@ -1627,7 +1627,16 @@ nfs_lookup_revalidate_done(struct inode *dir, struct dentry *dentry, ...@@ -1627,7 +1627,16 @@ nfs_lookup_revalidate_done(struct inode *dir, struct dentry *dentry,
switch (error) { switch (error) {
case 1: case 1:
break; 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: * 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 * 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, ...@@ -1682,18 +1691,8 @@ static int nfs_lookup_revalidate_dentry(struct inode *dir,
dir_verifier = nfs_save_change_attribute(dir); dir_verifier = nfs_save_change_attribute(dir);
ret = NFS_PROTO(dir)->lookup(dir, dentry, fhandle, fattr); ret = NFS_PROTO(dir)->lookup(dir, dentry, fhandle, fattr);
if (ret < 0) { if (ret < 0)
switch (ret) {
case -ESTALE:
case -ENOENT:
ret = 0;
break;
case -ETIMEDOUT:
if (NFS_SERVER(inode)->flags & NFS_MOUNT_SOFTREVAL)
ret = 1;
}
goto out; goto out;
}
/* Request help from readdirplus */ /* Request help from readdirplus */
nfs_lookup_advise_force_readdirplus(dir, flags); nfs_lookup_advise_force_readdirplus(dir, flags);
...@@ -1737,7 +1736,7 @@ nfs_do_lookup_revalidate(struct inode *dir, struct dentry *dentry, ...@@ -1737,7 +1736,7 @@ nfs_do_lookup_revalidate(struct inode *dir, struct dentry *dentry,
unsigned int flags) unsigned int flags)
{ {
struct inode *inode; struct inode *inode;
int error; int error = 0;
nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE); nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE);
inode = d_inode(dentry); inode = d_inode(dentry);
...@@ -1782,7 +1781,7 @@ nfs_do_lookup_revalidate(struct inode *dir, struct dentry *dentry, ...@@ -1782,7 +1781,7 @@ nfs_do_lookup_revalidate(struct inode *dir, struct dentry *dentry,
out_bad: out_bad:
if (flags & LOOKUP_RCU) if (flags & LOOKUP_RCU)
return -ECHILD; return -ECHILD;
return nfs_lookup_revalidate_done(dir, dentry, inode, 0); return nfs_lookup_revalidate_done(dir, dentry, inode, error);
} }
static int static int
...@@ -1804,9 +1803,10 @@ __nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags, ...@@ -1804,9 +1803,10 @@ __nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags,
if (parent != READ_ONCE(dentry->d_parent)) if (parent != READ_ONCE(dentry->d_parent))
return -ECHILD; return -ECHILD;
} else { } else {
/* Wait for unlink to complete */ /* Wait for unlink to complete - see unblock_revalidate() */
wait_var_event(&dentry->d_fsdata, 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); parent = dget_parent(dentry);
ret = reval(d_inode(parent), dentry, flags); ret = reval(d_inode(parent), dentry, flags);
dput(parent); dput(parent);
...@@ -1819,6 +1819,29 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags) ...@@ -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); 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) * 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 * 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, ...@@ -2255,6 +2278,9 @@ int nfs_atomic_open_v23(struct inode *dir, struct dentry *dentry,
*/ */
int error = 0; int error = 0;
if (dentry->d_name.len > NFS_SERVER(dir)->namelen)
return -ENAMETOOLONG;
if (open_flags & O_CREAT) { if (open_flags & O_CREAT) {
file->f_mode |= FMODE_CREATED; file->f_mode |= FMODE_CREATED;
error = nfs_do_create(dir, dentry, mode, open_flags); error = nfs_do_create(dir, dentry, mode, open_flags);
...@@ -2549,15 +2575,12 @@ int nfs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -2549,15 +2575,12 @@ int nfs_unlink(struct inode *dir, struct dentry *dentry)
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
goto out; goto out;
} }
/* old devname */ block_revalidate(dentry);
kfree(dentry->d_fsdata);
dentry->d_fsdata = NFS_FSDATA_BLOCKED;
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
error = nfs_safe_remove(dentry); error = nfs_safe_remove(dentry);
nfs_dentry_remove_handle_error(dir, dentry, error); nfs_dentry_remove_handle_error(dir, dentry, error);
dentry->d_fsdata = NULL; unblock_revalidate(dentry);
wake_up_var(&dentry->d_fsdata);
out: out:
trace_nfs_unlink_exit(dir, dentry, error); trace_nfs_unlink_exit(dir, dentry, error);
return error; return error;
...@@ -2664,8 +2687,7 @@ nfs_unblock_rename(struct rpc_task *task, struct nfs_renamedata *data) ...@@ -2664,8 +2687,7 @@ nfs_unblock_rename(struct rpc_task *task, struct nfs_renamedata *data)
{ {
struct dentry *new_dentry = data->new_dentry; struct dentry *new_dentry = data->new_dentry;
new_dentry->d_fsdata = NULL; unblock_revalidate(new_dentry);
wake_up_var(&new_dentry->d_fsdata);
} }
/* /*
...@@ -2727,11 +2749,6 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir, ...@@ -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) || if (WARN_ON(new_dentry->d_flags & DCACHE_NFSFS_RENAMED) ||
WARN_ON(new_dentry->d_fsdata == NFS_FSDATA_BLOCKED)) WARN_ON(new_dentry->d_fsdata == NFS_FSDATA_BLOCKED))
goto out; 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); spin_lock(&new_dentry->d_lock);
if (d_count(new_dentry) > 2) { if (d_count(new_dentry) > 2) {
...@@ -2753,7 +2770,7 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir, ...@@ -2753,7 +2770,7 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
new_dentry = dentry; new_dentry = dentry;
new_inode = NULL; new_inode = NULL;
} else { } else {
new_dentry->d_fsdata = NFS_FSDATA_BLOCKED; block_revalidate(new_dentry);
must_unblock = true; must_unblock = true;
spin_unlock(&new_dentry->d_lock); spin_unlock(&new_dentry->d_lock);
} }
...@@ -2765,6 +2782,8 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir, ...@@ -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, task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry,
must_unblock ? nfs_unblock_rename : NULL); must_unblock ? nfs_unblock_rename : NULL);
if (IS_ERR(task)) { if (IS_ERR(task)) {
if (must_unblock)
unblock_revalidate(new_dentry);
error = PTR_ERR(task); error = PTR_ERR(task);
goto out; goto out;
} }
......
...@@ -4023,6 +4023,23 @@ static void test_fs_location_for_trunking(struct nfs4_fs_location *location, ...@@ -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, static int _nfs4_discover_trunking(struct nfs_server *server,
struct nfs_fh *fhandle) struct nfs_fh *fhandle)
{ {
...@@ -4056,9 +4073,13 @@ static int _nfs4_discover_trunking(struct nfs_server *server, ...@@ -4056,9 +4073,13 @@ static int _nfs4_discover_trunking(struct nfs_server *server,
if (status) if (status)
goto out_free_3; 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, test_fs_location_for_trunking(&locations->locations[i], clp,
server); server);
}
out_free_3: out_free_3:
kfree(locations->fattr); kfree(locations->fattr);
out_free_2: out_free_2:
...@@ -6268,6 +6289,7 @@ nfs4_set_security_label(struct inode *inode, const void *buf, size_t buflen) ...@@ -6268,6 +6289,7 @@ nfs4_set_security_label(struct inode *inode, const void *buf, size_t buflen)
if (status == 0) if (status == 0)
nfs_setsecurity(inode, fattr); nfs_setsecurity(inode, fattr);
nfs_free_fattr(fattr);
return status; return status;
} }
#endif /* CONFIG_NFS_V4_SECURITY_LABEL */ #endif /* CONFIG_NFS_V4_SECURITY_LABEL */
......
...@@ -1545,6 +1545,11 @@ void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index) ...@@ -1545,6 +1545,11 @@ void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index)
continue; continue;
} else if (index == prev->wb_index + 1) } else if (index == prev->wb_index + 1)
continue; continue;
/*
* We will submit more requests after these. Indicate
* this to the underlying layers.
*/
desc->pg_moreio = 1;
nfs_pageio_complete(desc); nfs_pageio_complete(desc);
break; break;
} }
......
...@@ -41,7 +41,7 @@ static int nfs_symlink_filler(struct file *file, struct folio *folio) ...@@ -41,7 +41,7 @@ static int nfs_symlink_filler(struct file *file, struct folio *folio)
error: error:
folio_set_error(folio); folio_set_error(folio);
folio_unlock(folio); folio_unlock(folio);
return -EIO; return error;
} }
static const char *nfs_get_link(struct dentry *dentry, 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, ...@@ -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; offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base;
maj_stat = gss_wrap(ctx->gc_gss_ctx, offset, snd_buf, inpages); maj_stat = gss_wrap(ctx->gc_gss_ctx, offset, snd_buf, inpages);
/* slack space should prevent this ever happening: */ /* 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; goto wrap_failed;
}
/* We're assuming that when GSS_S_CONTEXT_EXPIRED, the encryption was /* 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: */ * done anyway, so it's safe to put the request on the wire: */
if (maj_stat == GSS_S_CONTEXT_EXPIRED) 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