This is a note to let you know that I've just added the patch titled Revert "nfsd: separate nfsd_last_thread() from nfsd_put()" to the 6.1-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary The filename of the patch is: revert-nfsd-separate-nfsd_last_thread-from-nfsd_put.patch and it can be found in the queue-6.1 subdirectory. If you, or anyone else, feels it should not be added to the stable tree, please let <stable@xxxxxxxxxxxxxxx> know about it. >From c3cd2872f4aed958f70d7f871ea6cf3ff29d4674 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> Date: Sat, 13 Jan 2024 10:38:35 +0100 Subject: Revert "nfsd: separate nfsd_last_thread() from nfsd_put()" From: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> This reverts commit 03d68ffc48b94cc1e15bbf3b4f16f1e1e4fa286a which is commit 9f28a971ee9fdf1bf8ce8c88b103f483be610277 upstream. It is reported to cause issues, so revert it. Reported-by: email200202 <email200202@xxxxxxxxx> Link: https://lore.kernel.org/r/e341cb408b5663d8c91b8fa57b41bb984be43448.camel@xxxxxxxxxx Cc: NeilBrown <neilb@xxxxxxx> Cc: Jeff Layton <jlayton@xxxxxxxxxx> Cc: Chuck Lever <chuck.lever@xxxxxxxxxx> Cc: Sasha Levin <sashal@xxxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- fs/nfsd/nfsd.h | 7 +------ fs/nfsd/nfssvc.c | 52 +++++++++++++++++++++++++++++++++------------------- 2 files changed, 34 insertions(+), 25 deletions(-) --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -97,12 +97,7 @@ int nfsd_pool_stats_open(struct inode * int nfsd_pool_stats_release(struct inode *, struct file *); void nfsd_shutdown_threads(struct net *net); -static inline void nfsd_put(struct net *net) -{ - struct nfsd_net *nn = net_generic(net, nfsd_net_id); - - svc_put(nn->nfsd_serv); -} +void nfsd_put(struct net *net); bool i_am_nfsd(void); --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -523,14 +523,9 @@ static struct notifier_block nfsd_inet6a /* Only used under nfsd_mutex, so this atomic may be overkill: */ static atomic_t nfsd_notifier_refcount = ATOMIC_INIT(0); -static void nfsd_last_thread(struct net *net) +static void nfsd_last_thread(struct svc_serv *serv, struct net *net) { struct nfsd_net *nn = net_generic(net, nfsd_net_id); - struct svc_serv *serv = nn->nfsd_serv; - - spin_lock(&nfsd_notifier_lock); - nn->nfsd_serv = NULL; - spin_unlock(&nfsd_notifier_lock); /* check if the notifier still has clients */ if (atomic_dec_return(&nfsd_notifier_refcount) == 0) { @@ -540,8 +535,6 @@ static void nfsd_last_thread(struct net #endif } - svc_xprt_destroy_all(serv, net); - /* * write_ports can create the server without actually starting * any threads--if we get shut down before any threads are @@ -632,8 +625,7 @@ void nfsd_shutdown_threads(struct net *n svc_get(serv); /* Kill outstanding nfsd threads */ svc_set_num_threads(serv, NULL, 0); - nfsd_last_thread(net); - svc_put(serv); + nfsd_put(net); mutex_unlock(&nfsd_mutex); } @@ -663,6 +655,9 @@ int nfsd_create_serv(struct net *net) serv->sv_maxconn = nn->max_connections; error = svc_bind(serv, net); if (error < 0) { + /* NOT nfsd_put() as notifiers (see below) haven't + * been set up yet. + */ svc_put(serv); return error; } @@ -705,6 +700,29 @@ int nfsd_get_nrthreads(int n, int *nthre return 0; } +/* This is the callback for kref_put() below. + * There is no code here as the first thing to be done is + * call svc_shutdown_net(), but we cannot get the 'net' from + * the kref. So do all the work when kref_put returns true. + */ +static void nfsd_noop(struct kref *ref) +{ +} + +void nfsd_put(struct net *net) +{ + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + + if (kref_put(&nn->nfsd_serv->sv_refcnt, nfsd_noop)) { + svc_xprt_destroy_all(nn->nfsd_serv, net); + nfsd_last_thread(nn->nfsd_serv, net); + svc_destroy(&nn->nfsd_serv->sv_refcnt); + spin_lock(&nfsd_notifier_lock); + nn->nfsd_serv = NULL; + spin_unlock(&nfsd_notifier_lock); + } +} + int nfsd_set_nrthreads(int n, int *nthreads, struct net *net) { int i = 0; @@ -755,7 +773,7 @@ int nfsd_set_nrthreads(int n, int *nthre if (err) break; } - svc_put(nn->nfsd_serv); + nfsd_put(net); return err; } @@ -770,7 +788,6 @@ nfsd_svc(int nrservs, struct net *net, c int error; bool nfsd_up_before; struct nfsd_net *nn = net_generic(net, nfsd_net_id); - struct svc_serv *serv; mutex_lock(&nfsd_mutex); dprintk("nfsd: creating service\n"); @@ -790,25 +807,22 @@ nfsd_svc(int nrservs, struct net *net, c goto out; nfsd_up_before = nn->nfsd_net_up; - serv = nn->nfsd_serv; error = nfsd_startup_net(net, cred); if (error) goto out_put; - error = svc_set_num_threads(serv, NULL, nrservs); + error = svc_set_num_threads(nn->nfsd_serv, NULL, nrservs); if (error) goto out_shutdown; - error = serv->sv_nrthreads; - if (error == 0) - nfsd_last_thread(net); + error = nn->nfsd_serv->sv_nrthreads; out_shutdown: if (error < 0 && !nfsd_up_before) nfsd_shutdown_net(net); out_put: /* Threads now hold service active */ if (xchg(&nn->keep_active, 0)) - svc_put(serv); - svc_put(serv); + nfsd_put(net); + nfsd_put(net); out: mutex_unlock(&nfsd_mutex); return error; Patches currently in stable-queue which might be from gregkh@xxxxxxxxxxxxxxxxxxx are queue-6.1/revert-nfsd-separate-nfsd_last_thread-from-nfsd_put.patch queue-6.1/ipv6-remove-max_size-check-inline-with-ipv4.patch queue-6.1/revert-nfsd-call-nfsd_last_thread-before-final-nfsd_put.patch queue-6.1/cifs-fix-flushing-folio-regression-for-6.1-backport.patch