Linux-mm Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] mm/hugetlb: fix surplus accounting and availability checks during demotion
@ 2026-08-23  3:43 Longlong Xia
  2026-08-23  3:43 ` [PATCH 1/2] mm/hugetlb: preserve source surplus accounting " Longlong Xia
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Longlong Xia @ 2026-08-23  3:43 UTC (permalink / raw)
  To: muchun.song, osalvador, akpm, david, mike.kravetz, yuzhao,
	linux-mm, linux-kernel
  Cc: Longlong Xia

From: Longlong Xia <xialonglong@kylinos.cn>

This series fixes two problems in the hugetlb demote path.

Patch 1 fixes surplus accounting in the source hstate.
demote_pool_huge_page() removes every source folio as a persistent
folio, but a free folio may instead account for one of the source
hstate's surplus pages (for example after a vmemmap restoration
failure). Removing such a folio without adjusting surplus_huge_pages
makes the persistent count underflow, and later subtracting it from
max_huge_pages can underflow that counter as well.

Patch 2 fixes an availability overcount in the sysfs demote path. The
sysfs trigger checks whether any page is available but then passes the
entire request to demote_pool_huge_page(), which can remove free huge
pages that back existing reservations. With two free pages and one
reservation, a request for two pages removes both and leaves the
reservation without a backing page.

Both patches carry Fixes tags.

Longlong Xia (2):
  mm/hugetlb: preserve source surplus accounting during demotion
  mm/hugetlb: cap demotion at currently available free pages

 mm/hugetlb.c       | 57 ++++++++++++++++++++++++++++++++++++++++++----
 mm/hugetlb_sysfs.c | 10 ++++----
 2 files changed, 57 insertions(+), 10 deletions(-)

-- 
2.43.0



^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/2] mm/hugetlb: preserve source surplus accounting during demotion
  2026-08-23  3:43 [PATCH 0/2] mm/hugetlb: fix surplus accounting and availability checks during demotion Longlong Xia
@ 2026-08-23  3:43 ` Longlong Xia
  2026-08-23  3:43 ` [PATCH 2/2] mm/hugetlb: cap demotion at currently available free pages Longlong Xia
  2026-08-28 23:10 ` [PATCH 0/2] mm/hugetlb: fix surplus accounting and availability checks during demotion Andrew Morton
  2 siblings, 0 replies; 4+ messages in thread
From: Longlong Xia @ 2026-08-23  3:43 UTC (permalink / raw)
  To: muchun.song, osalvador, akpm, david, mike.kravetz, yuzhao,
	linux-mm, linux-kernel
  Cc: Longlong Xia

From: Longlong Xia <xialonglong@kylinos.cn>

demote_pool_huge_page() currently removes every source folio as a
persistent folio. A free folio can instead account for one of the
source hstate's surplus pages, for example after a vmemmap restoration
failure. Removing such a folio without adjusting surplus_huge_pages
makes the persistent count underflow, and later subtracting it from
max_huge_pages can underflow that counter as well.

Classify selected folios against the node's surplus count while holding
hugetlb_lock, and preserve that classification on rollback. Track the
number of successfully demoted persistent folios separately so only
those folios reduce the source max_huge_pages target. All successfully
demoted folios still increase the destination target because the new
destination folios are added as persistent pages.

Fixes: 8531fc6f52f5 ("hugetlb: add hugetlb demote page support")
Assisted-by: Codex:gpt-5.6-sol
Signed-off-by: Longlong Xia <xialonglong@kylinos.cn>
---
 mm/hugetlb.c | 35 +++++++++++++++++++++++++++++++----
 1 file changed, 31 insertions(+), 4 deletions(-)

diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index ed26105b84de..640df58be4e5 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -3983,6 +3983,7 @@ long demote_pool_huge_page(struct hstate *src, nodemask_t *nodes_allowed,
 	struct hstate *dst;
 	long rc = 0;
 	long nr_demoted = 0;
+	long nr_persistent = 0;
 
 	lockdep_assert_held(&hugetlb_lock);
 
@@ -3995,22 +3996,40 @@ long demote_pool_huge_page(struct hstate *src, nodemask_t *nodes_allowed,
 
 	for_each_node_mask_to_free(src, nr_nodes, node, nodes_allowed) {
 		LIST_HEAD(list);
+		LIST_HEAD(surplus_list);
 		struct folio *folio, *next;
 
 		list_for_each_entry_safe(folio, next, &src->hugepage_freelists[node], lru) {
+			bool adjust_surplus;
+
 			if (folio_test_hwpoison(folio))
 				continue;
 
-			remove_hugetlb_folio(src, folio, false);
-			list_add(&folio->lru, &list);
+			/* Surplus accounting is maintained per node, not per folio. */
+			adjust_surplus = src->surplus_huge_pages_node[node] > 0;
+			remove_hugetlb_folio(src, folio, adjust_surplus);
+			list_add(&folio->lru, adjust_surplus ? &surplus_list : &list);
+			if (!adjust_surplus)
+				nr_persistent++;
 
 			if (++nr_demoted == nr_to_demote)
 				break;
 		}
 
+		if (list_empty(&list) && list_empty(&surplus_list))
+			continue;
+
 		spin_unlock_irq(&hugetlb_lock);
 
-		rc = demote_free_hugetlb_folios(src, dst, &list);
+		if (!list_empty(&list))
+			rc = demote_free_hugetlb_folios(src, dst, &list);
+		if (!list_empty(&surplus_list)) {
+			long tmp_rc;
+
+			tmp_rc = demote_free_hugetlb_folios(src, dst, &surplus_list);
+			if (rc >= 0)
+				rc = tmp_rc;
+		}
 
 		spin_lock_irq(&hugetlb_lock);
 
@@ -4018,6 +4037,14 @@ long demote_pool_huge_page(struct hstate *src, nodemask_t *nodes_allowed,
 			list_del(&folio->lru);
 			add_hugetlb_folio(src, folio, false);
 
+			nr_demoted--;
+			nr_persistent--;
+		}
+
+		list_for_each_entry_safe(folio, next, &surplus_list, lru) {
+			list_del(&folio->lru);
+			add_hugetlb_folio(src, folio, true);
+
 			nr_demoted--;
 		}
 
@@ -4029,7 +4056,7 @@ long demote_pool_huge_page(struct hstate *src, nodemask_t *nodes_allowed,
 	 * Not absolutely necessary, but for consistency update max_huge_pages
 	 * based on pool changes for the demoted page.
 	 */
-	src->max_huge_pages -= nr_demoted;
+	src->max_huge_pages -= nr_persistent;
 	dst->max_huge_pages += nr_demoted << (huge_page_order(src) - huge_page_order(dst));
 
 	if (rc < 0)
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/2] mm/hugetlb: cap demotion at currently available free pages
  2026-08-23  3:43 [PATCH 0/2] mm/hugetlb: fix surplus accounting and availability checks during demotion Longlong Xia
  2026-08-23  3:43 ` [PATCH 1/2] mm/hugetlb: preserve source surplus accounting " Longlong Xia
@ 2026-08-23  3:43 ` Longlong Xia
  2026-08-28 23:10 ` [PATCH 0/2] mm/hugetlb: fix surplus accounting and availability checks during demotion Andrew Morton
  2 siblings, 0 replies; 4+ messages in thread
From: Longlong Xia @ 2026-08-23  3:43 UTC (permalink / raw)
  To: muchun.song, osalvador, akpm, david, mike.kravetz, yuzhao,
	linux-mm, linux-kernel
  Cc: Longlong Xia

From: Longlong Xia <xialonglong@kylinos.cn>

Demotion must not remove free huge pages that back existing
reservations. The sysfs path checks whether any page is available, but
passes the entire request to demote_pool_huge_page(). For example, with
two free pages and one reservation, a request for two pages removes both
and leaves the reservation without a backing page.

Cap the sysfs request by both global availability and the selected
node's free pages. Recheck global availability in
demote_pool_huge_page() before each node batch because that function
drops hugetlb_lock while restoring vmemmap and reservations can change
before the next batch.

Fixes: c0f398c3b2cf ("mm/hugetlb_vmemmap: batch HVO work when demoting")
Assisted-by: Codex:gpt-5.6-sol
Signed-off-by: Longlong Xia <xialonglong@kylinos.cn>
---
 mm/hugetlb.c       | 22 +++++++++++++++++++++-
 mm/hugetlb_sysfs.c | 10 +++++-----
 2 files changed, 26 insertions(+), 6 deletions(-)

diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 640df58be4e5..ae26d400ad31 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -3998,6 +3998,26 @@ long demote_pool_huge_page(struct hstate *src, nodemask_t *nodes_allowed,
 		LIST_HEAD(list);
 		LIST_HEAD(surplus_list);
 		struct folio *folio, *next;
+		unsigned long nr_available, nr_target;
+
+		/*
+		 * Re-check available each node batch: the previous
+		 * batch released hugetlb_lock for vmemmap restore/split,
+		 * and a new reservation could have been added in that
+		 * window, shrinking the budget.  available is global
+		 * (resv is not per-node), so 0 means no node can
+		 * contribute -- stop the whole scan.
+		 */
+		nr_available = available_huge_pages(src);
+		if (!nr_available)
+			break;
+
+		/*
+		 * Cap this batch at the current budget; expressed as a
+		 * cumulative stop point because nr_demoted is running.
+		 */
+		nr_target = nr_demoted + min_t(unsigned long,
+				nr_to_demote - nr_demoted, nr_available);
 
 		list_for_each_entry_safe(folio, next, &src->hugepage_freelists[node], lru) {
 			bool adjust_surplus;
@@ -4012,7 +4032,7 @@ long demote_pool_huge_page(struct hstate *src, nodemask_t *nodes_allowed,
 			if (!adjust_surplus)
 				nr_persistent++;
 
-			if (++nr_demoted == nr_to_demote)
+			if (++nr_demoted == nr_target)
 				break;
 		}
 
diff --git a/mm/hugetlb_sysfs.c b/mm/hugetlb_sysfs.c
index 79ece91406bf..326a54b4d991 100644
--- a/mm/hugetlb_sysfs.c
+++ b/mm/hugetlb_sysfs.c
@@ -211,15 +211,15 @@ static ssize_t demote_store(struct kobject *kobj,
 		 * Check for available pages to demote each time thorough the
 		 * loop as demote_pool_huge_page will drop hugetlb_lock.
 		 */
+		nr_available = h->free_huge_pages - h->resv_huge_pages;
 		if (nid != NUMA_NO_NODE)
-			nr_available = h->free_huge_pages_node[nid];
-		else
-			nr_available = h->free_huge_pages;
-		nr_available -= h->resv_huge_pages;
+			nr_available = min(nr_available,
+					   h->free_huge_pages_node[nid]);
 		if (!nr_available)
 			break;
 
-		rc = demote_pool_huge_page(h, n_mask, nr_demote);
+		rc = demote_pool_huge_page(h, n_mask,
+					   min(nr_demote, nr_available));
 		if (rc < 0) {
 			err = rc;
 			break;
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH 0/2] mm/hugetlb: fix surplus accounting and availability checks during demotion
  2026-08-23  3:43 [PATCH 0/2] mm/hugetlb: fix surplus accounting and availability checks during demotion Longlong Xia
  2026-08-23  3:43 ` [PATCH 1/2] mm/hugetlb: preserve source surplus accounting " Longlong Xia
  2026-08-23  3:43 ` [PATCH 2/2] mm/hugetlb: cap demotion at currently available free pages Longlong Xia
@ 2026-08-28 23:10 ` Andrew Morton
  2 siblings, 0 replies; 4+ messages in thread
From: Andrew Morton @ 2026-08-28 23:10 UTC (permalink / raw)
  To: Longlong Xia
  Cc: muchun.song, osalvador, david, mike.kravetz, yuzhao, linux-mm,
	linux-kernel, Longlong Xia

On Sun, 23 Aug 2026 11:43:05 +0800 Longlong Xia <xialonglong2025@163.com> wrote:

> This series fixes two problems in the hugetlb demote path.
> 
> Patch 1 fixes surplus accounting in the source hstate.
> demote_pool_huge_page() removes every source folio as a persistent
> folio, but a free folio may instead account for one of the source
> hstate's surplus pages (for example after a vmemmap restoration
> failure). Removing such a folio without adjusting surplus_huge_pages
> makes the persistent count underflow, and later subtracting it from
> max_huge_pages can underflow that counter as well.
> 
> Patch 2 fixes an availability overcount in the sysfs demote path. The
> sysfs trigger checks whether any page is available but then passes the
> entire request to demote_pool_huge_page(), which can remove free huge
> pages that back existing reservations. With two free pages and one
> reservation, a request for two pages removes both and leaves the
> reservation without a backing page.

Thanks.  Have you created and tested reproducers for these?  Gemini was
trivially able to do this for me.

If so, it would be helpful to includes the details in the
changelogging.


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-08-28 23:10 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-23  3:43 [PATCH 0/2] mm/hugetlb: fix surplus accounting and availability checks during demotion Longlong Xia
2026-08-23  3:43 ` [PATCH 1/2] mm/hugetlb: preserve source surplus accounting " Longlong Xia
2026-08-23  3:43 ` [PATCH 2/2] mm/hugetlb: cap demotion at currently available free pages Longlong Xia
2026-08-28 23:10 ` [PATCH 0/2] mm/hugetlb: fix surplus accounting and availability checks during demotion Andrew Morton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox