[Devel] [PATCH RH9] cgroup_freezer: print information about unfreezable process
Pavel Tikhomirov
ptikhomirov at virtuozzo.com
Fri Nov 25 15:47:59 MSK 2022
Add a sysctl kernel.freeze_cgroup_timeout (default value 30 * HZ).
If one writes FROZEN to freezer.state file and after a timeout of
kernel.freeze_cgroup_timeout one still reads FREEZING from freezer.state
file (meaning that kernel does not succeed to freeze cgroup processes
still) - let's print a warning with information about the problem, e.g.:
[ 7196.621368] Freeze of /test took 0 sec, due to unfreezable process 13732:bash, stack:
[ 7196.621396] [<ffffffffa2df9556>] retint_careful+0x14/0x32
[ 7196.621431] [<ffffffffffffffff>] 0xffffffffffffffff
The output includes:
- path to problematic freezer cgroup
- timeout in seconds
- unfeezable process pid, comm and stack
https://jira.sw.ru/browse/PSBM-142970
Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
---
vz9: switch to new stack_trace_save_tsk, and also use css
---
include/linux/sysctl.h | 2 ++
kernel/cgroup/legacy_freezer.c | 53 ++++++++++++++++++++++++++++++++--
kernel/sysctl.c | 10 +++++++
3 files changed, 62 insertions(+), 3 deletions(-)
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 8fd2d3c217c2..b641dd2bba82 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -188,6 +188,8 @@ struct ctl_path {
};
extern int trusted_exec;
+#define DEFAULT_FREEZE_TIMEOUT (30 * HZ)
+extern int sysctl_freeze_timeout;
extern int ve_allow_module_load;
diff --git a/kernel/cgroup/legacy_freezer.c b/kernel/cgroup/legacy_freezer.c
index 08236798d173..fc7ee3ad529b 100644
--- a/kernel/cgroup/legacy_freezer.c
+++ b/kernel/cgroup/legacy_freezer.c
@@ -22,6 +22,10 @@
#include <linux/freezer.h>
#include <linux/seq_file.h>
#include <linux/mutex.h>
+#include <linux/jiffies.h>
+#include <linux/ratelimit.h>
+#include <linux/stacktrace.h>
+#include <linux/sysctl.h>
/*
* A cgroup is freezing if any FREEZING flags are set. FREEZING_SELF is
@@ -43,6 +47,7 @@ enum freezer_state_flags {
struct freezer {
struct cgroup_subsys_state css;
unsigned int state;
+ unsigned long freeze_jiffies;
};
static DEFINE_MUTEX(freezer_mutex);
@@ -225,6 +230,42 @@ static void freezer_fork(struct task_struct *task)
mutex_unlock(&freezer_mutex);
}
+#define MAX_STACK_TRACE_DEPTH 64
+
+static void check_freezer_timeout(struct cgroup_subsys_state *css, struct task_struct *task)
+{
+ static DEFINE_RATELIMIT_STATE(freeze_timeout_rs, DEFAULT_FREEZE_TIMEOUT, 1);
+ int __freeze_timeout = READ_ONCE(sysctl_freeze_timeout);
+ struct freezer *freezer = css_freezer(css);
+ unsigned long entries[MAX_STACK_TRACE_DEPTH];
+ static char freezer_cg_name[PATH_MAX];
+ unsigned long nr_entries;
+ pid_t tgid;
+ int i;
+
+ if (!freezer->freeze_jiffies ||
+ freezer->freeze_jiffies + __freeze_timeout > get_jiffies_64())
+ return;
+
+ if (!__ratelimit(&freeze_timeout_rs))
+ return;
+
+ if (cgroup_path(css->cgroup, freezer_cg_name, 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",
+ freezer_cg_name, __freeze_timeout/HZ, tgid, task->comm);
+
+ 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]);
+ }
+}
+
/**
* update_if_frozen - update whether a cgroup finished freezing
* @css: css of interest
@@ -278,8 +319,10 @@ static void update_if_frozen(struct cgroup_subsys_state *css)
* completion. Consider it frozen in addition to
* the usual frozen condition.
*/
- if (!frozen(task) && !freezer_should_skip(task))
+ if (!frozen(task) && !freezer_should_skip(task)) {
+ check_freezer_timeout(css, task);
goto out_iter_end;
+ }
}
}
@@ -356,8 +399,10 @@ static void freezer_apply_state(struct freezer *freezer, bool freeze,
return;
if (freeze) {
- if (!(freezer->state & CGROUP_FREEZING))
+ if (!(freezer->state & CGROUP_FREEZING)) {
atomic_inc(&system_freezing_cnt);
+ freezer->freeze_jiffies = get_jiffies_64();
+ }
freezer->state |= state;
freeze_cgroup(freezer);
} else {
@@ -366,8 +411,10 @@ static void freezer_apply_state(struct freezer *freezer, bool freeze,
freezer->state &= ~state;
if (!(freezer->state & CGROUP_FREEZING)) {
- if (was_freezing)
+ if (was_freezing) {
+ freezer->freeze_jiffies = 0;
atomic_dec(&system_freezing_cnt);
+ }
freezer->state &= ~CGROUP_FROZEN;
unfreeze_cgroup(freezer);
}
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 16b6bc8db93b..6e369ec106b4 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -120,6 +120,8 @@ __setup("trusted_exec", set_trusted_exec);
int ve_allow_module_load = 1;
EXPORT_SYMBOL(ve_allow_module_load);
+int sysctl_freeze_timeout = DEFAULT_FREEZE_TIMEOUT;
+
/* Constants used for minimum and maximum */
#ifdef CONFIG_LOCKUP_DETECTOR
static int sixty = 60;
@@ -2847,6 +2849,14 @@ static struct ctl_table kern_table[] = {
.extra2 = SYSCTL_ONE,
},
#endif
+ {
+ .procname = "freeze_cgroup_timeout",
+ .data = &sysctl_freeze_timeout,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = &zero,
+ },
{ }
};
--
2.37.3
More information about the Devel
mailing list