From: Joshua Hahn <joshua.hahnjy@gmail.com>
To: hannes@cmpxchg.org, shakeel.butt@linux.dev, mhocko@kernel.org
Cc: roman.gushchin@linux.dev, muchun.song@linux.dev,
akpm@linux-foundation.org, david@kernel.org, ljs@kernel.org,
liam@infradead.org, vbabka@kernel.org, rppt@kernel.org,
surenb@google.com, dev@lankhorst.se, mripard@kernel.org,
nat@pixelcluster.dev, tj@kernel.org, mkoutny@suse.com,
osalvador@suse.de, cgroups@vger.kernel.org, linux-mm@kvack.org,
linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org,
kernel-team@meta.com
Subject: [PATCH v5 2/7] mm/page_counter: report the number of pages charged
Date: Mon, 31 Aug 2026 09:37:46 -0700 [thread overview]
Message-ID: <20260831163752.2193337-3-joshua.hahnjy@gmail.com> (raw)
In-Reply-To: <20260831163752.2193337-1-joshua.hahnjy@gmail.com>
Add an optional @nr_charged parameter to page_counter_try_charge.
On success, it will be set to the number of pages actually charged to
the hierarchy. Today this number is always @nr_pages, so there is no
functional change.
Of the 6 callsites, only one user (try_charge_memcg) uses that
information. The number of charged pages is added to
current->memcg_nr_pages_over_high to indicate how many pages it charged
to the hierarchy while over high.
Today, try_charge_memcg requests "batch" from page_counter_try_charge
and adds that same amount to memcg_nr_pages_over_high on success, since
page_counter_try_charge's only source of charges is the hierarchy.
However, this invariant changes later in the series when stock is pushed
down from the memcg level to the page_counter level, and a page_counter
charge can be successful without growing the hierarchy size.
Plumb the new parameter to all callsites, passing NULL where the source
of charge does not matter to the caller, and passing &nr_charged in
try_charge_memcg to account the hierarchy size growth.
No functional change intended.
Signed-off-by: Joshua Hahn <joshua.hahnjy@gmail.com>
---
include/linux/page_counter.h | 4 ++--
kernel/cgroup/dmem.c | 2 +-
mm/hugetlb_cgroup.c | 2 +-
mm/memcontrol-v1.c | 2 +-
mm/memcontrol.c | 10 ++++++----
mm/page_counter.c | 10 ++++++++--
6 files changed, 19 insertions(+), 11 deletions(-)
diff --git a/include/linux/page_counter.h b/include/linux/page_counter.h
index d649b6bbbc871..89a083f16fbf7 100644
--- a/include/linux/page_counter.h
+++ b/include/linux/page_counter.h
@@ -71,8 +71,8 @@ static inline unsigned long page_counter_read(struct page_counter *counter)
void page_counter_cancel(struct page_counter *counter, unsigned long nr_pages);
void page_counter_charge(struct page_counter *counter, unsigned long nr_pages);
bool page_counter_try_charge(struct page_counter *counter,
- unsigned long nr_pages,
- struct page_counter **fail);
+ unsigned long nr_pages, struct page_counter **fail,
+ unsigned long *nr_charged);
void page_counter_uncharge(struct page_counter *counter, unsigned long nr_pages);
void page_counter_set_min(struct page_counter *counter, unsigned long nr_pages);
void page_counter_set_low(struct page_counter *counter, unsigned long nr_pages);
diff --git a/kernel/cgroup/dmem.c b/kernel/cgroup/dmem.c
index 4683f3d680226..fbbbd0b09d290 100644
--- a/kernel/cgroup/dmem.c
+++ b/kernel/cgroup/dmem.c
@@ -736,7 +736,7 @@ int dmem_cgroup_try_charge(struct dmem_cgroup_region *region, u64 size,
goto err;
}
- if (!page_counter_try_charge(&pool->cnt, size, &fail)) {
+ if (!page_counter_try_charge(&pool->cnt, size, &fail, NULL)) {
if (ret_limit_pool) {
*ret_limit_pool = container_of(fail, struct dmem_cgroup_pool_state, cnt);
css_get(&(*ret_limit_pool)->cs->css);
diff --git a/mm/hugetlb_cgroup.c b/mm/hugetlb_cgroup.c
index ecb6e0b7819a0..6df4a69b0d529 100644
--- a/mm/hugetlb_cgroup.c
+++ b/mm/hugetlb_cgroup.c
@@ -274,7 +274,7 @@ static int __hugetlb_cgroup_charge_cgroup(int idx, unsigned long nr_pages,
if (!page_counter_try_charge(
__hugetlb_cgroup_counter_from_cgroup(h_cg, idx, rsvd),
- nr_pages, &counter)) {
+ nr_pages, &counter, NULL)) {
ret = -ENOMEM;
hugetlb_event(h_cg, idx, HUGETLB_MAX);
css_put(&h_cg->css);
diff --git a/mm/memcontrol-v1.c b/mm/memcontrol-v1.c
index bf2c7d53b01b1..cf514d1bd7c38 100644
--- a/mm/memcontrol-v1.c
+++ b/mm/memcontrol-v1.c
@@ -2194,7 +2194,7 @@ bool memcg1_charge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages,
{
struct page_counter *fail;
- if (page_counter_try_charge(&memcg->tcpmem, nr_pages, &fail)) {
+ if (page_counter_try_charge(&memcg->tcpmem, nr_pages, &fail, NULL)) {
memcg->tcpmem_pressure = 0;
return true;
}
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 93c2fa04da4fd..71410084fa7fc 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -2663,6 +2663,7 @@ static int try_charge_memcg(struct mem_cgroup *memcg, gfp_t gfp_mask,
struct mem_cgroup *mem_over_limit;
struct page_counter *counter;
unsigned long nr_reclaimed;
+ unsigned long nr_charged = 0;
bool passed_oom = false;
unsigned int reclaim_options;
bool drained = false;
@@ -2680,13 +2681,14 @@ static int try_charge_memcg(struct mem_cgroup *memcg, gfp_t gfp_mask,
reclaim_options = MEMCG_RECLAIM_MAY_SWAP;
if (do_memsw_account() &&
- !page_counter_try_charge(&memcg->memsw, batch, &counter)) {
+ !page_counter_try_charge(&memcg->memsw, batch, &counter, NULL)) {
mem_over_limit = mem_cgroup_from_counter(counter, memsw);
reclaim_options &= ~MEMCG_RECLAIM_MAY_SWAP;
goto reclaim;
}
- if (page_counter_try_charge(&memcg->memory, batch, &counter))
+ if (page_counter_try_charge(&memcg->memory, batch, &counter,
+ &nr_charged))
goto done_restock;
if (do_memsw_account())
@@ -2847,7 +2849,7 @@ static int try_charge_memcg(struct mem_cgroup *memcg, gfp_t gfp_mask,
* and distribute reclaim work and delay penalties
* based on how much each task is actually allocating.
*/
- current->memcg_nr_pages_over_high += batch;
+ current->memcg_nr_pages_over_high += nr_charged;
set_notify_resume(current);
break;
}
@@ -5771,7 +5773,7 @@ int __mem_cgroup_try_charge_swap(struct folio *folio)
rcu_read_unlock();
if (!mem_cgroup_is_root(memcg) &&
- !page_counter_try_charge(&memcg->swap, nr_pages, &counter)) {
+ !page_counter_try_charge(&memcg->swap, nr_pages, &counter, NULL)) {
memcg_memory_event(memcg, MEMCG_SWAP_MAX);
memcg_memory_event(memcg, MEMCG_SWAP_FAIL);
mem_cgroup_private_id_put(memcg, nr_pages);
diff --git a/mm/page_counter.c b/mm/page_counter.c
index 661e0f2a5127a..a934619cc7bf7 100644
--- a/mm/page_counter.c
+++ b/mm/page_counter.c
@@ -111,13 +111,15 @@ void page_counter_charge(struct page_counter *counter, unsigned long nr_pages)
* @counter: counter
* @nr_pages: number of pages to charge
* @fail: points first counter to hit its limit, if any
+ * @nr_charged: optional; on success, set to the number of pages actually
+ * charged to the hierarchy
*
* Returns %true on success, or %false and @fail if the counter or one
* of its ancestors has hit its configured limit.
*/
bool page_counter_try_charge(struct page_counter *counter,
- unsigned long nr_pages,
- struct page_counter **fail)
+ unsigned long nr_pages, struct page_counter **fail,
+ unsigned long *nr_charged)
{
struct page_counter *c;
bool protection = track_protection(counter);
@@ -162,6 +164,10 @@ bool page_counter_try_charge(struct page_counter *counter,
WRITE_ONCE(c->watermark, new);
}
}
+
+ if (nr_charged)
+ *nr_charged = nr_pages;
+
return true;
failed:
--
2.53.0-Meta
next prev parent reply other threads:[~2026-08-31 16:38 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-31 16:37 [PATCH v5 0/7] move stock from mem_cgroup to page_counter Joshua Hahn
2026-08-31 16:37 ` [PATCH v5 1/7] mm/memcontrol: flatten try_charge_memcg control flow Joshua Hahn
2026-08-31 16:37 ` Joshua Hahn [this message]
2026-08-31 16:37 ` [PATCH v5 3/7] mm/page_counter: introduce per-page_counter stock Joshua Hahn
2026-08-31 16:37 ` [PATCH v5 4/7] mm/page_counter: use stock in page_counter_try_charge Joshua Hahn
2026-08-31 16:37 ` [PATCH v5 5/7] mm/page_counter: introduce an asynchronous drainer Joshua Hahn
2026-08-31 16:37 ` [PATCH v5 6/7] mm/memcontrol: convert memcg to use page_counter_stock Joshua Hahn
2026-08-31 16:37 ` [PATCH v5 7/7] mm/memcontrol: add stock to the memsw page_counter Joshua Hahn
2026-09-01 9:40 ` Michal Koutný
2026-09-01 14:11 ` Joshua Hahn
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=20260831163752.2193337-3-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=dri-devel@lists.freedesktop.org \
--cc=hannes@cmpxchg.org \
--cc=kernel-team@meta.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