Re: [RFC PATCH 4/4] mm: Split a slow path for updating mm counters

From: David Hildenbrand (Red Hat)
Date: Mon Dec 01 2025 - 05:19:20 EST


On 11/28/25 00:36, Gabriel Krisman Bertazi wrote:
For cases where we know we are not coming from local context, there is
no point in touching current when incrementing/decrementing the
counters. Split this path into another helper to avoid this cost.

Signed-off-by: Gabriel Krisman Bertazi <krisman@xxxxxxx>
---
arch/s390/mm/gmap_helpers.c | 4 ++--
arch/s390/mm/pgtable.c | 4 ++--
fs/exec.c | 2 +-
include/linux/mm.h | 14 +++++++++++---
kernel/events/uprobes.c | 2 +-
mm/filemap.c | 2 +-
mm/huge_memory.c | 22 +++++++++++-----------
mm/khugepaged.c | 6 +++---
mm/ksm.c | 2 +-
mm/madvise.c | 2 +-
mm/memory.c | 20 ++++++++++----------
mm/migrate.c | 2 +-
mm/migrate_device.c | 2 +-
mm/rmap.c | 16 ++++++++--------
mm/swapfile.c | 6 +++---
mm/userfaultfd.c | 2 +-
16 files changed, 58 insertions(+), 50 deletions(-)

diff --git a/arch/s390/mm/gmap_helpers.c b/arch/s390/mm/gmap_helpers.c
index d4c3c36855e2..6d8498c56d08 100644
--- a/arch/s390/mm/gmap_helpers.c
+++ b/arch/s390/mm/gmap_helpers.c
@@ -29,9 +29,9 @@
static void ptep_zap_swap_entry(struct mm_struct *mm, swp_entry_t entry)
{
if (!non_swap_entry(entry))
- dec_mm_counter(mm, MM_SWAPENTS);
+ dec_mm_counter_other(mm, MM_SWAPENTS);
else if (is_migration_entry(entry))
- dec_mm_counter(mm, mm_counter(pfn_swap_entry_folio(entry)));
+ dec_mm_counter_other(mm, mm_counter(pfn_swap_entry_folio(entry)));
free_swap_and_cache(entry);
}
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index 0fde20bbc50b..021a04f958e5 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -686,11 +686,11 @@ void ptep_unshadow_pte(struct mm_struct *mm, unsigned long saddr, pte_t *ptep)
static void ptep_zap_swap_entry(struct mm_struct *mm, swp_entry_t entry)
{
if (!non_swap_entry(entry))
- dec_mm_counter(mm, MM_SWAPENTS);
+ dec_mm_counter_other(mm, MM_SWAPENTS);
else if (is_migration_entry(entry)) {
struct folio *folio = pfn_swap_entry_folio(entry);
- dec_mm_counter(mm, mm_counter(folio));
+ dec_mm_counter_other(mm, mm_counter(folio));
}
free_swap_and_cache(entry);
}
diff --git a/fs/exec.c b/fs/exec.c
index 4298e7e08d5d..33d0eb00d315 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -137,7 +137,7 @@ static void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)
return;
bprm->vma_pages = pages;
- add_mm_counter(mm, MM_ANONPAGES, diff);
+ add_mm_counter_local(mm, MM_ANONPAGES, diff);
}
static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 29de4c60ac6c..2db12280e938 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2689,7 +2689,7 @@ static inline unsigned long get_mm_counter_sum(struct mm_struct *mm, int member)
void mm_trace_rss_stat(struct mm_struct *mm, int member);
-static inline void add_mm_counter(struct mm_struct *mm, int member, long value)
+static inline void add_mm_counter_local(struct mm_struct *mm, int member, long value)
{
if (READ_ONCE(current->mm) == mm)
lazy_percpu_counter_add_fast(&mm->rss_stat[member], value);
@@ -2698,9 +2698,17 @@ static inline void add_mm_counter(struct mm_struct *mm, int member, long value)
mm_trace_rss_stat(mm, member);
}
+static inline void add_mm_counter_other(struct mm_struct *mm, int member, long value)
+{
+ lazy_percpu_counter_add_atomic(&mm->rss_stat[member], value);
+
+ mm_trace_rss_stat(mm, member);
+}
-#define inc_mm_counter(mm, member) add_mm_counter(mm, member, 1)
-#define dec_mm_counter(mm, member) add_mm_counter(mm, member, -1)
+#define inc_mm_counter_local(mm, member) add_mm_counter_local(mm, member, 1)
+#define dec_mm_counter_local(mm, member) add_mm_counter_local(mm, member, -1)
+#define inc_mm_counter_other(mm, member) add_mm_counter_other(mm, member, 1)
+#define dec_mm_counter_other(mm, member) add_mm_counter_other(mm, member, -1)

I'd have thought that there is a local and !local version, whereby the latter one would simply maintain the old name. The "_other()" sticks out a bit.

E.g., cmpxch() vs. cmpxchg_local().

Or would "_remote()" better describe what "_other()" intends to do?

--
Cheers

David