From: Sourav Panda <souravpanda@google.com>
To: muchun.song@linux.dev, osalvador@suse.de, akpm@linux-foundation.org
Cc: david@kernel.org, ljs@kernel.org, liam@infradead.org,
vbabka@kernel.org, rppt@kernel.org, surenb@google.com,
mhocko@suse.com, mst@redhat.com, mhklinux@outlook.com,
souravpanda@google.com, fvdl@google.com, gthelen@google.com,
mike.kravetz@oracle.com, pasha.tatashin@soleen.com,
rientjes@google.com, riel@surriel.com, linux-mm@kvack.org,
linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org,
linux-doc@vger.kernel.org
Subject: [PATCH 2/6] mm/hugetlb: implement cache recycling and allocation
Date: Tue, 7 Jul 2026 06:42:31 +0000 [thread overview]
Message-ID: <20260707064235.1386552-3-souravpanda@google.com> (raw)
In-Reply-To: <20260707064235.1386552-1-souravpanda@google.com>
Implement the core recycling and allocation logic for the HugeTLB dynamic
cache.
Recycle surplus hugepages in free_huge_folio() up to max_cached_huge_pages.
Allocate from the cache in alloc_surplus_hugetlb_folio() if pages are
available.
To ensure safety and architecture correctness:
- Skip recycling of hardware-poisoned pages in free_huge_folio() and
skip poisoned pages in the cache during allocation.
- Call arch_clear_hugetlb_flags() before caching a page to clear stale
architecture-specific metadata (e.g. ARM64 MTE tags, dcache dirty).
- Use MRU (Most Recently Used) policy for allocation (taking from the
tail of the cache list) to prefer hot pages.
Signed-off-by: Sourav Panda <souravpanda@google.com>
---
include/linux/hugetlb.h | 4 +++
mm/hugetlb.c | 76 +++++++++++++++++++++++++++++++++++++++--
2 files changed, 77 insertions(+), 3 deletions(-)
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index 4768f52ddd35..e882c99780b6 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -650,6 +650,10 @@ HPAGEFLAG(RawHwpUnreliable, raw_hwp_unreliable)
HPAGEFLAG(Cma, cma)
#ifdef CONFIG_HUGETLB_CACHE
HPAGEFLAG(Cached, cached)
+#else
+static inline bool folio_test_hugetlb_cached(const struct folio *folio) { return false; }
+static inline void folio_clear_hugetlb_cached(struct folio *folio) { }
+static inline void folio_set_hugetlb_cached(struct folio *folio) { }
#endif
#ifdef CONFIG_HUGETLB_PAGE
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 15be3cf54606..d00aa67b8e13 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -125,6 +125,11 @@ static void hugetlb_unshare_pmds(struct vm_area_struct *vma,
unsigned long start, unsigned long end, bool take_locks);
static struct resv_map *vma_resv_map(struct vm_area_struct *vma);
+#ifdef CONFIG_HUGETLB_CACHE
+static void hugetlb_cache_add(struct hstate *h, struct folio *folio, bool from_surplus);
+static void hugetlb_cache_remove(struct hstate *h, struct folio *folio, bool to_surplus);
+#endif
+
static inline bool subpool_is_free(struct hugepage_subpool *spool)
{
if (spool->count)
@@ -1796,6 +1801,15 @@ void free_huge_folio(struct folio *folio)
spin_unlock_irqrestore(&hugetlb_lock, flags);
update_and_free_hugetlb_folio(h, folio, true);
} else if (h->surplus_huge_pages_node[nid]) {
+#ifdef CONFIG_HUGETLB_CACHE
+ if (h->nr_cached_hugepages < h->max_cached_huge_pages &&
+ !folio_test_hwpoison(folio)) {
+ arch_clear_hugetlb_flags(folio);
+ hugetlb_cache_add(h, folio, true);
+ spin_unlock_irqrestore(&hugetlb_lock, flags);
+ return;
+ }
+#endif
/* remove the page from active list */
remove_hugetlb_folio(h, folio, true);
spin_unlock_irqrestore(&hugetlb_lock, flags);
@@ -2035,8 +2049,14 @@ int dissolve_free_hugetlb_folio(struct folio *folio)
struct hstate *h = folio_hstate(folio);
bool adjust_surplus = false;
- if (!available_huge_pages(h))
+ if (!available_huge_pages(h) && !folio_test_hugetlb_cached(folio))
+ goto out;
+
+ /* If the folio is currently isolated for page reporting, skip it */
+ if (folio_test_hugetlb_cached(folio) && list_empty(&folio->lru)) {
+ rc = -EBUSY;
goto out;
+ }
/*
* We should make sure that the page is already on the free list
@@ -2128,6 +2148,50 @@ int dissolve_free_hugetlb_folios(unsigned long start_pfn, unsigned long end_pfn)
return rc;
}
+#ifdef CONFIG_HUGETLB_CACHE
+static struct folio *get_cached_folio(struct hstate *h, int nid, nodemask_t *nmask)
+{
+ int node;
+ struct folio *folio;
+
+ if (h->nr_cached_hugepages == 0)
+ return NULL;
+
+ if (nid != NUMA_NO_NODE && (!nmask || node_isset(nid, *nmask))) {
+ list_for_each_entry_reverse(folio, &h->hugepage_cache_lists[nid], lru) {
+ if (!folio_test_hwpoison(folio))
+ goto found;
+ }
+ }
+
+ if (nmask) {
+ for_each_node_mask(node, *nmask) {
+ list_for_each_entry_reverse(folio, &h->hugepage_cache_lists[node], lru) {
+ if (!folio_test_hwpoison(folio))
+ goto found;
+ }
+ }
+ } else {
+ for_each_node_state(node, N_MEMORY) {
+ list_for_each_entry_reverse(folio, &h->hugepage_cache_lists[node], lru) {
+ if (!folio_test_hwpoison(folio))
+ goto found;
+ }
+ }
+ }
+ return NULL;
+
+found:
+ hugetlb_cache_remove(h, folio, true);
+ return folio;
+}
+#else
+static inline struct folio *get_cached_folio(struct hstate *h, int nid, nodemask_t *nmask)
+{
+ return NULL;
+}
+#endif
+
/*
* Allocates a fresh surplus page from the page allocator.
*/
@@ -2136,10 +2200,16 @@ static struct folio *alloc_surplus_hugetlb_folio(struct hstate *h,
{
struct folio *folio = NULL;
+ spin_lock_irq(&hugetlb_lock);
+ folio = get_cached_folio(h, nid, nmask);
+ if (folio) {
+ spin_unlock_irq(&hugetlb_lock);
+ return folio;
+ }
+
if (hstate_is_gigantic_no_runtime(h))
- return NULL;
+ goto out_unlock;
- spin_lock_irq(&hugetlb_lock);
if (h->surplus_huge_pages >= h->nr_overcommit_huge_pages)
goto out_unlock;
spin_unlock_irq(&hugetlb_lock);
--
2.55.0.rc0.799.gd6f94ed593-goog
next prev parent reply other threads:[~2026-07-07 6:42 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-07 6:42 [RFC PATCH 0/6] mm/hugetlb: Dynamic, NUMA-aware HugePage Cache & Free Page Reporting Sourav Panda
2026-07-07 6:42 ` [PATCH 1/6] mm/hugetlb: add Kconfig and basic cache infrastructure Sourav Panda
2026-07-07 6:42 ` Sourav Panda [this message]
2026-07-07 6:42 ` [PATCH 3/6] mm/hugetlb: add sysfs interfaces for cache Sourav Panda
2026-07-07 6:42 ` [PATCH 4/6] mm/hugetlb: add memory shrinker " Sourav Panda
2026-07-07 6:42 ` [PATCH 5/6] Documentation/admin-guide/mm/hugetlbpage.rst: document cache interfaces Sourav Panda
2026-07-07 6:42 ` [PATCH 6/6] mm/hugetlb: support free page reporting for cached hugepages Sourav Panda
2026-07-07 7:18 ` Michael S. Tsirkin
2026-07-07 10:18 ` Michael S. Tsirkin
2026-07-07 6:56 ` [RFC PATCH 0/6] mm/hugetlb: Dynamic, NUMA-aware HugePage Cache & Free Page Reporting Michael S. Tsirkin
2026-07-07 7:21 ` Sourav Panda
2026-07-07 7:29 ` David Hildenbrand (Arm)
2026-07-07 8:09 ` Muchun Song
2026-07-07 10:25 ` Michael S. Tsirkin
2026-07-07 10:28 ` David Hildenbrand (Arm)
2026-07-07 11:06 ` Lorenzo Stoakes
2026-07-07 14:01 ` Michael S. Tsirkin
2026-07-07 18:46 ` Lorenzo Stoakes
2026-07-07 19:32 ` Michael S. Tsirkin
2026-07-07 19:46 ` David Hildenbrand (Arm)
2026-07-08 8:26 ` Lorenzo Stoakes
2026-07-08 9:16 ` Michael S. Tsirkin
2026-07-09 6:15 ` Sourav Panda
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260707064235.1386552-3-souravpanda@google.com \
--to=souravpanda@google.com \
--cc=akpm@linux-foundation.org \
--cc=david@kernel.org \
--cc=fvdl@google.com \
--cc=gthelen@google.com \
--cc=liam@infradead.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=ljs@kernel.org \
--cc=mhklinux@outlook.com \
--cc=mhocko@suse.com \
--cc=mike.kravetz@oracle.com \
--cc=mst@redhat.com \
--cc=muchun.song@linux.dev \
--cc=osalvador@suse.de \
--cc=pasha.tatashin@soleen.com \
--cc=riel@surriel.com \
--cc=rientjes@google.com \
--cc=rppt@kernel.org \
--cc=surenb@google.com \
--cc=vbabka@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.