public inbox for linux-fsdevel@vger.kernel.org
 help / color / mirror / Atom feed
From: Chuck Lever <cel@kernel.org>
To: NeilBrown <neilb@ownmail.net>, Jeff Layton <jlayton@kernel.org>,
	Olga Kornievskaia <okorniev@redhat.com>,
	Dai Ngo <dai.ngo@oracle.com>, Tom Talpey <tom@talpey.com>
Cc: linux-nfs@vger.kernel.org, linux-fsdevel@vger.kernel.org,
	Chuck Lever <chuck.lever@oracle.com>
Subject: [PATCH v3 3/3] nfsd: close cached files on filesystem unmount
Date: Tue, 24 Feb 2026 11:39:08 -0500	[thread overview]
Message-ID: <20260224163908.44060-4-cel@kernel.org> (raw)
In-Reply-To: <20260224163908.44060-1-cel@kernel.org>

From: Chuck Lever <chuck.lever@oracle.com>

When a filesystem is unmounted while NFS is exporting it, the
unmount can fail with EBUSY even after NFSv4 state has been revoked.
This occurs because the nfsd_file cache holds open NFSv2/3 file
handles that pin the filesystem.

Extend the mechanism that revokes NFSv4 state on unmount to also
close cached file handles. nfsd_file_close_sb() walks the nfsd_file
cache and disposes of entries belonging to the target superblock.
It runs after NFSv4 state revocation, handling NFSv2/3 file handles
that remain in the cache.

Entries under construction (nf_file not yet set) are skipped; these
have no open file to close.

The hashtable walk releases the mutex periodically to avoid blocking
other NFSD operations during large cache walks. Entries are disposed
incrementally in batches, keeping memory usage bounded and spreading
the I/O load.

A log message is emitted when cached file handles are closed during
unmount, informing administrators that NFS clients may receive stale
file handle errors.

A flush_workqueue() call is added to nfsd_sb_watch_shutdown() to
ensure that any work items still executing complete before shutdown
proceeds. Without this, if an unmount notification returns early
due to signal interruption while the work function is still running,
nfsd_file_cache_shutdown() could destroy the file cache slab while
nfsd_file_close_sb() is still disposing entries.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/filecache.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 fs/nfsd/filecache.h |  1 +
 fs/nfsd/sb_watch.c  | 10 ++++++++++
 3 files changed, 56 insertions(+)

diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c
index 1e2b38ed1d35..d1a6f7cf40b2 100644
--- a/fs/nfsd/filecache.c
+++ b/fs/nfsd/filecache.c
@@ -894,6 +894,51 @@ __nfsd_file_cache_purge(struct net *net)
 	nfsd_file_dispose_list(&dispose);
 }
 
