From nobody Mon Sep 28 10:49:17 2026 Received: from m16.mail.163.com (m16.mail.163.com [220.197.31.4]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1DB3B25B0A5 for ; Sun, 23 Aug 2026 03:44:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=220.197.31.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787456664; cv=none; b=vF3Hu0Q4TtmgBDw02qTkZqnK0hciZWmFN9gdrTwCt9t5cySf9DjJp7+wGsPhflNb0sUvDA5MrTBZ++dMm1NO9u2SnyvkV9JE3DXOGYUiH9VTiF0OiqmMD4VFL4rr1VzY50CYaux6yUbZCZtiyZs+9YupSPmfLQfGtn1TzEw2Q54= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787456664; c=relaxed/simple; bh=F/5kBYQ1aIVvTqVP7Gb+cclD473+R+Fck+4o3S5rEUY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=aD7qiNpJaT5Rb+BRIuhpKya7tS/YMi7hvsTJRlUvdY1ijWoavaVXUYKYLx8/SyUHMWL8bFHxvgwJLFUSTG6HJrK+btfePWcc0j6ONH5JhZ35wupcnblj8dwTOELtVPx3UZBXzoVLpiasHPt3W8KzqSrJDBTK2fE0LVDCeX7ynwc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com; spf=pass smtp.mailfrom=163.com; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b=Ci7T9s8E; arc=none smtp.client-ip=220.197.31.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=163.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b="Ci7T9s8E" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:To:Subject:Date:Message-ID:MIME-Version; bh=fB kKeEy0n7n1129jfqfo7mvp+BkKpcVoZE6BQwb1smA=; b=Ci7T9s8EQ4j3i6ubTY 6ecF3y6dNUlV3wvOdGYa+pHrawmpU4OOUm6wJ+eDkUam8opxkX1+skYYK7LWEMfp awZh8iUvWdsSjKhDjpYGvoP6QP+1ZD2TxtNrp7A/K/k0LkeoteooJISESkRWV8nO NBrNXnVvQlaMwTOR8h+fEkWXU= Received: from XLL-9950X.localdomain (unknown []) by gzga-smtp-mtada-g0-2 (Coremail) with SMTP id _____wCH5exMbIpqBB8uQw--.11509S3; Sun, 23 Aug 2026 11:43:11 +0800 (CST) From: Longlong Xia To: muchun.song@linux.dev, osalvador@suse.de, akpm@linux-foundation.org, david@kernel.org, mike.kravetz@oracle.com, yuzhao@google.com, linux-mm@kvack.org, linux-kernel@vger.kernel.org Cc: Longlong Xia Subject: [PATCH 1/2] mm/hugetlb: preserve source surplus accounting during demotion Date: Sun, 23 Aug 2026 11:43:06 +0800 Message-ID: <20260823034307.1072415-2-xialonglong2025@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260823034307.1072415-1-xialonglong2025@163.com> References: <20260823034307.1072415-1-xialonglong2025@163.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: _____wCH5exMbIpqBB8uQw--.11509S3 X-Coremail-Antispam: 1Uf129KBjvJXoWxZFykGry7Jw15Cw1ktrykGrg_yoW5KFyUpF yYkws3CrW8Ar9xCr1Sq34qkwn8W340v3yjya4fKr43J3ZxZr1UKr13G34UAa97WrW3Jr43 Wr4DXFyDWF43Zw7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x07j7PEfUUUUU= X-CM-SenderInfo: x0ldz0pqjo00rjsqjki6rwjhhfrp/xtbC+A9rZGqKbE-yDAAA3F Content-Type: text/plain; charset="utf-8" From: Longlong Xia 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 --- 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, nodema= sk_t *nodes_allowed, struct hstate *dst; long rc =3D 0; long nr_demoted =3D 0; + long nr_persistent =3D 0; =20 lockdep_assert_held(&hugetlb_lock); =20 @@ -3995,22 +3996,40 @@ long demote_pool_huge_page(struct hstate *src, node= mask_t *nodes_allowed, =20 for_each_node_mask_to_free(src, nr_nodes, node, nodes_allowed) { LIST_HEAD(list); + LIST_HEAD(surplus_list); struct folio *folio, *next; =20 list_for_each_entry_safe(folio, next, &src->hugepage_freelists[node], lr= u) { + bool adjust_surplus; + if (folio_test_hwpoison(folio)) continue; =20 - remove_hugetlb_folio(src, folio, false); - list_add(&folio->lru, &list); + /* Surplus accounting is maintained per node, not per folio. */ + adjust_surplus =3D 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++; =20 if (++nr_demoted =3D=3D nr_to_demote) break; } =20 + if (list_empty(&list) && list_empty(&surplus_list)) + continue; + spin_unlock_irq(&hugetlb_lock); =20 - rc =3D demote_free_hugetlb_folios(src, dst, &list); + if (!list_empty(&list)) + rc =3D demote_free_hugetlb_folios(src, dst, &list); + if (!list_empty(&surplus_list)) { + long tmp_rc; + + tmp_rc =3D demote_free_hugetlb_folios(src, dst, &surplus_list); + if (rc >=3D 0) + rc =3D tmp_rc; + } =20 spin_lock_irq(&hugetlb_lock); =20 @@ -4018,6 +4037,14 @@ long demote_pool_huge_page(struct hstate *src, nodem= ask_t *nodes_allowed, list_del(&folio->lru); add_hugetlb_folio(src, folio, false); =20 + 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--; } =20 @@ -4029,7 +4056,7 @@ long demote_pool_huge_page(struct hstate *src, nodema= sk_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 -=3D nr_demoted; + src->max_huge_pages -=3D nr_persistent; dst->max_huge_pages +=3D nr_demoted << (huge_page_order(src) - huge_page_= order(dst)); =20 if (rc < 0) --=20 2.43.0 From nobody Mon Sep 28 10:49:17 2026 Received: from m16.mail.163.com (m16.mail.163.com [220.197.31.2]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 640F63B14A8 for ; Sun, 23 Aug 2026 03:44:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=220.197.31.2 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787456669; cv=none; b=TM+DTsSBcDXTT4zyFmYgV5W0NPocM6UEQNB054ObxmGxmCFecLc8Znzd2da72N++8oRwCwXniQxXISAYU9gc3a8KiyacFy2en4f1bAkAAvrTswDsAWnBbt6+0QYspIeSwZYysnkwk8yoKryaHJ7myQ4CaIRaxJcsQ/4eCZUHcqE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787456669; c=relaxed/simple; bh=2hRBgAQiZEBhlrB31H8+U77qDt6MMpSxfF8am8i8kX8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ei+Ke+of7lNWYJL1RvAYaako4caij9FX4Yve8ooGzoLT3xCF2N0Axo/IB4zKzCZ2cUQsEXacznx8qVTYecUn2l7cIBedbDBG55ms63R54Rr1L+f0MnvfJBDokqkK/7YRgc7ZFXy5YxT6kNjvFex1GY1Cz3ZKHJ4bXyRz6ylIcfo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com; spf=pass smtp.mailfrom=163.com; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b=Ok/Ua7GT; arc=none smtp.client-ip=220.197.31.2 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=163.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b="Ok/Ua7GT" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:To:Subject:Date:Message-ID:MIME-Version; bh=pT MxwqiqizhxGvWUlHv/KW6PwYGh9ucvSLauqAzTYaM=; b=Ok/Ua7GTq6EZ0RgisJ hrKqORn3Mqq1bt47a3i5mL9qsuTNTVCBpVyQVxT3kcqzgBw6ug++Ntst+sHPabJg 5SyweZzAXmXAnTEMnRjmt5v3gmpCtauIZjUm64rH87kTJw7jx73u4HPs2YUrGaWi QonIeSwvqwINwWaWnSNcwry0M= Received: from XLL-9950X.localdomain (unknown []) by gzga-smtp-mtada-g0-2 (Coremail) with SMTP id _____wCH5exMbIpqBB8uQw--.11509S4; Sun, 23 Aug 2026 11:43:12 +0800 (CST) From: Longlong Xia To: muchun.song@linux.dev, osalvador@suse.de, akpm@linux-foundation.org, david@kernel.org, mike.kravetz@oracle.com, yuzhao@google.com, linux-mm@kvack.org, linux-kernel@vger.kernel.org Cc: Longlong Xia Subject: [PATCH 2/2] mm/hugetlb: cap demotion at currently available free pages Date: Sun, 23 Aug 2026 11:43:07 +0800 Message-ID: <20260823034307.1072415-3-xialonglong2025@163.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260823034307.1072415-1-xialonglong2025@163.com> References: <20260823034307.1072415-1-xialonglong2025@163.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: _____wCH5exMbIpqBB8uQw--.11509S4 X-Coremail-Antispam: 1Uf129KBjvJXoWxZr17Cw1xArW5Aw45tF1rCrg_yoW5Zr1rpr W8tr1Sk3yUZF9xWr1Sq3WDJ3W5Zw4xKFW8A3yxArWfZw13X3sI9r1xGryUZa4xuFWfJanF 9F4DZ3yDXry5XaUanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x07j2yxiUUUUU= X-CM-SenderInfo: x0ldz0pqjo00rjsqjki6rwjhhfrp/xtbC9xBsZWqKbFDtpQAA36 Content-Type: text/plain; charset="utf-8" From: Longlong Xia 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 --- 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, nodem= ask_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 =3D 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 =3D nr_demoted + min_t(unsigned long, + nr_to_demote - nr_demoted, nr_available); =20 list_for_each_entry_safe(folio, next, &src->hugepage_freelists[node], lr= u) { bool adjust_surplus; @@ -4012,7 +4032,7 @@ long demote_pool_huge_page(struct hstate *src, nodema= sk_t *nodes_allowed, if (!adjust_surplus) nr_persistent++; =20 - if (++nr_demoted =3D=3D nr_to_demote) + if (++nr_demoted =3D=3D nr_target) break; } =20 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 =3D h->free_huge_pages - h->resv_huge_pages; if (nid !=3D NUMA_NO_NODE) - nr_available =3D h->free_huge_pages_node[nid]; - else - nr_available =3D h->free_huge_pages; - nr_available -=3D h->resv_huge_pages; + nr_available =3D min(nr_available, + h->free_huge_pages_node[nid]); if (!nr_available) break; =20 - rc =3D demote_pool_huge_page(h, n_mask, nr_demote); + rc =3D demote_pool_huge_page(h, n_mask, + min(nr_demote, nr_available)); if (rc < 0) { err =3D rc; break; --=20 2.43.0