From: Joshua Hahn <joshua.hahnjy@gmail.com>
To: "Johannes Weiner" <hannes@cmpxchg.org>,
"Shakeel Butt" <shakeel.butt@linux.dev>,
"Michal Hocko" <mhocko@kernel.org>,
"Michal Koutný" <mkoutny@suse.com>
Cc: Roman Gushchin <roman.gushchin@linux.dev>,
Muchun Song <muchun.song@linux.dev>,
Andrew Morton <akpm@linux-foundation.org>,
Kuniyuki Iwashima <kuniyu@google.com>,
Harry Yoo <harry@kernel.org>,
David Hildenbrand <david@kernel.org>,
Lorenzo Stoakes <ljs@kernel.org>,
"Liam R. Howlett" <liam@infradead.org>,
Vlastimil Babka <vbabka@kernel.org>,
Mike Rapoport <rppt@kernel.org>,
Suren Baghdasaryan <surenb@google.com>,
Maarten Lankhorst <dev@lankhorst.se>,
Maxime Ripard <mripard@kernel.org>,
Natalie Vock <nat@pixelcluster.dev>, Tejun Heo <tj@kernel.org>,
Oscar Salvador <osalvador@suse.de>,
cgroups@vger.kernel.org, linux-mm@kvack.org,
linux-kernel@vger.kernel.org, kernel-team@meta.com
Subject: [PATCH v8 7/7] mm/memcontrol: restrict memory stock to leaf cgroups on v2
Date: Wed, 4 Nov 2026 15:30:28 -0800 [thread overview]
Message-ID: <20261104233029.3282438-8-joshua.hahnjy@gmail.com> (raw)
In-Reply-To: <20261104233029.3282438-1-joshua.hahnjy@gmail.com>
In the old memcg_stock world, non-leaf cgroups in cgroup v2 were never
directly charged (except for reparented objcgs), since processes can
only live in leaf cgroups. This meant that stocking was exclusive to
leaf cgroups.
In the new page_counter_stock world, stock belongs to each page_counter.
To get parity with vanilla stock, prevent stock from accumulating in
page_counters once they have children. This makes sure that stock does
not get stranded in the hierarchy, unable to be used by processes that
actually charge. When a parent becomes a leaf again, re-enable stock.
Prevent stock from accumulating in non-leaf page_counters in three ways:
1. Clear the parent's memory stock pointer to make sure the stock cannot
get refilled in the future.
2. Schedule drains for non-isolated CPUs that stock the new parent.
3. CPUs that are not drained due to either isolation or racing with a
refill are cleaned up lazily. The next local stock miss on that CPU
scans for any stock that has been disabled, and will drain its stock.
Note that this happens under the local stock lock, but this is rare.
Signed-off-by: Joshua Hahn <joshua.hahnjy@gmail.com>
---
mm/memcontrol.c | 28 ++++++++++++++++++++++++++++
mm/page_counter.c | 8 +++++++-
2 files changed, 35 insertions(+), 1 deletion(-)
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index aac987ebaab6f..a7549fd06d93e 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -2185,6 +2185,22 @@ static void schedule_stock_drain(struct page_counter_stock_pcp __percpu *stock,
clear_bit(FLUSHING_CACHED_CHARGE, &pcp_stock->flags);
}
+static void mem_cgroup_disable_stock(struct mem_cgroup *memcg)
+{
+ struct page_counter_stock_pcp __percpu *stock;
+ int cpu, curcpu;
+
+ stock = xchg(&memcg->memory.stock, NULL);
+ if (!stock)
+ return;
+
+ migrate_disable();
+ curcpu = smp_processor_id();
+ for_each_online_cpu(cpu)
+ schedule_stock_drain(stock, &memcg->css, cpu, curcpu);
+ migrate_enable();
+}
+
/*
* Drains all per-CPU charge caches for given root_memcg resp. subtree
* of the hierarchy under it.
@@ -4308,6 +4324,9 @@ static int mem_cgroup_css_online(struct cgroup_subsys_state *css)
*/
xa_store(&mem_cgroup_private_ids, memcg->private_id, memcg->private_id_objcg, GFP_KERNEL);
+ if (cgroup_subsys_on_dfl(memory_cgrp_subsys) && css->parent)
+ mem_cgroup_disable_stock(parent_mem_cgroup(memcg));
+
return 0;
free_objcg:
for_each_node(nid) {
@@ -4360,6 +4379,15 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css)
drain_all_stock(memcg);
mem_cgroup_private_id_kill(memcg);
+
+ if (cgroup_subsys_on_dfl(memory_cgrp_subsys)) {
+ struct mem_cgroup *parent = parent_mem_cgroup(memcg);
+
+ if (parent && !css_is_dying(&parent->css) &&
+ atomic_read(&parent->css.online_cnt) == 2 &&
+ !mem_cgroup_is_root(parent))
+ WRITE_ONCE(parent->memory.stock, &memory_stock);
+ }
}
static void mem_cgroup_css_released(struct cgroup_subsys_state *css)
diff --git a/mm/page_counter.c b/mm/page_counter.c
index e1feb2bd1e225..7a3b7cea0ff94 100644
--- a/mm/page_counter.c
+++ b/mm/page_counter.c
@@ -158,6 +158,7 @@ static void page_counter_drain_stock(struct page_counter_stock_pcp *stock,
* Consume the cached charge if enough nr_pages are present, otherwise return
* failure. Also return failure for charge requests larger than
* PAGE_COUNTER_STOCK_BATCH or if the local lock is already taken.
+ * Drain disabled cached counters while looking up the requested counter.
*/
static bool page_counter_consume_stock(struct page_counter *counter,
unsigned long nr_pages)
@@ -176,12 +177,17 @@ static bool page_counter_consume_stock(struct page_counter *counter,
for (i = 0; i < NR_PAGE_COUNTER_STOCK; i++) {
struct page_counter *cached = pcp_stock->cached[i];
+ /* Drain any stock that is disabled but hasn't drained yet */
+ if (cached && !READ_ONCE(cached->stock)) {
+ page_counter_drain_stock(pcp_stock, i);
+ continue;
+ }
if (counter != cached)
continue;
stock_pages = pcp_stock->nr_pages[i];
if (unlikely(stock_pages < nr_pages))
- break;
+ continue;
stock_pages -= nr_pages;
WRITE_ONCE(pcp_stock->nr_pages[i], stock_pages);
--
2.53.0-Meta
next prev parent reply other threads:[~2026-11-04 23:30 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-04 23:30 [PATCH v8 0/7] mm/page_counter: move stock from mem_cgroup to page_counter Joshua Hahn
2026-11-04 23:30 ` [PATCH v8 1/7] mm/memcontrol: flatten try_charge_memcg control flow Joshua Hahn
2026-11-05 6:08 ` Balbir Singh
2026-11-04 23:30 ` [PATCH v8 2/7] mm/page_counter: introduce per-CPU stock Joshua Hahn
2026-11-04 23:30 ` [PATCH v8 3/7] mm/page_counter: make page_counter_try_charge() stock-aware Joshua Hahn
2026-11-04 23:30 ` [PATCH v8 4/7] mm/memcontrol: check PF_MEMALLOC after trying the limits Joshua Hahn
2026-11-04 23:30 ` [PATCH v8 5/7] mm/memcontrol: move memory stock to page counters Joshua Hahn
2026-11-04 23:30 ` [PATCH v8 6/7] mm/memcontrol: add stock to the memsw page counter Joshua Hahn
2026-11-04 23:30 ` Joshua Hahn [this message]
2026-11-05 6:17 ` [PATCH v8 0/7] mm/page_counter: move stock from mem_cgroup to page_counter Balbir Singh
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=20261104233029.3282438-8-joshua.hahnjy@gmail.com \
--to=joshua.hahnjy@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=cgroups@vger.kernel.org \
--cc=david@kernel.org \
--cc=dev@lankhorst.se \
--cc=hannes@cmpxchg.org \
--cc=harry@kernel.org \
--cc=kernel-team@meta.com \
--cc=kuniyu@google.com \
--cc=liam@infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=ljs@kernel.org \
--cc=mhocko@kernel.org \
--cc=mkoutny@suse.com \
--cc=mripard@kernel.org \
--cc=muchun.song@linux.dev \
--cc=nat@pixelcluster.dev \
--cc=osalvador@suse.de \
--cc=roman.gushchin@linux.dev \
--cc=rppt@kernel.org \
--cc=shakeel.butt@linux.dev \
--cc=surenb@google.com \
--cc=tj@kernel.org \
--cc=vbabka@kernel.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®