From: Jonathan Flynn <jonathan.flynn@hammerspace.com>
To: NeilBrown <neil@brown.name>, Trond Myklebust <trondmy@kernel.org>,
Anna Schumaker <anna@kernel.org>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>,
Christian Brauner <brauner@kernel.org>,
Jeff Layton <jlayton@kernel.org>, Chuck Lever <cel@kernel.org>,
Jan Kara <jack@suse.cz>,
linux-nfs@vger.kernel.org, linux-fsdevel@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [PATCH 0/3] nfs: fix the silly-delete hand-off that 2/9 makes reachable
Date: Thu, 29 Oct 2026 12:09:47 -0600 [thread overview]
Message-ID: <20261029180950.387072-1-jonathan.flynn@hammerspace.com> (raw)
In-Reply-To: <20261028041023.3738553-3-neilb@ownmail.net>
Hi Neil,
Your "nfs: fix nfs_call_unlink()" computes the silly name's hash before
d_alloc_parallel(), so nfs_call_unlink() can now find another cached
entry for that name and hand it the pending silly-delete. With it
applied, that happens: an entry made by a fresh lookup of the silly
name, after the original entry was invalidated, receives the delete
when the file is closed. Three problems in the hand-off become
reachable with it, and these patches fix them:
1/3 the hand-off can overwrite NFS_FSDATA_BLOCKED on an entry whose
REMOVE or RENAME is in flight (Sashiko's review of 2/9 reports
this too);
2/3 the other order: nfs_rename() tests its target before it takes
->d_lock, so a hand-off landing in between is kfree()d by
block_revalidate(), leaving DCACHE_NFSFS_RENAMED set with no
data and a NULL dereference at the final dput(); a hand-off
that the VFS's unlocked test missed also trips the WARN_ON()s
in nfs_unlink() and nfs_rename(). nfs_rename() now tests under
->d_lock, and both return -EBUSY, as may_delete_dentry() does;
3/3 nfs_call_unlink() holds rmdir_sem for read across its lookup and
across the dput() of the alias, and either can kill a dentry
carrying a silly-delete, which re-enters nfs_call_unlink() with
rmdir_sem still held: that deadlocks against a waiting rmdir()
(Sashiko's review of 2/9 reports the alias case). It now takes
rmdir_sem only for the REMOVE it sends, which also closes an
older route to the same re-entry that does not need 2/9:
NFSv4's delegation return in ->unlink_setup().
They have to go wherever 2/9 goes, and its Fixes: tag will take it to
stable. Fold them into 2/9 if you prefer, as you did with the d_seq fix
in 1/9.
One window is not covered, and you may prefer to close it another way.
After nfs_unlink() or nfs_rename() clears the mark, and before the
VFS's d_delete() or nfs_rename()'s d_move(), a hand-off can still land
on the entry. For an unlink, that costs only a second REMOVE, which
finds nothing. For a rename onto the silly name, the target is left
owing a REMOVE of a name that now belongs to the renamed file. That
REMOVE is normally dropped, because nfs_call_unlink() then finds the
renamed file's own entry and its file handle differs; but if that entry
has left the dcache by the time the target's last reference goes, the
REMOVE is sent and deletes the renamed file. Closing the rename case
would take the hand-off refusing an alias that is no longer hashed, and
nfs_rename() dropping, under ->d_lock and after d_move(), a
silly-delete that landed after its mark cleared. I have a draft of
that, and can test and send it if you want it.
Tested with your v4 and these patches on a 7.3-based kernel, over
NFSv4.2 to a pNFS metadata server that is not knfsd. The hand-off
happens as described above. With 3/3, the nested nfs_call_unlink()
that follows it starts with rmdir_sem not held, where without 3/3 it
ran with rmdir_sem held for read, and the REMOVE is sent once. The
removal race tests of my RFC, posted in reply to your 0/9, passed on
this kernel, as did a PROVE_LOCKING and KASAN build running them,
though lockdep does not see rmdir_sem's read hold, which is taken with
down_read_non_owner(). No test here hits the races that 1/3 and 2/3
close, or the deadlock itself, so for those the fixes rest on the code.
The series applies to 83f32c773255 in Linus's tree with your v4, and
fs/ compiles without warnings at each patch.
Tools: these patches, their changelogs and this letter were written
with Claude Code, using Anthropic's Claude Opus 5 and Claude Opus 5.5
models, at my direction. It found the problems fixed by 1/3 and 2/3,
and two of the three routes in 3/3, reading the code with and without
Sashiko's review prompts; Sashiko's own review of 2/9 reported the
problem in 1/3 as well, and the route through the alias in 3/3.
Thanks,
Jonathan
Jonathan Flynn (3):
nfs: do not transfer a sillydelete onto a blocked dentry
nfs: answer a handed-off silly-delete on a removal target with -EBUSY
nfs: take rmdir_sem for a silly-delete only when its REMOVE is sent
fs/nfs/dir.c | 32 ++++++++++++++++++++++++++------
fs/nfs/unlink.c | 39 ++++++++++++++++++++++++++++++++-------
2 files changed, 58 insertions(+), 13 deletions(-)
base-commit: 83f32c773255720a661aa45d83e36278135f23f5
prerequisite-patch-id: 3405b4d6ab8b0bf24ba63a898083d617deec4f24
prerequisite-patch-id: 096657d6d80d7ca533ccb574d2af65611ede4af2
prerequisite-patch-id: 1a2319c14739918aef86116647fea28ae85ad4df
prerequisite-patch-id: 725cb18c3936d50141ef27dafc159bf50b64a5bd
prerequisite-patch-id: b39cdd352b97e2cd247311fd5db620dbff227bd7
prerequisite-patch-id: f9f3f0e945cadf96113d4ac9ab8f7b0c207af4e5
prerequisite-patch-id: 4c09a15390bb556d79bea1ee733f52a58bec80ef
prerequisite-patch-id: 7c026717a97b2c86a169539822f5d14650f68f8a
prerequisite-patch-id: a702d54495d0f3d7f88b82411d884dcf5aacf9a0
--
2.43.0
next prev parent reply other threads:[~2026-10-29 18:09 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-28 4:06 [PATCH v4 0/9] nfs: prepare for locking changes NeilBrown
2026-10-28 4:06 ` [PATCH v4 1/9] nfs: fix open-blocking with d_fsdata NeilBrown
2026-10-28 4:06 ` [PATCH v4 2/9] nfs: fix nfs_call_unlink() NeilBrown
2026-10-29 18:09 ` Jonathan Flynn [this message]
2026-10-29 18:09 ` [PATCH 1/3] nfs: do not transfer a sillydelete onto a blocked dentry Jonathan Flynn
2026-10-29 18:09 ` [PATCH 2/3] nfs: answer a handed-off silly-delete on a removal target with -EBUSY Jonathan Flynn
2026-10-29 18:09 ` [PATCH 3/3] nfs: take rmdir_sem for a silly-delete only when its REMOVE is sent Jonathan Flynn
2026-10-29 21:58 ` [PATCH 0/3] nfs: fix the silly-delete hand-off that 2/9 makes reachable NeilBrown
2026-10-28 4:06 ` [PATCH v4 3/9] nfs: remove d_drop()/d_alloc_parallel() from nfs_atomic_open() NeilBrown
2026-10-28 4:06 ` [PATCH v4 4/9] nfs: use d_splice_alias() in nfs_link() NeilBrown
2026-10-28 4:06 ` [PATCH v4 5/9] nfs: don't d_drop() before d_splice_alias() NeilBrown
2026-10-28 4:06 ` [PATCH v4 6/9] nfs: don't d_drop() before d_splice_alias() in atomic_create NeilBrown
2026-10-28 4:06 ` [PATCH v4 7/9] nfs: Use d_alloc_trylock() in nfs_prime_dcache() NeilBrown
2026-10-28 4:06 ` [PATCH v4 8/9] nfs: use d_alloc_trylock() in silly-rename NeilBrown
2026-10-28 4:06 ` [PATCH v4 9/9] nfs: use d_duplicate() NeilBrown
2026-10-28 17:21 ` [PATCH v4 0/9] nfs: prepare for locking changes Anna Schumaker
2026-10-29 18:09 ` [PATCH RFC 00/12] vfs, nfs: concurrent create and unlink in one directory Jonathan Flynn
2026-10-29 18:09 ` [PATCH RFC 01/12] nfs: update a server's capabilities in one step Jonathan Flynn
2026-10-29 18:09 ` [PATCH RFC 02/12] vfs: allow the parent lock to be shared for O_CREAT Jonathan Flynn
2026-10-29 18:09 ` [PATCH RFC 03/12] nfs: tell the VFS when two names can be one entry on the server Jonathan Flynn
2026-10-29 22:23 ` NeilBrown
2026-10-29 18:09 ` [PATCH RFC 04/12] nfs: concurrent O_CREAT in one NFSv4 directory Jonathan Flynn
2026-10-29 18:09 ` [PATCH RFC 05/12] vfs: factor file removal into a helper, no functional change Jonathan Flynn
2026-10-29 18:09 ` [PATCH RFC 06/12] vfs: let a filesystem remove files with the parent directory locked shared Jonathan Flynn
2026-10-29 18:09 ` [PATCH RFC 07/12] nfs: add a second mark for a removal made with the parent " Jonathan Flynn
2026-10-29 18:09 ` [PATCH RFC 08/12] nfs: keep the dentry of a shared-parent removal hashed Jonathan Flynn
2026-10-29 18:09 ` [PATCH RFC 09/12] nfs: do not cache a name from a listing that a removal overlapped Jonathan Flynn
2026-10-29 18:09 ` [PATCH RFC 10/12] nfs: add the removal method for a parent directory locked shared Jonathan Flynn
2026-10-29 18:09 ` [PATCH RFC 11/12] nfs: look a name up again once its removal has unhashed it Jonathan Flynn
2026-10-29 18:09 ` [PATCH RFC 12/12] nfs: remove files with the parent directory locked shared on NFSv4 Jonathan Flynn
2026-10-29 22:18 ` [PATCH RFC 00/12] vfs, nfs: concurrent create and unlink in one directory NeilBrown
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=20261029180950.387072-1-jonathan.flynn@hammerspace.com \
--to=jonathan.flynn@hammerspace.com \
--cc=anna@kernel.org \
--cc=brauner@kernel.org \
--cc=cel@kernel.org \
--cc=jack@suse.cz \
--cc=jlayton@kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-nfs@vger.kernel.org \
--cc=neil@brown.name \
--cc=trondmy@kernel.org \
--cc=viro@zeniv.linux.org.uk \
/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
all inboxes | Powered by JetHome®