[PATCH] ceph: keep dentry in cache when inode still holds caps

Xiubo Li via B4 Relay <[email protected]>
Newsgroups org.kernel.vger.ceph-devel,org.kernel.feeds.b4-sent,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
From: Xiubo Li <[email protected]>

ceph_d_delete() drops a dentry once its lease expires, which
releases the inode and destroys its page cache at the last close.
A buffered write that outlasts the dentry lease duration (30s by
default on the MDS side) is flushed and closed, yet the reopen
re-reads everything from the OSDs instead of the page cache, even
though the caps and the pages are still valid.

Keep the dentry when the inode still holds caps: the caps guarantee
the inode object is still valid, and the name linkage is revalidated
against the MDS by ceph_d_revalidate() on the next lookup anyway.

Keeping the dentry also keeps the inode and its page cache around
longer than before.  This is bounded: caps no longer needed by any
open file or by dirty data are released once the delayed release
window expires (caps_wanted_delay_max, 60s by default) via
ceph_check_delayed_caps(), after which the dentry is just an
ordinary cached dentry.  It is also fully reclaimable: ->d_delete()
is only consulted on the last dput (in retain_dentry()), while the
dcache shrinker (shrink_dentry_list() -> __dentry_kill()) does not
call it, so memory pressure frees these dentries like any others.

The check is deliberately racy: i_ceph_lock cannot be taken under
dentry->d_lock, but a false result only means keeping or dropping a
dentry that could have gone the other way, which is safe.

Signed-off-by: Xiubo Li <[email protected]>
---
 fs/ceph/dir.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index f4e0bf244fd2..a7d33ad9d2c7 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -2090,6 +2090,20 @@ static int ceph_d_delete(const struct dentry *dentry)
 		if (__dir_lease_try_check(dentry))
 			return 0;
 	}
+	/*
+	 * The lease has expired, but if the inode still holds caps, keep
+	 * the dentry: dropping it would release the inode and destroy its
+	 * page cache (e.g. on the last close after a long write).  The
+	 * caps guarantee the inode itself is still valid, and the name
+	 * linkage is revalidated against the MDS on the next lookup
+	 * anyway.
+	 *
+	 * This is deliberately racy: we can't take i_ceph_lock under
+	 * dentry->d_lock, but a false result only means we keep or drop a
+	 * dentry we could have done the opposite with, which is safe.
+	 */
+	if (__ceph_is_any_real_caps(ceph_inode(d_inode(dentry))))
+		return 0;
 	return 1;
 }
 

---
base-commit: 6a8322d32e2e2d3e364d31fc86c784e0e0105c08
change-id: 20260821-b4-b4-ceph-dentry-caps-ad44734dea85

Best regards,
--  
Xiubo Li <[email protected]>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.