From 81b4ba8b686bcc027f0a7fc93386fdf3956e1700 Mon Sep 17 00:00:00 2001 From: Jinjiang Tu Date: Fri, 21 Mar 2025 11:06:16 +0800 Subject: [PATCH] mm/hugetlb: fix surplus pages in dissolve_free_huge_page() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mainline inclusion from mainline-v6.14-rc6 commit cb402bbdabcaa5a765068c5b8673bbfc1c264242 category: bugfix bugzilla: 190517 CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=cb402bbdabcaa5a765068c5b8673bbfc1c264242 ------------------------------------------- In dissolve_free_huge_page(), free huge pages are dissolved without adjusting surplus count. However, free huge pages may be accounted as surplus pages, and will lead to wrong surplus count. I reproduce this issue on qemu. The steps are: 1) Node1 is memory-less at first. Hot-add memory to node1 by executing the two commands in qemu monitor: object_add memory-backend-ram,id=mem1,size=1G device_add pc-dimm,id=dimm1,memdev=mem1,node=1 2) online one memory block of Node1 with: echo online_movable > /sys/devices/system/node/node1/memoryX/state 3) create 64 huge pages for node1 4) run a program to reserve (don't consume) all the huge pages 5) echo 0 > nr_huge_pages for node1. After this step, free huge pages in Node1 are surplus. 6) create 80 huge pages for node0 7) offline memory of node1, The memory range to offline contains the free surplus huge pages created in step3) ~ step5) echo offline > /sys/devices/system/node/node1/memoryX/state 8) kill the program in step 4) The result: Node0 Node1 total 80 0 free 80 0 surplus 0 61 To fix it, adjust surplus when destroying huge pages if the node has surplus pages in dissolve_free_hugetlb_folio(). The result with this patch: Node0 Node1 total 80 0 free 80 0 surplus 0 0 Link: https://lkml.kernel.org/r/20250304132106.2872754-1-tujinjiang@huawei.com Fixes: c8721bbbdd36 ("mm: memory-hotplug: enable memory hotplug to handle hugepage") Signed-off-by: Jinjiang Tu Acked-by: David Hildenbrand Acked-by: Oscar Salvador Cc: Jinjiang Tu Cc: Kefeng Wang Cc: Muchun Song Cc: Nanyong Sun Signed-off-by: Andrew Morton Conflicts: mm/hugetlb.c [Context conflicts, and HVO isn't introduced, so don't need to handle HVO err case.] Signed-off-by: Jinjiang Tu --- mm/hugetlb.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 69dd1e096a48..ac6f18afdf76 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -1823,6 +1823,7 @@ int dissolve_free_huge_page(struct page *page) if (!page_count(page)) { struct page *head = compound_head(page); struct hstate *h = page_hstate(head); + bool adjust_surplus = false; if (h->free_huge_pages - h->resv_huge_pages == 0) goto out; @@ -1853,7 +1854,9 @@ int dissolve_free_huge_page(struct page *page) SetPageHWPoison(page); ClearPageHWPoison(head); } - remove_hugetlb_page(h, head, false); + if (h->surplus_huge_pages_node[page_to_nid(head)]) + adjust_surplus = true; + remove_hugetlb_page(h, head, adjust_surplus); h->max_huge_pages--; spin_unlock_irq(&hugetlb_lock); update_and_free_page(h, head); -- Gitee