* [PATCH v4 1/6] mm: debug_vm_pgtable: add debug_vm_pgtable_free_huge_page()
2025-12-16 11:48 [PATCH v4 RESEND 0/6] mm: hugetlb: allocate frozen gigantic folio Kefeng Wang
@ 2025-12-16 11:48 ` Kefeng Wang
2025-12-16 16:08 ` Zi Yan
2025-12-17 2:40 ` Muchun Song
2025-12-16 11:48 ` [PATCH v4 2/6] mm: page_alloc: add __split_page() Kefeng Wang
` (4 subsequent siblings)
5 siblings, 2 replies; 33+ messages in thread
From: Kefeng Wang @ 2025-12-16 11:48 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Oscar Salvador, Muchun Song, linux-mm
Cc: sidhartha.kumar, jane.chu, Zi Yan, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand, Kefeng Wang
Add a new helper to free huge page to be consistency to
debug_vm_pgtable_alloc_huge_page(), and use HPAGE_PUD_ORDER
instead of open-code.
Also move the free_contig_range() under CONFIG_ALLOC_CONTIG
since all caller are built with CONFIG_ALLOC_CONTIG.
Acked-by: David Hildenbrand <david@redhat.com>
Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
---
include/linux/gfp.h | 2 +-
mm/debug_vm_pgtable.c | 38 +++++++++++++++++---------------------
mm/page_alloc.c | 2 +-
3 files changed, 19 insertions(+), 23 deletions(-)
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index b155929af5b1..ea053f1cfa16 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -438,8 +438,8 @@ extern struct page *alloc_contig_pages_noprof(unsigned long nr_pages, gfp_t gfp_
int nid, nodemask_t *nodemask);
#define alloc_contig_pages(...) alloc_hooks(alloc_contig_pages_noprof(__VA_ARGS__))
-#endif
void free_contig_range(unsigned long pfn, unsigned long nr_pages);
+#endif
#ifdef CONFIG_CONTIG_ALLOC
static inline struct folio *folio_alloc_gigantic_noprof(int order, gfp_t gfp,
diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c
index ae9b9310d96f..83cf07269f13 100644
--- a/mm/debug_vm_pgtable.c
+++ b/mm/debug_vm_pgtable.c
@@ -971,22 +971,26 @@ static unsigned long __init get_random_vaddr(void)
return random_vaddr;
}
-static void __init destroy_args(struct pgtable_debug_args *args)
+static void __init
+debug_vm_pgtable_free_huge_page(struct pgtable_debug_args *args,
+ unsigned long pfn, int order)
{
- struct page *page = NULL;
+#ifdef CONFIG_CONTIG_ALLOC
+ if (args->is_contiguous_page) {
+ free_contig_range(pfn, 1 << order);
+ return;
+ }
+#endif
+ __free_pages(pfn_to_page(pfn), order);
+}
+static void __init destroy_args(struct pgtable_debug_args *args)
+{
/* Free (huge) page */
if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) &&
has_transparent_pud_hugepage() &&
args->pud_pfn != ULONG_MAX) {
- if (args->is_contiguous_page) {
- free_contig_range(args->pud_pfn,
- (1 << (HPAGE_PUD_SHIFT - PAGE_SHIFT)));
- } else {
- page = pfn_to_page(args->pud_pfn);
- __free_pages(page, HPAGE_PUD_SHIFT - PAGE_SHIFT);
- }
-
+ debug_vm_pgtable_free_huge_page(args, args->pud_pfn, HPAGE_PUD_ORDER);
args->pud_pfn = ULONG_MAX;
args->pmd_pfn = ULONG_MAX;
args->pte_pfn = ULONG_MAX;
@@ -995,20 +999,13 @@ static void __init destroy_args(struct pgtable_debug_args *args)
if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) &&
has_transparent_hugepage() &&
args->pmd_pfn != ULONG_MAX) {
- if (args->is_contiguous_page) {
- free_contig_range(args->pmd_pfn, (1 << HPAGE_PMD_ORDER));
- } else {
- page = pfn_to_page(args->pmd_pfn);
- __free_pages(page, HPAGE_PMD_ORDER);
- }
-
+ debug_vm_pgtable_free_huge_page(args, args->pmd_pfn, HPAGE_PMD_ORDER);
args->pmd_pfn = ULONG_MAX;
args->pte_pfn = ULONG_MAX;
}
if (args->pte_pfn != ULONG_MAX) {
- page = pfn_to_page(args->pte_pfn);
- __free_page(page);
+ __free_page(pfn_to_page(args->pte_pfn));
args->pte_pfn = ULONG_MAX;
}
@@ -1242,8 +1239,7 @@ static int __init init_args(struct pgtable_debug_args *args)
*/
if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) &&
has_transparent_pud_hugepage()) {
- page = debug_vm_pgtable_alloc_huge_page(args,
- HPAGE_PUD_SHIFT - PAGE_SHIFT);
+ page = debug_vm_pgtable_alloc_huge_page(args, HPAGE_PUD_ORDER);
if (page) {
args->pud_pfn = page_to_pfn(page);
args->pmd_pfn = args->pud_pfn;
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 5bb3a7844abb..da32397b4313 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -7180,7 +7180,6 @@ struct page *alloc_contig_pages_noprof(unsigned long nr_pages, gfp_t gfp_mask,
}
return NULL;
}
-#endif /* CONFIG_CONTIG_ALLOC */
void free_contig_range(unsigned long pfn, unsigned long nr_pages)
{
@@ -7207,6 +7206,7 @@ void free_contig_range(unsigned long pfn, unsigned long nr_pages)
WARN(count != 0, "%lu pages are still in use!\n", count);
}
EXPORT_SYMBOL(free_contig_range);
+#endif /* CONFIG_CONTIG_ALLOC */
/*
* Effectively disable pcplists for the zone by setting the high limit to 0
--
2.27.0
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v4 1/6] mm: debug_vm_pgtable: add debug_vm_pgtable_free_huge_page()
2025-12-16 11:48 ` [PATCH v4 1/6] mm: debug_vm_pgtable: add debug_vm_pgtable_free_huge_page() Kefeng Wang
@ 2025-12-16 16:08 ` Zi Yan
2025-12-17 2:40 ` Muchun Song
1 sibling, 0 replies; 33+ messages in thread
From: Zi Yan @ 2025-12-16 16:08 UTC (permalink / raw)
To: Kefeng Wang
Cc: Andrew Morton, David Hildenbrand, Oscar Salvador, Muchun Song,
linux-mm, sidhartha.kumar, jane.chu, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand
On 16 Dec 2025, at 6:48, Kefeng Wang wrote:
> Add a new helper to free huge page to be consistency to
> debug_vm_pgtable_alloc_huge_page(), and use HPAGE_PUD_ORDER
> instead of open-code.
>
> Also move the free_contig_range() under CONFIG_ALLOC_CONTIG
> since all caller are built with CONFIG_ALLOC_CONTIG.
>
> Acked-by: David Hildenbrand <david@redhat.com>
> Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
> ---
> include/linux/gfp.h | 2 +-
> mm/debug_vm_pgtable.c | 38 +++++++++++++++++---------------------
> mm/page_alloc.c | 2 +-
> 3 files changed, 19 insertions(+), 23 deletions(-)
>
LGTM. Reviewed-by: Zi Yan <ziy@nvidia.com>
Best Regards,
Yan, Zi
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v4 1/6] mm: debug_vm_pgtable: add debug_vm_pgtable_free_huge_page()
2025-12-16 11:48 ` [PATCH v4 1/6] mm: debug_vm_pgtable: add debug_vm_pgtable_free_huge_page() Kefeng Wang
2025-12-16 16:08 ` Zi Yan
@ 2025-12-17 2:40 ` Muchun Song
1 sibling, 0 replies; 33+ messages in thread
From: Muchun Song @ 2025-12-17 2:40 UTC (permalink / raw)
To: Kefeng Wang
Cc: Andrew Morton, David Hildenbrand, Oscar Salvador, linux-mm,
sidhartha.kumar, jane.chu, Zi Yan, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand
> On Dec 16, 2025, at 19:48, Kefeng Wang <wangkefeng.wang@huawei.com> wrote:
>
> Add a new helper to free huge page to be consistency to
> debug_vm_pgtable_alloc_huge_page(), and use HPAGE_PUD_ORDER
> instead of open-code.
>
> Also move the free_contig_range() under CONFIG_ALLOC_CONTIG
> since all caller are built with CONFIG_ALLOC_CONTIG.
>
> Acked-by: David Hildenbrand <david@redhat.com>
> Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
Reviewed-by: Muchun Song <muchun.song@linux.dev>
Thanks.
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v4 2/6] mm: page_alloc: add __split_page()
2025-12-16 11:48 [PATCH v4 RESEND 0/6] mm: hugetlb: allocate frozen gigantic folio Kefeng Wang
2025-12-16 11:48 ` [PATCH v4 1/6] mm: debug_vm_pgtable: add debug_vm_pgtable_free_huge_page() Kefeng Wang
@ 2025-12-16 11:48 ` Kefeng Wang
2025-12-16 16:21 ` Zi Yan
2025-12-17 2:45 ` Muchun Song
2025-12-16 11:48 ` [PATCH v4 3/6] mm: cma: add __cma_release() Kefeng Wang
` (3 subsequent siblings)
5 siblings, 2 replies; 33+ messages in thread
From: Kefeng Wang @ 2025-12-16 11:48 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Oscar Salvador, Muchun Song, linux-mm
Cc: sidhartha.kumar, jane.chu, Zi Yan, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand, Kefeng Wang
Factor out the splitting of non-compound page from make_alloc_exact()
and split_page() into a new helper function __split_page().
While at it, convert the VM_BUG_ON_PAGE() into a VM_WARN_ON_PAGE().
Acked-by: David Hildenbrand <david@redhat.com>
Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
---
include/linux/mmdebug.h | 10 ++++++++++
mm/page_alloc.c | 19 ++++++++++++-------
2 files changed, 22 insertions(+), 7 deletions(-)
diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h
index 14a45979cccc..ab60ffba08f5 100644
--- a/include/linux/mmdebug.h
+++ b/include/linux/mmdebug.h
@@ -47,6 +47,15 @@ void vma_iter_dump_tree(const struct vma_iterator *vmi);
BUG(); \
} \
} while (0)
+#define VM_WARN_ON_PAGE(cond, page) ({ \
+ int __ret_warn = !!(cond); \
+ \
+ if (unlikely(__ret_warn)) { \
+ dump_page(page, "VM_WARN_ON_PAGE(" __stringify(cond)")");\
+ WARN_ON(1); \
+ } \
+ unlikely(__ret_warn); \
+})
#define VM_WARN_ON_ONCE_PAGE(cond, page) ({ \
static bool __section(".data..once") __warned; \
int __ret_warn_once = !!(cond); \
@@ -122,6 +131,7 @@ void vma_iter_dump_tree(const struct vma_iterator *vmi);
#define VM_BUG_ON_MM(cond, mm) VM_BUG_ON(cond)
#define VM_WARN_ON(cond) BUILD_BUG_ON_INVALID(cond)
#define VM_WARN_ON_ONCE(cond) BUILD_BUG_ON_INVALID(cond)
+#define VM_WARN_ON_PAGE(cond, page) BUILD_BUG_ON_INVALID(cond)
#define VM_WARN_ON_ONCE_PAGE(cond, page) BUILD_BUG_ON_INVALID(cond)
#define VM_WARN_ON_FOLIO(cond, folio) BUILD_BUG_ON_INVALID(cond)
#define VM_WARN_ON_ONCE_FOLIO(cond, folio) BUILD_BUG_ON_INVALID(cond)
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index da32397b4313..aa30d4436296 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -3077,6 +3077,15 @@ void free_unref_folios(struct folio_batch *folios)
folio_batch_reinit(folios);
}
+static void __split_page(struct page *page, unsigned int order)
+{
+ VM_WARN_ON_PAGE(PageCompound(page), page);
+
+ split_page_owner(page, order, 0);
+ pgalloc_tag_split(page_folio(page), order, 0);
+ split_page_memcg(page, order);
+}
+
/*
* split_page takes a non-compound higher-order page, and splits it into
* n (1<<order) sub-pages: page[0..n]
@@ -3089,14 +3098,12 @@ void split_page(struct page *page, unsigned int order)
{
int i;
- VM_BUG_ON_PAGE(PageCompound(page), page);
VM_BUG_ON_PAGE(!page_count(page), page);
for (i = 1; i < (1 << order); i++)
set_page_refcounted(page + i);
- split_page_owner(page, order, 0);
- pgalloc_tag_split(page_folio(page), order, 0);
- split_page_memcg(page, order);
+
+ __split_page(page, order);
}
EXPORT_SYMBOL_GPL(split_page);
@@ -5366,9 +5373,7 @@ static void *make_alloc_exact(unsigned long addr, unsigned int order,
struct page *page = virt_to_page((void *)addr);
struct page *last = page + nr;
- split_page_owner(page, order, 0);
- pgalloc_tag_split(page_folio(page), order, 0);
- split_page_memcg(page, order);
+ __split_page(page, order);
while (page < --last)
set_page_refcounted(last);
--
2.27.0
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v4 2/6] mm: page_alloc: add __split_page()
2025-12-16 11:48 ` [PATCH v4 2/6] mm: page_alloc: add __split_page() Kefeng Wang
@ 2025-12-16 16:21 ` Zi Yan
2025-12-17 7:01 ` Kefeng Wang
2025-12-17 2:45 ` Muchun Song
1 sibling, 1 reply; 33+ messages in thread
From: Zi Yan @ 2025-12-16 16:21 UTC (permalink / raw)
To: Kefeng Wang
Cc: Andrew Morton, David Hildenbrand, Oscar Salvador, Muchun Song,
linux-mm, sidhartha.kumar, jane.chu, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand
On 16 Dec 2025, at 6:48, Kefeng Wang wrote:
> Factor out the splitting of non-compound page from make_alloc_exact()
> and split_page() into a new helper function __split_page().
>
> While at it, convert the VM_BUG_ON_PAGE() into a VM_WARN_ON_PAGE().
>
> Acked-by: David Hildenbrand <david@redhat.com>
> Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
> ---
> include/linux/mmdebug.h | 10 ++++++++++
> mm/page_alloc.c | 19 ++++++++++++-------
> 2 files changed, 22 insertions(+), 7 deletions(-)
>
> diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h
> index 14a45979cccc..ab60ffba08f5 100644
> --- a/include/linux/mmdebug.h
> +++ b/include/linux/mmdebug.h
> @@ -47,6 +47,15 @@ void vma_iter_dump_tree(const struct vma_iterator *vmi);
> BUG(); \
> } \
> } while (0)
> +#define VM_WARN_ON_PAGE(cond, page) ({ \
> + int __ret_warn = !!(cond); \
> + \
> + if (unlikely(__ret_warn)) { \
> + dump_page(page, "VM_WARN_ON_PAGE(" __stringify(cond)")");\
> + WARN_ON(1); \
> + } \
> + unlikely(__ret_warn); \
> +})
> #define VM_WARN_ON_ONCE_PAGE(cond, page) ({ \
> static bool __section(".data..once") __warned; \
> int __ret_warn_once = !!(cond); \
> @@ -122,6 +131,7 @@ void vma_iter_dump_tree(const struct vma_iterator *vmi);
> #define VM_BUG_ON_MM(cond, mm) VM_BUG_ON(cond)
> #define VM_WARN_ON(cond) BUILD_BUG_ON_INVALID(cond)
> #define VM_WARN_ON_ONCE(cond) BUILD_BUG_ON_INVALID(cond)
> +#define VM_WARN_ON_PAGE(cond, page) BUILD_BUG_ON_INVALID(cond)
> #define VM_WARN_ON_ONCE_PAGE(cond, page) BUILD_BUG_ON_INVALID(cond)
> #define VM_WARN_ON_FOLIO(cond, folio) BUILD_BUG_ON_INVALID(cond)
> #define VM_WARN_ON_ONCE_FOLIO(cond, folio) BUILD_BUG_ON_INVALID(cond)
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index da32397b4313..aa30d4436296 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -3077,6 +3077,15 @@ void free_unref_folios(struct folio_batch *folios)
> folio_batch_reinit(folios);
> }
>
> +static void __split_page(struct page *page, unsigned int order)
> +{
> + VM_WARN_ON_PAGE(PageCompound(page), page);
> +
> + split_page_owner(page, order, 0);
> + pgalloc_tag_split(page_folio(page), order, 0);
> + split_page_memcg(page, order);
> +}
> +
> /*
> * split_page takes a non-compound higher-order page, and splits it into
> * n (1<<order) sub-pages: page[0..n]
> @@ -3089,14 +3098,12 @@ void split_page(struct page *page, unsigned int order)
> {
> int i;
>
> - VM_BUG_ON_PAGE(PageCompound(page), page);
> VM_BUG_ON_PAGE(!page_count(page), page);
Could this be converted to VM_WARN_ON_PAGE() as well?
Otherwise, LGTM. Reviewed-by: Zi Yan <ziy@nvidia.com>
Best Regards,
Yan, Zi
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v4 2/6] mm: page_alloc: add __split_page()
2025-12-16 16:21 ` Zi Yan
@ 2025-12-17 7:01 ` Kefeng Wang
0 siblings, 0 replies; 33+ messages in thread
From: Kefeng Wang @ 2025-12-17 7:01 UTC (permalink / raw)
To: Zi Yan
Cc: Andrew Morton, David Hildenbrand, Oscar Salvador, Muchun Song,
linux-mm, sidhartha.kumar, jane.chu, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand
On 2025/12/17 0:21, Zi Yan wrote:
> On 16 Dec 2025, at 6:48, Kefeng Wang wrote:
>
>> Factor out the splitting of non-compound page from make_alloc_exact()
>> and split_page() into a new helper function __split_page().
>>
>> While at it, convert the VM_BUG_ON_PAGE() into a VM_WARN_ON_PAGE().
>>
>> Acked-by: David Hildenbrand <david@redhat.com>
>> Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
>> ---
>> include/linux/mmdebug.h | 10 ++++++++++
>> mm/page_alloc.c | 19 ++++++++++++-------
>> 2 files changed, 22 insertions(+), 7 deletions(-)
>>
>> diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h
>> index 14a45979cccc..ab60ffba08f5 100644
>> --- a/include/linux/mmdebug.h
>> +++ b/include/linux/mmdebug.h
>> @@ -47,6 +47,15 @@ void vma_iter_dump_tree(const struct vma_iterator *vmi);
>> BUG(); \
>> } \
>> } while (0)
>> +#define VM_WARN_ON_PAGE(cond, page) ({ \
>> + int __ret_warn = !!(cond); \
>> + \
>> + if (unlikely(__ret_warn)) { \
>> + dump_page(page, "VM_WARN_ON_PAGE(" __stringify(cond)")");\
>> + WARN_ON(1); \
>> + } \
>> + unlikely(__ret_warn); \
>> +})
>> #define VM_WARN_ON_ONCE_PAGE(cond, page) ({ \
>> static bool __section(".data..once") __warned; \
>> int __ret_warn_once = !!(cond); \
>> @@ -122,6 +131,7 @@ void vma_iter_dump_tree(const struct vma_iterator *vmi);
>> #define VM_BUG_ON_MM(cond, mm) VM_BUG_ON(cond)
>> #define VM_WARN_ON(cond) BUILD_BUG_ON_INVALID(cond)
>> #define VM_WARN_ON_ONCE(cond) BUILD_BUG_ON_INVALID(cond)
>> +#define VM_WARN_ON_PAGE(cond, page) BUILD_BUG_ON_INVALID(cond)
>> #define VM_WARN_ON_ONCE_PAGE(cond, page) BUILD_BUG_ON_INVALID(cond)
>> #define VM_WARN_ON_FOLIO(cond, folio) BUILD_BUG_ON_INVALID(cond)
>> #define VM_WARN_ON_ONCE_FOLIO(cond, folio) BUILD_BUG_ON_INVALID(cond)
>> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
>> index da32397b4313..aa30d4436296 100644
>> --- a/mm/page_alloc.c
>> +++ b/mm/page_alloc.c
>> @@ -3077,6 +3077,15 @@ void free_unref_folios(struct folio_batch *folios)
>> folio_batch_reinit(folios);
>> }
>>
>> +static void __split_page(struct page *page, unsigned int order)
>> +{
>> + VM_WARN_ON_PAGE(PageCompound(page), page);
>> +
>> + split_page_owner(page, order, 0);
>> + pgalloc_tag_split(page_folio(page), order, 0);
>> + split_page_memcg(page, order);
>> +}
>> +
>> /*
>> * split_page takes a non-compound higher-order page, and splits it into
>> * n (1<<order) sub-pages: page[0..n]
>> @@ -3089,14 +3098,12 @@ void split_page(struct page *page, unsigned int order)
>> {
>> int i;
>>
>> - VM_BUG_ON_PAGE(PageCompound(page), page);
>> VM_BUG_ON_PAGE(!page_count(page), page);
>
> Could this be converted to VM_WARN_ON_PAGE() as well?
Yep, will change it too.
Thanks.
>
> Otherwise, LGTM. Reviewed-by: Zi Yan <ziy@nvidia.com>
>
> Best Regards,
> Yan, Zi
>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v4 2/6] mm: page_alloc: add __split_page()
2025-12-16 11:48 ` [PATCH v4 2/6] mm: page_alloc: add __split_page() Kefeng Wang
2025-12-16 16:21 ` Zi Yan
@ 2025-12-17 2:45 ` Muchun Song
1 sibling, 0 replies; 33+ messages in thread
From: Muchun Song @ 2025-12-17 2:45 UTC (permalink / raw)
To: Kefeng Wang
Cc: Andrew Morton, David Hildenbrand, Oscar Salvador, linux-mm,
sidhartha.kumar, jane.chu, Zi Yan, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand
> On Dec 16, 2025, at 19:48, Kefeng Wang <wangkefeng.wang@huawei.com> wrote:
>
> Factor out the splitting of non-compound page from make_alloc_exact()
> and split_page() into a new helper function __split_page().
>
> While at it, convert the VM_BUG_ON_PAGE() into a VM_WARN_ON_PAGE().
>
> Acked-by: David Hildenbrand <david@redhat.com>
> Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
Acked-by: Muchun Song <muchun.song@linux.dev>
Thanks.
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v4 3/6] mm: cma: add __cma_release()
2025-12-16 11:48 [PATCH v4 RESEND 0/6] mm: hugetlb: allocate frozen gigantic folio Kefeng Wang
2025-12-16 11:48 ` [PATCH v4 1/6] mm: debug_vm_pgtable: add debug_vm_pgtable_free_huge_page() Kefeng Wang
2025-12-16 11:48 ` [PATCH v4 2/6] mm: page_alloc: add __split_page() Kefeng Wang
@ 2025-12-16 11:48 ` Kefeng Wang
2025-12-16 16:39 ` Zi Yan
2025-12-17 2:46 ` Muchun Song
2025-12-16 11:48 ` [PATCH v4 4/6] mm: page_alloc: add alloc_contig_frozen_{range,pages}() Kefeng Wang
` (2 subsequent siblings)
5 siblings, 2 replies; 33+ messages in thread
From: Kefeng Wang @ 2025-12-16 11:48 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Oscar Salvador, Muchun Song, linux-mm
Cc: sidhartha.kumar, jane.chu, Zi Yan, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand, Kefeng Wang
Kill cma_pages_valid() which only used in cma_release(), also
cleanup code duplication between cma pages valid checking and
cma memrange finding, add __cma_release() helper to prepare for
the upcoming frozen page release.
Reviewed-by: Jane Chu <jane.chu@oracle.com>
Acked-by: David Hildenbrand <david@redhat.com>
Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
---
include/linux/cma.h | 1 -
mm/cma.c | 62 +++++++++++++++------------------------------
2 files changed, 21 insertions(+), 42 deletions(-)
diff --git a/include/linux/cma.h b/include/linux/cma.h
index 62d9c1cf6326..e5745d2aec55 100644
--- a/include/linux/cma.h
+++ b/include/linux/cma.h
@@ -49,7 +49,6 @@ extern int cma_init_reserved_mem(phys_addr_t base, phys_addr_t size,
struct cma **res_cma);
extern struct page *cma_alloc(struct cma *cma, unsigned long count, unsigned int align,
bool no_warn);
-extern bool cma_pages_valid(struct cma *cma, const struct page *pages, unsigned long count);
extern bool cma_release(struct cma *cma, const struct page *pages, unsigned long count);
extern int cma_for_each_area(int (*it)(struct cma *cma, void *data), void *data);
diff --git a/mm/cma.c b/mm/cma.c
index 813e6dc7b095..6df44541933a 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -942,34 +942,43 @@ struct folio *cma_alloc_folio(struct cma *cma, int order, gfp_t gfp)
return page ? page_folio(page) : NULL;
}
-bool cma_pages_valid(struct cma *cma, const struct page *pages,
- unsigned long count)
+static bool __cma_release(struct cma *cma, const struct page *pages,
+ unsigned long count)
{
unsigned long pfn, end;
int r;
struct cma_memrange *cmr;
- bool ret;
+
+ pr_debug("%s(page %p, count %lu)\n", __func__, (void *)pages, count);
if (!cma || !pages || count > cma->count)
return false;
pfn = page_to_pfn(pages);
- ret = false;
for (r = 0; r < cma->nranges; r++) {
cmr = &cma->ranges[r];
end = cmr->base_pfn + cmr->count;
if (pfn >= cmr->base_pfn && pfn < end) {
- ret = pfn + count <= end;
- break;
+ if (pfn + count <= end)
+ break;
+
+ VM_WARN_ON_ONCE(1);
}
}
- if (!ret)
- pr_debug("%s(page %p, count %lu)\n",
- __func__, (void *)pages, count);
+ if (r == cma->nranges) {
+ pr_debug("%s(page %p, count %lu, no cma range matches the page range)\n",
+ __func__, (void *)pages, count);
+ return false;
+ }
- return ret;
+ free_contig_range(pfn, count);
+ cma_clear_bitmap(cma, cmr, pfn, count);
+ cma_sysfs_account_release_pages(cma, count);
+ trace_cma_release(cma->name, pfn, pages, count);
+
+ return true;
}
/**
@@ -985,36 +994,7 @@ bool cma_pages_valid(struct cma *cma, const struct page *pages,
bool cma_release(struct cma *cma, const struct page *pages,
unsigned long count)
{
- struct cma_memrange *cmr;
- unsigned long pfn, end_pfn;
- int r;
-
- pr_debug("%s(page %p, count %lu)\n", __func__, (void *)pages, count);
-
- if (!cma_pages_valid(cma, pages, count))
- return false;
-
- pfn = page_to_pfn(pages);
- end_pfn = pfn + count;
-
- for (r = 0; r < cma->nranges; r++) {
- cmr = &cma->ranges[r];
- if (pfn >= cmr->base_pfn &&
- pfn < (cmr->base_pfn + cmr->count)) {
- VM_BUG_ON(end_pfn > cmr->base_pfn + cmr->count);
- break;
- }
- }
-
- if (r == cma->nranges)
- return false;
-
- free_contig_range(pfn, count);
- cma_clear_bitmap(cma, cmr, pfn, count);
- cma_sysfs_account_release_pages(cma, count);
- trace_cma_release(cma->name, pfn, pages, count);
-
- return true;
+ return __cma_release(cma, pages, count);
}
bool cma_free_folio(struct cma *cma, const struct folio *folio)
@@ -1022,7 +1002,7 @@ bool cma_free_folio(struct cma *cma, const struct folio *folio)
if (WARN_ON(!folio_test_large(folio)))
return false;
- return cma_release(cma, &folio->page, folio_nr_pages(folio));
+ return __cma_release(cma, &folio->page, folio_nr_pages(folio));
}
int cma_for_each_area(int (*it)(struct cma *cma, void *data), void *data)
--
2.27.0
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v4 3/6] mm: cma: add __cma_release()
2025-12-16 11:48 ` [PATCH v4 3/6] mm: cma: add __cma_release() Kefeng Wang
@ 2025-12-16 16:39 ` Zi Yan
2025-12-17 2:46 ` Muchun Song
1 sibling, 0 replies; 33+ messages in thread
From: Zi Yan @ 2025-12-16 16:39 UTC (permalink / raw)
To: Kefeng Wang
Cc: Andrew Morton, David Hildenbrand, Oscar Salvador, Muchun Song,
linux-mm, sidhartha.kumar, jane.chu, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand
On 16 Dec 2025, at 6:48, Kefeng Wang wrote:
> Kill cma_pages_valid() which only used in cma_release(), also
> cleanup code duplication between cma pages valid checking and
> cma memrange finding, add __cma_release() helper to prepare for
> the upcoming frozen page release.
>
> Reviewed-by: Jane Chu <jane.chu@oracle.com>
> Acked-by: David Hildenbrand <david@redhat.com>
> Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
> ---
> include/linux/cma.h | 1 -
> mm/cma.c | 62 +++++++++++++++------------------------------
> 2 files changed, 21 insertions(+), 42 deletions(-)
>
LGTM. Reviewed-by: Zi Yan <ziy@nvidia.com>
Best Regards,
Yan, Zi
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v4 3/6] mm: cma: add __cma_release()
2025-12-16 11:48 ` [PATCH v4 3/6] mm: cma: add __cma_release() Kefeng Wang
2025-12-16 16:39 ` Zi Yan
@ 2025-12-17 2:46 ` Muchun Song
1 sibling, 0 replies; 33+ messages in thread
From: Muchun Song @ 2025-12-17 2:46 UTC (permalink / raw)
To: Kefeng Wang
Cc: Andrew Morton, David Hildenbrand, Oscar Salvador, linux-mm,
sidhartha.kumar, jane.chu, Zi Yan, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand
> On Dec 16, 2025, at 19:48, Kefeng Wang <wangkefeng.wang@huawei.com> wrote:
>
> Kill cma_pages_valid() which only used in cma_release(), also
> cleanup code duplication between cma pages valid checking and
> cma memrange finding, add __cma_release() helper to prepare for
> the upcoming frozen page release.
>
> Reviewed-by: Jane Chu <jane.chu@oracle.com>
> Acked-by: David Hildenbrand <david@redhat.com>
> Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
Reviewed-by: Muchun Song <muchun.song@linux.dev>
Thanks.
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v4 4/6] mm: page_alloc: add alloc_contig_frozen_{range,pages}()
2025-12-16 11:48 [PATCH v4 RESEND 0/6] mm: hugetlb: allocate frozen gigantic folio Kefeng Wang
` (2 preceding siblings ...)
2025-12-16 11:48 ` [PATCH v4 3/6] mm: cma: add __cma_release() Kefeng Wang
@ 2025-12-16 11:48 ` Kefeng Wang
2025-12-16 17:20 ` Zi Yan
2025-12-16 11:48 ` [PATCH v4 5/6] mm: cma: add cma_alloc_frozen{_compound}() Kefeng Wang
2025-12-16 11:48 ` [PATCH v4 6/6] mm: hugetlb: allocate frozen pages in alloc_gigantic_folio() Kefeng Wang
5 siblings, 1 reply; 33+ messages in thread
From: Kefeng Wang @ 2025-12-16 11:48 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Oscar Salvador, Muchun Song, linux-mm
Cc: sidhartha.kumar, jane.chu, Zi Yan, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand, Kefeng Wang
In order to allocate given range of pages or allocate compound
pages without incrementing their refcount, adding two new helper
alloc_contig_frozen_{range,pages}() which may be beneficial
to some users (eg hugetlb).
The new alloc_contig_{range,pages} only take !__GFP_COMP gfp now,
and the free_contig_range() is refactored to only free non-compound
pages, the only caller to free compound pages in cma_free_folio() is
changed accordingly, and the free_contig_frozen_range() is provided
to match the alloc_contig_frozen_range(), which is used to free
frozen pages.
Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
---
include/linux/gfp.h | 52 +++++--------
mm/cma.c | 15 ++--
mm/hugetlb.c | 9 ++-
mm/internal.h | 13 ++++
mm/page_alloc.c | 183 ++++++++++++++++++++++++++++++++------------
5 files changed, 184 insertions(+), 88 deletions(-)
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index ea053f1cfa16..aa45989f410d 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -430,40 +430,30 @@ typedef unsigned int __bitwise acr_flags_t;
#define ACR_FLAGS_CMA ((__force acr_flags_t)BIT(0)) // allocate for CMA
/* The below functions must be run on a range from a single zone. */
-extern int alloc_contig_range_noprof(unsigned long start, unsigned long end,
- acr_flags_t alloc_flags, gfp_t gfp_mask);
-#define alloc_contig_range(...) alloc_hooks(alloc_contig_range_noprof(__VA_ARGS__))
-
-extern struct page *alloc_contig_pages_noprof(unsigned long nr_pages, gfp_t gfp_mask,
- int nid, nodemask_t *nodemask);
-#define alloc_contig_pages(...) alloc_hooks(alloc_contig_pages_noprof(__VA_ARGS__))
-
+int alloc_contig_frozen_range_noprof(unsigned long start, unsigned long end,
+ acr_flags_t alloc_flags, gfp_t gfp_mask);
+#define alloc_contig_frozen_range(...) \
+ alloc_hooks(alloc_contig_frozen_range_noprof(__VA_ARGS__))
+
+int alloc_contig_range_noprof(unsigned long start, unsigned long end,
+ acr_flags_t alloc_flags, gfp_t gfp_mask);
+#define alloc_contig_range(...) \
+ alloc_hooks(alloc_contig_range_noprof(__VA_ARGS__))
+
+struct page *alloc_contig_frozen_pages_noprof(unsigned long nr_pages,
+ gfp_t gfp_mask, int nid, nodemask_t *nodemask);
+#define alloc_contig_frozen_pages(...) \
+ alloc_hooks(alloc_contig_frozen_pages_noprof(__VA_ARGS__))
+
+struct page *alloc_contig_pages_noprof(unsigned long nr_pages, gfp_t gfp_mask,
+ int nid, nodemask_t *nodemask);
+#define alloc_contig_pages(...) \
+ alloc_hooks(alloc_contig_pages_noprof(__VA_ARGS__))
+
+void free_contig_frozen_range(unsigned long pfn, unsigned long nr_pages);
void free_contig_range(unsigned long pfn, unsigned long nr_pages);
#endif
-#ifdef CONFIG_CONTIG_ALLOC
-static inline struct folio *folio_alloc_gigantic_noprof(int order, gfp_t gfp,
- int nid, nodemask_t *node)
-{
- struct page *page;
-
- if (WARN_ON(!order || !(gfp & __GFP_COMP)))
- return NULL;
-
- page = alloc_contig_pages_noprof(1 << order, gfp, nid, node);
-
- return page ? page_folio(page) : NULL;
-}
-#else
-static inline struct folio *folio_alloc_gigantic_noprof(int order, gfp_t gfp,
- int nid, nodemask_t *node)
-{
- return NULL;
-}
-#endif
-/* This should be paired with folio_put() rather than free_contig_range(). */
-#define folio_alloc_gigantic(...) alloc_hooks(folio_alloc_gigantic_noprof(__VA_ARGS__))
-
DEFINE_FREE(free_page, void *, free_page((unsigned long)_T))
#endif /* __LINUX_GFP_H */
diff --git a/mm/cma.c b/mm/cma.c
index 6df44541933a..7f050cf24383 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -836,7 +836,7 @@ static int cma_range_alloc(struct cma *cma, struct cma_memrange *cmr,
spin_unlock_irq(&cma->lock);
mutex_lock(&cma->alloc_mutex);
- ret = alloc_contig_range(pfn, pfn + count, ACR_FLAGS_CMA, gfp);
+ ret = alloc_contig_frozen_range(pfn, pfn + count, ACR_FLAGS_CMA, gfp);
mutex_unlock(&cma->alloc_mutex);
if (!ret)
break;
@@ -904,6 +904,7 @@ static struct page *__cma_alloc(struct cma *cma, unsigned long count,
trace_cma_alloc_finish(name, page ? page_to_pfn(page) : 0,
page, count, align, ret);
if (page) {
+ set_pages_refcounted(page, count);
count_vm_event(CMA_ALLOC_SUCCESS);
cma_sysfs_account_success_pages(cma, count);
} else {
@@ -943,7 +944,7 @@ struct folio *cma_alloc_folio(struct cma *cma, int order, gfp_t gfp)
}
static bool __cma_release(struct cma *cma, const struct page *pages,
- unsigned long count)
+ unsigned long count, bool compound)
{
unsigned long pfn, end;
int r;
@@ -973,7 +974,11 @@ static bool __cma_release(struct cma *cma, const struct page *pages,
return false;
}
- free_contig_range(pfn, count);
+ if (compound)
+ __free_pages((struct page *)pages, compound_order(pages));
+ else
+ free_contig_range(pfn, count);
+
cma_clear_bitmap(cma, cmr, pfn, count);
cma_sysfs_account_release_pages(cma, count);
trace_cma_release(cma->name, pfn, pages, count);
@@ -994,7 +999,7 @@ static bool __cma_release(struct cma *cma, const struct page *pages,
bool cma_release(struct cma *cma, const struct page *pages,
unsigned long count)
{
- return __cma_release(cma, pages, count);
+ return __cma_release(cma, pages, count, false);
}
bool cma_free_folio(struct cma *cma, const struct folio *folio)
@@ -1002,7 +1007,7 @@ bool cma_free_folio(struct cma *cma, const struct folio *folio)
if (WARN_ON(!folio_test_large(folio)))
return false;
- return __cma_release(cma, &folio->page, folio_nr_pages(folio));
+ return __cma_release(cma, &folio->page, folio_nr_pages(folio), true);
}
int cma_for_each_area(int (*it)(struct cma *cma, void *data), void *data)
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 3db94693a06f..ed185bbca419 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -1428,12 +1428,17 @@ static struct folio *alloc_gigantic_folio(int order, gfp_t gfp_mask,
retry:
folio = hugetlb_cma_alloc_folio(order, gfp_mask, nid, nodemask);
if (!folio) {
+ struct page *page;
+
if (hugetlb_cma_exclusive_alloc())
return NULL;
- folio = folio_alloc_gigantic(order, gfp_mask, nid, nodemask);
- if (!folio)
+ page = alloc_contig_frozen_pages(1 << order, gfp_mask, nid, nodemask);
+ if (!page)
return NULL;
+
+ set_page_refcounted(page);
+ folio = page_folio(page);
}
if (folio_ref_freeze(folio, 1))
diff --git a/mm/internal.h b/mm/internal.h
index e430da900430..75f624236ff8 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -513,6 +513,19 @@ static inline void set_page_refcounted(struct page *page)
set_page_count(page, 1);
}
+static inline void set_pages_refcounted(struct page *page, unsigned long nr_pages)
+{
+ unsigned long pfn = page_to_pfn(page);
+
+ if (PageHead(page)) {
+ set_page_refcounted(page);
+ return;
+ }
+
+ for (; nr_pages--; pfn++)
+ set_page_refcounted(pfn_to_page(pfn));
+}
+
/*
* Return true if a folio needs ->release_folio() calling upon it.
*/
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index aa30d4436296..a7fc83bf806f 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -6865,7 +6865,7 @@ static int __alloc_contig_migrate_range(struct compact_control *cc,
return (ret < 0) ? ret : 0;
}
-static void split_free_pages(struct list_head *list, gfp_t gfp_mask)
+static void split_free_frozen_pages(struct list_head *list, gfp_t gfp_mask)
{
int order;
@@ -6877,11 +6877,10 @@ static void split_free_pages(struct list_head *list, gfp_t gfp_mask)
int i;
post_alloc_hook(page, order, gfp_mask);
- set_page_refcounted(page);
if (!order)
continue;
- split_page(page, order);
+ __split_page(page, order);
/* Add all subpages to the order-0 head, in sequence. */
list_del(&page->lru);
@@ -6925,8 +6924,14 @@ static int __alloc_contig_verify_gfp_mask(gfp_t gfp_mask, gfp_t *gfp_cc_mask)
return 0;
}
+static void __free_contig_frozen_range(unsigned long pfn, unsigned long nr_pages)
+{
+ for (; nr_pages--; pfn++)
+ free_frozen_pages(pfn_to_page(pfn), 0);
+}
+
/**
- * alloc_contig_range() -- tries to allocate given range of pages
+ * alloc_contig_frozen_range() -- tries to allocate given range of frozen pages
* @start: start PFN to allocate
* @end: one-past-the-last PFN to allocate
* @alloc_flags: allocation information
@@ -6941,12 +6946,15 @@ static int __alloc_contig_verify_gfp_mask(gfp_t gfp_mask, gfp_t *gfp_cc_mask)
* pageblocks in the range. Once isolated, the pageblocks should not
* be modified by others.
*
- * Return: zero on success or negative error code. On success all
- * pages which PFN is in [start, end) are allocated for the caller and
- * need to be freed with free_contig_range().
+ * All frozen pages which PFN is in [start, end) are allocated for the
+ * caller, and they could be freed with free_contig_frozen_range(),
+ * free_frozen_pages() also could be used to free compound frozen pages
+ * directly.
+ *
+ * Return: zero on success or negative error code.
*/
-int alloc_contig_range_noprof(unsigned long start, unsigned long end,
- acr_flags_t alloc_flags, gfp_t gfp_mask)
+int alloc_contig_frozen_range_noprof(unsigned long start, unsigned long end,
+ acr_flags_t alloc_flags, gfp_t gfp_mask)
{
const unsigned int order = ilog2(end - start);
unsigned long outer_start, outer_end;
@@ -7062,19 +7070,18 @@ int alloc_contig_range_noprof(unsigned long start, unsigned long end,
}
if (!(gfp_mask & __GFP_COMP)) {
- split_free_pages(cc.freepages, gfp_mask);
+ split_free_frozen_pages(cc.freepages, gfp_mask);
/* Free head and tail (if any) */
if (start != outer_start)
- free_contig_range(outer_start, start - outer_start);
+ __free_contig_frozen_range(outer_start, start - outer_start);
if (end != outer_end)
- free_contig_range(end, outer_end - end);
+ __free_contig_frozen_range(end, outer_end - end);
} else if (start == outer_start && end == outer_end && is_power_of_2(end - start)) {
struct page *head = pfn_to_page(start);
check_new_pages(head, order);
prep_new_page(head, order, gfp_mask, 0);
- set_page_refcounted(head);
} else {
ret = -EINVAL;
WARN(true, "PFN range: requested [%lu, %lu), allocated [%lu, %lu)\n",
@@ -7084,16 +7091,40 @@ int alloc_contig_range_noprof(unsigned long start, unsigned long end,
undo_isolate_page_range(start, end);
return ret;
}
-EXPORT_SYMBOL(alloc_contig_range_noprof);
+EXPORT_SYMBOL(alloc_contig_frozen_range_noprof);
-static int __alloc_contig_pages(unsigned long start_pfn,
- unsigned long nr_pages, gfp_t gfp_mask)
+/**
+ * alloc_contig_range() -- tries to allocate given range of pages
+ * @start: start PFN to allocate
+ * @end: one-past-the-last PFN to allocate
+ * @alloc_flags: allocation information
+ * @gfp_mask: GFP mask.
+ *
+ * This routine is a wrapper around alloc_contig_frozen_range(), it can't
+ * be used to allocate compound pages, the refcount of each allocated page
+ * will be set to one.
+ *
+ * All pages which PFN is in [start, end) are allocated for the caller,
+ * and should be freed with free_contig_range() or by manually calling
+ * __free_page() on each allocated page.
+ *
+ * Return: zero on success or negative error code.
+ */
+int alloc_contig_range_noprof(unsigned long start, unsigned long end,
+ acr_flags_t alloc_flags, gfp_t gfp_mask)
{
- unsigned long end_pfn = start_pfn + nr_pages;
+ int ret;
+
+ if (WARN_ON(gfp_mask & __GFP_COMP))
+ return -EINVAL;
+
+ ret = alloc_contig_frozen_range_noprof(start, end, alloc_flags, gfp_mask);
+ if (!ret)
+ set_pages_refcounted(pfn_to_page(start), end - start);
- return alloc_contig_range_noprof(start_pfn, end_pfn, ACR_FLAGS_NONE,
- gfp_mask);
+ return ret;
}
+EXPORT_SYMBOL(alloc_contig_range_noprof);
static bool pfn_range_valid_contig(struct zone *z, unsigned long start_pfn,
unsigned long nr_pages)
@@ -7127,7 +7158,7 @@ static bool zone_spans_last_pfn(const struct zone *zone,
}
/**
- * alloc_contig_pages() -- tries to find and allocate contiguous range of pages
+ * alloc_contig_frozen_pages() -- tries to find and allocate contiguous range of frozen pages
* @nr_pages: Number of contiguous pages to allocate
* @gfp_mask: GFP mask. Node/zone/placement hints limit the search; only some
* action and reclaim modifiers are supported. Reclaim modifiers
@@ -7135,22 +7166,25 @@ static bool zone_spans_last_pfn(const struct zone *zone,
* @nid: Target node
* @nodemask: Mask for other possible nodes
*
- * This routine is a wrapper around alloc_contig_range(). It scans over zones
- * on an applicable zonelist to find a contiguous pfn range which can then be
- * tried for allocation with alloc_contig_range(). This routine is intended
- * for allocation requests which can not be fulfilled with the buddy allocator.
+ * This routine is a wrapper around alloc_contig_frozen_range(). It scans over
+ * zones on an applicable zonelist to find a contiguous pfn range which can then
+ * be tried for allocation with alloc_contig_frozen_range(). This routine is
+ * intended for allocation requests which can not be fulfilled with the buddy
+ * allocator.
*
* The allocated memory is always aligned to a page boundary. If nr_pages is a
* power of two, then allocated range is also guaranteed to be aligned to same
* nr_pages (e.g. 1GB request would be aligned to 1GB).
*
- * Allocated pages can be freed with free_contig_range() or by manually calling
- * __free_page() on each allocated page.
+ * Allocated frozen pages need be freed with free_contig_frozen_range(),
+ * or by manually calling free_frozen_pages() on each allocated frozen
+ * non-compound page, for compound frozen pages could be freed with
+ * free_frozen_pages() directly.
*
- * Return: pointer to contiguous pages on success, or NULL if not successful.
+ * Return: pointer to contiguous frozen pages on success, or NULL if not successful.
*/
-struct page *alloc_contig_pages_noprof(unsigned long nr_pages, gfp_t gfp_mask,
- int nid, nodemask_t *nodemask)
+struct page *alloc_contig_frozen_pages_noprof(unsigned long nr_pages,
+ gfp_t gfp_mask, int nid, nodemask_t *nodemask)
{
unsigned long ret, pfn, flags;
struct zonelist *zonelist;
@@ -7167,13 +7201,15 @@ struct page *alloc_contig_pages_noprof(unsigned long nr_pages, gfp_t gfp_mask,
if (pfn_range_valid_contig(zone, pfn, nr_pages)) {
/*
* We release the zone lock here because
- * alloc_contig_range() will also lock the zone
- * at some point. If there's an allocation
- * spinning on this lock, it may win the race
- * and cause alloc_contig_range() to fail...
+ * alloc_contig_frozen_range() will also lock
+ * the zone at some point. If there's an
+ * allocation spinning on this lock, it may
+ * win the race and cause allocation to fail.
*/
spin_unlock_irqrestore(&zone->lock, flags);
- ret = __alloc_contig_pages(pfn, nr_pages,
+ ret = alloc_contig_frozen_range_noprof(pfn,
+ pfn + nr_pages,
+ ACR_FLAGS_NONE,
gfp_mask);
if (!ret)
return pfn_to_page(pfn);
@@ -7185,30 +7221,77 @@ struct page *alloc_contig_pages_noprof(unsigned long nr_pages, gfp_t gfp_mask,
}
return NULL;
}
+EXPORT_SYMBOL(alloc_contig_frozen_pages_noprof);
-void free_contig_range(unsigned long pfn, unsigned long nr_pages)
+/**
+ * alloc_contig_pages() -- tries to find and allocate contiguous range of pages
+ * @nr_pages: Number of contiguous pages to allocate
+ * @gfp_mask: GFP mask.
+ * @nid: Target node
+ * @nodemask: Mask for other possible nodes
+ *
+ * This routine is a wrapper around alloc_contig_frozen_pages(), it can't
+ * be used to allocate compound pages, the refcount of each allocated page
+ * will be set to one.
+ *
+ * Allocated pages can be freed with free_contig_range() or by manually
+ * calling __free_page() on each allocated page.
+ *
+ * Return: pointer to contiguous pages on success, or NULL if not successful.
+ */
+struct page *alloc_contig_pages_noprof(unsigned long nr_pages, gfp_t gfp_mask,
+ int nid, nodemask_t *nodemask)
{
- unsigned long count = 0;
- struct folio *folio = pfn_folio(pfn);
+ struct page *page;
+
+ if (WARN_ON(gfp_mask & __GFP_COMP))
+ return NULL;
- if (folio_test_large(folio)) {
- int expected = folio_nr_pages(folio);
+ page = alloc_contig_frozen_pages_noprof(nr_pages, gfp_mask, nid,
+ nodemask);
+ if (page)
+ set_pages_refcounted(page, nr_pages);
- if (nr_pages == expected)
- folio_put(folio);
- else
- WARN(true, "PFN %lu: nr_pages %lu != expected %d\n",
- pfn, nr_pages, expected);
+ return page;
+}
+EXPORT_SYMBOL(alloc_contig_pages_noprof);
+
+/**
+ * free_contig_frozen_range() -- free the contiguous range of frozen pages
+ * @pfn: start PFN to free
+ * @nr_pages: Number of contiguous frozen pages to free
+ *
+ * This can be used to free the allocated compound/non-compound frozen pages.
+ */
+void free_contig_frozen_range(unsigned long pfn, unsigned long nr_pages)
+{
+ struct page *first_page = pfn_to_page(pfn);
+ const unsigned int order = ilog2(nr_pages);
+
+ if (PageHead(first_page)) {
+ WARN_ON_ONCE(order != compound_order(first_page));
+ free_frozen_pages(first_page, order);
return;
}
- for (; nr_pages--; pfn++) {
- struct page *page = pfn_to_page(pfn);
+ __free_contig_frozen_range(pfn, nr_pages);
+}
+EXPORT_SYMBOL(free_contig_frozen_range);
+
+/**
+ * free_contig_range() -- free the contiguous range of pages
+ * @pfn: start PFN to free
+ * @nr_pages: Number of contiguous pages to free
+ *
+ * This can be only used to free the allocated non-compound pages.
+ */
+void free_contig_range(unsigned long pfn, unsigned long nr_pages)
+{
+ if (WARN_ON_ONCE(PageHead(pfn_to_page(pfn))))
+ return;
- count += page_count(page) != 1;
- __free_page(page);
- }
- WARN(count != 0, "%lu pages are still in use!\n", count);
+ for (; nr_pages--; pfn++)
+ __free_page(pfn_to_page(pfn));
}
EXPORT_SYMBOL(free_contig_range);
#endif /* CONFIG_CONTIG_ALLOC */
--
2.27.0
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v4 4/6] mm: page_alloc: add alloc_contig_frozen_{range,pages}()
2025-12-16 11:48 ` [PATCH v4 4/6] mm: page_alloc: add alloc_contig_frozen_{range,pages}() Kefeng Wang
@ 2025-12-16 17:20 ` Zi Yan
2025-12-17 7:17 ` Kefeng Wang
0 siblings, 1 reply; 33+ messages in thread
From: Zi Yan @ 2025-12-16 17:20 UTC (permalink / raw)
To: Kefeng Wang
Cc: Andrew Morton, David Hildenbrand, Oscar Salvador, Muchun Song,
linux-mm, sidhartha.kumar, jane.chu, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand
On 16 Dec 2025, at 6:48, Kefeng Wang wrote:
> In order to allocate given range of pages or allocate compound
> pages without incrementing their refcount, adding two new helper
> alloc_contig_frozen_{range,pages}() which may be beneficial
> to some users (eg hugetlb).
>
> The new alloc_contig_{range,pages} only take !__GFP_COMP gfp now,
> and the free_contig_range() is refactored to only free non-compound
> pages, the only caller to free compound pages in cma_free_folio() is
> changed accordingly, and the free_contig_frozen_range() is provided
> to match the alloc_contig_frozen_range(), which is used to free
> frozen pages.
>
> Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
> ---
> include/linux/gfp.h | 52 +++++--------
> mm/cma.c | 15 ++--
> mm/hugetlb.c | 9 ++-
> mm/internal.h | 13 ++++
> mm/page_alloc.c | 183 ++++++++++++++++++++++++++++++++------------
> 5 files changed, 184 insertions(+), 88 deletions(-)
>
<snip>
> diff --git a/mm/internal.h b/mm/internal.h
> index e430da900430..75f624236ff8 100644
> --- a/mm/internal.h
> +++ b/mm/internal.h
> @@ -513,6 +513,19 @@ static inline void set_page_refcounted(struct page *page)
> set_page_count(page, 1);
> }
>
> +static inline void set_pages_refcounted(struct page *page, unsigned long nr_pages)
> +{
> + unsigned long pfn = page_to_pfn(page);
> +
> + if (PageHead(page)) {
> + set_page_refcounted(page);
> + return;
> + }
This looks fragile, since if a tail page is passed, the refcount will be wrong.
But I see you remove this part in the next patch. It might be OK as a temporary
step.
> +
> + for (; nr_pages--; pfn++)
> + set_page_refcounted(pfn_to_page(pfn));
> +}
> +
> /*
> * Return true if a folio needs ->release_folio() calling upon it.
> */
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index aa30d4436296..a7fc83bf806f 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
<snip>
>
> +static void __free_contig_frozen_range(unsigned long pfn, unsigned long nr_pages)
> +{
> + for (; nr_pages--; pfn++)
> + free_frozen_pages(pfn_to_page(pfn), 0);
> +}
> +
Is it possible to use pageblock_order to speed this up?
And can it be moved before free_contig_frozen_range() for a easy read?
<snip>
> +
> +/**
> + * free_contig_frozen_range() -- free the contiguous range of frozen pages
> + * @pfn: start PFN to free
> + * @nr_pages: Number of contiguous frozen pages to free
> + *
> + * This can be used to free the allocated compound/non-compound frozen pages.
> + */
> +void free_contig_frozen_range(unsigned long pfn, unsigned long nr_pages)
> +{
> + struct page *first_page = pfn_to_page(pfn);
> + const unsigned int order = ilog2(nr_pages);
Maybe WARN_ON_ONCE(first_page != compound_head(first_page) and return
immediately here to catch a tail page.
> +
> + if (PageHead(first_page)) {
> + WARN_ON_ONCE(order != compound_order(first_page));
> + free_frozen_pages(first_page, order);
> return;
> }
>
> - for (; nr_pages--; pfn++) {
> - struct page *page = pfn_to_page(pfn);
> + __free_contig_frozen_range(pfn, nr_pages);
> +}
> +EXPORT_SYMBOL(free_contig_frozen_range);
> +
Best Regards,
Yan, Zi
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v4 4/6] mm: page_alloc: add alloc_contig_frozen_{range,pages}()
2025-12-16 17:20 ` Zi Yan
@ 2025-12-17 7:17 ` Kefeng Wang
2025-12-17 19:20 ` Zi Yan
0 siblings, 1 reply; 33+ messages in thread
From: Kefeng Wang @ 2025-12-17 7:17 UTC (permalink / raw)
To: Zi Yan
Cc: Andrew Morton, David Hildenbrand, Oscar Salvador, Muchun Song,
linux-mm, sidhartha.kumar, jane.chu, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand
On 2025/12/17 1:20, Zi Yan wrote:
> On 16 Dec 2025, at 6:48, Kefeng Wang wrote:
>
>> In order to allocate given range of pages or allocate compound
>> pages without incrementing their refcount, adding two new helper
>> alloc_contig_frozen_{range,pages}() which may be beneficial
>> to some users (eg hugetlb).
>>
>> The new alloc_contig_{range,pages} only take !__GFP_COMP gfp now,
>> and the free_contig_range() is refactored to only free non-compound
>> pages, the only caller to free compound pages in cma_free_folio() is
>> changed accordingly, and the free_contig_frozen_range() is provided
>> to match the alloc_contig_frozen_range(), which is used to free
>> frozen pages.
>>
>> Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
>> ---
>> include/linux/gfp.h | 52 +++++--------
>> mm/cma.c | 15 ++--
>> mm/hugetlb.c | 9 ++-
>> mm/internal.h | 13 ++++
>> mm/page_alloc.c | 183 ++++++++++++++++++++++++++++++++------------
>> 5 files changed, 184 insertions(+), 88 deletions(-)
>>
>
> <snip>
>
>> diff --git a/mm/internal.h b/mm/internal.h
>> index e430da900430..75f624236ff8 100644
>> --- a/mm/internal.h
>> +++ b/mm/internal.h
>> @@ -513,6 +513,19 @@ static inline void set_page_refcounted(struct page *page)
>> set_page_count(page, 1);
>> }
>>
>> +static inline void set_pages_refcounted(struct page *page, unsigned long nr_pages)
>> +{
>> + unsigned long pfn = page_to_pfn(page);
>> +
>> + if (PageHead(page)) {
>> + set_page_refcounted(page);
>> + return;
>> + }
>
> This looks fragile, since if a tail page is passed, the refcount will be wrong.
> But I see you remove this part in the next patch. It might be OK as a temporary
> step.
Yes, this temporary.
>
>> +
>> + for (; nr_pages--; pfn++)
>> + set_page_refcounted(pfn_to_page(pfn));
>> +}
>> +
>> /*
>> * Return true if a folio needs ->release_folio() calling upon it.
>> */
>> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
>> index aa30d4436296..a7fc83bf806f 100644
>> --- a/mm/page_alloc.c
>> +++ b/mm/page_alloc.c
>
> <snip>
>
>>
>> +static void __free_contig_frozen_range(unsigned long pfn, unsigned long nr_pages)
>> +{
>> + for (; nr_pages--; pfn++)
>> + free_frozen_pages(pfn_to_page(pfn), 0);
>> +}
>> +
>
> Is it possible to use pageblock_order to speed this up?
It should be no different since the page order always zero, maybe I
didn't get your point.
> And can it be moved before free_contig_frozen_range() for a easy read?
>
It is used by alloc_contig_frozen_range too, put it here could avoid an
additional declaration.
> <snip>
>
>> +
>> +/**
>> + * free_contig_frozen_range() -- free the contiguous range of frozen pages
>> + * @pfn: start PFN to free
>> + * @nr_pages: Number of contiguous frozen pages to free
>> + *
>> + * This can be used to free the allocated compound/non-compound frozen pages.
>> + */
>> +void free_contig_frozen_range(unsigned long pfn, unsigned long nr_pages)
>> +{
>> + struct page *first_page = pfn_to_page(pfn);
>> + const unsigned int order = ilog2(nr_pages);
>
> Maybe WARN_ON_ONCE(first_page != compound_head(first_page) and return
> immediately here to catch a tail page.
Sure, will add this new check here.
>
>> +
>> + if (PageHead(first_page)) {
>> + WARN_ON_ONCE(order != compound_order(first_page));
>> + free_frozen_pages(first_page, order);
>> return;
>> }
>>
>> - for (; nr_pages--; pfn++) {
>> - struct page *page = pfn_to_page(pfn);
>> + __free_contig_frozen_range(pfn, nr_pages);
>> +}
>> +EXPORT_SYMBOL(free_contig_frozen_range);
>> +
Thanks.
>
> Best Regards,
> Yan, Zi
>
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v4 4/6] mm: page_alloc: add alloc_contig_frozen_{range,pages}()
2025-12-17 7:17 ` Kefeng Wang
@ 2025-12-17 19:20 ` Zi Yan
2025-12-18 12:00 ` Kefeng Wang
0 siblings, 1 reply; 33+ messages in thread
From: Zi Yan @ 2025-12-17 19:20 UTC (permalink / raw)
To: Kefeng Wang
Cc: Andrew Morton, David Hildenbrand, Oscar Salvador, Muchun Song,
linux-mm, sidhartha.kumar, jane.chu, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand
On 17 Dec 2025, at 2:17, Kefeng Wang wrote:
> On 2025/12/17 1:20, Zi Yan wrote:
>> On 16 Dec 2025, at 6:48, Kefeng Wang wrote:
>>
>>> In order to allocate given range of pages or allocate compound
>>> pages without incrementing their refcount, adding two new helper
>>> alloc_contig_frozen_{range,pages}() which may be beneficial
>>> to some users (eg hugetlb).
>>>
>>> The new alloc_contig_{range,pages} only take !__GFP_COMP gfp now,
>>> and the free_contig_range() is refactored to only free non-compound
>>> pages, the only caller to free compound pages in cma_free_folio() is
>>> changed accordingly, and the free_contig_frozen_range() is provided
>>> to match the alloc_contig_frozen_range(), which is used to free
>>> frozen pages.
>>>
>>> Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
>>> ---
>>> include/linux/gfp.h | 52 +++++--------
>>> mm/cma.c | 15 ++--
>>> mm/hugetlb.c | 9 ++-
>>> mm/internal.h | 13 ++++
>>> mm/page_alloc.c | 183 ++++++++++++++++++++++++++++++++------------
>>> 5 files changed, 184 insertions(+), 88 deletions(-)
>>>
>>
>> <snip>
>>
>>> diff --git a/mm/internal.h b/mm/internal.h
>>> index e430da900430..75f624236ff8 100644
>>> --- a/mm/internal.h
>>> +++ b/mm/internal.h
>>> @@ -513,6 +513,19 @@ static inline void set_page_refcounted(struct page *page)
>>> set_page_count(page, 1);
>>> }
>>>
>>> +static inline void set_pages_refcounted(struct page *page, unsigned long nr_pages)
>>> +{
>>> + unsigned long pfn = page_to_pfn(page);
>>> +
>>> + if (PageHead(page)) {
>>> + set_page_refcounted(page);
>>> + return;
>>> + }
>>
>> This looks fragile, since if a tail page is passed, the refcount will be wrong.
>> But I see you remove this part in the next patch. It might be OK as a temporary
>> step.
>
> Yes, this temporary.
>
>>
>>> +
>>> + for (; nr_pages--; pfn++)
>>> + set_page_refcounted(pfn_to_page(pfn));
>>> +}
>>> +
>>> /*
>>> * Return true if a folio needs ->release_folio() calling upon it.
>>> */
>>> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
>>> index aa30d4436296..a7fc83bf806f 100644
>>> --- a/mm/page_alloc.c
>>> +++ b/mm/page_alloc.c
>>
>> <snip>
>>
>>>
>>> +static void __free_contig_frozen_range(unsigned long pfn, unsigned long nr_pages)
>>> +{
>>> + for (; nr_pages--; pfn++)
>>> + free_frozen_pages(pfn_to_page(pfn), 0);
>>> +}
>>> +
>>
>> Is it possible to use pageblock_order to speed this up?
>
> It should be no different since the page order always zero, maybe I
> didn't get your point.
Something like but take care of the cases when pfn and nr_pages are
not aligned to pageblock_nr_pages:
for (; nr_pages -= pageblock_nr_pages; pfn += pageblock_nr_pages)
free_frozen_pages(pfn_to_page(pfn), pageblock_order);
It makes fewer calls.
>> And can it be moved before free_contig_frozen_range() for a easy read?
>>
>
> It is used by alloc_contig_frozen_range too, put it here could avoid an additional declaration.
>
Got it.
>
>> <snip>
>>
>>> +
>>> +/**
>>> + * free_contig_frozen_range() -- free the contiguous range of frozen pages
>>> + * @pfn: start PFN to free
>>> + * @nr_pages: Number of contiguous frozen pages to free
>>> + *
>>> + * This can be used to free the allocated compound/non-compound frozen pages.
>>> + */
>>> +void free_contig_frozen_range(unsigned long pfn, unsigned long nr_pages)
>>> +{
>>> + struct page *first_page = pfn_to_page(pfn);
>>> + const unsigned int order = ilog2(nr_pages);
>>
>> Maybe WARN_ON_ONCE(first_page != compound_head(first_page) and return
>> immediately here to catch a tail page.
>
> Sure, will add this new check here.
>
>>
>>> +
>>> + if (PageHead(first_page)) {
>>> + WARN_ON_ONCE(order != compound_order(first_page));
>>> + free_frozen_pages(first_page, order);
>>> return;
>>> }
>>>
>>> - for (; nr_pages--; pfn++) {
>>> - struct page *page = pfn_to_page(pfn);
>>> + __free_contig_frozen_range(pfn, nr_pages);
>>> +}
>>> +EXPORT_SYMBOL(free_contig_frozen_range);
>>> +
> Thanks.
>>
>> Best Regards,
>> Yan, Zi
>>
Best Regards,
Yan, Zi
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v4 4/6] mm: page_alloc: add alloc_contig_frozen_{range,pages}()
2025-12-17 19:20 ` Zi Yan
@ 2025-12-18 12:00 ` Kefeng Wang
0 siblings, 0 replies; 33+ messages in thread
From: Kefeng Wang @ 2025-12-18 12:00 UTC (permalink / raw)
To: Zi Yan
Cc: Andrew Morton, David Hildenbrand, Oscar Salvador, Muchun Song,
linux-mm, sidhartha.kumar, jane.chu, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand
On 2025/12/18 3:20, Zi Yan wrote:
> On 17 Dec 2025, at 2:17, Kefeng Wang wrote:
>
>> On 2025/12/17 1:20, Zi Yan wrote:
>>> On 16 Dec 2025, at 6:48, Kefeng Wang wrote:
...
>>>>
>>>> +static void __free_contig_frozen_range(unsigned long pfn, unsigned long nr_pages)
>>>> +{
>>>> + for (; nr_pages--; pfn++)
>>>> + free_frozen_pages(pfn_to_page(pfn), 0);
>>>> +}
>>>> +
>>>
>>> Is it possible to use pageblock_order to speed this up?
>>
>> It should be no different since the page order always zero, maybe I
>> didn't get your point.
>
> Something like but take care of the cases when pfn and nr_pages are
> not aligned to pageblock_nr_pages:
>
> for (; nr_pages -= pageblock_nr_pages; pfn += pageblock_nr_pages)
> free_frozen_pages(pfn_to_page(pfn), pageblock_order);
>
> It makes fewer calls.
One of the drawbacks I though is that the pages can't be released to PCP
when the pageblock_order != PMD_ORDER, or released to different PCP
list (order-0 vs order-PMD_ORDER).
We maybe optimize it later if it's critical, but I don't want to do it
in this patchset.
Thanks.
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v4 5/6] mm: cma: add cma_alloc_frozen{_compound}()
2025-12-16 11:48 [PATCH v4 RESEND 0/6] mm: hugetlb: allocate frozen gigantic folio Kefeng Wang
` (3 preceding siblings ...)
2025-12-16 11:48 ` [PATCH v4 4/6] mm: page_alloc: add alloc_contig_frozen_{range,pages}() Kefeng Wang
@ 2025-12-16 11:48 ` Kefeng Wang
2025-12-16 18:40 ` Zi Yan
2025-12-20 14:34 ` kernel test robot
2025-12-16 11:48 ` [PATCH v4 6/6] mm: hugetlb: allocate frozen pages in alloc_gigantic_folio() Kefeng Wang
5 siblings, 2 replies; 33+ messages in thread
From: Kefeng Wang @ 2025-12-16 11:48 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Oscar Salvador, Muchun Song, linux-mm
Cc: sidhartha.kumar, jane.chu, Zi Yan, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand, Kefeng Wang
Introduce cma_alloc_frozen{_compound}() helper to alloc pages without
incrementing their refcount, then convert hugetlb cma to use the
cma_alloc_frozen_compound() and cma_release_frozen() and remove the
unused cma_{alloc,free}_folio(), also move the cma_validate_zones()
into mm/internal.h since no outside user.
The set_pages_refcounted() is only called to set non-compound pages
after above changes, so remove the processing about PageHead.
Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
---
include/linux/cma.h | 26 ++++++------------------
mm/cma.c | 48 +++++++++++++++++++++++++--------------------
mm/hugetlb_cma.c | 24 +++++++++++++----------
mm/internal.h | 10 +++++-----
4 files changed, 52 insertions(+), 56 deletions(-)
diff --git a/include/linux/cma.h b/include/linux/cma.h
index e5745d2aec55..e2a690f7e77e 100644
--- a/include/linux/cma.h
+++ b/include/linux/cma.h
@@ -51,29 +51,15 @@ extern struct page *cma_alloc(struct cma *cma, unsigned long count, unsigned int
bool no_warn);
extern bool cma_release(struct cma *cma, const struct page *pages, unsigned long count);
+struct page *cma_alloc_frozen(struct cma *cma, unsigned long count,
+ unsigned int align, bool no_warn);
+struct page *cma_alloc_frozen_compound(struct cma *cma, unsigned int order);
+bool cma_release_frozen(struct cma *cma, const struct page *pages,
+ unsigned long count);
+
extern int cma_for_each_area(int (*it)(struct cma *cma, void *data), void *data);
extern bool cma_intersects(struct cma *cma, unsigned long start, unsigned long end);
extern void cma_reserve_pages_on_error(struct cma *cma);
-#ifdef CONFIG_CMA
-struct folio *cma_alloc_folio(struct cma *cma, int order, gfp_t gfp);
-bool cma_free_folio(struct cma *cma, const struct folio *folio);
-bool cma_validate_zones(struct cma *cma);
-#else
-static inline struct folio *cma_alloc_folio(struct cma *cma, int order, gfp_t gfp)
-{
- return NULL;
-}
-
-static inline bool cma_free_folio(struct cma *cma, const struct folio *folio)
-{
- return false;
-}
-static inline bool cma_validate_zones(struct cma *cma)
-{
- return false;
-}
-#endif
-
#endif
diff --git a/mm/cma.c b/mm/cma.c
index 7f050cf24383..1aa1d821fbe9 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -856,8 +856,8 @@ static int cma_range_alloc(struct cma *cma, struct cma_memrange *cmr,
return ret;
}
-static struct page *__cma_alloc(struct cma *cma, unsigned long count,
- unsigned int align, gfp_t gfp)
+static struct page *__cma_alloc_frozen(struct cma *cma,
+ unsigned long count, unsigned int align, gfp_t gfp)
{
struct page *page = NULL;
int ret = -ENOMEM, r;
@@ -904,7 +904,6 @@ static struct page *__cma_alloc(struct cma *cma, unsigned long count,
trace_cma_alloc_finish(name, page ? page_to_pfn(page) : 0,
page, count, align, ret);
if (page) {
- set_pages_refcounted(page, count);
count_vm_event(CMA_ALLOC_SUCCESS);
cma_sysfs_account_success_pages(cma, count);
} else {
@@ -915,6 +914,21 @@ static struct page *__cma_alloc(struct cma *cma, unsigned long count,
return page;
}
+struct page *cma_alloc_frozen(struct cma *cma, unsigned long count,
+ unsigned int align, bool no_warn)
+{
+ gfp_t gfp = GFP_KERNEL | (no_warn ? __GFP_NOWARN : 0);
+
+ return __cma_alloc_frozen(cma, count, align, gfp);
+}
+
+struct page *cma_alloc_frozen_compound(struct cma *cma, unsigned int order)
+{
+ gfp_t gfp = GFP_KERNEL | __GFP_COMP | __GFP_NOWARN;
+
+ return __cma_alloc_frozen(cma, 1 << order, order, gfp);
+}
+
/**
* cma_alloc() - allocate pages from contiguous area
* @cma: Contiguous memory region for which the allocation is performed.
@@ -927,24 +941,18 @@ static struct page *__cma_alloc(struct cma *cma, unsigned long count,
*/
struct page *cma_alloc(struct cma *cma, unsigned long count,
unsigned int align, bool no_warn)
-{
- return __cma_alloc(cma, count, align, GFP_KERNEL | (no_warn ? __GFP_NOWARN : 0));
-}
-
-struct folio *cma_alloc_folio(struct cma *cma, int order, gfp_t gfp)
{
struct page *page;
- if (WARN_ON(!order || !(gfp & __GFP_COMP)))
- return NULL;
-
- page = __cma_alloc(cma, 1 << order, order, gfp);
+ page = cma_alloc_frozen(cma, count, align, no_warn);
+ if (page)
+ set_pages_refcounted(page, count);
- return page ? page_folio(page) : NULL;
+ return page;
}
static bool __cma_release(struct cma *cma, const struct page *pages,
- unsigned long count, bool compound)
+ unsigned long count, bool frozen)
{
unsigned long pfn, end;
int r;
@@ -974,8 +982,8 @@ static bool __cma_release(struct cma *cma, const struct page *pages,
return false;
}
- if (compound)
- __free_pages((struct page *)pages, compound_order(pages));
+ if (frozen)
+ free_contig_frozen_range(pfn, count);
else
free_contig_range(pfn, count);
@@ -1002,12 +1010,10 @@ bool cma_release(struct cma *cma, const struct page *pages,
return __cma_release(cma, pages, count, false);
}
-bool cma_free_folio(struct cma *cma, const struct folio *folio)
+bool cma_release_frozen(struct cma *cma, const struct page *pages,
+ unsigned long count)
{
- if (WARN_ON(!folio_test_large(folio)))
- return false;
-
- return __cma_release(cma, &folio->page, folio_nr_pages(folio), true);
+ return __cma_release(cma, pages, count, true);
}
int cma_for_each_area(int (*it)(struct cma *cma, void *data), void *data)
diff --git a/mm/hugetlb_cma.c b/mm/hugetlb_cma.c
index e8e4dc7182d5..0a57d3776c8d 100644
--- a/mm/hugetlb_cma.c
+++ b/mm/hugetlb_cma.c
@@ -20,35 +20,39 @@ static unsigned long hugetlb_cma_size __initdata;
void hugetlb_cma_free_folio(struct folio *folio)
{
- int nid = folio_nid(folio);
+ folio_ref_dec(folio);
- WARN_ON_ONCE(!cma_free_folio(hugetlb_cma[nid], folio));
+ WARN_ON_ONCE(!cma_release_frozen(hugetlb_cma[folio_nid(folio)],
+ &folio->page, folio_nr_pages(folio)));
}
-
struct folio *hugetlb_cma_alloc_folio(int order, gfp_t gfp_mask,
int nid, nodemask_t *nodemask)
{
int node;
- struct folio *folio = NULL;
+ struct folio *folio;
+ struct page *page = NULL;
if (hugetlb_cma[nid])
- folio = cma_alloc_folio(hugetlb_cma[nid], order, gfp_mask);
+ page = cma_alloc_frozen_compound(hugetlb_cma[nid], order);
- if (!folio && !(gfp_mask & __GFP_THISNODE)) {
+ if (!page && !(gfp_mask & __GFP_THISNODE)) {
for_each_node_mask(node, *nodemask) {
if (node == nid || !hugetlb_cma[node])
continue;
- folio = cma_alloc_folio(hugetlb_cma[node], order, gfp_mask);
- if (folio)
+ page = cma_alloc_frozen_compound(hugetlb_cma[nid], order);
+ if (page)
break;
}
}
- if (folio)
- folio_set_hugetlb_cma(folio);
+ if (!page)
+ return NULL;
+ set_page_refcounted(page);
+ folio = page_folio(page);
+ folio_set_hugetlb_cma(folio);
return folio;
}
diff --git a/mm/internal.h b/mm/internal.h
index 75f624236ff8..6a3258f5ce7e 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -517,11 +517,6 @@ static inline void set_pages_refcounted(struct page *page, unsigned long nr_page
{
unsigned long pfn = page_to_pfn(page);
- if (PageHead(page)) {
- set_page_refcounted(page);
- return;
- }
-
for (; nr_pages--; pfn++)
set_page_refcounted(pfn_to_page(pfn));
}
@@ -949,9 +944,14 @@ void init_cma_reserved_pageblock(struct page *page);
struct cma;
#ifdef CONFIG_CMA
+bool cma_validate_zones(struct cma *cma);
void *cma_reserve_early(struct cma *cma, unsigned long size);
void init_cma_pageblock(struct page *page);
#else
+static inline bool cma_validate_zones(struct cma *cma)
+{
+ return false;
+}
static inline void *cma_reserve_early(struct cma *cma, unsigned long size)
{
return NULL;
--
2.27.0
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v4 5/6] mm: cma: add cma_alloc_frozen{_compound}()
2025-12-16 11:48 ` [PATCH v4 5/6] mm: cma: add cma_alloc_frozen{_compound}() Kefeng Wang
@ 2025-12-16 18:40 ` Zi Yan
2025-12-17 8:02 ` Kefeng Wang
2025-12-20 14:34 ` kernel test robot
1 sibling, 1 reply; 33+ messages in thread
From: Zi Yan @ 2025-12-16 18:40 UTC (permalink / raw)
To: Kefeng Wang
Cc: Andrew Morton, David Hildenbrand, Oscar Salvador, Muchun Song,
linux-mm, sidhartha.kumar, jane.chu, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand
On 16 Dec 2025, at 6:48, Kefeng Wang wrote:
> Introduce cma_alloc_frozen{_compound}() helper to alloc pages without
> incrementing their refcount, then convert hugetlb cma to use the
> cma_alloc_frozen_compound() and cma_release_frozen() and remove the
> unused cma_{alloc,free}_folio(), also move the cma_validate_zones()
> into mm/internal.h since no outside user.
>
> The set_pages_refcounted() is only called to set non-compound pages
> after above changes, so remove the processing about PageHead.
>
> Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
> ---
> include/linux/cma.h | 26 ++++++------------------
> mm/cma.c | 48 +++++++++++++++++++++++++--------------------
> mm/hugetlb_cma.c | 24 +++++++++++++----------
> mm/internal.h | 10 +++++-----
> 4 files changed, 52 insertions(+), 56 deletions(-)
>
> diff --git a/include/linux/cma.h b/include/linux/cma.h
> index e5745d2aec55..e2a690f7e77e 100644
> --- a/include/linux/cma.h
> +++ b/include/linux/cma.h
> @@ -51,29 +51,15 @@ extern struct page *cma_alloc(struct cma *cma, unsigned long count, unsigned int
> bool no_warn);
> extern bool cma_release(struct cma *cma, const struct page *pages, unsigned long count);
>
> +struct page *cma_alloc_frozen(struct cma *cma, unsigned long count,
> + unsigned int align, bool no_warn);
> +struct page *cma_alloc_frozen_compound(struct cma *cma, unsigned int order);
> +bool cma_release_frozen(struct cma *cma, const struct page *pages,
> + unsigned long count);
> +
> extern int cma_for_each_area(int (*it)(struct cma *cma, void *data), void *data);
> extern bool cma_intersects(struct cma *cma, unsigned long start, unsigned long end);
>
> extern void cma_reserve_pages_on_error(struct cma *cma);
>
> -#ifdef CONFIG_CMA
> -struct folio *cma_alloc_folio(struct cma *cma, int order, gfp_t gfp);
> -bool cma_free_folio(struct cma *cma, const struct folio *folio);
> -bool cma_validate_zones(struct cma *cma);
> -#else
> -static inline struct folio *cma_alloc_folio(struct cma *cma, int order, gfp_t gfp)
> -{
> - return NULL;
> -}
> -
> -static inline bool cma_free_folio(struct cma *cma, const struct folio *folio)
> -{
> - return false;
> -}
> -static inline bool cma_validate_zones(struct cma *cma)
> -{
> - return false;
> -}
> -#endif
> -
> #endif
> diff --git a/mm/cma.c b/mm/cma.c
> index 7f050cf24383..1aa1d821fbe9 100644
> --- a/mm/cma.c
> +++ b/mm/cma.c
> @@ -856,8 +856,8 @@ static int cma_range_alloc(struct cma *cma, struct cma_memrange *cmr,
> return ret;
> }
>
> -static struct page *__cma_alloc(struct cma *cma, unsigned long count,
> - unsigned int align, gfp_t gfp)
> +static struct page *__cma_alloc_frozen(struct cma *cma,
> + unsigned long count, unsigned int align, gfp_t gfp)
> {
> struct page *page = NULL;
> int ret = -ENOMEM, r;
> @@ -904,7 +904,6 @@ static struct page *__cma_alloc(struct cma *cma, unsigned long count,
> trace_cma_alloc_finish(name, page ? page_to_pfn(page) : 0,
> page, count, align, ret);
> if (page) {
> - set_pages_refcounted(page, count);
> count_vm_event(CMA_ALLOC_SUCCESS);
> cma_sysfs_account_success_pages(cma, count);
> } else {
> @@ -915,6 +914,21 @@ static struct page *__cma_alloc(struct cma *cma, unsigned long count,
> return page;
> }
>
> +struct page *cma_alloc_frozen(struct cma *cma, unsigned long count,
> + unsigned int align, bool no_warn)
> +{
> + gfp_t gfp = GFP_KERNEL | (no_warn ? __GFP_NOWARN : 0);
> +
> + return __cma_alloc_frozen(cma, count, align, gfp);
> +}
> +
> +struct page *cma_alloc_frozen_compound(struct cma *cma, unsigned int order)
> +{
> + gfp_t gfp = GFP_KERNEL | __GFP_COMP | __GFP_NOWARN;
> +
> + return __cma_alloc_frozen(cma, 1 << order, order, gfp);
> +}
> +
> /**
> * cma_alloc() - allocate pages from contiguous area
> * @cma: Contiguous memory region for which the allocation is performed.
> @@ -927,24 +941,18 @@ static struct page *__cma_alloc(struct cma *cma, unsigned long count,
> */
> struct page *cma_alloc(struct cma *cma, unsigned long count,
> unsigned int align, bool no_warn)
> -{
> - return __cma_alloc(cma, count, align, GFP_KERNEL | (no_warn ? __GFP_NOWARN : 0));
> -}
> -
> -struct folio *cma_alloc_folio(struct cma *cma, int order, gfp_t gfp)
> {
> struct page *page;
>
> - if (WARN_ON(!order || !(gfp & __GFP_COMP)))
> - return NULL;
> -
> - page = __cma_alloc(cma, 1 << order, order, gfp);
> + page = cma_alloc_frozen(cma, count, align, no_warn);
> + if (page)
> + set_pages_refcounted(page, count);
>
> - return page ? page_folio(page) : NULL;
> + return page;
> }
>
> static bool __cma_release(struct cma *cma, const struct page *pages,
> - unsigned long count, bool compound)
> + unsigned long count, bool frozen)
> {
> unsigned long pfn, end;
> int r;
> @@ -974,8 +982,8 @@ static bool __cma_release(struct cma *cma, const struct page *pages,
> return false;
> }
>
> - if (compound)
> - __free_pages((struct page *)pages, compound_order(pages));
> + if (frozen)
> + free_contig_frozen_range(pfn, count);
> else
> free_contig_range(pfn, count);
Can we get rid of free_contig_range() branch by making cma_release() put
each page’s refcount? Then, __cma_relase() becomes cma_release_frozen()
and the release pattern matches allocation pattern:
1. cma_alloc() calls cma_alloc_frozen() and manipulates page refcount.
2. cma_release() manipulates page refcount and calls cma_release_frozen().
The rest of changes looks good to me.
Best Regards,
Yan, Zi
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v4 5/6] mm: cma: add cma_alloc_frozen{_compound}()
2025-12-16 18:40 ` Zi Yan
@ 2025-12-17 8:02 ` Kefeng Wang
2025-12-17 19:38 ` Zi Yan
0 siblings, 1 reply; 33+ messages in thread
From: Kefeng Wang @ 2025-12-17 8:02 UTC (permalink / raw)
To: Zi Yan
Cc: Andrew Morton, David Hildenbrand, Oscar Salvador, Muchun Song,
linux-mm, sidhartha.kumar, jane.chu, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand
On 2025/12/17 2:40, Zi Yan wrote:
> On 16 Dec 2025, at 6:48, Kefeng Wang wrote:
>
>> Introduce cma_alloc_frozen{_compound}() helper to alloc pages without
>> incrementing their refcount, then convert hugetlb cma to use the
>> cma_alloc_frozen_compound() and cma_release_frozen() and remove the
>> unused cma_{alloc,free}_folio(), also move the cma_validate_zones()
>> into mm/internal.h since no outside user.
>>
>> The set_pages_refcounted() is only called to set non-compound pages
>> after above changes, so remove the processing about PageHead.
>>
>> Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
>> ---
>> include/linux/cma.h | 26 ++++++------------------
>> mm/cma.c | 48 +++++++++++++++++++++++++--------------------
>> mm/hugetlb_cma.c | 24 +++++++++++++----------
>> mm/internal.h | 10 +++++-----
>> 4 files changed, 52 insertions(+), 56 deletions(-)
>>
...
>> static bool __cma_release(struct cma *cma, const struct page *pages,
>> - unsigned long count, bool compound)
>> + unsigned long count, bool frozen)
>> {
>> unsigned long pfn, end;
>> int r;
>> @@ -974,8 +982,8 @@ static bool __cma_release(struct cma *cma, const struct page *pages,
>> return false;
>> }
>>
>> - if (compound)
>> - __free_pages((struct page *)pages, compound_order(pages));
>> + if (frozen)
>> + free_contig_frozen_range(pfn, count);
>> else
>> free_contig_range(pfn, count);
>
> Can we get rid of free_contig_range() branch by making cma_release() put
> each page’s refcount? Then, __cma_relase() becomes cma_release_frozen()
> and the release pattern matches allocation pattern:
> 1. cma_alloc() calls cma_alloc_frozen() and manipulates page refcount.
> 2. cma_release() manipulates page refcount and calls cma_release_frozen().
>
Have considered similar things before, but we need manipulates page
refcount only find the correct cma memrange from cma/pages, it seems
that no big improvement, any more comments?
1) for cma_release:
a. cma find memrange
b. manipulates page refcount when cmr found
c. free page and release cma resource
2) for cma_release_frozen
a. cma find memrange
b. free page and release cma resource whne cmr found
> The rest of changes looks good to me.
Thanks.
>
> Best Regards,
> Yan, Zi
>
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v4 5/6] mm: cma: add cma_alloc_frozen{_compound}()
2025-12-17 8:02 ` Kefeng Wang
@ 2025-12-17 19:38 ` Zi Yan
2025-12-18 12:54 ` Kefeng Wang
0 siblings, 1 reply; 33+ messages in thread
From: Zi Yan @ 2025-12-17 19:38 UTC (permalink / raw)
To: Kefeng Wang
Cc: Andrew Morton, David Hildenbrand, Oscar Salvador, Muchun Song,
linux-mm, sidhartha.kumar, jane.chu, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand
On 17 Dec 2025, at 3:02, Kefeng Wang wrote:
> On 2025/12/17 2:40, Zi Yan wrote:
>> On 16 Dec 2025, at 6:48, Kefeng Wang wrote:
>>
>>> Introduce cma_alloc_frozen{_compound}() helper to alloc pages without
>>> incrementing their refcount, then convert hugetlb cma to use the
>>> cma_alloc_frozen_compound() and cma_release_frozen() and remove the
>>> unused cma_{alloc,free}_folio(), also move the cma_validate_zones()
>>> into mm/internal.h since no outside user.
>>>
>>> The set_pages_refcounted() is only called to set non-compound pages
>>> after above changes, so remove the processing about PageHead.
>>>
>>> Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
>>> ---
>>> include/linux/cma.h | 26 ++++++------------------
>>> mm/cma.c | 48 +++++++++++++++++++++++++--------------------
>>> mm/hugetlb_cma.c | 24 +++++++++++++----------
>>> mm/internal.h | 10 +++++-----
>>> 4 files changed, 52 insertions(+), 56 deletions(-)
>>>
>
> ...
>
>>> static bool __cma_release(struct cma *cma, const struct page *pages,
>>> - unsigned long count, bool compound)
>>> + unsigned long count, bool frozen)
>>> {
>>> unsigned long pfn, end;
>>> int r;
>>> @@ -974,8 +982,8 @@ static bool __cma_release(struct cma *cma, const struct page *pages,
>>> return false;
>>> }
>>>
>>> - if (compound)
>>> - __free_pages((struct page *)pages, compound_order(pages));
>>> + if (frozen)
>>> + free_contig_frozen_range(pfn, count);
>>> else
>>> free_contig_range(pfn, count);
>>
>> Can we get rid of free_contig_range() branch by making cma_release() put
>> each page’s refcount? Then, __cma_relase() becomes cma_release_frozen()
>> and the release pattern matches allocation pattern:
>> 1. cma_alloc() calls cma_alloc_frozen() and manipulates page refcount.
>> 2. cma_release() manipulates page refcount and calls cma_release_frozen().
>>
>
> Have considered similar things before, but we need manipulates page
> refcount only find the correct cma memrange from cma/pages, it seems
> that no big improvement, any more comments?
>
> 1) for cma_release:
> a. cma find memrange
> b. manipulates page refcount when cmr found
> c. free page and release cma resource
> 2) for cma_release_frozen
> a. cma find memrange
> b. free page and release cma resource whne cmr found
Right, I think it makes code simpler.
Basically add a helper function:
struct cma_memrange* find_cma_memrange(struct cma *cma,
const struct page *pages, unsigned long count);
Then
__cma_release_frozen()
{
free_contig_frozen_range(pfn, count);
cma_clear_bitmap(cma, cmr, pfn, count);
cma_sysfs_account_release_pages(cma, count);
trace_cma_release(cma->name, pfn, pages, count);
}
cma_release()
{
cmr = find_cma_memrange();
if (!cmr)
return false;
for (; count--; pages++)
VM_WARN_ON(!put_page_testzero(pages);
__cma_release_frozen();
}
cma_release_frozen()
{
cmr = find_cma_memrange();
if (!cmr)
return false;
__cma_release_frozen();
}
Let me know your thoughts.
Best Regards,
Yan, Zi
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v4 5/6] mm: cma: add cma_alloc_frozen{_compound}()
2025-12-17 19:38 ` Zi Yan
@ 2025-12-18 12:54 ` Kefeng Wang
2025-12-18 15:52 ` Zi Yan
0 siblings, 1 reply; 33+ messages in thread
From: Kefeng Wang @ 2025-12-18 12:54 UTC (permalink / raw)
To: Zi Yan
Cc: Andrew Morton, David Hildenbrand, Oscar Salvador, Muchun Song,
linux-mm, sidhartha.kumar, jane.chu, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand
On 2025/12/18 3:38, Zi Yan wrote:
> On 17 Dec 2025, at 3:02, Kefeng Wang wrote:
>
>> On 2025/12/17 2:40, Zi Yan wrote:
>>> On 16 Dec 2025, at 6:48, Kefeng Wang wrote:
>>>
>>>> Introduce cma_alloc_frozen{_compound}() helper to alloc pages without
>>>> incrementing their refcount, then convert hugetlb cma to use the
>>>> cma_alloc_frozen_compound() and cma_release_frozen() and remove the
>>>> unused cma_{alloc,free}_folio(), also move the cma_validate_zones()
>>>> into mm/internal.h since no outside user.
>>>>
>>>> The set_pages_refcounted() is only called to set non-compound pages
>>>> after above changes, so remove the processing about PageHead.
>>>>
>>>> Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
>>>> ---
>>>> include/linux/cma.h | 26 ++++++------------------
>>>> mm/cma.c | 48 +++++++++++++++++++++++++--------------------
>>>> mm/hugetlb_cma.c | 24 +++++++++++++----------
>>>> mm/internal.h | 10 +++++-----
>>>> 4 files changed, 52 insertions(+), 56 deletions(-)
>>>>
>>
>> ...
>>
>>>> static bool __cma_release(struct cma *cma, const struct page *pages,
>>>> - unsigned long count, bool compound)
>>>> + unsigned long count, bool frozen)
>>>> {
>>>> unsigned long pfn, end;
>>>> int r;
>>>> @@ -974,8 +982,8 @@ static bool __cma_release(struct cma *cma, const struct page *pages,
>>>> return false;
>>>> }
>>>>
>>>> - if (compound)
>>>> - __free_pages((struct page *)pages, compound_order(pages));
>>>> + if (frozen)
>>>> + free_contig_frozen_range(pfn, count);
>>>> else
>>>> free_contig_range(pfn, count);
>>>
>>> Can we get rid of free_contig_range() branch by making cma_release() put
>>> each page’s refcount? Then, __cma_relase() becomes cma_release_frozen()
>>> and the release pattern matches allocation pattern:
>>> 1. cma_alloc() calls cma_alloc_frozen() and manipulates page refcount.
>>> 2. cma_release() manipulates page refcount and calls cma_release_frozen().
>>>
>>
>> Have considered similar things before, but we need manipulates page
>> refcount only find the correct cma memrange from cma/pages, it seems
>> that no big improvement, any more comments?
>>
>> 1) for cma_release:
>> a. cma find memrange
>> b. manipulates page refcount when cmr found
>> c. free page and release cma resource
>> 2) for cma_release_frozen
>> a. cma find memrange
>> b. free page and release cma resource whne cmr found
>
> Right, I think it makes code simpler.
>
> Basically add a helper function:
> struct cma_memrange* find_cma_memrange(struct cma *cma,
> const struct page *pages, unsigned long count);
>
> Then
>
> __cma_release_frozen()
> {
> free_contig_frozen_range(pfn, count);
> cma_clear_bitmap(cma, cmr, pfn, count);
> cma_sysfs_account_release_pages(cma, count);
> trace_cma_release(cma->name, pfn, pages, count);
> }
>
>
> cma_release()
> {
> cmr = find_cma_memrange();
>
> if (!cmr)
> return false;
>
> for (; count--; pages++)
> VM_WARN_ON(!put_page_testzero(pages);
>
> __cma_release_frozen();
> }
>
> cma_release_frozen()
> {
> cmr = find_cma_memrange();
>
> if (!cmr)
> return false;
>
> __cma_release_frozen();
>
> }
>
> Let me know your thoughts.
Yes, this is exactly what I described above that needs to be done, but I
think it will add more codes :)
Our goal is that convert all cma_{alloc,release} caller to
cma_frozen_{alloc,release}, and complete remove free_contig_range in
cma, Maybe no changes? But if you prefer above way, I can also update
it.
Thanks
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v4 5/6] mm: cma: add cma_alloc_frozen{_compound}()
2025-12-18 12:54 ` Kefeng Wang
@ 2025-12-18 15:52 ` Zi Yan
2025-12-19 4:09 ` Kefeng Wang
0 siblings, 1 reply; 33+ messages in thread
From: Zi Yan @ 2025-12-18 15:52 UTC (permalink / raw)
To: Kefeng Wang
Cc: Andrew Morton, David Hildenbrand, Oscar Salvador, Muchun Song,
linux-mm, sidhartha.kumar, jane.chu, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand
On 18 Dec 2025, at 7:54, Kefeng Wang wrote:
> On 2025/12/18 3:38, Zi Yan wrote:
>> On 17 Dec 2025, at 3:02, Kefeng Wang wrote:
>>
>>> On 2025/12/17 2:40, Zi Yan wrote:
>>>> On 16 Dec 2025, at 6:48, Kefeng Wang wrote:
>>>>
>>>>> Introduce cma_alloc_frozen{_compound}() helper to alloc pages without
>>>>> incrementing their refcount, then convert hugetlb cma to use the
>>>>> cma_alloc_frozen_compound() and cma_release_frozen() and remove the
>>>>> unused cma_{alloc,free}_folio(), also move the cma_validate_zones()
>>>>> into mm/internal.h since no outside user.
>>>>>
>>>>> The set_pages_refcounted() is only called to set non-compound pages
>>>>> after above changes, so remove the processing about PageHead.
>>>>>
>>>>> Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
>>>>> ---
>>>>> include/linux/cma.h | 26 ++++++------------------
>>>>> mm/cma.c | 48 +++++++++++++++++++++++++--------------------
>>>>> mm/hugetlb_cma.c | 24 +++++++++++++----------
>>>>> mm/internal.h | 10 +++++-----
>>>>> 4 files changed, 52 insertions(+), 56 deletions(-)
>>>>>
>>>
>>> ...
>>>
>>>>> static bool __cma_release(struct cma *cma, const struct page *pages,
>>>>> - unsigned long count, bool compound)
>>>>> + unsigned long count, bool frozen)
>>>>> {
>>>>> unsigned long pfn, end;
>>>>> int r;
>>>>> @@ -974,8 +982,8 @@ static bool __cma_release(struct cma *cma, const struct page *pages,
>>>>> return false;
>>>>> }
>>>>>
>>>>> - if (compound)
>>>>> - __free_pages((struct page *)pages, compound_order(pages));
>>>>> + if (frozen)
>>>>> + free_contig_frozen_range(pfn, count);
>>>>> else
>>>>> free_contig_range(pfn, count);
>>>>
>>>> Can we get rid of free_contig_range() branch by making cma_release() put
>>>> each page’s refcount? Then, __cma_relase() becomes cma_release_frozen()
>>>> and the release pattern matches allocation pattern:
>>>> 1. cma_alloc() calls cma_alloc_frozen() and manipulates page refcount.
>>>> 2. cma_release() manipulates page refcount and calls cma_release_frozen().
>>>>
>>>
>>> Have considered similar things before, but we need manipulates page
>>> refcount only find the correct cma memrange from cma/pages, it seems
>>> that no big improvement, any more comments?
>>>
>>> 1) for cma_release:
>>> a. cma find memrange
>>> b. manipulates page refcount when cmr found
>>> c. free page and release cma resource
>>> 2) for cma_release_frozen
>>> a. cma find memrange
>>> b. free page and release cma resource whne cmr found
>>
>> Right, I think it makes code simpler.
>>
>> Basically add a helper function:
>> struct cma_memrange* find_cma_memrange(struct cma *cma,
>> const struct page *pages, unsigned long count);
>>
>> Then
>>
>> __cma_release_frozen()
>> {
>> free_contig_frozen_range(pfn, count);
>> cma_clear_bitmap(cma, cmr, pfn, count);
>> cma_sysfs_account_release_pages(cma, count);
>> trace_cma_release(cma->name, pfn, pages, count);
>> }
>>
>>
>> cma_release()
>> {
>> cmr = find_cma_memrange();
>>
>> if (!cmr)
>> return false;
>>
>> for (; count--; pages++)
>> VM_WARN_ON(!put_page_testzero(pages);
>>
>> __cma_release_frozen();
>> }
>>
>> cma_release_frozen()
>> {
>> cmr = find_cma_memrange();
>>
>> if (!cmr)
>> return false;
>>
>> __cma_release_frozen();
>>
>> }
>>
>> Let me know your thoughts.
>
> Yes, this is exactly what I described above that needs to be done, but I
> think it will add more codes :)
>
> Our goal is that convert all cma_{alloc,release} caller to
> cma_frozen_{alloc,release}, and complete remove free_contig_range in cma, Maybe no changes? But if you prefer above way, I can also update
> it.
If the goal is to replace all cma_{alloc,release}() calls with the frozen version,
there is no need to make the change as I suggested. Are you planning to send
another patchset to do the replacement after this one?
Best Regards,
Yan, Zi
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v4 5/6] mm: cma: add cma_alloc_frozen{_compound}()
2025-12-18 15:52 ` Zi Yan
@ 2025-12-19 4:09 ` Kefeng Wang
2025-12-22 2:30 ` Zi Yan
0 siblings, 1 reply; 33+ messages in thread
From: Kefeng Wang @ 2025-12-19 4:09 UTC (permalink / raw)
To: Zi Yan
Cc: Andrew Morton, David Hildenbrand, Oscar Salvador, Muchun Song,
linux-mm, sidhartha.kumar, jane.chu, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand
On 2025/12/18 23:52, Zi Yan wrote:
> On 18 Dec 2025, at 7:54, Kefeng Wang wrote:
>
>> On 2025/12/18 3:38, Zi Yan wrote:
>>> On 17 Dec 2025, at 3:02, Kefeng Wang wrote:
>>>
>>>> On 2025/12/17 2:40, Zi Yan wrote:
>>>>> On 16 Dec 2025, at 6:48, Kefeng Wang wrote:
>>>>>
>>>>>> Introduce cma_alloc_frozen{_compound}() helper to alloc pages without
>>>>>> incrementing their refcount, then convert hugetlb cma to use the
>>>>>> cma_alloc_frozen_compound() and cma_release_frozen() and remove the
>>>>>> unused cma_{alloc,free}_folio(), also move the cma_validate_zones()
>>>>>> into mm/internal.h since no outside user.
>>>>>>
>>>>>> The set_pages_refcounted() is only called to set non-compound pages
>>>>>> after above changes, so remove the processing about PageHead.
>>>>>>
>>>>>> Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
>>>>>> ---
>>>>>> include/linux/cma.h | 26 ++++++------------------
>>>>>> mm/cma.c | 48 +++++++++++++++++++++++++--------------------
>>>>>> mm/hugetlb_cma.c | 24 +++++++++++++----------
>>>>>> mm/internal.h | 10 +++++-----
>>>>>> 4 files changed, 52 insertions(+), 56 deletions(-)
>>>>>>
>>>>
>>>> ...
>>>>
>>>>>> static bool __cma_release(struct cma *cma, const struct page *pages,
>>>>>> - unsigned long count, bool compound)
>>>>>> + unsigned long count, bool frozen)
>>>>>> {
>>>>>> unsigned long pfn, end;
>>>>>> int r;
>>>>>> @@ -974,8 +982,8 @@ static bool __cma_release(struct cma *cma, const struct page *pages,
>>>>>> return false;
>>>>>> }
>>>>>>
>>>>>> - if (compound)
>>>>>> - __free_pages((struct page *)pages, compound_order(pages));
>>>>>> + if (frozen)
>>>>>> + free_contig_frozen_range(pfn, count);
>>>>>> else
>>>>>> free_contig_range(pfn, count);
>>>>>
>>>>> Can we get rid of free_contig_range() branch by making cma_release() put
>>>>> each page’s refcount? Then, __cma_relase() becomes cma_release_frozen()
>>>>> and the release pattern matches allocation pattern:
>>>>> 1. cma_alloc() calls cma_alloc_frozen() and manipulates page refcount.
>>>>> 2. cma_release() manipulates page refcount and calls cma_release_frozen().
>>>>>
>>>>
>>>> Have considered similar things before, but we need manipulates page
>>>> refcount only find the correct cma memrange from cma/pages, it seems
>>>> that no big improvement, any more comments?
>>>>
>>>> 1) for cma_release:
>>>> a. cma find memrange
>>>> b. manipulates page refcount when cmr found
>>>> c. free page and release cma resource
>>>> 2) for cma_release_frozen
>>>> a. cma find memrange
>>>> b. free page and release cma resource whne cmr found
>>>
>>> Right, I think it makes code simpler.
>>>
>>> Basically add a helper function:
>>> struct cma_memrange* find_cma_memrange(struct cma *cma,
>>> const struct page *pages, unsigned long count);
>>>
>>> Then
>>>
>>> __cma_release_frozen()
>>> {
>>> free_contig_frozen_range(pfn, count);
>>> cma_clear_bitmap(cma, cmr, pfn, count);
>>> cma_sysfs_account_release_pages(cma, count);
>>> trace_cma_release(cma->name, pfn, pages, count);
>>> }
>>>
>>>
>>> cma_release()
>>> {
>>> cmr = find_cma_memrange();
>>>
>>> if (!cmr)
>>> return false;
>>>
>>> for (; count--; pages++)
>>> VM_WARN_ON(!put_page_testzero(pages);
>>>
>>> __cma_release_frozen();
>>> }
>>>
>>> cma_release_frozen()
>>> {
>>> cmr = find_cma_memrange();
>>>
>>> if (!cmr)
>>> return false;
>>>
>>> __cma_release_frozen();
>>>
>>> }
>>>
>>> Let me know your thoughts.
>>
>> Yes, this is exactly what I described above that needs to be done, but I
>> think it will add more codes :)
>>
>> Our goal is that convert all cma_{alloc,release} caller to
>> cma_frozen_{alloc,release}, and complete remove free_contig_range in cma, Maybe no changes? But if you prefer above way, I can also update
>> it.
>
> If the goal is to replace all cma_{alloc,release}() calls with the frozen version,
> there is no need to make the change as I suggested. Are you planning to send
> another patchset to do the replacement after this one?
There are few callers, the following can be straightforwardly converted
to a frozen version.
mm/cma_debug.c
drivers/dma-buf/heaps/cma_heap.c
drivers/s390/char/vmcp.c
arch/powerpc/kvm/book3s_hv_builtin.c
For the DMA part, we suppose there is no driver using the page refcount,
as too many drivers are involved, maybe there is a very special usage in
the driver,I can't be sure.
kernel/dma/contiguous.c
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v4 5/6] mm: cma: add cma_alloc_frozen{_compound}()
2025-12-19 4:09 ` Kefeng Wang
@ 2025-12-22 2:30 ` Zi Yan
2025-12-22 13:03 ` Kefeng Wang
0 siblings, 1 reply; 33+ messages in thread
From: Zi Yan @ 2025-12-22 2:30 UTC (permalink / raw)
To: Kefeng Wang
Cc: Andrew Morton, David Hildenbrand, Oscar Salvador, Muchun Song,
linux-mm, sidhartha.kumar, jane.chu, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand
On 18 Dec 2025, at 23:09, Kefeng Wang wrote:
> On 2025/12/18 23:52, Zi Yan wrote:
>> On 18 Dec 2025, at 7:54, Kefeng Wang wrote:
>>
>>> On 2025/12/18 3:38, Zi Yan wrote:
>>>> On 17 Dec 2025, at 3:02, Kefeng Wang wrote:
>>>>
>>>>> On 2025/12/17 2:40, Zi Yan wrote:
>>>>>> On 16 Dec 2025, at 6:48, Kefeng Wang wrote:
>>>>>>
>>>>>>> Introduce cma_alloc_frozen{_compound}() helper to alloc pages without
>>>>>>> incrementing their refcount, then convert hugetlb cma to use the
>>>>>>> cma_alloc_frozen_compound() and cma_release_frozen() and remove the
>>>>>>> unused cma_{alloc,free}_folio(), also move the cma_validate_zones()
>>>>>>> into mm/internal.h since no outside user.
>>>>>>>
>>>>>>> The set_pages_refcounted() is only called to set non-compound pages
>>>>>>> after above changes, so remove the processing about PageHead.
>>>>>>>
>>>>>>> Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
>>>>>>> ---
>>>>>>> include/linux/cma.h | 26 ++++++------------------
>>>>>>> mm/cma.c | 48 +++++++++++++++++++++++++--------------------
>>>>>>> mm/hugetlb_cma.c | 24 +++++++++++++----------
>>>>>>> mm/internal.h | 10 +++++-----
>>>>>>> 4 files changed, 52 insertions(+), 56 deletions(-)
>>>>>>>
>>>>>
>>>>> ...
>>>>>
>>>>>>> static bool __cma_release(struct cma *cma, const struct page *pages,
>>>>>>> - unsigned long count, bool compound)
>>>>>>> + unsigned long count, bool frozen)
>>>>>>> {
>>>>>>> unsigned long pfn, end;
>>>>>>> int r;
>>>>>>> @@ -974,8 +982,8 @@ static bool __cma_release(struct cma *cma, const struct page *pages,
>>>>>>> return false;
>>>>>>> }
>>>>>>>
>>>>>>> - if (compound)
>>>>>>> - __free_pages((struct page *)pages, compound_order(pages));
>>>>>>> + if (frozen)
>>>>>>> + free_contig_frozen_range(pfn, count);
>>>>>>> else
>>>>>>> free_contig_range(pfn, count);
>>>>>>
>>>>>> Can we get rid of free_contig_range() branch by making cma_release() put
>>>>>> each page’s refcount? Then, __cma_relase() becomes cma_release_frozen()
>>>>>> and the release pattern matches allocation pattern:
>>>>>> 1. cma_alloc() calls cma_alloc_frozen() and manipulates page refcount.
>>>>>> 2. cma_release() manipulates page refcount and calls cma_release_frozen().
>>>>>>
>>>>>
>>>>> Have considered similar things before, but we need manipulates page
>>>>> refcount only find the correct cma memrange from cma/pages, it seems
>>>>> that no big improvement, any more comments?
>>>>>
>>>>> 1) for cma_release:
>>>>> a. cma find memrange
>>>>> b. manipulates page refcount when cmr found
>>>>> c. free page and release cma resource
>>>>> 2) for cma_release_frozen
>>>>> a. cma find memrange
>>>>> b. free page and release cma resource whne cmr found
>>>>
>>>> Right, I think it makes code simpler.
>>>>
>>>> Basically add a helper function:
>>>> struct cma_memrange* find_cma_memrange(struct cma *cma,
>>>> const struct page *pages, unsigned long count);
>>>>
>>>> Then
>>>>
>>>> __cma_release_frozen()
>>>> {
>>>> free_contig_frozen_range(pfn, count);
>>>> cma_clear_bitmap(cma, cmr, pfn, count);
>>>> cma_sysfs_account_release_pages(cma, count);
>>>> trace_cma_release(cma->name, pfn, pages, count);
>>>> }
>>>>
>>>>
>>>> cma_release()
>>>> {
>>>> cmr = find_cma_memrange();
>>>>
>>>> if (!cmr)
>>>> return false;
>>>>
>>>> for (; count--; pages++)
>>>> VM_WARN_ON(!put_page_testzero(pages);
>>>>
>>>> __cma_release_frozen();
>>>> }
>>>>
>>>> cma_release_frozen()
>>>> {
>>>> cmr = find_cma_memrange();
>>>>
>>>> if (!cmr)
>>>> return false;
>>>>
>>>> __cma_release_frozen();
>>>>
>>>> }
>>>>
>>>> Let me know your thoughts.
>>>
>>> Yes, this is exactly what I described above that needs to be done, but I
>>> think it will add more codes :)
>>>
>>> Our goal is that convert all cma_{alloc,release} caller to
>>> cma_frozen_{alloc,release}, and complete remove free_contig_range in cma, Maybe no changes? But if you prefer above way, I can also update
>>> it.
>>
>> If the goal is to replace all cma_{alloc,release}() calls with the frozen version,
>> there is no need to make the change as I suggested. Are you planning to send
>> another patchset to do the replacement after this one?
>
> There are few callers, the following can be straightforwardly converted
> to a frozen version.
>
> mm/cma_debug.c
> drivers/dma-buf/heaps/cma_heap.c
> drivers/s390/char/vmcp.c
> arch/powerpc/kvm/book3s_hv_builtin.c
>
> For the DMA part, we suppose there is no driver using the page refcount, as too many drivers are involved, maybe there is a very special usage in the driver,I can't be sure.
>
> kernel/dma/contiguous.c
Even if drivers are not using page refcount, these allocated cma pages should
be still have a elevated refcount to indicate they are in use, right? So
cma_alloc() and cma_release() can be converted to frozen + refcount manipulation,
right? I am not sure letting drivers use froze pages directly is the right move.
Frozen pages should only be changed by the one freezes the pages and no one else
should touch it.
Best Regards,
Yan, Zi
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v4 5/6] mm: cma: add cma_alloc_frozen{_compound}()
2025-12-22 2:30 ` Zi Yan
@ 2025-12-22 13:03 ` Kefeng Wang
0 siblings, 0 replies; 33+ messages in thread
From: Kefeng Wang @ 2025-12-22 13:03 UTC (permalink / raw)
To: Zi Yan
Cc: Andrew Morton, David Hildenbrand, Oscar Salvador, Muchun Song,
linux-mm, sidhartha.kumar, jane.chu, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand
On 2025/12/22 10:30, Zi Yan wrote:
> On 18 Dec 2025, at 23:09, Kefeng Wang wrote:
>
>> On 2025/12/18 23:52, Zi Yan wrote:
>>> On 18 Dec 2025, at 7:54, Kefeng Wang wrote:
>>>
>>>> On 2025/12/18 3:38, Zi Yan wrote:
>>>>> On 17 Dec 2025, at 3:02, Kefeng Wang wrote:
>>>>>
>>>>>> On 2025/12/17 2:40, Zi Yan wrote:
>>>>>>> On 16 Dec 2025, at 6:48, Kefeng Wang wrote:
>>>>>>>
>>>>>>>> Introduce cma_alloc_frozen{_compound}() helper to alloc pages without
>>>>>>>> incrementing their refcount, then convert hugetlb cma to use the
>>>>>>>> cma_alloc_frozen_compound() and cma_release_frozen() and remove the
>>>>>>>> unused cma_{alloc,free}_folio(), also move the cma_validate_zones()
>>>>>>>> into mm/internal.h since no outside user.
>>>>>>>>
>>>>>>>> The set_pages_refcounted() is only called to set non-compound pages
>>>>>>>> after above changes, so remove the processing about PageHead.
>>>>>>>>
>>>>>>>> Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
>>>>>>>> ---
>>>>>>>> include/linux/cma.h | 26 ++++++------------------
>>>>>>>> mm/cma.c | 48 +++++++++++++++++++++++++--------------------
>>>>>>>> mm/hugetlb_cma.c | 24 +++++++++++++----------
>>>>>>>> mm/internal.h | 10 +++++-----
>>>>>>>> 4 files changed, 52 insertions(+), 56 deletions(-)
>>>>>>>>
>>>>>>
>>>>>> ...
>>>>>>
>>>>>>>> static bool __cma_release(struct cma *cma, const struct page *pages,
>>>>>>>> - unsigned long count, bool compound)
>>>>>>>> + unsigned long count, bool frozen)
>>>>>>>> {
>>>>>>>> unsigned long pfn, end;
>>>>>>>> int r;
>>>>>>>> @@ -974,8 +982,8 @@ static bool __cma_release(struct cma *cma, const struct page *pages,
>>>>>>>> return false;
>>>>>>>> }
>>>>>>>>
>>>>>>>> - if (compound)
>>>>>>>> - __free_pages((struct page *)pages, compound_order(pages));
>>>>>>>> + if (frozen)
>>>>>>>> + free_contig_frozen_range(pfn, count);
>>>>>>>> else
>>>>>>>> free_contig_range(pfn, count);
>>>>>>>
>>>>>>> Can we get rid of free_contig_range() branch by making cma_release() put
>>>>>>> each page’s refcount? Then, __cma_relase() becomes cma_release_frozen()
>>>>>>> and the release pattern matches allocation pattern:
>>>>>>> 1. cma_alloc() calls cma_alloc_frozen() and manipulates page refcount.
>>>>>>> 2. cma_release() manipulates page refcount and calls cma_release_frozen().
>>>>>>>
>>>>>>
>>>>>> Have considered similar things before, but we need manipulates page
>>>>>> refcount only find the correct cma memrange from cma/pages, it seems
>>>>>> that no big improvement, any more comments?
>>>>>>
>>>>>> 1) for cma_release:
>>>>>> a. cma find memrange
>>>>>> b. manipulates page refcount when cmr found
>>>>>> c. free page and release cma resource
>>>>>> 2) for cma_release_frozen
>>>>>> a. cma find memrange
>>>>>> b. free page and release cma resource whne cmr found
>>>>>
>>>>> Right, I think it makes code simpler.
>>>>>
>>>>> Basically add a helper function:
>>>>> struct cma_memrange* find_cma_memrange(struct cma *cma,
>>>>> const struct page *pages, unsigned long count);
>>>>>
>>>>> Then
>>>>>
>>>>> __cma_release_frozen()
>>>>> {
>>>>> free_contig_frozen_range(pfn, count);
>>>>> cma_clear_bitmap(cma, cmr, pfn, count);
>>>>> cma_sysfs_account_release_pages(cma, count);
>>>>> trace_cma_release(cma->name, pfn, pages, count);
>>>>> }
>>>>>
>>>>>
>>>>> cma_release()
>>>>> {
>>>>> cmr = find_cma_memrange();
>>>>>
>>>>> if (!cmr)
>>>>> return false;
>>>>>
>>>>> for (; count--; pages++)
>>>>> VM_WARN_ON(!put_page_testzero(pages);
>>>>>
>>>>> __cma_release_frozen();
>>>>> }
>>>>>
>>>>> cma_release_frozen()
>>>>> {
>>>>> cmr = find_cma_memrange();
>>>>>
>>>>> if (!cmr)
>>>>> return false;
>>>>>
>>>>> __cma_release_frozen();
>>>>>
>>>>> }
>>>>>
>>>>> Let me know your thoughts.
>>>>
>>>> Yes, this is exactly what I described above that needs to be done, but I
>>>> think it will add more codes :)
>>>>
>>>> Our goal is that convert all cma_{alloc,release} caller to
>>>> cma_frozen_{alloc,release}, and complete remove free_contig_range in cma, Maybe no changes? But if you prefer above way, I can also update
>>>> it.
>>>
>>> If the goal is to replace all cma_{alloc,release}() calls with the frozen version,
>>> there is no need to make the change as I suggested. Are you planning to send
>>> another patchset to do the replacement after this one?
>>
>> There are few callers, the following can be straightforwardly converted
>> to a frozen version.
>>
>> mm/cma_debug.c
>> drivers/dma-buf/heaps/cma_heap.c
>> drivers/s390/char/vmcp.c
>> arch/powerpc/kvm/book3s_hv_builtin.c
>>
>> For the DMA part, we suppose there is no driver using the page refcount, as too many drivers are involved, maybe there is a very special usage in the driver,I can't be sure.
>>
>> kernel/dma/contiguous.c
>
> Even if drivers are not using page refcount, these allocated cma pages should
> be still have a elevated refcount to indicate they are in use, right? So
> cma_alloc() and cma_release() can be converted to frozen + refcount manipulation,
> right? I am not sure letting drivers use froze pages directly is the right move.
OK. I previously simply believed there might be an opportunity, but it
seems it might not be that straightforward.
> Frozen pages should only be changed by the one freezes the pages and no one else
> should touch it.
Anyway,thank for sharing your points, I will change cma_release()
according to your suggestion in next version.
Thanks.
>
> Best Regards,
> Yan, Zi
>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v4 5/6] mm: cma: add cma_alloc_frozen{_compound}()
2025-12-16 11:48 ` [PATCH v4 5/6] mm: cma: add cma_alloc_frozen{_compound}() Kefeng Wang
2025-12-16 18:40 ` Zi Yan
@ 2025-12-20 14:34 ` kernel test robot
2025-12-22 1:46 ` Kefeng Wang
1 sibling, 1 reply; 33+ messages in thread
From: kernel test robot @ 2025-12-20 14:34 UTC (permalink / raw)
To: Kefeng Wang, Andrew Morton, David Hildenbrand, Oscar Salvador,
Muchun Song
Cc: oe-kbuild-all, Linux Memory Management List, sidhartha.kumar,
jane.chu, Zi Yan, Vlastimil Babka, Brendan Jackman,
Johannes Weiner, Matthew Wilcox, Kefeng Wang
Hi Kefeng,
kernel test robot noticed the following build warnings:
[auto build test WARNING on akpm-mm/mm-everything]
url: https://github.com/intel-lab-lkp/linux/commits/Kefeng-Wang/mm-debug_vm_pgtable-add-debug_vm_pgtable_free_huge_page/20251216-195027
base: https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything
patch link: https://lore.kernel.org/r/20251216114844.2126250-6-wangkefeng.wang%40huawei.com
patch subject: [PATCH v4 5/6] mm: cma: add cma_alloc_frozen{_compound}()
config: s390-randconfig-r053-20251218 (https://download.01.org/0day-ci/archive/20251220/202512202141.mGkUgIRF-lkp@intel.com/config)
compiler: s390-linux-gcc (GCC) 8.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251220/202512202141.mGkUgIRF-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512202141.mGkUgIRF-lkp@intel.com/
All warnings (new ones prefixed by >>):
mm/hugetlb_cma.c: In function 'hugetlb_cma_alloc_folio':
>> mm/hugetlb_cma.c:44:11: warning: array subscript [0, 0] is outside array bounds of 'struct cma *[1]' [-Warray-bounds]
page = cma_alloc_frozen_compound(hugetlb_cma[nid], order);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Kconfig warnings: (for reference only)
WARNING: unmet direct dependencies detected for CAN_DEV
Depends on [n]: NETDEVICES [=n] && CAN [=m]
Selected by [m]:
- CAN [=m] && NET [=y]
vim +44 mm/hugetlb_cma.c
28
29 struct folio *hugetlb_cma_alloc_folio(int order, gfp_t gfp_mask,
30 int nid, nodemask_t *nodemask)
31 {
32 int node;
33 struct folio *folio;
34 struct page *page = NULL;
35
36 if (hugetlb_cma[nid])
37 page = cma_alloc_frozen_compound(hugetlb_cma[nid], order);
38
39 if (!page && !(gfp_mask & __GFP_THISNODE)) {
40 for_each_node_mask(node, *nodemask) {
41 if (node == nid || !hugetlb_cma[node])
42 continue;
43
> 44 page = cma_alloc_frozen_compound(hugetlb_cma[nid], order);
45 if (page)
46 break;
47 }
48 }
49
50 if (!page)
51 return NULL;
52
53 set_page_refcounted(page);
54 folio = page_folio(page);
55 folio_set_hugetlb_cma(folio);
56 return folio;
57 }
58
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v4 5/6] mm: cma: add cma_alloc_frozen{_compound}()
2025-12-20 14:34 ` kernel test robot
@ 2025-12-22 1:46 ` Kefeng Wang
0 siblings, 0 replies; 33+ messages in thread
From: Kefeng Wang @ 2025-12-22 1:46 UTC (permalink / raw)
To: kernel test robot, Andrew Morton, David Hildenbrand,
Oscar Salvador, Muchun Song
Cc: oe-kbuild-all, Linux Memory Management List, sidhartha.kumar,
jane.chu, Zi Yan, Vlastimil Babka, Brendan Jackman,
Johannes Weiner, Matthew Wilcox
On 2025/12/20 22:34, kernel test robot wrote:
> Hi Kefeng,
>
> kernel test robot noticed the following build warnings:
>
> [auto build test WARNING on akpm-mm/mm-everything]
>
> url: https://github.com/intel-lab-lkp/linux/commits/Kefeng-Wang/mm-debug_vm_pgtable-add-debug_vm_pgtable_free_huge_page/20251216-195027
> base: https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything
> patch link: https://lore.kernel.org/r/20251216114844.2126250-6-wangkefeng.wang%40huawei.com
> patch subject: [PATCH v4 5/6] mm: cma: add cma_alloc_frozen{_compound}()
> config: s390-randconfig-r053-20251218 (https://download.01.org/0day-ci/archive/20251220/202512202141.mGkUgIRF-lkp@intel.com/config)
> compiler: s390-linux-gcc (GCC) 8.5.0
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251220/202512202141.mGkUgIRF-lkp@intel.com/reproduce)
>
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp@intel.com>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202512202141.mGkUgIRF-lkp@intel.com/
>
> All warnings (new ones prefixed by >>):
>
> mm/hugetlb_cma.c: In function 'hugetlb_cma_alloc_folio':
>>> mm/hugetlb_cma.c:44:11: warning: array subscript [0, 0] is outside array bounds of 'struct cma *[1]' [-Warray-bounds]
> page = cma_alloc_frozen_compound(hugetlb_cma[nid], order);
> ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
> Kconfig warnings: (for reference only)
> WARNING: unmet direct dependencies detected for CAN_DEV
> Depends on [n]: NETDEVICES [=n] && CAN [=m]
> Selected by [m]:
> - CAN [=m] && NET [=y]
>
>
> vim +44 mm/hugetlb_cma.c
>
> 28
> 29 struct folio *hugetlb_cma_alloc_folio(int order, gfp_t gfp_mask,
> 30 int nid, nodemask_t *nodemask)
> 31 {
> 32 int node;
> 33 struct folio *folio;
> 34 struct page *page = NULL;
> 35
> 36 if (hugetlb_cma[nid])
> 37 page = cma_alloc_frozen_compound(hugetlb_cma[nid], order);
> 38
> 39 if (!page && !(gfp_mask & __GFP_THISNODE)) {
> 40 for_each_node_mask(node, *nodemask) {
> 41 if (node == nid || !hugetlb_cma[node])
> 42 continue;
> 43
> > 44 page = cma_alloc_frozen_compound(hugetlb_cma[nid], order);
Oh, it should be hugetlb_cma[node] in the fallback path, thanks for the
reporting.
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v4 6/6] mm: hugetlb: allocate frozen pages in alloc_gigantic_folio()
2025-12-16 11:48 [PATCH v4 RESEND 0/6] mm: hugetlb: allocate frozen gigantic folio Kefeng Wang
` (4 preceding siblings ...)
2025-12-16 11:48 ` [PATCH v4 5/6] mm: cma: add cma_alloc_frozen{_compound}() Kefeng Wang
@ 2025-12-16 11:48 ` Kefeng Wang
2025-12-16 18:44 ` Zi Yan
5 siblings, 1 reply; 33+ messages in thread
From: Kefeng Wang @ 2025-12-16 11:48 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Oscar Salvador, Muchun Song, linux-mm
Cc: sidhartha.kumar, jane.chu, Zi Yan, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand, Kefeng Wang
The alloc_gigantic_folio() allocates a folio with refcount increated
and then freeze it, convert to allocate a frozen folio to remove the
atomic operation about folio refcount, and saving atomic operation
during __update_and_free_hugetlb_folio() too.
Besides, rename hugetlb_cma_{alloc,free}_folio() with frozen which
make them more self-explanatory.
Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
---
mm/hugetlb.c | 63 +++++++++++-------------------------------------
mm/hugetlb_cma.c | 9 +++----
mm/hugetlb_cma.h | 10 ++++----
3 files changed, 22 insertions(+), 60 deletions(-)
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index ed185bbca419..7779ec838da0 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -121,16 +121,6 @@ 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);
-static void hugetlb_free_folio(struct folio *folio)
-{
- if (folio_test_hugetlb_cma(folio)) {
- hugetlb_cma_free_folio(folio);
- return;
- }
-
- folio_put(folio);
-}
-
static inline bool subpool_is_free(struct hugepage_subpool *spool)
{
if (spool->count)
@@ -1417,51 +1407,24 @@ static struct folio *dequeue_hugetlb_folio_vma(struct hstate *h,
return NULL;
}
-#ifdef CONFIG_ARCH_HAS_GIGANTIC_PAGE
-#ifdef CONFIG_CONTIG_ALLOC
+#if defined(CONFIG_ARCH_HAS_GIGANTIC_PAGE) && defined(CONFIG_CONTIG_ALLOC)
static struct folio *alloc_gigantic_folio(int order, gfp_t gfp_mask,
int nid, nodemask_t *nodemask)
{
struct folio *folio;
- bool retried = false;
-retry:
- folio = hugetlb_cma_alloc_folio(order, gfp_mask, nid, nodemask);
- if (!folio) {
- struct page *page;
-
- if (hugetlb_cma_exclusive_alloc())
- return NULL;
-
- page = alloc_contig_frozen_pages(1 << order, gfp_mask, nid, nodemask);
- if (!page)
- return NULL;
-
- set_page_refcounted(page);
- folio = page_folio(page);
- }
-
- if (folio_ref_freeze(folio, 1))
+ folio = hugetlb_cma_alloc_frozen_folio(order, gfp_mask, nid, nodemask);
+ if (folio)
return folio;
- pr_warn("HugeTLB: unexpected refcount on PFN %lu\n", folio_pfn(folio));
- hugetlb_free_folio(folio);
- if (!retried) {
- retried = true;
- goto retry;
- }
- return NULL;
-}
+ if (hugetlb_cma_exclusive_alloc())
+ return NULL;
-#else /* !CONFIG_CONTIG_ALLOC */
-static struct folio *alloc_gigantic_folio(int order, gfp_t gfp_mask, int nid,
- nodemask_t *nodemask)
-{
- return NULL;
+ folio = (struct folio *)alloc_contig_frozen_pages(1 << order, gfp_mask,
+ nid, nodemask);
+ return folio;
}
-#endif /* CONFIG_CONTIG_ALLOC */
-
-#else /* !CONFIG_ARCH_HAS_GIGANTIC_PAGE */
+#else /* !CONFIG_ARCH_HAS_GIGANTIC_PAGE || !CONFIG_CONTIG_ALLOC */
static struct folio *alloc_gigantic_folio(int order, gfp_t gfp_mask, int nid,
nodemask_t *nodemask)
{
@@ -1592,9 +1555,11 @@ static void __update_and_free_hugetlb_folio(struct hstate *h,
if (unlikely(folio_test_hwpoison(folio)))
folio_clear_hugetlb_hwpoison(folio);
- folio_ref_unfreeze(folio, 1);
-
- hugetlb_free_folio(folio);
+ VM_BUG_ON_FOLIO(folio_ref_count(folio), folio);
+ if (folio_test_hugetlb_cma(folio))
+ hugetlb_cma_free_frozen_folio(folio);
+ else
+ free_frozen_pages(&folio->page, folio_order(folio));
}
/*
diff --git a/mm/hugetlb_cma.c b/mm/hugetlb_cma.c
index 0a57d3776c8d..7a33fa4981aa 100644
--- a/mm/hugetlb_cma.c
+++ b/mm/hugetlb_cma.c
@@ -18,16 +18,14 @@ static unsigned long hugetlb_cma_size_in_node[MAX_NUMNODES] __initdata;
static bool hugetlb_cma_only;
static unsigned long hugetlb_cma_size __initdata;
-void hugetlb_cma_free_folio(struct folio *folio)
+void hugetlb_cma_free_frozen_folio(struct folio *folio)
{
- folio_ref_dec(folio);
-
WARN_ON_ONCE(!cma_release_frozen(hugetlb_cma[folio_nid(folio)],
&folio->page, folio_nr_pages(folio)));
}
-struct folio *hugetlb_cma_alloc_folio(int order, gfp_t gfp_mask,
- int nid, nodemask_t *nodemask)
+struct folio *hugetlb_cma_alloc_frozen_folio(int order, gfp_t gfp_mask,
+ int nid, nodemask_t *nodemask)
{
int node;
struct folio *folio;
@@ -50,7 +48,6 @@ struct folio *hugetlb_cma_alloc_folio(int order, gfp_t gfp_mask,
if (!page)
return NULL;
- set_page_refcounted(page);
folio = page_folio(page);
folio_set_hugetlb_cma(folio);
return folio;
diff --git a/mm/hugetlb_cma.h b/mm/hugetlb_cma.h
index 2c2ec8a7e134..3bc295c8c38e 100644
--- a/mm/hugetlb_cma.h
+++ b/mm/hugetlb_cma.h
@@ -3,8 +3,8 @@
#define _LINUX_HUGETLB_CMA_H
#ifdef CONFIG_CMA
-void hugetlb_cma_free_folio(struct folio *folio);
-struct folio *hugetlb_cma_alloc_folio(int order, gfp_t gfp_mask,
+void hugetlb_cma_free_frozen_folio(struct folio *folio);
+struct folio *hugetlb_cma_alloc_frozen_folio(int order, gfp_t gfp_mask,
int nid, nodemask_t *nodemask);
struct huge_bootmem_page *hugetlb_cma_alloc_bootmem(struct hstate *h, int *nid,
bool node_exact);
@@ -14,12 +14,12 @@ unsigned long hugetlb_cma_total_size(void);
void hugetlb_cma_validate_params(void);
bool hugetlb_early_cma(struct hstate *h);
#else
-static inline void hugetlb_cma_free_folio(struct folio *folio)
+static inline void hugetlb_cma_free_frozen_folio(struct folio *folio)
{
}
-static inline struct folio *hugetlb_cma_alloc_folio(int order, gfp_t gfp_mask,
- int nid, nodemask_t *nodemask)
+static inline struct folio *hugetlb_cma_alloc_frozen_folio(int order,
+ gfp_t gfp_mask, int nid, nodemask_t *nodemask)
{
return NULL;
}
--
2.27.0
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v4 6/6] mm: hugetlb: allocate frozen pages in alloc_gigantic_folio()
2025-12-16 11:48 ` [PATCH v4 6/6] mm: hugetlb: allocate frozen pages in alloc_gigantic_folio() Kefeng Wang
@ 2025-12-16 18:44 ` Zi Yan
2025-12-17 8:09 ` Kefeng Wang
0 siblings, 1 reply; 33+ messages in thread
From: Zi Yan @ 2025-12-16 18:44 UTC (permalink / raw)
To: Kefeng Wang
Cc: Andrew Morton, David Hildenbrand, Oscar Salvador, Muchun Song,
linux-mm, sidhartha.kumar, jane.chu, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand
On 16 Dec 2025, at 6:48, Kefeng Wang wrote:
> The alloc_gigantic_folio() allocates a folio with refcount increated
> and then freeze it, convert to allocate a frozen folio to remove the
> atomic operation about folio refcount, and saving atomic operation
> during __update_and_free_hugetlb_folio() too.
>
> Besides, rename hugetlb_cma_{alloc,free}_folio() with frozen which
> make them more self-explanatory.
>
> Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
> ---
> mm/hugetlb.c | 63 +++++++++++-------------------------------------
> mm/hugetlb_cma.c | 9 +++----
> mm/hugetlb_cma.h | 10 ++++----
> 3 files changed, 22 insertions(+), 60 deletions(-)
>
> diff --git a/mm/hugetlb.c b/mm/hugetlb.c
> index ed185bbca419..7779ec838da0 100644
> --- a/mm/hugetlb.c
> +++ b/mm/hugetlb.c
> @@ -121,16 +121,6 @@ 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);
>
> -static void hugetlb_free_folio(struct folio *folio)
> -{
> - if (folio_test_hugetlb_cma(folio)) {
> - hugetlb_cma_free_folio(folio);
> - return;
> - }
> -
> - folio_put(folio);
> -}
> -
> static inline bool subpool_is_free(struct hugepage_subpool *spool)
> {
> if (spool->count)
> @@ -1417,51 +1407,24 @@ static struct folio *dequeue_hugetlb_folio_vma(struct hstate *h,
> return NULL;
> }
>
> -#ifdef CONFIG_ARCH_HAS_GIGANTIC_PAGE
> -#ifdef CONFIG_CONTIG_ALLOC
> +#if defined(CONFIG_ARCH_HAS_GIGANTIC_PAGE) && defined(CONFIG_CONTIG_ALLOC)
> static struct folio *alloc_gigantic_folio(int order, gfp_t gfp_mask,
> int nid, nodemask_t *nodemask)
> {
> struct folio *folio;
> - bool retried = false;
>
> -retry:
> - folio = hugetlb_cma_alloc_folio(order, gfp_mask, nid, nodemask);
> - if (!folio) {
> - struct page *page;
> -
> - if (hugetlb_cma_exclusive_alloc())
> - return NULL;
> -
> - page = alloc_contig_frozen_pages(1 << order, gfp_mask, nid, nodemask);
> - if (!page)
> - return NULL;
> -
> - set_page_refcounted(page);
> - folio = page_folio(page);
> - }
> -
> - if (folio_ref_freeze(folio, 1))
> + folio = hugetlb_cma_alloc_frozen_folio(order, gfp_mask, nid, nodemask);
> + if (folio)
> return folio;
alloc_gigantic_folio() actually returns a frozen folio. Should it be renamed
to alloc_frozen_gigantic_folio()?
Best Regards,
Yan, Zi
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v4 6/6] mm: hugetlb: allocate frozen pages in alloc_gigantic_folio()
2025-12-16 18:44 ` Zi Yan
@ 2025-12-17 8:09 ` Kefeng Wang
2025-12-17 19:40 ` Zi Yan
0 siblings, 1 reply; 33+ messages in thread
From: Kefeng Wang @ 2025-12-17 8:09 UTC (permalink / raw)
To: Zi Yan
Cc: Andrew Morton, David Hildenbrand, Oscar Salvador, Muchun Song,
linux-mm, sidhartha.kumar, jane.chu, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand
On 2025/12/17 2:44, Zi Yan wrote:
> On 16 Dec 2025, at 6:48, Kefeng Wang wrote:
>
>> The alloc_gigantic_folio() allocates a folio with refcount increated
>> and then freeze it, convert to allocate a frozen folio to remove the
>> atomic operation about folio refcount, and saving atomic operation
>> during __update_and_free_hugetlb_folio() too.
>>
>> Besides, rename hugetlb_cma_{alloc,free}_folio() with frozen which
>> make them more self-explanatory.
>>
>> Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
>> ---
>> mm/hugetlb.c | 63 +++++++++++-------------------------------------
>> mm/hugetlb_cma.c | 9 +++----
>> mm/hugetlb_cma.h | 10 ++++----
>> 3 files changed, 22 insertions(+), 60 deletions(-)
>>
>> diff --git a/mm/hugetlb.c b/mm/hugetlb.c
>> index ed185bbca419..7779ec838da0 100644
>> --- a/mm/hugetlb.c
>> +++ b/mm/hugetlb.c
>> @@ -121,16 +121,6 @@ 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);
>>
>> -static void hugetlb_free_folio(struct folio *folio)
>> -{
>> - if (folio_test_hugetlb_cma(folio)) {
>> - hugetlb_cma_free_folio(folio);
>> - return;
>> - }
>> -
>> - folio_put(folio);
>> -}
>> -
>> static inline bool subpool_is_free(struct hugepage_subpool *spool)
>> {
>> if (spool->count)
>> @@ -1417,51 +1407,24 @@ static struct folio *dequeue_hugetlb_folio_vma(struct hstate *h,
>> return NULL;
>> }
>>
>> -#ifdef CONFIG_ARCH_HAS_GIGANTIC_PAGE
>> -#ifdef CONFIG_CONTIG_ALLOC
>> +#if defined(CONFIG_ARCH_HAS_GIGANTIC_PAGE) && defined(CONFIG_CONTIG_ALLOC)
>> static struct folio *alloc_gigantic_folio(int order, gfp_t gfp_mask,
>> int nid, nodemask_t *nodemask)
>> {
>> struct folio *folio;
>> - bool retried = false;
>>
>> -retry:
>> - folio = hugetlb_cma_alloc_folio(order, gfp_mask, nid, nodemask);
>> - if (!folio) {
>> - struct page *page;
>> -
>> - if (hugetlb_cma_exclusive_alloc())
>> - return NULL;
>> -
>> - page = alloc_contig_frozen_pages(1 << order, gfp_mask, nid, nodemask);
>> - if (!page)
>> - return NULL;
>> -
>> - set_page_refcounted(page);
>> - folio = page_folio(page);
>> - }
>> -
>> - if (folio_ref_freeze(folio, 1))
>> + folio = hugetlb_cma_alloc_frozen_folio(order, gfp_mask, nid, nodemask);
>> + if (folio)
>> return folio;
>
> alloc_gigantic_folio() actually returns a frozen folio. Should it be renamed
> to alloc_frozen_gigantic_folio()?
I don't change it as alloc_buddy_hugetlb_folio is not with frozen, we
could change both of them if you prefer with frozen :)
>
>
> Best Regards,
> Yan, Zi
>
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v4 6/6] mm: hugetlb: allocate frozen pages in alloc_gigantic_folio()
2025-12-17 8:09 ` Kefeng Wang
@ 2025-12-17 19:40 ` Zi Yan
2025-12-18 12:56 ` Kefeng Wang
0 siblings, 1 reply; 33+ messages in thread
From: Zi Yan @ 2025-12-17 19:40 UTC (permalink / raw)
To: Kefeng Wang
Cc: Andrew Morton, David Hildenbrand, Oscar Salvador, Muchun Song,
linux-mm, sidhartha.kumar, jane.chu, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand
On 17 Dec 2025, at 3:09, Kefeng Wang wrote:
> On 2025/12/17 2:44, Zi Yan wrote:
>> On 16 Dec 2025, at 6:48, Kefeng Wang wrote:
>>
>>> The alloc_gigantic_folio() allocates a folio with refcount increated
>>> and then freeze it, convert to allocate a frozen folio to remove the
>>> atomic operation about folio refcount, and saving atomic operation
>>> during __update_and_free_hugetlb_folio() too.
>>>
>>> Besides, rename hugetlb_cma_{alloc,free}_folio() with frozen which
>>> make them more self-explanatory.
>>>
>>> Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
>>> ---
>>> mm/hugetlb.c | 63 +++++++++++-------------------------------------
>>> mm/hugetlb_cma.c | 9 +++----
>>> mm/hugetlb_cma.h | 10 ++++----
>>> 3 files changed, 22 insertions(+), 60 deletions(-)
>>>
>>> diff --git a/mm/hugetlb.c b/mm/hugetlb.c
>>> index ed185bbca419..7779ec838da0 100644
>>> --- a/mm/hugetlb.c
>>> +++ b/mm/hugetlb.c
>>> @@ -121,16 +121,6 @@ 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);
>>>
>>> -static void hugetlb_free_folio(struct folio *folio)
>>> -{
>>> - if (folio_test_hugetlb_cma(folio)) {
>>> - hugetlb_cma_free_folio(folio);
>>> - return;
>>> - }
>>> -
>>> - folio_put(folio);
>>> -}
>>> -
>>> static inline bool subpool_is_free(struct hugepage_subpool *spool)
>>> {
>>> if (spool->count)
>>> @@ -1417,51 +1407,24 @@ static struct folio *dequeue_hugetlb_folio_vma(struct hstate *h,
>>> return NULL;
>>> }
>>>
>>> -#ifdef CONFIG_ARCH_HAS_GIGANTIC_PAGE
>>> -#ifdef CONFIG_CONTIG_ALLOC
>>> +#if defined(CONFIG_ARCH_HAS_GIGANTIC_PAGE) && defined(CONFIG_CONTIG_ALLOC)
>>> static struct folio *alloc_gigantic_folio(int order, gfp_t gfp_mask,
>>> int nid, nodemask_t *nodemask)
>>> {
>>> struct folio *folio;
>>> - bool retried = false;
>>>
>>> -retry:
>>> - folio = hugetlb_cma_alloc_folio(order, gfp_mask, nid, nodemask);
>>> - if (!folio) {
>>> - struct page *page;
>>> -
>>> - if (hugetlb_cma_exclusive_alloc())
>>> - return NULL;
>>> -
>>> - page = alloc_contig_frozen_pages(1 << order, gfp_mask, nid, nodemask);
>>> - if (!page)
>>> - return NULL;
>>> -
>>> - set_page_refcounted(page);
>>> - folio = page_folio(page);
>>> - }
>>> -
>>> - if (folio_ref_freeze(folio, 1))
>>> + folio = hugetlb_cma_alloc_frozen_folio(order, gfp_mask, nid, nodemask);
>>> + if (folio)
>>> return folio;
>>
>> alloc_gigantic_folio() actually returns a frozen folio. Should it be renamed
>> to alloc_frozen_gigantic_folio()?
>
> I don't change it as alloc_buddy_hugetlb_folio is not with frozen, we could change both of them if you prefer with frozen :)
Better to change both for clearer function names. Thanks.
Best Regards,
Yan, Zi
^ permalink raw reply [flat|nested] 33+ messages in thread* Re: [PATCH v4 6/6] mm: hugetlb: allocate frozen pages in alloc_gigantic_folio()
2025-12-17 19:40 ` Zi Yan
@ 2025-12-18 12:56 ` Kefeng Wang
0 siblings, 0 replies; 33+ messages in thread
From: Kefeng Wang @ 2025-12-18 12:56 UTC (permalink / raw)
To: Zi Yan
Cc: Andrew Morton, David Hildenbrand, Oscar Salvador, Muchun Song,
linux-mm, sidhartha.kumar, jane.chu, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox,
David Hildenbrand
On 2025/12/18 3:40, Zi Yan wrote:
> On 17 Dec 2025, at 3:09, Kefeng Wang wrote:
>
>> On 2025/12/17 2:44, Zi Yan wrote:
>>> On 16 Dec 2025, at 6:48, Kefeng Wang wrote:
>>>
>>>> The alloc_gigantic_folio() allocates a folio with refcount increated
>>>> and then freeze it, convert to allocate a frozen folio to remove the
>>>> atomic operation about folio refcount, and saving atomic operation
>>>> during __update_and_free_hugetlb_folio() too.
>>>>
>>>> Besides, rename hugetlb_cma_{alloc,free}_folio() with frozen which
>>>> make them more self-explanatory.
>>>>
>>>> Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
>>>> ---
>>>> mm/hugetlb.c | 63 +++++++++++-------------------------------------
>>>> mm/hugetlb_cma.c | 9 +++----
>>>> mm/hugetlb_cma.h | 10 ++++----
>>>> 3 files changed, 22 insertions(+), 60 deletions(-)
>>>>
>>>> diff --git a/mm/hugetlb.c b/mm/hugetlb.c
>>>> index ed185bbca419..7779ec838da0 100644
>>>> --- a/mm/hugetlb.c
>>>> +++ b/mm/hugetlb.c
>>>> @@ -121,16 +121,6 @@ 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);
>>>>
>>>> -static void hugetlb_free_folio(struct folio *folio)
>>>> -{
>>>> - if (folio_test_hugetlb_cma(folio)) {
>>>> - hugetlb_cma_free_folio(folio);
>>>> - return;
>>>> - }
>>>> -
>>>> - folio_put(folio);
>>>> -}
>>>> -
>>>> static inline bool subpool_is_free(struct hugepage_subpool *spool)
>>>> {
>>>> if (spool->count)
>>>> @@ -1417,51 +1407,24 @@ static struct folio *dequeue_hugetlb_folio_vma(struct hstate *h,
>>>> return NULL;
>>>> }
>>>>
>>>> -#ifdef CONFIG_ARCH_HAS_GIGANTIC_PAGE
>>>> -#ifdef CONFIG_CONTIG_ALLOC
>>>> +#if defined(CONFIG_ARCH_HAS_GIGANTIC_PAGE) && defined(CONFIG_CONTIG_ALLOC)
>>>> static struct folio *alloc_gigantic_folio(int order, gfp_t gfp_mask,
>>>> int nid, nodemask_t *nodemask)
>>>> {
>>>> struct folio *folio;
>>>> - bool retried = false;
>>>>
>>>> -retry:
>>>> - folio = hugetlb_cma_alloc_folio(order, gfp_mask, nid, nodemask);
>>>> - if (!folio) {
>>>> - struct page *page;
>>>> -
>>>> - if (hugetlb_cma_exclusive_alloc())
>>>> - return NULL;
>>>> -
>>>> - page = alloc_contig_frozen_pages(1 << order, gfp_mask, nid, nodemask);
>>>> - if (!page)
>>>> - return NULL;
>>>> -
>>>> - set_page_refcounted(page);
>>>> - folio = page_folio(page);
>>>> - }
>>>> -
>>>> - if (folio_ref_freeze(folio, 1))
>>>> + folio = hugetlb_cma_alloc_frozen_folio(order, gfp_mask, nid, nodemask);
>>>> + if (folio)
>>>> return folio;
>>>
>>> alloc_gigantic_folio() actually returns a frozen folio. Should it be renamed
>>> to alloc_frozen_gigantic_folio()?
>>
>> I don't change it as alloc_buddy_hugetlb_folio is not with frozen, we could change both of them if you prefer with frozen :)
>
> Better to change both for clearer function names. Thanks.
Sure, I will change both alloc_buddy_hugetlb_folio and alloc_gigantic_folio.
>
> Best Regards,
> Yan, Zi
>
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v4 4/6] mm: page_alloc: add alloc_contig_frozen_{range,pages}()
2025-10-23 11:59 [PATCH v4 0/6] mm: hugetlb: allocate frozen gigantic folio Kefeng Wang
@ 2025-10-23 11:59 ` Kefeng Wang
0 siblings, 0 replies; 33+ messages in thread
From: Kefeng Wang @ 2025-10-23 11:59 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Oscar Salvador, Muchun Song, linux-mm
Cc: sidhartha.kumar, jane.chu, Zi Yan, Vlastimil Babka,
Brendan Jackman, Johannes Weiner, Matthew Wilcox, Kefeng Wang
In order to allocate given range of pages or allocate compound
pages without incrementing their refcount, adding two new helper
alloc_contig_frozen_{range,pages}() which may be beneficial
to some users (eg hugetlb).
The free_contig_range() is refactored to only free non-compound
pages, the only caller to free compound pages in cma_free_folio() is
changed accordingly, and the free_contig_frozen_range() is provided
to match the alloc_contig_frozen_range(), which is used to free
frozen pages.
Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
---
include/linux/gfp.h | 29 +++++--
mm/cma.c | 15 ++--
mm/internal.h | 13 ++++
mm/page_alloc.c | 183 ++++++++++++++++++++++++++++++++------------
4 files changed, 177 insertions(+), 63 deletions(-)
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 92582a329d47..6aba25904f36 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -429,14 +429,27 @@ typedef unsigned int __bitwise acr_flags_t;
#define ACR_FLAGS_CMA ((__force acr_flags_t)BIT(0)) // allocate for CMA
/* The below functions must be run on a range from a single zone. */
-extern int alloc_contig_range_noprof(unsigned long start, unsigned long end,
- acr_flags_t alloc_flags, gfp_t gfp_mask);
-#define alloc_contig_range(...) alloc_hooks(alloc_contig_range_noprof(__VA_ARGS__))
-
-extern struct page *alloc_contig_pages_noprof(unsigned long nr_pages, gfp_t gfp_mask,
- int nid, nodemask_t *nodemask);
-#define alloc_contig_pages(...) alloc_hooks(alloc_contig_pages_noprof(__VA_ARGS__))
-
+int alloc_contig_frozen_range_noprof(unsigned long start, unsigned long end,
+ acr_flags_t alloc_flags, gfp_t gfp_mask);
+#define alloc_contig_frozen_range(...) \
+ alloc_hooks(alloc_contig_frozen_range_noprof(__VA_ARGS__))
+
+int alloc_contig_range_noprof(unsigned long start, unsigned long end,
+ acr_flags_t alloc_flags, gfp_t gfp_mask);
+#define alloc_contig_range(...) \
+ alloc_hooks(alloc_contig_range_noprof(__VA_ARGS__))
+
+struct page *alloc_contig_frozen_pages_noprof(unsigned long nr_pages,
+ gfp_t gfp_mask, int nid, nodemask_t *nodemask);
+#define alloc_contig_frozen_pages(...) \
+ alloc_hooks(alloc_contig_frozen_pages_noprof(__VA_ARGS__))
+
+struct page *alloc_contig_pages_noprof(unsigned long nr_pages, gfp_t gfp_mask,
+ int nid, nodemask_t *nodemask);
+#define alloc_contig_pages(...) \
+ alloc_hooks(alloc_contig_pages_noprof(__VA_ARGS__))
+
+void free_contig_frozen_range(unsigned long pfn, unsigned long nr_pages);
void free_contig_range(unsigned long pfn, unsigned long nr_pages);
#endif
diff --git a/mm/cma.c b/mm/cma.c
index 6df44541933a..7f050cf24383 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -836,7 +836,7 @@ static int cma_range_alloc(struct cma *cma, struct cma_memrange *cmr,
spin_unlock_irq(&cma->lock);
mutex_lock(&cma->alloc_mutex);
- ret = alloc_contig_range(pfn, pfn + count, ACR_FLAGS_CMA, gfp);
+ ret = alloc_contig_frozen_range(pfn, pfn + count, ACR_FLAGS_CMA, gfp);
mutex_unlock(&cma->alloc_mutex);
if (!ret)
break;
@@ -904,6 +904,7 @@ static struct page *__cma_alloc(struct cma *cma, unsigned long count,
trace_cma_alloc_finish(name, page ? page_to_pfn(page) : 0,
page, count, align, ret);
if (page) {
+ set_pages_refcounted(page, count);
count_vm_event(CMA_ALLOC_SUCCESS);
cma_sysfs_account_success_pages(cma, count);
} else {
@@ -943,7 +944,7 @@ struct folio *cma_alloc_folio(struct cma *cma, int order, gfp_t gfp)
}
static bool __cma_release(struct cma *cma, const struct page *pages,
- unsigned long count)
+ unsigned long count, bool compound)
{
unsigned long pfn, end;
int r;
@@ -973,7 +974,11 @@ static bool __cma_release(struct cma *cma, const struct page *pages,
return false;
}
- free_contig_range(pfn, count);
+ if (compound)
+ __free_pages((struct page *)pages, compound_order(pages));
+ else
+ free_contig_range(pfn, count);
+
cma_clear_bitmap(cma, cmr, pfn, count);
cma_sysfs_account_release_pages(cma, count);
trace_cma_release(cma->name, pfn, pages, count);
@@ -994,7 +999,7 @@ static bool __cma_release(struct cma *cma, const struct page *pages,
bool cma_release(struct cma *cma, const struct page *pages,
unsigned long count)
{
- return __cma_release(cma, pages, count);
+ return __cma_release(cma, pages, count, false);
}
bool cma_free_folio(struct cma *cma, const struct folio *folio)
@@ -1002,7 +1007,7 @@ bool cma_free_folio(struct cma *cma, const struct folio *folio)
if (WARN_ON(!folio_test_large(folio)))
return false;
- return __cma_release(cma, &folio->page, folio_nr_pages(folio));
+ return __cma_release(cma, &folio->page, folio_nr_pages(folio), true);
}
int cma_for_each_area(int (*it)(struct cma *cma, void *data), void *data)
diff --git a/mm/internal.h b/mm/internal.h
index 26e7901e963f..ec1e47a9044f 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -513,6 +513,19 @@ static inline void set_page_refcounted(struct page *page)
set_page_count(page, 1);
}
+static inline void set_pages_refcounted(struct page *page, unsigned long nr_pages)
+{
+ unsigned long pfn = page_to_pfn(page);
+
+ if (PageHead(page)) {
+ set_page_refcounted(page);
+ return;
+ }
+
+ for (; nr_pages--; pfn++)
+ set_page_refcounted(pfn_to_page(pfn));
+}
+
/*
* Return true if a folio needs ->release_folio() calling upon it.
*/
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index d619c70c6892..9aebab17974b 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -6836,7 +6836,7 @@ static int __alloc_contig_migrate_range(struct compact_control *cc,
return (ret < 0) ? ret : 0;
}
-static void split_free_pages(struct list_head *list, gfp_t gfp_mask)
+static void split_free_frozen_pages(struct list_head *list, gfp_t gfp_mask)
{
int order;
@@ -6848,11 +6848,10 @@ static void split_free_pages(struct list_head *list, gfp_t gfp_mask)
int i;
post_alloc_hook(page, order, gfp_mask);
- set_page_refcounted(page);
if (!order)
continue;
- split_page(page, order);
+ __split_page(page, order);
/* Add all subpages to the order-0 head, in sequence. */
list_del(&page->lru);
@@ -6896,8 +6895,14 @@ static int __alloc_contig_verify_gfp_mask(gfp_t gfp_mask, gfp_t *gfp_cc_mask)
return 0;
}
+static void __free_contig_frozen_range(unsigned long pfn, unsigned long nr_pages)
+{
+ for (; nr_pages--; pfn++)
+ free_frozen_pages(pfn_to_page(pfn), 0);
+}
+
/**
- * alloc_contig_range() -- tries to allocate given range of pages
+ * alloc_contig_frozen_range() -- tries to allocate given range of frozen pages
* @start: start PFN to allocate
* @end: one-past-the-last PFN to allocate
* @alloc_flags: allocation information
@@ -6912,12 +6917,15 @@ static int __alloc_contig_verify_gfp_mask(gfp_t gfp_mask, gfp_t *gfp_cc_mask)
* pageblocks in the range. Once isolated, the pageblocks should not
* be modified by others.
*
- * Return: zero on success or negative error code. On success all
- * pages which PFN is in [start, end) are allocated for the caller and
- * need to be freed with free_contig_range().
+ * All frozen pages which PFN is in [start, end) are allocated for the
+ * caller, and they could be freed with free_contig_frozen_range(),
+ * free_frozen_pages() also could be used to free compound frozen pages
+ * directly.
+ *
+ * Return: zero on success or negative error code.
*/
-int alloc_contig_range_noprof(unsigned long start, unsigned long end,
- acr_flags_t alloc_flags, gfp_t gfp_mask)
+int alloc_contig_frozen_range_noprof(unsigned long start, unsigned long end,
+ acr_flags_t alloc_flags, gfp_t gfp_mask)
{
const unsigned int order = ilog2(end - start);
unsigned long outer_start, outer_end;
@@ -7033,19 +7041,18 @@ int alloc_contig_range_noprof(unsigned long start, unsigned long end,
}
if (!(gfp_mask & __GFP_COMP)) {
- split_free_pages(cc.freepages, gfp_mask);
+ split_free_frozen_pages(cc.freepages, gfp_mask);
/* Free head and tail (if any) */
if (start != outer_start)
- free_contig_range(outer_start, start - outer_start);
+ __free_contig_frozen_range(outer_start, start - outer_start);
if (end != outer_end)
- free_contig_range(end, outer_end - end);
+ __free_contig_frozen_range(end, outer_end - end);
} else if (start == outer_start && end == outer_end && is_power_of_2(end - start)) {
struct page *head = pfn_to_page(start);
check_new_pages(head, order);
prep_new_page(head, order, gfp_mask, 0);
- set_page_refcounted(head);
} else {
ret = -EINVAL;
WARN(true, "PFN range: requested [%lu, %lu), allocated [%lu, %lu)\n",
@@ -7055,16 +7062,40 @@ int alloc_contig_range_noprof(unsigned long start, unsigned long end,
undo_isolate_page_range(start, end);
return ret;
}
-EXPORT_SYMBOL(alloc_contig_range_noprof);
+EXPORT_SYMBOL(alloc_contig_frozen_range_noprof);
-static int __alloc_contig_pages(unsigned long start_pfn,
- unsigned long nr_pages, gfp_t gfp_mask)
+/**
+ * alloc_contig_range() -- tries to allocate given range of pages
+ * @start: start PFN to allocate
+ * @end: one-past-the-last PFN to allocate
+ * @alloc_flags: allocation information
+ * @gfp_mask: GFP mask.
+ *
+ * This routine is a wrapper around alloc_contig_frozen_range(), it can't
+ * be used to allocate compound pages, the refcount of each allocated page
+ * will be set to one.
+ *
+ * All pages which PFN is in [start, end) are allocated for the caller,
+ * and should be freed with free_contig_range() or by manually calling
+ * __free_page() on each allocated page.
+ *
+ * Return: zero on success or negative error code.
+ */
+int alloc_contig_range_noprof(unsigned long start, unsigned long end,
+ acr_flags_t alloc_flags, gfp_t gfp_mask)
{
- unsigned long end_pfn = start_pfn + nr_pages;
+ int ret;
+
+ if (WARN_ON(gfp_mask & __GFP_COMP))
+ return -EINVAL;
+
+ ret = alloc_contig_frozen_range_noprof(start, end, alloc_flags, gfp_mask);
+ if (!ret)
+ set_pages_refcounted(pfn_to_page(start), end - start);
- return alloc_contig_range_noprof(start_pfn, end_pfn, ACR_FLAGS_NONE,
- gfp_mask);
+ return ret;
}
+EXPORT_SYMBOL(alloc_contig_range_noprof);
static bool pfn_range_valid_contig(struct zone *z, unsigned long start_pfn,
unsigned long nr_pages)
@@ -7098,7 +7129,7 @@ static bool zone_spans_last_pfn(const struct zone *zone,
}
/**
- * alloc_contig_pages() -- tries to find and allocate contiguous range of pages
+ * alloc_contig_frozen_pages() -- tries to find and allocate contiguous range of frozen pages
* @nr_pages: Number of contiguous pages to allocate
* @gfp_mask: GFP mask. Node/zone/placement hints limit the search; only some
* action and reclaim modifiers are supported. Reclaim modifiers
@@ -7106,22 +7137,25 @@ static bool zone_spans_last_pfn(const struct zone *zone,
* @nid: Target node
* @nodemask: Mask for other possible nodes
*
- * This routine is a wrapper around alloc_contig_range(). It scans over zones
- * on an applicable zonelist to find a contiguous pfn range which can then be
- * tried for allocation with alloc_contig_range(). This routine is intended
- * for allocation requests which can not be fulfilled with the buddy allocator.
+ * This routine is a wrapper around alloc_contig_frozen_range(). It scans over
+ * zones on an applicable zonelist to find a contiguous pfn range which can then
+ * be tried for allocation with alloc_contig_frozen_range(). This routine is
+ * intended for allocation requests which can not be fulfilled with the buddy
+ * allocator.
*
* The allocated memory is always aligned to a page boundary. If nr_pages is a
* power of two, then allocated range is also guaranteed to be aligned to same
* nr_pages (e.g. 1GB request would be aligned to 1GB).
*
- * Allocated pages can be freed with free_contig_range() or by manually calling
- * __free_page() on each allocated page.
+ * Allocated frozen pages need be freed with free_contig_frozen_range(),
+ * or by manually calling free_frozen_pages() on each allocated frozen
+ * non-compound page, for compound frozen pages could be freed with
+ * free_frozen_pages() directly.
*
- * Return: pointer to contiguous pages on success, or NULL if not successful.
+ * Return: pointer to contiguous frozen pages on success, or NULL if not successful.
*/
-struct page *alloc_contig_pages_noprof(unsigned long nr_pages, gfp_t gfp_mask,
- int nid, nodemask_t *nodemask)
+struct page *alloc_contig_frozen_pages_noprof(unsigned long nr_pages,
+ gfp_t gfp_mask, int nid, nodemask_t *nodemask)
{
unsigned long ret, pfn, flags;
struct zonelist *zonelist;
@@ -7138,13 +7172,15 @@ struct page *alloc_contig_pages_noprof(unsigned long nr_pages, gfp_t gfp_mask,
if (pfn_range_valid_contig(zone, pfn, nr_pages)) {
/*
* We release the zone lock here because
- * alloc_contig_range() will also lock the zone
- * at some point. If there's an allocation
- * spinning on this lock, it may win the race
- * and cause alloc_contig_range() to fail...
+ * alloc_contig_frozen_range() will also lock
+ * the zone at some point. If there's an
+ * allocation spinning on this lock, it may
+ * win the race and cause allocation to fail.
*/
spin_unlock_irqrestore(&zone->lock, flags);
- ret = __alloc_contig_pages(pfn, nr_pages,
+ ret = alloc_contig_frozen_range_noprof(pfn,
+ pfn + nr_pages,
+ ACR_FLAGS_NONE,
gfp_mask);
if (!ret)
return pfn_to_page(pfn);
@@ -7156,30 +7192,77 @@ struct page *alloc_contig_pages_noprof(unsigned long nr_pages, gfp_t gfp_mask,
}
return NULL;
}
+EXPORT_SYMBOL(alloc_contig_frozen_pages_noprof);
-void free_contig_range(unsigned long pfn, unsigned long nr_pages)
+/**
+ * alloc_contig_pages() -- tries to find and allocate contiguous range of pages
+ * @nr_pages: Number of contiguous pages to allocate
+ * @gfp_mask: GFP mask.
+ * @nid: Target node
+ * @nodemask: Mask for other possible nodes
+ *
+ * This routine is a wrapper around alloc_contig_frozen_pages(), it can't
+ * be used to allocate compound pages, the refcount of each allocated page
+ * will be set to one.
+ *
+ * Allocated pages can be freed with free_contig_range() or by manually
+ * calling __free_page() on each allocated page.
+ *
+ * Return: pointer to contiguous pages on success, or NULL if not successful.
+ */
+struct page *alloc_contig_pages_noprof(unsigned long nr_pages, gfp_t gfp_mask,
+ int nid, nodemask_t *nodemask)
{
- unsigned long count = 0;
- struct folio *folio = pfn_folio(pfn);
+ struct page *page;
+
+ if (WARN_ON(gfp_mask & __GFP_COMP))
+ return NULL;
- if (folio_test_large(folio)) {
- int expected = folio_nr_pages(folio);
+ page = alloc_contig_frozen_pages_noprof(nr_pages, gfp_mask, nid,
+ nodemask);
+ if (page)
+ set_pages_refcounted(page, nr_pages);
- if (nr_pages == expected)
- folio_put(folio);
- else
- WARN(true, "PFN %lu: nr_pages %lu != expected %d\n",
- pfn, nr_pages, expected);
+ return page;
+}
+EXPORT_SYMBOL(alloc_contig_pages_noprof);
+
+/**
+ * free_contig_frozen_range() -- free the contiguous range of frozen pages
+ * @pfn: start PFN to free
+ * @nr_pages: Number of contiguous frozen pages to free
+ *
+ * This can be used to free the allocated compound/non-compound frozen pages.
+ */
+void free_contig_frozen_range(unsigned long pfn, unsigned long nr_pages)
+{
+ struct page *first_page = pfn_to_page(pfn);
+ const unsigned int order = ilog2(nr_pages);
+
+ if (PageHead(first_page)) {
+ WARN_ON_ONCE(order != compound_order(first_page));
+ free_frozen_pages(first_page, order);
return;
}
- for (; nr_pages--; pfn++) {
- struct page *page = pfn_to_page(pfn);
+ __free_contig_frozen_range(pfn, nr_pages);
+}
+EXPORT_SYMBOL(free_contig_frozen_range);
+
+/**
+ * free_contig_range() -- free the contiguous range of pages
+ * @pfn: start PFN to free
+ * @nr_pages: Number of contiguous pages to free
+ *
+ * This can be only used to free the allocated non-compound pages.
+ */
+void free_contig_range(unsigned long pfn, unsigned long nr_pages)
+{
+ if (WARN_ON_ONCE(PageHead(pfn_to_page(pfn))))
+ return;
- count += page_count(page) != 1;
- __free_page(page);
- }
- WARN(count != 0, "%lu pages are still in use!\n", count);
+ for (; nr_pages--; pfn++)
+ __free_page(pfn_to_page(pfn));
}
EXPORT_SYMBOL(free_contig_range);
#endif /* CONFIG_CONTIG_ALLOC */
--
2.27.0
^ permalink raw reply [flat|nested] 33+ messages in thread