From nobody Thu Apr 2 01:10:08 2026 Received: from fout-a3-smtp.messagingengine.com (fout-a3-smtp.messagingengine.com [103.168.172.146]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 685CB361DA2; Tue, 31 Mar 2026 01:30:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.168.172.146 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774920631; cv=none; b=a+Zu+GTUlvIV6qkdyUBMLD3M9n4lhva14BCSaU9yi9QjFY+Ky83whjGG/iltAS8odxF876VMWrt35oKd3CDWE+hA6zZeRjGM1rkDlMC4BIvQ3f/Ko0qat9lVUDHTvovLN7mSaXYtX6lvyH/6OdNkBZiYqDgWMmQ2XLMmKDkHJVw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774920631; c=relaxed/simple; bh=QwXtXOf7jYOyNON3k4INnHhmNa4DnKTs3UmlR0WNN4Q=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ahGvYeLbM2YbGXO1bpPcJy1IEzKF1AQ9iXnaNHi/HBUPn5PhOoVTzbkDa6c/v8nYmKeC/vyiGNgd0HnGGkIL8qaXI/EfqNrTP6/d7WqFEg4dR1s+TD6cDcq1h2eTrSM196A17412lsnhhcxJyqOLooC7EtJvRoRLsSc5nWofq28= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=themaw.net; spf=pass smtp.mailfrom=themaw.net; dkim=pass (2048-bit key) header.d=themaw.net header.i=@themaw.net header.b=TOuTZPMv; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=I3MRLV1B; arc=none smtp.client-ip=103.168.172.146 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=themaw.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=themaw.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=themaw.net header.i=@themaw.net header.b="TOuTZPMv"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="I3MRLV1B" Received: from phl-compute-02.internal (phl-compute-02.internal [10.202.2.42]) by mailfout.phl.internal (Postfix) with ESMTP id 92F57EC00EB; Mon, 30 Mar 2026 21:30:29 -0400 (EDT) Received: from phl-frontend-03 ([10.202.2.162]) by phl-compute-02.internal (MEProxy); Mon, 30 Mar 2026 21:30:29 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=themaw.net; h=cc :cc:content-transfer-encoding:content-type:date:date:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm3; t=1774920629; x= 1775007029; bh=6KDde5DhWzz5okBA1igZHYy01UUgchyUxpv5kg2XGDQ=; b=T OuTZPMv9TawKueM4aUqUxM1o1MWUT65xCvdz0fNaNVaF+8W9l1uweIJEpy63x5em hq6b4vGxlBtoRmONT3LOTVAzf1r8bgkH4Ohc6SoqKx2sjAqmCC0bfYHuwIb06Ct0 0CIyVFE1Jtz0t+/DeSbgETDQuttjQq/l2iq7eJgQcj3ZX3Fw3LPcusZo1mzN0x3G CW1zScCslQ0faZRQDI/XED7KuKMQslTjQj7gzdj0yhA/4nwElWjf9PtXsHnBTdU7 +L9+EIOruCQahgtSVKdyz+8/yXvY3MaPhliyx4UZKzNpWbbQw4VcMW4gsjYg8504 a8KKDjn4HzH4xUWezjYsw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm1; t=1774920629; x=1775007029; bh=6 KDde5DhWzz5okBA1igZHYy01UUgchyUxpv5kg2XGDQ=; b=I3MRLV1BGz88iBDPu 5APTMnh1a62avHvjDy3z0mVUZXCfqiUmBRM4NccZiAoLYeNYOWHSNeubDy1GaPgZ q2vnAAG8U3o/fBM3sM5sxQRw7VKmRkZGg1bAIUd86nmHJrTYfIH48hWa/T4l6wva K4PeFSCdLQNK/3UdpJtGFEwWQpGOKHUFzOMXp69ZCF2b9ZGUa33KTZEGeRmtoXFf f0EvcgQaKA6prVtut+5F6+fTJWD+DhZKxluVtPtUscP/WuWYokOwCT3g/glw8k4R 1SnwcXBrwAQmFCTfZbJ3yKBy6/pKT1JiEz1fRw7sZ2Ds0buNfyfm+n7OGojFNk20 lGZ/w== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefgedrtddtgdefgedtheegucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfurfetoffkrfgpnffqhgenuceu rghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmnecujf gurhephffvvefufffkofgjfhgggfestdekredtredttdenucfhrhhomhepkfgrnhcumfgv nhhtuceorhgrvhgvnhesthhhvghmrgifrdhnvghtqeenucggtffrrghtthgvrhhnpedule egueffgfehudeufedtffeiudfghfejgeehvdffgefgjeetvdfffeeihfdvveenucevlhhu shhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehrrghvvghnsehthh gvmhgrfidrnhgvthdpnhgspghrtghpthhtohepudeipdhmohguvgepshhmthhpohhuthdp rhgtphhtthhopegsrhgruhhnvghrsehkvghrnhgvlhdrohhrghdprhgtphhtthhopehvih hrohesiigvnhhivhdrlhhinhhugidrohhrghdruhhkpdhrtghpthhtoheprhgrvhgvnhes thhhvghmrgifrdhnvghtpdhrtghpthhtohepmhhikhhlohhssehsiigvrhgvughirdhhuh dprhgtphhtthhopehsrghnuggvvghnsehsrghnuggvvghnrdhnvghtpdhrtghpthhtohep fhhsohhrvghnshhosehrvgguhhgrthdrtghomhdprhgtphhtthhopehjrggvshhhihhnse hrvgguhhgrthdrtghomhdprhgtphhtthhopehtohhrvhgrlhgusheslhhinhhugidqfhho uhhnuggrthhiohhnrdhorhhgpdhrtghpthhtoheplhgrohgrrhdrshhhrghosehgmhgrih hlrdgtohhm X-ME-Proxy: Feedback-ID: i31e841b0:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 30 Mar 2026 21:30:23 -0400 (EDT) From: Ian Kent To: Christian Brauner , Al Viro Cc: Ian Kent , Miklos Szeredi , Eric Sandeen , Frank Sorenson , Jay Shin , Linus Torvalds , Yafang Shao , Jan Kara , Waiman Long , Matthew Wilcox , Wangkai , Colin Walters , linux-fsdevel , Kernel Mailing List Subject: [RFC PATCH] vfs: limit directory child dentry retention Date: Tue, 31 Mar 2026 09:29:09 +0800 Message-ID: <20260331012925.74840-2-raven@themaw.net> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260331012925.74840-1-raven@themaw.net> References: <20260331012925.74840-1-raven@themaw.net> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" If there's a very large number of children present in a directory dentry then the benifit from retaining stale child dentries for re-use can become ineffective. Even hashed lookup can become ineffective as hash chains grow, time taken to umount a file system can increase a lot, as well as child dentry traversals resulting in lock held too long log messages. But when a directory dentry has a very large number of children the parent dentry reference count is dominated by the contribution of its children. So it makes sense to not retain dentries if the parent reference count is large. Setting some large high water mark (eg. 500000) over which dentries are discarded instead of retained on final dput() would help a lot by preventing dentry caching contributing to the problem. Signed-off-by: Ian Kent --- Documentation/admin-guide/sysctl/fs.rst | 7 +++++++ fs/dcache.c | 28 +++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/Documentation/admin-guide/sysctl/fs.rst b/Documentation/admin-= guide/sysctl/fs.rst index 9b7f65c3efd8..7649254f2d0d 100644 --- a/Documentation/admin-guide/sysctl/fs.rst +++ b/Documentation/admin-guide/sysctl/fs.rst @@ -75,6 +75,13 @@ negative dentries which do not map to any files. Instead, they help speeding up rejection of non-existing files provided by the users. =20 +dir-stale-max +------------- + +Used to limit the number of stale child dentries retained in a +directory before the benifit of caching the dentry is negated by +the cost of traversing hash buckets during lookups or enumerating +the directory children. Initially set to 500000. =20 file-max & file-nr ------------------ diff --git a/fs/dcache.c b/fs/dcache.c index 7ba1801d8132..298b4c3b1493 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -86,6 +86,14 @@ __cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock); =20 EXPORT_SYMBOL(rename_lock); =20 +static long dsm_zero =3D 0; +static long dsm_max =3D ULONG_MAX/2; + +/* Highwater mark for number of stale entries in a directory (loosely + * measured by parent dentry reference count). + */ +static unsigned long dir_stale_max __read_mostly =3D 500000; + static struct kmem_cache *__dentry_cache __ro_after_init; #define dentry_cache runtime_const_ptr(__dentry_cache) =20 @@ -216,6 +224,15 @@ static const struct ctl_table fs_dcache_sysctls[] =3D { .extra1 =3D SYSCTL_ZERO, .extra2 =3D SYSCTL_ONE, }, + { + .procname =3D "dir-stale-max", + .data =3D &dir_stale_max, + .maxlen =3D sizeof(dir_stale_max), + .mode =3D 0644, + .proc_handler =3D proc_doulongvec_minmax, + .extra1 =3D &dsm_zero, + .extra2 =3D &dsm_max, + }, }; =20 static const struct ctl_table vm_dcache_sysctls[] =3D { @@ -768,6 +785,17 @@ static inline bool retain_dentry(struct dentry *dentry= , bool locked) if (unlikely(d_flags & DCACHE_DONTCACHE)) return false; =20 + if (dir_stale_max) { + unsigned long p_count; + + // If the parent reference count is higher than some large value + // its dominated by the contribution of its children so there's + // no benefit caching the dentry over re-allocating it. + p_count =3D READ_ONCE(dentry->d_parent->d_lockref.count); + if (unlikely(p_count > dir_stale_max)) + return false; + } + // At this point it looks like we ought to keep it. We also might // need to do something - put it on LRU if it wasn't there already // and mark it referenced if it was on LRU, but not marked yet. --=20 2.53.0