release 6.14.2
This commit is contained in:
@@ -1,128 +0,0 @@
|
||||
From ae5d3e4f701948dd6241451d41d9dfa0f0f703cd Mon Sep 17 00:00:00 2001
|
||||
From: Olga Kornievskaia <okorniev@redhat.com>
|
||||
Date: Fri, 17 Jan 2025 11:32:58 -0500
|
||||
Subject: nfsd: fix management of listener transports
|
||||
|
||||
Currently, when no active threads are running, a root user using nfsdctl
|
||||
command can try to remove a particular listener from the list of previously
|
||||
added ones, then start the server by increasing the number of threads,
|
||||
it leads to the following problem:
|
||||
|
||||
[ 158.835354] refcount_t: addition on 0; use-after-free.
|
||||
[ 158.835603] WARNING: CPU: 2 PID: 9145 at lib/refcount.c:25 refcount_warn_saturate+0x160/0x1a0
|
||||
[ 158.836017] Modules linked in: rpcrdma rdma_cm iw_cm ib_cm ib_core nfsd auth_rpcgss nfs_acl lockd grace overlay isofs uinput snd_seq_dummy snd_hrtimer nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib nft_reject_inet nf_reject_ipv4 nf_reject_ipv6 nft_reject nft_ct nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 rfkill ip_set nf_tables qrtr sunrpc vfat fat uvcvideo videobuf2_vmalloc videobuf2_memops uvc videobuf2_v4l2 videodev videobuf2_common snd_hda_codec_generic mc e1000e snd_hda_intel snd_intel_dspcfg snd_hda_codec snd_hda_core snd_hwdep snd_seq snd_seq_device snd_pcm snd_timer snd soundcore sg loop dm_multipath dm_mod nfnetlink vsock_loopback vmw_vsock_virtio_transport_common vmw_vsock_vmci_transport vmw_vmci vsock xfs libcrc32c crct10dif_ce ghash_ce vmwgfx sha2_ce sha256_arm64 sr_mod sha1_ce cdrom nvme drm_client_lib drm_ttm_helper ttm nvme_core drm_kms_helper nvme_auth drm fuse
|
||||
[ 158.840093] CPU: 2 UID: 0 PID: 9145 Comm: nfsd Kdump: loaded Tainted: G B W 6.13.0-rc6+ #7
|
||||
[ 158.840624] Tainted: [B]=BAD_PAGE, [W]=WARN
|
||||
[ 158.840802] Hardware name: VMware, Inc. VMware20,1/VBSA, BIOS VMW201.00V.24006586.BA64.2406042154 06/04/2024
|
||||
[ 158.841220] pstate: 61400005 (nZCv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--)
|
||||
[ 158.841563] pc : refcount_warn_saturate+0x160/0x1a0
|
||||
[ 158.841780] lr : refcount_warn_saturate+0x160/0x1a0
|
||||
[ 158.842000] sp : ffff800089be7d80
|
||||
[ 158.842147] x29: ffff800089be7d80 x28: ffff00008e68c148 x27: ffff00008e68c148
|
||||
[ 158.842492] x26: ffff0002e3b5c000 x25: ffff600011cd1829 x24: ffff00008653c010
|
||||
[ 158.842832] x23: ffff00008653c000 x22: 1fffe00011cd1829 x21: ffff00008653c028
|
||||
[ 158.843175] x20: 0000000000000002 x19: ffff00008653c010 x18: 0000000000000000
|
||||
[ 158.843505] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000
|
||||
[ 158.843836] x14: 0000000000000000 x13: 0000000000000001 x12: ffff600050a26493
|
||||
[ 158.844143] x11: 1fffe00050a26492 x10: ffff600050a26492 x9 : dfff800000000000
|
||||
[ 158.844475] x8 : 00009fffaf5d9b6e x7 : ffff000285132493 x6 : 0000000000000001
|
||||
[ 158.844823] x5 : ffff000285132490 x4 : ffff600050a26493 x3 : ffff8000805e72bc
|
||||
[ 158.845174] x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffff000098588000
|
||||
[ 158.845528] Call trace:
|
||||
[ 158.845658] refcount_warn_saturate+0x160/0x1a0 (P)
|
||||
[ 158.845894] svc_recv+0x58c/0x680 [sunrpc]
|
||||
[ 158.846183] nfsd+0x1fc/0x348 [nfsd]
|
||||
[ 158.846390] kthread+0x274/0x2f8
|
||||
[ 158.846546] ret_from_fork+0x10/0x20
|
||||
[ 158.846714] ---[ end trace 0000000000000000 ]---
|
||||
|
||||
nfsd_nl_listener_set_doit() would manipulate the list of transports of
|
||||
server's sv_permsocks and close the specified listener but the other
|
||||
list of transports (server's sp_xprts list) would not be changed leading
|
||||
to the problem above.
|
||||
|
||||
Instead, determined if the nfsdctl is trying to remove a listener, in
|
||||
which case, delete all the existing listener transports and re-create
|
||||
all-but-the-removed ones.
|
||||
|
||||
Fixes: 16a471177496 ("NFSD: add listener-{set,get} netlink command")
|
||||
Signed-off-by: Olga Kornievskaia <okorniev@redhat.com>
|
||||
Reviewed-by: Jeff Layton <jlayton@kernel.org>
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
|
||||
---
|
||||
fs/nfsd/nfsctl.c | 44 +++++++++++++++++++++-----------------------
|
||||
1 file changed, 21 insertions(+), 23 deletions(-)
|
||||
|
||||
--- a/fs/nfsd/nfsctl.c
|
||||
+++ b/fs/nfsd/nfsctl.c
|
||||
@@ -1917,6 +1917,7 @@ int nfsd_nl_listener_set_doit(struct sk_
|
||||
struct svc_serv *serv;
|
||||
LIST_HEAD(permsocks);
|
||||
struct nfsd_net *nn;
|
||||
+ bool delete = false;
|
||||
int err, rem;
|
||||
|
||||
mutex_lock(&nfsd_mutex);
|
||||
@@ -1977,34 +1978,28 @@ int nfsd_nl_listener_set_doit(struct sk_
|
||||
}
|
||||
}
|
||||
|
||||
- /* For now, no removing old sockets while server is running */
|
||||
- if (serv->sv_nrthreads && !list_empty(&permsocks)) {
|
||||
+ /*
|
||||
+ * If there are listener transports remaining on the permsocks list,
|
||||
+ * it means we were asked to remove a listener.
|
||||
+ */
|
||||
+ if (!list_empty(&permsocks)) {
|
||||
list_splice_init(&permsocks, &serv->sv_permsocks);
|
||||
- spin_unlock_bh(&serv->sv_lock);
|
||||
- err = -EBUSY;
|
||||
- goto out_unlock_mtx;
|
||||
+ delete = true;
|
||||
}
|
||||
+ spin_unlock_bh(&serv->sv_lock);
|
||||
|
||||
- /* Close the remaining sockets on the permsocks list */
|
||||
- while (!list_empty(&permsocks)) {
|
||||
- xprt = list_first_entry(&permsocks, struct svc_xprt, xpt_list);
|
||||
- list_move(&xprt->xpt_list, &serv->sv_permsocks);
|
||||
-
|
||||
- /*
|
||||
- * Newly-created sockets are born with the BUSY bit set. Clear
|
||||
- * it if there are no threads, since nothing can pick it up
|
||||
- * in that case.
|
||||
- */
|
||||
- if (!serv->sv_nrthreads)
|
||||
- clear_bit(XPT_BUSY, &xprt->xpt_flags);
|
||||
-
|
||||
- set_bit(XPT_CLOSE, &xprt->xpt_flags);
|
||||
- spin_unlock_bh(&serv->sv_lock);
|
||||
- svc_xprt_close(xprt);
|
||||
- spin_lock_bh(&serv->sv_lock);
|
||||
+ /* Do not remove listeners while there are active threads. */
|
||||
+ if (serv->sv_nrthreads) {
|
||||
+ err = -EBUSY;
|
||||
+ goto out_unlock_mtx;
|
||||
}
|
||||
|
||||
- spin_unlock_bh(&serv->sv_lock);
|
||||
+ /*
|
||||
+ * Since we can't delete an arbitrary llist entry, destroy the
|
||||
+ * remaining listeners and recreate the list.
|
||||
+ */
|
||||
+ if (delete)
|
||||
+ svc_xprt_destroy_all(serv, net);
|
||||
|
||||
/* walk list of addrs again, open any that still don't exist */
|
||||
nlmsg_for_each_attr(attr, info->nlhdr, GENL_HDRLEN, rem) {
|
||||
@@ -2031,6 +2026,9 @@ int nfsd_nl_listener_set_doit(struct sk_
|
||||
|
||||
xprt = svc_find_listener(serv, xcl_name, net, sa);
|
||||
if (xprt) {
|
||||
+ if (delete)
|
||||
+ WARN_ONCE(1, "Transport type=%s already exists\n",
|
||||
+ xcl_name);
|
||||
svc_xprt_put(xprt);
|
||||
continue;
|
||||
}
|
@@ -1,55 +0,0 @@
|
||||
From 71e2b1f41ebbead746c5b99384ebb9fb7c73a079 Mon Sep 17 00:00:00 2001
|
||||
From: Chuck Lever <chuck.lever@oracle.com>
|
||||
Date: Tue, 14 Jan 2025 17:09:24 -0500
|
||||
Subject: NFSD: Skip sending CB_RECALL_ANY when the backchannel isn't up
|
||||
|
||||
NFSD sends CB_RECALL_ANY to clients when the server is low on
|
||||
memory or that client has a large number of delegations outstanding.
|
||||
|
||||
We've seen cases where NFSD attempts to send CB_RECALL_ANY requests
|
||||
to disconnected clients, and gets confused. These calls never go
|
||||
anywhere if a backchannel transport to the target client isn't
|
||||
available. Before the server can send any backchannel operation, the
|
||||
client has to connect first and then do a BIND_CONN_TO_SESSION.
|
||||
|
||||
This patch doesn't address the root cause of the confusion, but
|
||||
there's no need to queue up these optional operations if they can't
|
||||
go anywhere.
|
||||
|
||||
Fixes: 44df6f439a17 ("NFSD: add delegation reaper to react to low memory condition")
|
||||
Reviewed-by: Jeff Layton <jlayton@kernel.org>
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
|
||||
---
|
||||
fs/nfsd/nfs4state.c | 19 ++++++++++++-------
|
||||
1 file changed, 12 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/fs/nfsd/nfs4state.c
|
||||
+++ b/fs/nfsd/nfs4state.c
|
||||
@@ -6860,14 +6860,19 @@ deleg_reaper(struct nfsd_net *nn)
|
||||
spin_lock(&nn->client_lock);
|
||||
list_for_each_safe(pos, next, &nn->client_lru) {
|
||||
clp = list_entry(pos, struct nfs4_client, cl_lru);
|
||||
- if (clp->cl_state != NFSD4_ACTIVE ||
|
||||
- list_empty(&clp->cl_delegations) ||
|
||||
- atomic_read(&clp->cl_delegs_in_recall) ||
|
||||
- test_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags) ||
|
||||
- (ktime_get_boottime_seconds() -
|
||||
- clp->cl_ra_time < 5)) {
|
||||
+
|
||||
+ if (clp->cl_state != NFSD4_ACTIVE)
|
||||
+ continue;
|
||||
+ if (list_empty(&clp->cl_delegations))
|
||||
+ continue;
|
||||
+ if (atomic_read(&clp->cl_delegs_in_recall))
|
||||
+ continue;
|
||||
+ if (test_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags))
|
||||
+ continue;
|
||||
+ if (ktime_get_boottime_seconds() - clp->cl_ra_time < 5)
|
||||
+ continue;
|
||||
+ if (clp->cl_cb_state != NFSD4_CB_UP)
|
||||
continue;
|
||||
- }
|
||||
list_add(&clp->cl_ra_cblist, &cblist);
|
||||
|
||||
/* release in nfsd4_cb_recall_any_release */
|
@@ -1,35 +0,0 @@
|
||||
From e9976f5c50b6513c156c4f5a1d9fde96efb50d29 Mon Sep 17 00:00:00 2001
|
||||
From: Chuck Lever <chuck.lever@oracle.com>
|
||||
Date: Sun, 26 Jan 2025 16:50:17 -0500
|
||||
Subject: NFSD: nfsd_unlink() clobbers non-zero status returned from
|
||||
fh_fill_pre_attrs()
|
||||
|
||||
If fh_fill_pre_attrs() returns a non-zero status, the error flow
|
||||
takes it through out_unlock, which then overwrites the returned
|
||||
status code with
|
||||
|
||||
err = nfserrno(host_err);
|
||||
|
||||
Fixes: a332018a91c4 ("nfsd: handle failure to collect pre/post-op attrs more sanely")
|
||||
Reviewed-by: Jeff Layton <jlayton@kernel.org>
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
|
||||
---
|
||||
fs/nfsd/vfs.c | 4 +---
|
||||
1 file changed, 1 insertion(+), 3 deletions(-)
|
||||
|
||||
--- a/fs/nfsd/vfs.c
|
||||
+++ b/fs/nfsd/vfs.c
|
||||
@@ -2011,11 +2011,9 @@ out_nfserr:
|
||||
* error status.
|
||||
*/
|
||||
err = nfserr_file_open;
|
||||
- } else {
|
||||
- err = nfserrno(host_err);
|
||||
}
|
||||
out:
|
||||
- return err;
|
||||
+ return err != nfs_ok ? err : nfserrno(host_err);
|
||||
out_unlock:
|
||||
inode_unlock(dirp);
|
||||
goto out_drop_write;
|
@@ -1,68 +0,0 @@
|
||||
From c6e51270335aa72d7f255051119792629ed2ad2d Mon Sep 17 00:00:00 2001
|
||||
From: Chuck Lever <chuck.lever@oracle.com>
|
||||
Date: Sun, 26 Jan 2025 16:50:18 -0500
|
||||
Subject: NFSD: Never return NFS4ERR_FILE_OPEN when removing a directory
|
||||
|
||||
RFC 8881 Section 18.25.4 paragraph 5 tells us that the server
|
||||
should return NFS4ERR_FILE_OPEN only if the target object is an
|
||||
opened file. This suggests that returning this status when removing
|
||||
a directory will confuse NFS clients.
|
||||
|
||||
This is a version-specific issue; nfsd_proc_remove/rmdir() and
|
||||
nfsd3_proc_remove/rmdir() already return nfserr_access as
|
||||
appropriate.
|
||||
|
||||
Unfortunately there is no quick way for nfsd4_remove() to determine
|
||||
whether the target object is a file or not, so the check is done in
|
||||
in nfsd_unlink() for now.
|
||||
|
||||
Reported-by: Trond Myklebust <trondmy@hammerspace.com>
|
||||
Fixes: 466e16f0920f ("nfsd: check for EBUSY from vfs_rmdir/vfs_unink.")
|
||||
Reviewed-by: Jeff Layton <jlayton@kernel.org>
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
|
||||
---
|
||||
fs/nfsd/vfs.c | 24 ++++++++++++++++++------
|
||||
1 file changed, 18 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/fs/nfsd/vfs.c
|
||||
+++ b/fs/nfsd/vfs.c
|
||||
@@ -1931,9 +1931,17 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
-/*
|
||||
- * Unlink a file or directory
|
||||
- * N.B. After this call fhp needs an fh_put
|
||||
+/**
|
||||
+ * nfsd_unlink - remove a directory entry
|
||||
+ * @rqstp: RPC transaction context
|
||||
+ * @fhp: the file handle of the parent directory to be modified
|
||||
+ * @type: enforced file type of the object to be removed
|
||||
+ * @fname: the name of directory entry to be removed
|
||||
+ * @flen: length of @fname in octets
|
||||
+ *
|
||||
+ * After this call fhp needs an fh_put.
|
||||
+ *
|
||||
+ * Returns a generic NFS status code in network byte-order.
|
||||
*/
|
||||
__be32
|
||||
nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
|
||||
@@ -2007,10 +2015,14 @@ out_drop_write:
|
||||
fh_drop_write(fhp);
|
||||
out_nfserr:
|
||||
if (host_err == -EBUSY) {
|
||||
- /* name is mounted-on. There is no perfect
|
||||
- * error status.
|
||||
+ /*
|
||||
+ * See RFC 8881 Section 18.25.4 para 4: NFSv4 REMOVE
|
||||
+ * wants a status unique to the object type.
|
||||
*/
|
||||
- err = nfserr_file_open;
|
||||
+ if (type != S_IFDIR)
|
||||
+ err = nfserr_file_open;
|
||||
+ else
|
||||
+ err = nfserr_acces;
|
||||
}
|
||||
out:
|
||||
return err != nfs_ok ? err : nfserrno(host_err);
|
@@ -1,88 +0,0 @@
|
||||
From be9eb38c29f63437120c1b4c5d1e7df98851e05e Mon Sep 17 00:00:00 2001
|
||||
From: Jeff Layton <jlayton@kernel.org>
|
||||
Date: Thu, 6 Feb 2025 13:12:13 -0500
|
||||
Subject: nfsd: don't ignore the return code of svc_proc_register()
|
||||
|
||||
Currently, nfsd_proc_stat_init() ignores the return value of
|
||||
svc_proc_register(). If the procfile creation fails, then the kernel
|
||||
will WARN when it tries to remove the entry later.
|
||||
|
||||
Fix nfsd_proc_stat_init() to return the same type of pointer as
|
||||
svc_proc_register(), and fix up nfsd_net_init() to check that and fail
|
||||
the nfsd_net construction if it occurs.
|
||||
|
||||
svc_proc_register() can fail if the dentry can't be allocated, or if an
|
||||
identical dentry already exists. The second case is pretty unlikely in
|
||||
the nfsd_net construction codepath, so if this happens, return -ENOMEM.
|
||||
|
||||
Reported-by: syzbot+e34ad04f27991521104c@syzkaller.appspotmail.com
|
||||
Closes: https://lore.kernel.org/linux-nfs/67a47501.050a0220.19061f.05f9.GAE@google.com/
|
||||
Cc: stable@vger.kernel.org # v6.9
|
||||
Signed-off-by: Jeff Layton <jlayton@kernel.org>
|
||||
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
|
||||
---
|
||||
fs/nfsd/nfsctl.c | 9 ++++++++-
|
||||
fs/nfsd/stats.c | 4 ++--
|
||||
fs/nfsd/stats.h | 2 +-
|
||||
3 files changed, 11 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/fs/nfsd/nfsctl.c
|
||||
+++ b/fs/nfsd/nfsctl.c
|
||||
@@ -2202,8 +2202,14 @@ static __net_init int nfsd_net_init(stru
|
||||
NFSD_STATS_COUNTERS_NUM);
|
||||
if (retval)
|
||||
goto out_repcache_error;
|
||||
+
|
||||
memset(&nn->nfsd_svcstats, 0, sizeof(nn->nfsd_svcstats));
|
||||
nn->nfsd_svcstats.program = &nfsd_programs[0];
|
||||
+ if (!nfsd_proc_stat_init(net)) {
|
||||
+ retval = -ENOMEM;
|
||||
+ goto out_proc_error;
|
||||
+ }
|
||||
+
|
||||
for (i = 0; i < sizeof(nn->nfsd_versions); i++)
|
||||
nn->nfsd_versions[i] = nfsd_support_version(i);
|
||||
for (i = 0; i < sizeof(nn->nfsd4_minorversions); i++)
|
||||
@@ -2213,13 +2219,14 @@ static __net_init int nfsd_net_init(stru
|
||||
nfsd4_init_leases_net(nn);
|
||||
get_random_bytes(&nn->siphash_key, sizeof(nn->siphash_key));
|
||||
seqlock_init(&nn->writeverf_lock);
|
||||
- nfsd_proc_stat_init(net);
|
||||
#if IS_ENABLED(CONFIG_NFS_LOCALIO)
|
||||
spin_lock_init(&nn->local_clients_lock);
|
||||
INIT_LIST_HEAD(&nn->local_clients);
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
+out_proc_error:
|
||||
+ percpu_counter_destroy_many(nn->counter, NFSD_STATS_COUNTERS_NUM);
|
||||
out_repcache_error:
|
||||
nfsd_idmap_shutdown(net);
|
||||
out_idmap_error:
|
||||
--- a/fs/nfsd/stats.c
|
||||
+++ b/fs/nfsd/stats.c
|
||||
@@ -73,11 +73,11 @@ static int nfsd_show(struct seq_file *se
|
||||
|
||||
DEFINE_PROC_SHOW_ATTRIBUTE(nfsd);
|
||||
|
||||
-void nfsd_proc_stat_init(struct net *net)
|
||||
+struct proc_dir_entry *nfsd_proc_stat_init(struct net *net)
|
||||
{
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
|
||||
- svc_proc_register(net, &nn->nfsd_svcstats, &nfsd_proc_ops);
|
||||
+ return svc_proc_register(net, &nn->nfsd_svcstats, &nfsd_proc_ops);
|
||||
}
|
||||
|
||||
void nfsd_proc_stat_shutdown(struct net *net)
|
||||
--- a/fs/nfsd/stats.h
|
||||
+++ b/fs/nfsd/stats.h
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <uapi/linux/nfsd/stats.h>
|
||||
#include <linux/percpu_counter.h>
|
||||
|
||||
-void nfsd_proc_stat_init(struct net *net);
|
||||
+struct proc_dir_entry *nfsd_proc_stat_init(struct net *net);
|
||||
void nfsd_proc_stat_shutdown(struct net *net);
|
||||
|
||||
static inline void nfsd_stats_rc_hits_inc(struct nfsd_net *nn)
|
@@ -1,54 +0,0 @@
|
||||
From 8ae7239f6e86e8eaf9b2d95164b9d88b0af1c9c7 Mon Sep 17 00:00:00 2001
|
||||
From: Jeff Layton <jlayton@kernel.org>
|
||||
Date: Thu, 13 Feb 2025 09:08:29 -0500
|
||||
Subject: nfsd: allow SC_STATUS_FREEABLE when searching via
|
||||
nfs4_lookup_stateid()
|
||||
|
||||
The pynfs DELEG8 test fails when run against nfsd. It acquires a
|
||||
delegation and then lets the lease time out. It then tries to use the
|
||||
deleg stateid and expects to see NFS4ERR_DELEG_REVOKED, but it gets
|
||||
bad NFS4ERR_BAD_STATEID instead.
|
||||
|
||||
When a delegation is revoked, it's initially marked with
|
||||
SC_STATUS_REVOKED, or SC_STATUS_ADMIN_REVOKED and later, it's marked
|
||||
with the SC_STATUS_FREEABLE flag, which denotes that it is waiting for
|
||||
s FREE_STATEID call.
|
||||
|
||||
nfs4_lookup_stateid() accepts a statusmask that includes the status
|
||||
flags that a found stateid is allowed to have. Currently, that mask
|
||||
never includes SC_STATUS_FREEABLE, which means that revoked delegations
|
||||
are (almost) never found.
|
||||
|
||||
Add SC_STATUS_FREEABLE to the always-allowed status flags, and remove it
|
||||
from nfsd4_delegreturn() since it's now always implied.
|
||||
|
||||
Fixes: 8dd91e8d31fe ("nfsd: fix race between laundromat and free_stateid")
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Jeff Layton <jlayton@kernel.org>
|
||||
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
|
||||
---
|
||||
fs/nfsd/nfs4state.c | 6 ++----
|
||||
1 file changed, 2 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/fs/nfsd/nfs4state.c
|
||||
+++ b/fs/nfsd/nfs4state.c
|
||||
@@ -7056,7 +7056,7 @@ nfsd4_lookup_stateid(struct nfsd4_compou
|
||||
*/
|
||||
statusmask |= SC_STATUS_REVOKED;
|
||||
|
||||
- statusmask |= SC_STATUS_ADMIN_REVOKED;
|
||||
+ statusmask |= SC_STATUS_ADMIN_REVOKED | SC_STATUS_FREEABLE;
|
||||
|
||||
if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) ||
|
||||
CLOSE_STATEID(stateid))
|
||||
@@ -7711,9 +7711,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp
|
||||
if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
|
||||
return status;
|
||||
|
||||
- status = nfsd4_lookup_stateid(cstate, stateid, SC_TYPE_DELEG,
|
||||
- SC_STATUS_REVOKED | SC_STATUS_FREEABLE,
|
||||
- &s, nn);
|
||||
+ status = nfsd4_lookup_stateid(cstate, stateid, SC_TYPE_DELEG, SC_STATUS_REVOKED, &s, nn);
|
||||
if (status)
|
||||
goto out;
|
||||
dp = delegstateid(s);
|
@@ -1,97 +0,0 @@
|
||||
From e5747c32073db3e624d454b80c94f5cb9b362370 Mon Sep 17 00:00:00 2001
|
||||
From: Li Lingfeng <lilingfeng3@huawei.com>
|
||||
Date: Thu, 13 Feb 2025 22:42:20 +0800
|
||||
Subject: nfsd: put dl_stid if fail to queue dl_recall
|
||||
|
||||
Before calling nfsd4_run_cb to queue dl_recall to the callback_wq, we
|
||||
increment the reference count of dl_stid.
|
||||
We expect that after the corresponding work_struct is processed, the
|
||||
reference count of dl_stid will be decremented through the callback
|
||||
function nfsd4_cb_recall_release.
|
||||
However, if the call to nfsd4_run_cb fails, the incremented reference
|
||||
count of dl_stid will not be decremented correspondingly, leading to the
|
||||
following nfs4_stid leak:
|
||||
unreferenced object 0xffff88812067b578 (size 344):
|
||||
comm "nfsd", pid 2761, jiffies 4295044002 (age 5541.241s)
|
||||
hex dump (first 32 bytes):
|
||||
01 00 00 00 6b 6b 6b 6b b8 02 c0 e2 81 88 ff ff ....kkkk........
|
||||
00 6b 6b 6b 6b 6b 6b 6b 00 00 00 00 ad 4e ad de .kkkkkkk.....N..
|
||||
backtrace:
|
||||
kmem_cache_alloc+0x4b9/0x700
|
||||
nfsd4_process_open1+0x34/0x300
|
||||
nfsd4_open+0x2d1/0x9d0
|
||||
nfsd4_proc_compound+0x7a2/0xe30
|
||||
nfsd_dispatch+0x241/0x3e0
|
||||
svc_process_common+0x5d3/0xcc0
|
||||
svc_process+0x2a3/0x320
|
||||
nfsd+0x180/0x2e0
|
||||
kthread+0x199/0x1d0
|
||||
ret_from_fork+0x30/0x50
|
||||
ret_from_fork_asm+0x1b/0x30
|
||||
unreferenced object 0xffff8881499f4d28 (size 368):
|
||||
comm "nfsd", pid 2761, jiffies 4295044005 (age 5541.239s)
|
||||
hex dump (first 32 bytes):
|
||||
01 00 00 00 00 00 00 00 30 4d 9f 49 81 88 ff ff ........0M.I....
|
||||
30 4d 9f 49 81 88 ff ff 20 00 00 00 01 00 00 00 0M.I.... .......
|
||||
backtrace:
|
||||
kmem_cache_alloc+0x4b9/0x700
|
||||
nfs4_alloc_stid+0x29/0x210
|
||||
alloc_init_deleg+0x92/0x2e0
|
||||
nfs4_set_delegation+0x284/0xc00
|
||||
nfs4_open_delegation+0x216/0x3f0
|
||||
nfsd4_process_open2+0x2b3/0xee0
|
||||
nfsd4_open+0x770/0x9d0
|
||||
nfsd4_proc_compound+0x7a2/0xe30
|
||||
nfsd_dispatch+0x241/0x3e0
|
||||
svc_process_common+0x5d3/0xcc0
|
||||
svc_process+0x2a3/0x320
|
||||
nfsd+0x180/0x2e0
|
||||
kthread+0x199/0x1d0
|
||||
ret_from_fork+0x30/0x50
|
||||
ret_from_fork_asm+0x1b/0x30
|
||||
Fix it by checking the result of nfsd4_run_cb and call nfs4_put_stid if
|
||||
fail to queue dl_recall.
|
||||
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Li Lingfeng <lilingfeng3@huawei.com>
|
||||
Reviewed-by: Jeff Layton <jlayton@kernel.org>
|
||||
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
|
||||
---
|
||||
fs/nfsd/nfs4state.c | 12 +++++++++++-
|
||||
1 file changed, 11 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/fs/nfsd/nfs4state.c
|
||||
+++ b/fs/nfsd/nfs4state.c
|
||||
@@ -1050,6 +1050,12 @@ static struct nfs4_ol_stateid * nfs4_all
|
||||
return openlockstateid(stid);
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * As the sc_free callback of deleg, this may be called by nfs4_put_stid
|
||||
+ * in nfsd_break_one_deleg.
|
||||
+ * Considering nfsd_break_one_deleg is called with the flc->flc_lock held,
|
||||
+ * this function mustn't ever sleep.
|
||||
+ */
|
||||
static void nfs4_free_deleg(struct nfs4_stid *stid)
|
||||
{
|
||||
struct nfs4_delegation *dp = delegstateid(stid);
|
||||
@@ -5414,6 +5420,7 @@ static const struct nfsd4_callback_ops n
|
||||
|
||||
static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
|
||||
{
|
||||
+ bool queued;
|
||||
/*
|
||||
* We're assuming the state code never drops its reference
|
||||
* without first removing the lease. Since we're in this lease
|
||||
@@ -5422,7 +5429,10 @@ static void nfsd_break_one_deleg(struct
|
||||
* we know it's safe to take a reference.
|
||||
*/
|
||||
refcount_inc(&dp->dl_stid.sc_count);
|
||||
- WARN_ON_ONCE(!nfsd4_run_cb(&dp->dl_recall));
|
||||
+ queued = nfsd4_run_cb(&dp->dl_recall);
|
||||
+ WARN_ON_ONCE(!queued);
|
||||
+ if (!queued)
|
||||
+ nfs4_put_stid(&dp->dl_stid);
|
||||
}
|
||||
|
||||
/* Called from break_lease() with flc_lock held. */
|
@@ -1,74 +0,0 @@
|
||||
From 26d356ebfcd275f01c22349404676755dd36a4c4 Mon Sep 17 00:00:00 2001
|
||||
From: Chuck Lever <chuck.lever@oracle.com>
|
||||
Date: Tue, 11 Mar 2025 23:06:38 -0400
|
||||
Subject: NFSD: Add a Kconfig setting to enable delegated timestamps
|
||||
|
||||
After three tries, we still see test failures with delegated
|
||||
timestamps. Disable them by default, but leave the implementation
|
||||
intact so that development can continue.
|
||||
|
||||
Cc: stable@vger.kernel.org # v6.14
|
||||
Reviewed-by: Jeff Layton <jlayton@kernel.org>
|
||||
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
|
||||
---
|
||||
fs/nfsd/Kconfig | 12 +++++++++++-
|
||||
fs/nfsd/nfs4state.c | 16 ++++++++++++++--
|
||||
2 files changed, 25 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/fs/nfsd/Kconfig
|
||||
+++ b/fs/nfsd/Kconfig
|
||||
@@ -172,6 +172,16 @@ config NFSD_LEGACY_CLIENT_TRACKING
|
||||
recoverydir, or spawn a process directly using a usermodehelper
|
||||
upcall.
|
||||
|
||||
- These legacy client tracking methods have proven to be probelmatic
|
||||
+ These legacy client tracking methods have proven to be problematic
|
||||
and will be removed in the future. Say Y here if you need support
|
||||
for them in the interim.
|
||||
+
|
||||
+config NFSD_V4_DELEG_TIMESTAMPS
|
||||
+ bool "Support delegated timestamps"
|
||||
+ depends on NFSD_V4
|
||||
+ default n
|
||||
+ help
|
||||
+ NFSD implements delegated timestamps according to
|
||||
+ draft-ietf-nfsv4-delstid-08 "Extending the Opening of Files". This
|
||||
+ is currently an experimental feature and is therefore left disabled
|
||||
+ by default.
|
||||
--- a/fs/nfsd/nfs4state.c
|
||||
+++ b/fs/nfsd/nfs4state.c
|
||||
@@ -5958,11 +5958,23 @@ nfsd4_verify_setuid_write(struct nfsd4_o
|
||||
return 0;
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_NFSD_V4_DELEG_TIMESTAMPS
|
||||
+static bool nfsd4_want_deleg_timestamps(const struct nfsd4_open *open)
|
||||
+{
|
||||
+ return open->op_deleg_want & OPEN4_SHARE_ACCESS_WANT_DELEG_TIMESTAMPS;
|
||||
+}
|
||||
+#else /* CONFIG_NFSD_V4_DELEG_TIMESTAMPS */
|
||||
+static bool nfsd4_want_deleg_timestamps(const struct nfsd4_open *open)
|
||||
+{
|
||||
+ return false;
|
||||
+}
|
||||
+#endif /* CONFIG NFSD_V4_DELEG_TIMESTAMPS */
|
||||
+
|
||||
static struct nfs4_delegation *
|
||||
nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
|
||||
struct svc_fh *parent)
|
||||
{
|
||||
- bool deleg_ts = open->op_deleg_want & OPEN4_SHARE_ACCESS_WANT_DELEG_TIMESTAMPS;
|
||||
+ bool deleg_ts = nfsd4_want_deleg_timestamps(open);
|
||||
struct nfs4_client *clp = stp->st_stid.sc_client;
|
||||
struct nfs4_file *fp = stp->st_stid.sc_file;
|
||||
struct nfs4_clnt_odstate *odstate = stp->st_clnt_odstate;
|
||||
@@ -6161,8 +6173,8 @@ static void
|
||||
nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
|
||||
struct svc_fh *currentfh)
|
||||
{
|
||||
- bool deleg_ts = open->op_deleg_want & OPEN4_SHARE_ACCESS_WANT_DELEG_TIMESTAMPS;
|
||||
struct nfs4_openowner *oo = openowner(stp->st_stateowner);
|
||||
+ bool deleg_ts = nfsd4_want_deleg_timestamps(open);
|
||||
struct nfs4_client *clp = stp->st_stid.sc_client;
|
||||
struct svc_fh *parent = NULL;
|
||||
struct nfs4_delegation *dp;
|
Reference in New Issue
Block a user