+/**
+ * nfsd_file_close_sb - close GC-managed cached files for a superblock
+ * @sb: target superblock
+ *
+ * Walk the nfsd_file cache and close out GC-managed entries (those
+ * acquired via nfsd_file_acquire_gc) that belong to @sb. Called during
+ * filesystem unmount after NFSv4 state revocation to release remaining
+ * cached file handles that may be pinning the filesystem.
+ */
+void nfsd_file_close_sb(struct super_block *sb)
+{
+	struct rhashtable_iter iter;
+	struct nfsd_file *nf;
+	unsigned int closed = 0;
+	LIST_HEAD(dispose);
+
+	if (!test_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags))
+		return;
+
+	rhltable_walk_enter(&nfsd_file_rhltable, &iter);
+	do {
+		rhashtable_walk_start(&iter);
+
+		nf = rhashtable_walk_next(&iter);
+		while (!IS_ERR_OR_NULL(nf)) {
+			if (test_bit(NFSD_FILE_GC, &nf->nf_flags) &&
+			    nf->nf_file &&
+			    file_inode(nf->nf_file)->i_sb == sb) {
+				nfsd_file_cond_queue(nf, &dispose);
+				closed++;
+			}
+			nf = rhashtable_walk_next(&iter);
+		}
+
+		rhashtable_walk_stop(&iter);
+	} while (nf == ERR_PTR(-EAGAIN));
+	rhashtable_walk_exit(&iter);
+
+	nfsd_file_dispose_list(&dispose);
+
+	if (closed)
+		pr_info("nfsd: closed %u cached file handle%s on %s\n",
+			closed, closed == 1 ? "" : "s", sb->s_id);
+}
+
 static struct nfsd_fcache_disposal *
 nfsd_alloc_fcache_disposal(void)
 {
diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h
index b383dbc5b921..66ca7fc6189b 100644
--- a/fs/nfsd/filecache.h
+++ b/fs/nfsd/filecache.h
@@ -70,6 +70,7 @@ struct net *nfsd_file_put_local(struct nfsd_file __rcu **nf);
 struct nfsd_file *nfsd_file_get(struct nfsd_file *nf);
 struct file *nfsd_file_file(struct nfsd_file *nf);
 void nfsd_file_close_inode_sync(struct inode *inode);
+void nfsd_file_close_sb(struct super_block *sb);
 void nfsd_file_net_dispose(struct nfsd_net *nn);
 bool nfsd_file_is_cached(struct inode *inode);
 __be32 nfsd_file_acquire_gc(struct svc_rqst *rqstp, struct svc_fh *fhp,
diff --git a/fs/nfsd/sb_watch.c b/fs/nfsd/sb_watch.c
index 8f711956a12e..34e50afe566c 100644
--- a/fs/nfsd/sb_watch.c
+++ b/fs/nfsd/sb_watch.c
@@ -65,6 +65,7 @@ static void nfsd_sb_revoke_work(struct work_struct *work)
 	/* Errors are logged by lockd; no recovery is possible. */
 	(void)nlmsvc_unlock_all_by_sb(watch->sb);
 	nfsd4_revoke_states(nn, watch->sb);
+	nfsd_file_close_sb(watch->sb);
 
 	pr_info("nfsd: state revocation for %s complete\n", watch->sb->s_id);
 
@@ -257,6 +258,15 @@ void nfsd_sb_watch_shutdown(struct nfsd_net *nn)
 {
 	umount_unregister_notifier(&nn->nfsd_umount_notifier);
 	nfsd_sb_watches_destroy(nn);
+	/*
+	 * Ensure any work items still running complete before shutdown
+	 * proceeds. This handles the case where an unmount notification
+	 * returned early due to signal interruption but the work function
+	 * is still executing nfsd_file_close_sb(). Without this flush,
+	 * nfsd_file_cache_shutdown() could destroy the slab while the
+	 * work function is still disposing file cache entries.
+	 */
+	flush_workqueue(nfsd_sb_watch_wq);
 }
 
 int nfsd_sb_watch_init(void)
-- 
2.53.0


  parent reply	other threads:[~2026-02-24 16:39 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-24 16:39 [PATCH v3 0/3] Automatic NFSv4 state revocation on filesystem unmount Chuck Lever
2026-02-24 16:39 ` [PATCH v3 1/3] fs: add umount notifier chain for filesystem unmount notification Chuck Lever
2026-02-26  8:48   ` Christian Brauner
2026-02-26 10:52     ` Amir Goldstein
2026-02-26 13:27       ` Chuck Lever
2026-02-26 13:32         ` Jan Kara
2026-02-27 15:10           ` Chuck Lever
2026-03-01 14:37             ` Amir Goldstein
2026-03-01 17:20               ` Chuck Lever
2026-03-01 18:09                 ` Amir Goldstein
2026-03-01 18:19                   ` Chuck Lever
2026-03-02  4:09                     ` NeilBrown
2026-03-02 13:57                       ` Chuck Lever
2026-03-02 15:26                         ` Jan Kara
2026-03-02 17:10                           ` Jeff Layton
2026-03-02 17:37                             ` Jan Kara
2026-03-02 17:53                               ` Jeff Layton
2026-03-04 13:17                                 ` Christian Brauner
2026-03-04 15:15                                   ` Chuck Lever
2026-03-02 20:46                               ` NeilBrown
2026-03-02 17:01                         ` Chuck Lever
2026-03-02 20:36                           ` NeilBrown
2026-03-03 20:02                             ` Chuck Lever
2026-03-03 21:23                               ` NeilBrown
2026-03-03 22:50                                 ` Chuck Lever
2026-03-04  1:01                                   ` NeilBrown
2026-03-04 13:05                             ` Christian Brauner
2026-02-24 16:39 ` [PATCH v3 2/3] nfsd: revoke NFSv4 state when filesystem is unmounted Chuck Lever
2026-02-24 16:39 ` Chuck Lever [this message]
2026-02-24 17:14 ` [PATCH v3 0/3] Automatic NFSv4 state revocation on filesystem unmount Al Viro

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260224163908.44060-4-cel@kernel.org \
    --to=cel@kernel.org \
    --cc=chuck.lever@oracle.com \
    --cc=dai.ngo@oracle.com \
    --cc=jlayton@kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=neilb@ownmail.net \
    --cc=okorniev@redhat.com \
    --cc=tom@talpey.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox