]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
cgroup: reduce cgroup_file_kn_lock hold time in cgroup_file_notify()
authorShakeel Butt <shakeel.butt@linux.dev>
Wed, 11 Mar 2026 01:00:59 +0000 (18:00 -0700)
committerTejun Heo <tj@kernel.org>
Wed, 11 Mar 2026 22:16:21 +0000 (12:16 -1000)
cgroup_file_notify() calls kernfs_notify() while holding the global
cgroup_file_kn_lock.  kernfs_notify() does non-trivial work including
wake_up_interruptible() and acquisition of a second global spinlock
(kernfs_notify_lock), inflating the hold time.

Take a kernfs_get() reference under the lock and call kernfs_notify()
after dropping it, following the pattern from cgroup_file_show().

Reported-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Shakeel Butt <shakeel.butt@linux.dev>
Signed-off-by: Tejun Heo <tj@kernel.org>
kernel/cgroup/cgroup.c

index cdc63be63f2c7f3d8d9d309d71a11404add0faaf..26d8df60a59fa8670ac6f11e292ffc9274a64d78 100644 (file)
@@ -4632,6 +4632,7 @@ int cgroup_add_legacy_cftypes(struct cgroup_subsys *ss, struct cftype *cfts)
 void cgroup_file_notify(struct cgroup_file *cfile)
 {
        unsigned long flags;
+       struct kernfs_node *kn = NULL;
 
        spin_lock_irqsave(&cgroup_file_kn_lock, flags);
        if (cfile->kn) {
@@ -4641,11 +4642,17 @@ void cgroup_file_notify(struct cgroup_file *cfile)
                if (time_in_range(jiffies, last, next)) {
                        timer_reduce(&cfile->notify_timer, next);
                } else {
-                       kernfs_notify(cfile->kn);
+                       kn = cfile->kn;
+                       kernfs_get(kn);
                        cfile->notified_at = jiffies;
                }
        }
        spin_unlock_irqrestore(&cgroup_file_kn_lock, flags);
+
+       if (kn) {
+               kernfs_notify(kn);
+               kernfs_put(kn);
+       }
 }
 EXPORT_SYMBOL_GPL(cgroup_file_notify);