Re: [REGRESSION] kernfs: empty cgroup rmdir latency after delete-notification changes
From: "T.J. Mercier" <tjmercier@google.com>
Date: 2026-09-13 16:17:55
Also in:
driver-core, linux-fsdevel, lkml, regressions
Subsystem:
filesystems (vfs and infrastructure), kernfs, the rest · Maintainers:
Alexander Viro, Christian Brauner, Greg Kroah-Hartman, Tejun Heo, Linus Torvalds
On Sun, Sep 13, 2026 at 8:47 AM Chengfeng Lin [off-list ref] wrote:
Hi Tejun, Thanks. I found this during research into kernel performance regressions, using a microbenchmark of cgroup creation and removal. This was not prompted by a production issue. I reported it to document the added removal cost and ask whether some of it could be reduced while preserving the fixes. I agree that the roughly 3 us increase per removal does not, by itself, demonstrate a significant impact on real workloads. Thanks, Chengfeng Tejun Heo [off-list ref] 于2026年9月13日周日 23:03写道:quoted
Hello, On Sun, Sep 13, 2026 at 10:43:04PM +0800, Chengfeng Lin wrote:quoted
I found an increase in empty cgroup removal latency across 507d8ce13f5b ("kernfs: Don't set_nlink for directories being removed") and eea5d2bb34ba ("kernfs: Send IN_DELETE_SELF and IN_IGNORED"). With sched_ext disabled, rmdir() went from about 6.5 us to 9.6 us, an increase of 46-47%. The result held in two independent runs.I don't want to make cgroup removal unnecessarily expensive but at the same time it's not an operation that I consider to be a hot path, so as long as the operaiton can finish in a reasonable amount of time and single digit us definitely is, performance of rmdir usually isn't something which is high in priority. Can you please detail why this matters for you? Thanks. -- tejun
Hi Chengfeng and Tejun, We use this kernfs IN_DELETE_SELF feature on Android where multiple cgroups are created and removed frequently on a per-application basis, but we hadn't noticed a significant delay due to the inotify functionality during cgroup removal. It's probably masked by much larger delays (milliseconds) we regularly see due to unreleated issues with cgroup locks like priority inversion with cgroup_mutex, and contention for cgroup_threadgroup_rwsem. As far as what we can do, I think avoiding inode lookups for kernfs nodes that never had an inode created should improve the situation. It doesn't eliminate the locking overhead, which I don't think can easily be eliminated. The code below doesn't deal with inode eviction either, but at least files which are never accessed won't introduce the inode lookup overhead.
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 4f9ade82b08a..3ec9f79b1aa2 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c@@ -1523,6 +1523,9 @@ static void kernfs_clear_inode_nlink(structkernfs_node *kn)
struct kernfs_root *root = kernfs_root(kn);
struct kernfs_super_info *info;
+ if (!(kn->flags & KERNFS_INODE_INITED))
+ return;
+
lockdep_assert_held_read(&root->kernfs_supers_rwsem);
list_for_each_entry(info, &root->supers, node) {diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c
index 38b28aa7cd02..f8b4a8b8ade4 100644
--- a/fs/kernfs/inode.c
+++ b/fs/kernfs/inode.c@@ -208,6 +208,10 @@ static void kernfs_init_inode(struct kernfs_node*kn, struct inode *inode)
set_default_inode_attr(inode, kn->mode);
kernfs_refresh_inode(kn, inode);
+ down_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
+ kn->flags |= KERNFS_INODE_INITED;
+ up_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
+
/* initialize inode according to type */
switch (kernfs_type(kn)) {
case KERNFS_DIR:diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h
index e21b2f7f4159..87f074ce19d3 100644
--- a/include/linux/kernfs.h
+++ b/include/linux/kernfs.h@@ -113,6 +113,7 @@ enum kernfs_node_flag { KERNFS_EMPTY_DIR = 0x1000, KERNFS_HAS_RELEASE = 0x2000, KERNFS_REMOVING = 0x4000, + KERNFS_INODE_INITED = 0x8000, }; -T.J.