* [PATCH v2 1/2] mm: decrement MTHP_STAT_NR_ANON in free_zone_device_folio()
2026-07-17 6:44 [PATCH v2 0/2] mm: fix PMD level mTHP accounting bugs Nico Pache
@ 2026-07-17 6:44 ` Nico Pache
2026-07-17 6:45 ` [PATCH v2 2/2] mm/migrate: exclude hugetlb folios from MTHP_STAT_NR_ANON accounting Nico Pache
2026-07-18 1:29 ` [PATCH v2 0/2] mm: fix PMD level mTHP accounting bugs Andrew Morton
2 siblings, 0 replies; 5+ messages in thread
From: Nico Pache @ 2026-07-17 6:44 UTC (permalink / raw)
To: Barry Song, David Hildenbrand, linux-cxl, linux-kernel, linux-mm
Cc: ljs, willy, Nico Pache, Zi Yan, Oscar Salvador, Andrew Morton,
Matthew Brost, Joshua Hahn, Rakie Kim, Byungchul Park,
Gregory Price, Ying Huang, Alistair Popple
When a zone device folio is mapped as anonymous, folio_add_new_anon_rmap()
increments MTHP_STAT_NR_ANON. The corresponding decrement lives in
__free_pages_prepare() in page_alloc.c, but zone device folios are freed
via free_zone_device_folio() which never calls __free_pages_prepare().
This causes nr_anon to remain permanently elevated after zone device
folios are freed.
Add the missing mod_mthp_stat() decrement to free_zone_device_folio()
so that the counter is properly balanced.
Fixes: 5d65c8d758f2 ("mm: count the number of anonymous THPs per size")
Reviewed-by: Zi Yan <ziy@nvidia.com>
Co-developed-by: David Hildenbrand <david@kernel.org>
Signed-off-by: David Hildenbrand <david@kernel.org>
Signed-off-by: Nico Pache <npache@redhat.com>
---
mm/memremap.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/mm/memremap.c b/mm/memremap.c
index 81766d822400..accba23aef28 100644
--- a/mm/memremap.c
+++ b/mm/memremap.c
@@ -425,6 +425,7 @@ void free_zone_device_folio(struct folio *folio)
mem_cgroup_uncharge(folio);
if (folio_test_anon(folio)) {
+ mod_mthp_stat(folio_order(folio), MTHP_STAT_NR_ANON, -1);
for (i = 0; i < nr; i++)
__ClearPageAnonExclusive(folio_page(folio, i));
}
--
2.55.0
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH v2 2/2] mm/migrate: exclude hugetlb folios from MTHP_STAT_NR_ANON accounting
2026-07-17 6:44 [PATCH v2 0/2] mm: fix PMD level mTHP accounting bugs Nico Pache
2026-07-17 6:44 ` [PATCH v2 1/2] mm: decrement MTHP_STAT_NR_ANON in free_zone_device_folio() Nico Pache
@ 2026-07-17 6:45 ` Nico Pache
2026-07-17 10:14 ` Baolin Wang
2026-07-18 1:29 ` [PATCH v2 0/2] mm: fix PMD level mTHP accounting bugs Andrew Morton
2 siblings, 1 reply; 5+ messages in thread
From: Nico Pache @ 2026-07-17 6:45 UTC (permalink / raw)
To: Barry Song, David Hildenbrand, linux-cxl, linux-kernel, linux-mm
Cc: ljs, willy, Nico Pache, Zi Yan, Oscar Salvador, Andrew Morton,
Matthew Brost, Joshua Hahn, Rakie Kim, Byungchul Park,
Gregory Price, Ying Huang, Alistair Popple
__folio_migrate_mapping() increments MTHP_STAT_NR_ANON for the
destination folio when `folio_test_anon(folio) && folio_test_large(folio)`
is true. However, hugetlb folios satisfy both conditions despite having a
completely separate accounting system — they use hugetlb_add_anon_rmap()
which does not touch mTHP stats, and their free path also bypasses the
mTHP decrement in __free_pages_prepare().
This causes MTHP_STAT_NR_ANON to be incremented on each hugetlb
migration without a corresponding decrement, permanently inflating the
nr_anon counter.
Add a !folio_test_hugetlb() check to __folio_migrate_mapping() so that
only actual mTHP folios are counted.
Fixes: 5d65c8d758f2 ("mm: count the number of anonymous THPs per size")
Reviewed-by: Zi Yan <ziy@nvidia.com>
Co-developed-by: David Hildenbrand <david@kernel.org>
Signed-off-by: David Hildenbrand <david@kernel.org>
Signed-off-by: Nico Pache <npache@redhat.com>
---
mm/migrate.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/mm/migrate.c b/mm/migrate.c
index d9b23909d716..dd15a84b2a52 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -590,7 +590,8 @@ static int __folio_migrate_mapping(struct address_space *mapping,
/* No turning back from here */
newfolio->index = folio->index;
newfolio->mapping = folio->mapping;
- if (folio_test_anon(folio) && folio_test_large(folio))
+ if (folio_test_anon(folio) && folio_test_large(folio) &&
+ !folio_test_hugetlb(folio))
mod_mthp_stat(folio_order(folio), MTHP_STAT_NR_ANON, 1);
if (folio_test_swapbacked(folio))
__folio_set_swapbacked(newfolio);
--
2.55.0
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH v2 2/2] mm/migrate: exclude hugetlb folios from MTHP_STAT_NR_ANON accounting
2026-07-17 6:45 ` [PATCH v2 2/2] mm/migrate: exclude hugetlb folios from MTHP_STAT_NR_ANON accounting Nico Pache
@ 2026-07-17 10:14 ` Baolin Wang
0 siblings, 0 replies; 5+ messages in thread
From: Baolin Wang @ 2026-07-17 10:14 UTC (permalink / raw)
To: Nico Pache, Barry Song, David Hildenbrand, linux-cxl,
linux-kernel, linux-mm
Cc: ljs, willy, Zi Yan, Oscar Salvador, Andrew Morton, Matthew Brost,
Joshua Hahn, Rakie Kim, Byungchul Park, Gregory Price,
Ying Huang, Alistair Popple
On 7/17/26 2:45 PM, Nico Pache wrote:
> __folio_migrate_mapping() increments MTHP_STAT_NR_ANON for the
> destination folio when `folio_test_anon(folio) && folio_test_large(folio)`
> is true. However, hugetlb folios satisfy both conditions despite having a
> completely separate accounting system — they use hugetlb_add_anon_rmap()
> which does not touch mTHP stats, and their free path also bypasses the
> mTHP decrement in __free_pages_prepare().
>
> This causes MTHP_STAT_NR_ANON to be incremented on each hugetlb
> migration without a corresponding decrement, permanently inflating the
> nr_anon counter.
>
> Add a !folio_test_hugetlb() check to __folio_migrate_mapping() so that
> only actual mTHP folios are counted.
>
> Fixes: 5d65c8d758f2 ("mm: count the number of anonymous THPs per size")
> Reviewed-by: Zi Yan <ziy@nvidia.com>
> Co-developed-by: David Hildenbrand <david@kernel.org>
> Signed-off-by: David Hildenbrand <david@kernel.org>
> Signed-off-by: Nico Pache <npache@redhat.com>
> ---
LGTM.
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2 0/2] mm: fix PMD level mTHP accounting bugs
2026-07-17 6:44 [PATCH v2 0/2] mm: fix PMD level mTHP accounting bugs Nico Pache
2026-07-17 6:44 ` [PATCH v2 1/2] mm: decrement MTHP_STAT_NR_ANON in free_zone_device_folio() Nico Pache
2026-07-17 6:45 ` [PATCH v2 2/2] mm/migrate: exclude hugetlb folios from MTHP_STAT_NR_ANON accounting Nico Pache
@ 2026-07-18 1:29 ` Andrew Morton
2 siblings, 0 replies; 5+ messages in thread
From: Andrew Morton @ 2026-07-18 1:29 UTC (permalink / raw)
To: Nico Pache
Cc: Barry Song, David Hildenbrand, linux-cxl, linux-kernel, linux-mm,
ljs, willy, Oscar Salvador, Zi Yan, Matthew Brost, Joshua Hahn,
Rakie Kim, Byungchul Park, Gregory Price, Ying Huang,
Alistair Popple
On Fri, 17 Jul 2026 00:44:58 -0600 Nico Pache <npache@redhat.com> wrote:
> While running selftests I noticed the PMD level per-mTHP stats (nr_anon)
> remained elevated after each run. After further investigation I noticed
> this accounting error occurs for both the migration.private_anon_htlb_test
> and the HMM tests.
>
> In the HMM case this is due to folio_add_new_anon_rmap() incrementing the
> mTHP stats, but never containing a corresponding decrement in
> free_zone_device_folio(). We solve this by making sure to decrement the
> counter when freeing device memory.
>
> In the migration case, we are incrementing this counter without first
> checking whether this folio is a hugetlb folio, which relies on a separate
> accounting system. We solve this by adding the proper hugetlb check before
> incrementing this counter.
>
> With these changes in place, the two tests no longer cause elevated PMD
> level accounting issues.
Thanks, I've updated mm.git's mm-hotfixes-unstable branch to this
version.
Sashiko is worried about the existing code ("list corruption or a
use-after-free panic"):
https://sashiko.dev/#/patchset/20260717064502.1980173-1-npache@redhat.com
>
> V2 Changes:
> - add RB from Zi
> - Drop unnecessary check in __folio_migrate_folio(). HugeTLB has its own
> migration system in hugetlbfs_migrate_folio().
Here's how v2 altered mm.git:
mm/migrate.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
--- a/mm/migrate.c~b
+++ a/mm/migrate.c
@@ -624,8 +624,7 @@ static int __folio_migrate_mapping(struc
*/
newfolio->index = folio->index;
newfolio->mapping = folio->mapping;
- if (folio_test_anon(folio) && folio_test_large(folio) &&
- !folio_test_hugetlb(folio))
+ if (folio_test_anon(folio) && folio_test_large(folio))
mod_mthp_stat(folio_order(folio), MTHP_STAT_NR_ANON, 1);
folio_ref_add(newfolio, nr); /* add cache reference */
if (folio_test_swapbacked(folio))
_
^ permalink raw reply [flat|nested] 5+ messages in thread