[Devel] [PATCH RHEL10 COMMIT] cgroup-v2/freezer: Print information about unfreezable process

Konstantin Khorenko khorenko at virtuozzo.com
Wed Nov 19 16:46:49 MSK 2025


The commit is pushed to "branch-rh10-6.12.0-55.13.1.2.x.vz10-ovz" and will appear at git at bitbucket.org:openvz/vzkernel.git
after rh10-6.12.0-55.13.1.2.18.vz10
------>
commit 2b16bcfc28fc704da99f56f6b868a07d5be874eb
Author: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
Date:   Wed Nov 19 11:36:45 2025 +0800

    cgroup-v2/freezer: Print information about unfreezable process
    
    We already had this feature in cgroup-v1 freezer, so let's also have it
    for cgroup-v2. Difference in cgroup-v2 freezer is that there is no loop
    over tasks like in freezer_read() -> update_if_frozen(),
    cgroup_events_show() only checks CGRP_FROZEN flag, so we have to
    add our own loop over each descendant css and each task in it.
    
    Note: freeze_jiffies is protected with css_set_lock together with
    CGRP_FREEZE bit.
    
    https://virtuozzo.atlassian.net/browse/VSTOR-118578
    Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
    
    Feature: cgroup/freeze: enhance logging
---
 include/linux/cgroup-defs.h    |  5 +++
 include/linux/cgroup.h         |  3 ++
 kernel/cgroup/cgroup.c         | 97 ++++++++++++++++++++++++++++++++++++++++++
 kernel/cgroup/freezer.c        |  8 +++-
 kernel/cgroup/legacy_freezer.c | 36 +---------------
 5 files changed, 112 insertions(+), 37 deletions(-)

diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h
index d68fca31e6e65..d8c489a408815 100644
--- a/include/linux/cgroup-defs.h
+++ b/include/linux/cgroup-defs.h
@@ -424,6 +424,11 @@ struct cgroup_freezer_state {
 	 * Number of kernel threads in this cgroup
 	 */
 	int nr_kthreads;
+
+	/*
+	 * Jiffies of last freeze
+	 */
+	u64 freeze_jiffies;
 };
 
 struct cgroup {
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 86ee6604a5207..2e01e484cbac7 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -876,4 +876,7 @@ struct cgroup *task_get_cgroup1(struct task_struct *tsk, int hierarchy_id);
 
 struct cgroup_of_peak *of_peak(struct kernfs_open_file *of);
 
+void warn_freeze_timeout_task(struct cgroup *cgrp, int timeout,
+			      struct task_struct *task);
+
 #endif /* _LINUX_CGROUP_H */
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 2f7db20f8a460..561fab2179d24 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -61,6 +61,9 @@
 #include <linux/psi.h>
 #include <net/sock.h>
 #include <linux/task_work.h>
+#include <linux/ratelimit.h>
+#include <linux/stacktrace.h>
+#include <linux/sysctl.h>
 #include <linux/ve.h>
 
 #define CREATE_TRACE_POINTS
@@ -4099,6 +4102,98 @@ static ssize_t cgroup_max_depth_write(struct kernfs_open_file *of,
 	return nbytes;
 }
 
+#define MAX_STACK_TRACE_DEPTH 64
+
+void warn_freeze_timeout_task(struct cgroup *cgrp, int timeout,
+			      struct task_struct *task)
+{
+	char *buf __free(kfree) = NULL;
+	unsigned long *entries __free(kfree) = NULL;
+	unsigned long nr_entries, i;
+	pid_t tgid;
+
+	buf = kmalloc(PATH_MAX, GFP_KERNEL);
+	if (!buf)
+		return;
+
+	if (cgroup_path(cgrp, buf, PATH_MAX) < 0)
+		return;
+
+	tgid = task_pid_nr_ns(task, &init_pid_ns);
+	printk(KERN_WARNING "Freeze of %s took %d sec, "
+	       "due to unfreezable process %d:%s, stack:\n",
+	       buf, timeout/HZ, tgid, task->comm);
+
+	entries = kmalloc(MAX_STACK_TRACE_DEPTH * sizeof(*entries),
+			  GFP_KERNEL);
+	if (!entries)
+		return;
+	nr_entries = stack_trace_save_tsk(task, entries,
+					  MAX_STACK_TRACE_DEPTH, 0);
+	for (i = 0; i < nr_entries; i++)
+		printk(KERN_WARNING "[<%pK>] %pB\n",
+		       (void *)entries[i], (void *)entries[i]);
+}
+
+static void warn_freeze_timeout(struct cgroup *cgrp, int timeout)
+{
+	struct cgroup_subsys_state *css;
+	char *buf __free(kfree) = NULL;
+
+	guard(rcu)();
+	css_for_each_descendant_post(css, &cgrp->self) {
+		struct task_struct *task;
+		struct css_task_iter it;
+
+		css_task_iter_start(css, 0, &it);
+		while ((task = css_task_iter_next(&it))) {
+			if (task->flags & PF_KTHREAD)
+				continue;
+			if (task->frozen)
+				continue;
+
+			warn_freeze_timeout_task(cgrp, timeout, task);
+			css_task_iter_end(&it);
+			return;
+		}
+		css_task_iter_end(&it);
+	}
+
+	buf = kmalloc(PATH_MAX, GFP_KERNEL);
+	if (!buf)
+		return;
+
+	if (cgroup_path(cgrp, buf, PATH_MAX) < 0)
+		return;
+
+	printk(KERN_WARNING "Freeze of %s took %d sec, "
+	       "but no unfreezable process detected\n", buf, timeout/HZ);
+}
+
+static void check_freeze_timeout(struct cgroup *cgrp)
+{
+	static DEFINE_RATELIMIT_STATE(freeze_timeout_rs,
+				      DEFAULT_FREEZE_TIMEOUT, 1);
+	u64 freeze_jiffies;
+	int timeout;
+
+	scoped_guard(spinlock, &css_set_lock) {
+		if (!test_bit(CGRP_FREEZE, &cgrp->flags) ||
+		    test_bit(CGRP_FROZEN, &cgrp->flags))
+			return;
+		freeze_jiffies = READ_ONCE(cgrp->freezer.freeze_jiffies);
+	}
+
+	timeout = READ_ONCE(sysctl_freeze_timeout);
+	if (!freeze_jiffies || time_is_after_jiffies64(freeze_jiffies + timeout))
+		return;
+
+	if (!__ratelimit(&freeze_timeout_rs))
+		return;
+
+	warn_freeze_timeout(cgrp, timeout);
+}
+
 static int cgroup_events_show(struct seq_file *seq, void *v)
 {
 	struct cgroup *cgrp = seq_css(seq)->cgroup;
@@ -4106,6 +4201,8 @@ static int cgroup_events_show(struct seq_file *seq, void *v)
 	seq_printf(seq, "populated %d\n", cgroup_is_populated(cgrp));
 	seq_printf(seq, "frozen %d\n", test_bit(CGRP_FROZEN, &cgrp->flags));
 
+	check_freeze_timeout(cgrp);
+
 	return 0;
 }
 
diff --git a/kernel/cgroup/freezer.c b/kernel/cgroup/freezer.c
index a2d9e55257bcc..e6ef44d0ab4a8 100644
--- a/kernel/cgroup/freezer.c
+++ b/kernel/cgroup/freezer.c
@@ -3,6 +3,7 @@
 #include <linux/sched.h>
 #include <linux/sched/task.h>
 #include <linux/sched/signal.h>
+#include <linux/jiffies.h>
 
 #include "cgroup-internal.h"
 
@@ -183,10 +184,13 @@ static void cgroup_do_freeze(struct cgroup *cgrp, bool freeze)
 	lockdep_assert_held(&cgroup_mutex);
 
 	spin_lock_irq(&css_set_lock);
-	if (freeze)
+	if (freeze) {
 		set_bit(CGRP_FREEZE, &cgrp->flags);
-	else
+		cgrp->freezer.freeze_jiffies = get_jiffies_64();
+	} else {
 		clear_bit(CGRP_FREEZE, &cgrp->flags);
+		cgrp->freezer.freeze_jiffies = 0;
+	}
 	spin_unlock_irq(&css_set_lock);
 
 	if (freeze)
diff --git a/kernel/cgroup/legacy_freezer.c b/kernel/cgroup/legacy_freezer.c
index b048f6b530688..a59e5a14f45ed 100644
--- a/kernel/cgroup/legacy_freezer.c
+++ b/kernel/cgroup/legacy_freezer.c
@@ -25,7 +25,6 @@
 #include <linux/cpu.h>
 #include <linux/jiffies.h>
 #include <linux/ratelimit.h>
-#include <linux/stacktrace.h>
 #include <linux/sysctl.h>
 
 /*
@@ -244,11 +243,6 @@ static void check_freezer_timeout(struct cgroup_subsys_state *css,
 				      DEFAULT_FREEZE_TIMEOUT, 1);
 	int __freeze_timeout = READ_ONCE(sysctl_freeze_timeout);
 	struct freezer *freezer = css_freezer(css);
-	unsigned long nr_entries;
-	unsigned long *entries;
-	char *freezer_cg_name;
-	pid_t tgid;
-	int i;
 
 	if (!freezer->freeze_jiffies ||
 	    freezer->freeze_jiffies + __freeze_timeout > get_jiffies_64())
@@ -257,35 +251,7 @@ static void check_freezer_timeout(struct cgroup_subsys_state *css,
 	if (!__ratelimit(&freeze_timeout_rs))
 		return;
 
-	freezer_cg_name = kmalloc(PATH_MAX, GFP_KERNEL);
-	if (!freezer_cg_name)
-		return;
-
-	if (cgroup_path(css->cgroup, freezer_cg_name, PATH_MAX) < 0)
-		goto free_cg_name;
-
-	tgid = task_pid_nr_ns(task, &init_pid_ns);
-
-	printk(KERN_WARNING "Freeze of %s took %d sec, "
-	       "due to unfreezable process %d:%s, stack:\n",
-	       freezer_cg_name, __freeze_timeout/HZ, tgid, task->comm);
-
-	entries = kmalloc(MAX_STACK_TRACE_DEPTH * sizeof(*entries),
-			  GFP_KERNEL);
-	if (!entries)
-		goto free_cg_name;
-
-	nr_entries = stack_trace_save_tsk(task, entries,
-					  MAX_STACK_TRACE_DEPTH, 0);
-
-	for (i = 0; i < nr_entries; i++) {
-		printk(KERN_WARNING "[<%pK>] %pB\n",
-		       (void *)entries[i], (void *)entries[i]);
-	}
-
-	kfree(entries);
-free_cg_name:
-	kfree(freezer_cg_name);
+	warn_freeze_timeout_task(css->cgroup, __freeze_timeout, task);
 }
 
 /**


More information about the Devel mailing list