[PATCH] ceph: revalidate dentries under snapdir to drop stale snapshots
From: zhangdaolong
Date: Thu Nov 05 2026 - 21:13:43 EST
When a snapshot is deleted on one client node, its corresponding
'.snap/<snapname>' dentry cached in the VFS dcache on other client nodes
never gets invalidated. As a result, recreating a snapshot with the same
name on another node fails with -EEXIST, and removing it fails with
-ENOENT while still leaving the stale positive dentry in the dcache.
In ceph_d_revalidate(), the condition 'if (ceph_in_snap(dir))' matches
both immutable snapped directories (ceph_snap(dir) <= CEPH_MAXSNAP) and
the mutable virtual '.snap' directory itself (ceph_snap(dir) ==
CEPH_SNAPDIR). Because it unconditionally sets valid = 1 when dir is
CEPH_SNAPDIR, the CEPH_MDS_OP_LOOKUPSNAP revalidation path below inside
'if (!valid)' is rendered unreachable dead code.
Fix this by excluding CEPH_SNAPDIR from the unconditional trust check in
ceph_d_revalidate() so that cached dentries directly under '.snap' are
revalidated via CEPH_MDS_OP_LOOKUPSNAP. Additionally, drop the dentry in
ceph_unlink() when the MDS returns -ENOENT.
Fixes: 200fd27c8fa2 ("ceph: use lookup request to revalidate dentry")
Link: https://tracker.ceph.com/issues/81579
Signed-off-by: zhangdaolong <dlzhangak@xxxxxxxxxxxxxx>
---
fs/ceph/dir.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index 6eb5b1cb039b..9f84beac189e 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -1475,6 +1475,8 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
err = ceph_mdsc_do_request(mdsc, dir, req);
if (!err && !req->r_reply_info.head->is_dentry)
d_delete(dentry);
+ else if (err == -ENOENT)
+ d_drop(dentry);
}
ceph_mdsc_put_request(req);
@@ -2003,7 +2005,7 @@ static int ceph_d_revalidate(struct inode *dir, const struct qstr *name,
mdsc = ceph_sb_to_fs_client(dir->i_sb)->mdsc;
/* always trust cached snapped dentries, snapdir dentry */
- if (ceph_in_snap(dir)) {
+ if (ceph_in_snap(dir) && ceph_snap(dir) != CEPH_SNAPDIR) {
doutc(cl, "%p '%pd' inode %p is SNAPPED\n", dentry,
dentry, inode);
valid = 1;
--
2.48.1