From: Rohit Ner <rohitner@google.com>
To: Johannes Weiner <hannes@cmpxchg.org>,
Michal Hocko <mhocko@kernel.org>,
Roman Gushchin <roman.gushchin@linux.dev>,
Shakeel Butt <shakeel.butt@linux.dev>,
Andrew Morton <akpm@linux-foundation.org>
Cc: Muchun Song <muchun.song@linux.dev>,
cgroups@vger.kernel.org, linux-mm@kvack.org,
linux-kernel@vger.kernel.org, Rohit Ner <rohitner@google.com>
Subject: [PATCH] mm/memcontrol: log userspace OOM wait entry and completion
Date: Tue, 13 Oct 2026 04:00:34 +0000 [thread overview]
Message-ID: <20261013040034.3919469-1-rohitner@google.com> (raw)
When a memory cgroup hits its limit with memory.oom_control
oom_kill_disable configured, mem_cgroup_oom_synchronize() puts the
faulting task to sleep on memcg_oom_waitq and notifies userspace OOM
handlers to reclaim memory, enlarge limits, or terminate tasks. On
platforms where userspace is severely stalled under memory pressure
before a hardware or software watchdog reset, no kernel breadcrumb is
currently emitted when a memcg enters or exits this userspace OOM wait.
Log rate-limited KERN_ERR messages (pr_err_ratelimited) upon entering
and completing the userspace OOM wait in mem_cgroup_oom_synchronize(),
including the memcg path, memory usage/limit/unevictable stats, elapsed
waited_ms, and whether the task exited due to a fatal signal.
Signed-off-by: Rohit Ner <rohitner@google.com>
---
mm/memcontrol-v1.c | 49 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 48 insertions(+), 1 deletion(-)
diff --git a/mm/memcontrol-v1.c b/mm/memcontrol-v1.c
index 05ef55cae..7832ce11f 100644
--- a/mm/memcontrol-v1.c
+++ b/mm/memcontrol-v1.c
@@ -91,6 +91,12 @@ struct mem_cgroup_event {
#define MEMFILE_TYPE(val) ((val) >> 16 & 0xffff)
#define MEMFILE_ATTR(val) ((val) & 0xffff)
+#define MEMCG_OOM_WAIT_PATH_LEN 128
+#define MEMCG_OOM_STAGE_ENTER "enter"
+#define MEMCG_OOM_STAGE_RECOVERED "recovered"
+#define MEMCG_OOM_STAGE_KILLED "killed"
+#define MEMCG_OOM_UNKNOWN_PATH "<unknown>"
+
enum {
RES_USAGE,
RES_LIMIT,
@@ -1372,6 +1378,34 @@ void memcg1_oom_recover(struct mem_cgroup *memcg)
__wake_up(&memcg_oom_waitq, TASK_NORMAL, 0, memcg);
}
+/**
+ * memcg1_log_oom_wait - Log memcg userspace OOM wait entry and completion
+ * @memcg: The memory cgroup experiencing the userspace OOM wait
+ * @stage: Lifecycle stage string ("enter", "recovered", or "killed")
+ * @waited_ms: Elapsed time spent waiting on memcg_oom_waitq in milliseconds
+ * @killed: Whether the waiting task woke with a fatal signal pending
+ *
+ * Emits a rate-limited KERN_ERR message so that memcg userspace OOM handler
+ * stalls are captured on serial consoles even when booted with quiet
+ * (console_loglevel=4) and preserved in dmesg.
+ */
+static void memcg1_log_oom_wait(struct mem_cgroup *memcg, const char *stage,
+ unsigned int waited_ms, bool killed)
+{
+ char cgrp_path[MEMCG_OOM_WAIT_PATH_LEN];
+ u64 usage_kb = K((u64)page_counter_read(&memcg->memory));
+ u64 limit_kb = K((u64)READ_ONCE(memcg->memory.max));
+ u64 unevictable_kb = K((u64)memcg_page_state(memcg, NR_UNEVICTABLE));
+
+ if (cgroup_path(memcg->css.cgroup, cgrp_path, sizeof(cgrp_path)) < 0)
+ strscpy(cgrp_path, MEMCG_OOM_UNKNOWN_PATH, sizeof(cgrp_path));
+
+ pr_err_ratelimited("memcg_oom_wait: stage=%s cgroup=%s comm=%s pid=%d usage_kb=%llu limit_kb=%llu unevictable_kb=%llu waited_ms=%u killed=%d\n",
+ stage, cgrp_path, current->comm, current->pid,
+ usage_kb, limit_kb, unevictable_kb,
+ waited_ms, killed);
+}
+
/**
* mem_cgroup_oom_synchronize - complete memcg OOM handling
* @handle: actually kill/wait or just clean up the OOM state
@@ -1393,6 +1427,7 @@ bool mem_cgroup_oom_synchronize(bool handle)
{
struct mem_cgroup *memcg = current->memcg_in_oom;
struct oom_wait_info owait;
+ unsigned long start_jiffies = 0;
bool locked;
/* OOM is global, do not handle */
@@ -1413,10 +1448,22 @@ bool mem_cgroup_oom_synchronize(bool handle)
locked = mem_cgroup_oom_trylock(memcg);
- if (locked)
+ if (locked) {
+ start_jiffies = jiffies;
+ memcg1_log_oom_wait(memcg, MEMCG_OOM_STAGE_ENTER, 0, false);
mem_cgroup_oom_notify(memcg);
+ }
schedule();
+ if (locked) {
+ bool killed = fatal_signal_pending(current);
+
+ memcg1_log_oom_wait(memcg,
+ killed ? MEMCG_OOM_STAGE_KILLED :
+ MEMCG_OOM_STAGE_RECOVERED,
+ jiffies_to_msecs(jiffies - start_jiffies),
+ killed);
+ }
mem_cgroup_unmark_under_oom(memcg);
finish_wait(&memcg_oom_waitq, &owait.wait);
--
2.56.0.385.gd3acb90ef8-goog
next reply other threads:[~2026-10-13 4:00 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-13 4:00 Rohit Ner [this message]
2026-10-13 8:22 ` [PATCH] mm/memcontrol: log userspace OOM wait entry and completion Michal Hocko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261013040034.3919469-1-rohitner@google.com \
--to=rohitner@google.com \
--cc=akpm@linux-foundation.org \
--cc=cgroups@vger.kernel.org \
--cc=hannes@cmpxchg.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=mhocko@kernel.org \
--cc=muchun.song@linux.dev \
--cc=roman.gushchin@linux.dev \
--cc=shakeel.butt@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.