mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-12 13:55:32 +00:00
NFS client bugfixes for Linux 6.10
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 -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEESQctxSBg8JpV8KqEZwvnipYKAPIFAmZrD7kACgkQZwvnipYK APJo/RAAlg5uU8kTzXCbUbe9LImF5nh+9XFtg6nnQ+rxQqCU17noT0bazghvBcDP N6v4evWJVeZhnqspVZkdMQWeyNEqsew5uPRoC+gy0sh4RdwT+BHsMwLMWtNTzXoc GW7DOJ7LePzxmh0bksIFn6vmsuhxyI7hKkDx8XuG0YjmHQDcl2TeyHLfii7TFIMP hFEVw63ZFb+HKV0oInyP27iiM1HstvZ8MbxLcu1PoA3IaiNUYXUgBViWF2c5P6uY KV7KynUMgkWQc289aaR7QE5Yz2f4vsYF4oD72+Z3v65W+5HunYut/HUnUGgjHPGq dI5EwSgxW5YKoo/kIvto3yF+ppkppl2gUYFlN3+O/IEXwh+FTXBF2b/tUWFkKQPH 7X3YoosWV/WN1eWqa55znF5IzrG5gdR5z6Et1elTmn4xG4hwoC5U5lOP34DohS4Q N/MMxzVcL348j2teN+dFNXM3WkEVaMJudavJ7A7KehZKSTZAuFNHDxsMjvyGBbGI Za1DanWSCWBD8Bawt9hB8z+k4eN7dGfeWUgMHa2zxOowfeq0MYTjAlr1A8SuXADv E+1tjL7CL7HeHReOg0cbP11BxLOlXYiObsbivFcbYGglbWwtPqR4q4+CIA6AuhCF LSpxF/6uKCXUHCuuGdAgZ5nNApHvC+HoUN0gCBcpIALcazLq0TQ= =DeAG -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
fd88e181d8
6 changed files with 81 additions and 33 deletions
|
@ -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
|
||||
|
|
77
fs/nfs/dir.c
77
fs/nfs/dir.c
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue