* [PATCH] mm/page_alloc: free allocated PFNs if the range does not match
@ 2026-06-30 1:35 Zi Yan
2026-06-30 2:06 ` Andrew Morton
2026-06-30 7:44 ` Vlastimil Babka (SUSE)
0 siblings, 2 replies; 7+ messages in thread
From: Zi Yan @ 2026-06-30 1:35 UTC (permalink / raw)
To: Andrew Morton, Vlastimil Babka, Suren Baghdasaryan, Michal Hocko,
Brendan Jackman, Johannes Weiner, David Hildenbrand,
Lorenzo Stoakes, Liam R. Howlett, Mike Rapoport, Yu Zhao
Cc: linux-mm, linux-kernel, Zi Yan, stable
When using __GFP_COMP in alloc_contig_frozen_range(), if the allocated
range does not match the requested one, the code errors out with EINVAL
without freeing the allocated PFNs and causes free page leaks. Fix it by
calling release_free_list() in the error path.
The issue is reported by Sashiko[1].
Fixes: e98337d11bbd ("mm/contig_alloc: support __GFP_COMP")
Link: https://sashiko.dev/#/patchset/20260628-keep-subpage-private-zero-at-free-v1-0-f4ce3930d10f@nvidia.com [1]
Signed-off-by: Zi Yan <ziy@nvidia.com>
Cc: stable@vger.kernel.org
---
Sashiko reports that if alloc_contig_range() with __GFP_COMP cannot
allocate PFNs with the given range, it returns EINVAL without freeing the
allocated PFNs and causes free memory leaks. Fix it by properly freeing the
isolated free pages and adjusting WARN message for clarification.
---
mm/compaction.c | 2 +-
mm/internal.h | 1 +
mm/page_alloc.c | 6 ++++--
3 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/mm/compaction.c b/mm/compaction.c
index b776f35ad020..4e3f06ff9304 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -88,7 +88,7 @@ static struct page *mark_allocated_noprof(struct page *page, unsigned int order,
}
#define mark_allocated(...) alloc_hooks(mark_allocated_noprof(__VA_ARGS__))
-static unsigned long release_free_list(struct list_head *freepages)
+unsigned long release_free_list(struct list_head *freepages)
{
int order;
unsigned long high_pfn = 0;
diff --git a/mm/internal.h b/mm/internal.h
index 181e79f1d6a2..6f9e5c2a6065 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -821,6 +821,7 @@ static inline void clear_zone_contiguous(struct zone *zone)
}
extern int __isolate_free_page(struct page *page, unsigned int order);
+extern unsigned long release_free_list(struct list_head *freepages);
extern void __putback_isolated_page(struct page *page, unsigned int order,
int mt);
extern void memblock_free_pages(unsigned long pfn, unsigned int order);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index ee902a468c2f..c1a35adb40f1 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -7235,9 +7235,11 @@ int alloc_contig_frozen_range_noprof(unsigned long start, unsigned long end,
check_new_pages(head, order);
prep_new_page(head, order, gfp_mask, 0);
} else {
+ release_free_list(cc.freepages);
ret = -EINVAL;
- WARN(true, "PFN range: requested [%lu, %lu), allocated [%lu, %lu)\n",
- start, end, outer_start, outer_end);
+ WARN(true,
+ "PFN range: allocated [%lu, %lu) does not match requested [%lu, %lu), freeing allocated PFNs\n",
+ outer_start, outer_end, start, end);
}
done:
undo_isolate_page_range(start, end);
---
base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
change-id: 20260629-free-pfn-on-alloc-contig-range-error-path-acc001232468
Best regards,
--
Yan, Zi
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH] mm/page_alloc: free allocated PFNs if the range does not match
2026-06-30 1:35 [PATCH] mm/page_alloc: free allocated PFNs if the range does not match Zi Yan
@ 2026-06-30 2:06 ` Andrew Morton
2026-06-30 2:23 ` Zi Yan
2026-06-30 7:44 ` Vlastimil Babka (SUSE)
1 sibling, 1 reply; 7+ messages in thread
From: Andrew Morton @ 2026-06-30 2:06 UTC (permalink / raw)
To: Zi Yan
Cc: Vlastimil Babka, Suren Baghdasaryan, Michal Hocko,
Brendan Jackman, Johannes Weiner, David Hildenbrand,
Lorenzo Stoakes, Liam R. Howlett, Mike Rapoport, Yu Zhao,
linux-mm, linux-kernel, stable
On Mon, 29 Jun 2026 21:35:33 -0400 Zi Yan <ziy@nvidia.com> wrote:
> When using __GFP_COMP in alloc_contig_frozen_range(), if the allocated
> range does not match the requested one, the code errors out with EINVAL
> without freeing the allocated PFNs and causes free page leaks. Fix it by
> calling release_free_list() in the error path.
>
> The issue is reported by Sashiko[1].
>
> --- a/mm/compaction.c
> +++ b/mm/compaction.c
> @@ -88,7 +88,7 @@ static struct page *mark_allocated_noprof(struct page *page, unsigned int order,
> }
> #define mark_allocated(...) alloc_hooks(mark_allocated_noprof(__VA_ARGS__))
>
> -static unsigned long release_free_list(struct list_head *freepages)
> +unsigned long release_free_list(struct list_head *freepages)
> {
> int order;
> unsigned long high_pfn = 0;
>
> ...
>
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -7235,9 +7235,11 @@ int alloc_contig_frozen_range_noprof(unsigned long start, unsigned long end,
> check_new_pages(head, order);
> prep_new_page(head, order, gfp_mask, 0);
> } else {
> + release_free_list(cc.freepages);
I wonder if there's a Kconfig combination which results in this being
undefined.
I couldn't immediately find such a combination. No doubt we'll be told
if there is one ;)
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH] mm/page_alloc: free allocated PFNs if the range does not match
2026-06-30 2:06 ` Andrew Morton
@ 2026-06-30 2:23 ` Zi Yan
0 siblings, 0 replies; 7+ messages in thread
From: Zi Yan @ 2026-06-30 2:23 UTC (permalink / raw)
To: Andrew Morton
Cc: Vlastimil Babka, Suren Baghdasaryan, Michal Hocko,
Brendan Jackman, Johannes Weiner, David Hildenbrand,
Lorenzo Stoakes, Liam R. Howlett, Mike Rapoport, Yu Zhao,
linux-mm, linux-kernel, stable
On Mon Jun 29, 2026 at 10:06 PM EDT, Andrew Morton wrote:
> On Mon, 29 Jun 2026 21:35:33 -0400 Zi Yan <ziy@nvidia.com> wrote:
>
>> When using __GFP_COMP in alloc_contig_frozen_range(), if the allocated
>> range does not match the requested one, the code errors out with EINVAL
>> without freeing the allocated PFNs and causes free page leaks. Fix it by
>> calling release_free_list() in the error path.
>>
>> The issue is reported by Sashiko[1].
>>
>> --- a/mm/compaction.c
>> +++ b/mm/compaction.c
>> @@ -88,7 +88,7 @@ static struct page *mark_allocated_noprof(struct page *page, unsigned int order,
>> }
>> #define mark_allocated(...) alloc_hooks(mark_allocated_noprof(__VA_ARGS__))
>>
>> -static unsigned long release_free_list(struct list_head *freepages)
>> +unsigned long release_free_list(struct list_head *freepages)
>> {
>> int order;
>> unsigned long high_pfn = 0;
>>
>> ...
>>
>> --- a/mm/page_alloc.c
>> +++ b/mm/page_alloc.c
>> @@ -7235,9 +7235,11 @@ int alloc_contig_frozen_range_noprof(unsigned long start, unsigned long end,
>> check_new_pages(head, order);
>> prep_new_page(head, order, gfp_mask, 0);
>> } else {
>> + release_free_list(cc.freepages);
>
> I wonder if there's a Kconfig combination which results in this being
> undefined.
>
> I couldn't immediately find such a combination. No doubt we'll be told
> if there is one ;)
I asked Codex about this and think it is OK, since release_free_list()
is defined in CONGIF_COMPACTION || CONFIG_CMA and
alloc_contig_frozen_range() is compiled inside CONFIG_CONTIG_ALLOC,
which is def_bool (MEMORY_ISOLATION && COMPACTION) || CMA.
In addition, isolate_freepages_range() above is defined in the same
Kconfig condition as release_free_list() and there is no issue, so the
use of release_free_list() should be fine here.
Hmm, I think the fixup below places release_free_list() delcaration in a
better location, sitting next to isolate_freepages_range().
I will wait for feedbacks and send v2 with the fixup later.
diff --git a/mm/internal.h b/mm/internal.h
index 6f9e5c2a6065..764fdc0d7cbf 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -821,7 +821,6 @@ static inline void clear_zone_contiguous(struct zone *zone)
}
extern int __isolate_free_page(struct page *page, unsigned int order);
-extern unsigned long release_free_list(struct list_head *freepages);
extern void __putback_isolated_page(struct page *page, unsigned int order,
int mt);
extern void memblock_free_pages(unsigned long pfn, unsigned int order);
@@ -1067,6 +1066,7 @@ struct capture_control {
unsigned long
isolate_freepages_range(struct compact_control *cc,
unsigned long start_pfn, unsigned long end_pfn);
+unsigned long release_free_list(struct list_head *freepages);
int
isolate_migratepages_range(struct compact_control *cc,
unsigned long low_pfn, unsigned long end_pfn);
--
Best Regards,
Yan, Zi
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH] mm/page_alloc: free allocated PFNs if the range does not match
2026-06-30 1:35 [PATCH] mm/page_alloc: free allocated PFNs if the range does not match Zi Yan
2026-06-30 2:06 ` Andrew Morton
@ 2026-06-30 7:44 ` Vlastimil Babka (SUSE)
2026-06-30 13:39 ` David Hildenbrand (Arm)
1 sibling, 1 reply; 7+ messages in thread
From: Vlastimil Babka (SUSE) @ 2026-06-30 7:44 UTC (permalink / raw)
To: Zi Yan, Andrew Morton, Suren Baghdasaryan, Michal Hocko,
Brendan Jackman, Johannes Weiner, David Hildenbrand,
Lorenzo Stoakes, Liam R. Howlett, Mike Rapoport, Yu Zhao
Cc: linux-mm, linux-kernel, stable
On 6/30/26 03:35, Zi Yan wrote:
> When using __GFP_COMP in alloc_contig_frozen_range(), if the allocated
> range does not match the requested one, the code errors out with EINVAL
> without freeing the allocated PFNs and causes free page leaks. Fix it by
> calling release_free_list() in the error path.
>
> The issue is reported by Sashiko[1].
So this?
Reported-by: Sashiko <sashiko-bot@kernel.org>
> Fixes: e98337d11bbd ("mm/contig_alloc: support __GFP_COMP")
> Link: https://sashiko.dev/#/patchset/20260628-keep-subpage-private-zero-at-free-v1-0-f4ce3930d10f@nvidia.com [1]
> Signed-off-by: Zi Yan <ziy@nvidia.com>
> Cc: stable@vger.kernel.org
Hm well, it's a path that warns, can only happen due to a development error?
Not sure we care about stable then. Anyway.
Reviewed-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
> ---
> Sashiko reports that if alloc_contig_range() with __GFP_COMP cannot
> allocate PFNs with the given range, it returns EINVAL without freeing the
> allocated PFNs and causes free memory leaks. Fix it by properly freeing the
> isolated free pages and adjusting WARN message for clarification.
> ---
> mm/compaction.c | 2 +-
> mm/internal.h | 1 +
> mm/page_alloc.c | 6 ++++--
> 3 files changed, 6 insertions(+), 3 deletions(-)
>
> diff --git a/mm/compaction.c b/mm/compaction.c
> index b776f35ad020..4e3f06ff9304 100644
> --- a/mm/compaction.c
> +++ b/mm/compaction.c
> @@ -88,7 +88,7 @@ static struct page *mark_allocated_noprof(struct page *page, unsigned int order,
> }
> #define mark_allocated(...) alloc_hooks(mark_allocated_noprof(__VA_ARGS__))
>
> -static unsigned long release_free_list(struct list_head *freepages)
> +unsigned long release_free_list(struct list_head *freepages)
> {
> int order;
> unsigned long high_pfn = 0;
> diff --git a/mm/internal.h b/mm/internal.h
> index 181e79f1d6a2..6f9e5c2a6065 100644
> --- a/mm/internal.h
> +++ b/mm/internal.h
> @@ -821,6 +821,7 @@ static inline void clear_zone_contiguous(struct zone *zone)
> }
>
> extern int __isolate_free_page(struct page *page, unsigned int order);
> +extern unsigned long release_free_list(struct list_head *freepages);
> extern void __putback_isolated_page(struct page *page, unsigned int order,
> int mt);
> extern void memblock_free_pages(unsigned long pfn, unsigned int order);
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index ee902a468c2f..c1a35adb40f1 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -7235,9 +7235,11 @@ int alloc_contig_frozen_range_noprof(unsigned long start, unsigned long end,
> check_new_pages(head, order);
> prep_new_page(head, order, gfp_mask, 0);
> } else {
> + release_free_list(cc.freepages);
> ret = -EINVAL;
> - WARN(true, "PFN range: requested [%lu, %lu), allocated [%lu, %lu)\n",
> - start, end, outer_start, outer_end);
> + WARN(true,
> + "PFN range: allocated [%lu, %lu) does not match requested [%lu, %lu), freeing allocated PFNs\n",
> + outer_start, outer_end, start, end);
> }
> done:
> undo_isolate_page_range(start, end);
>
> ---
> base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
> change-id: 20260629-free-pfn-on-alloc-contig-range-error-path-acc001232468
>
> Best regards,
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH] mm/page_alloc: free allocated PFNs if the range does not match
2026-06-30 7:44 ` Vlastimil Babka (SUSE)
@ 2026-06-30 13:39 ` David Hildenbrand (Arm)
2026-06-30 14:47 ` Lance Yang
2026-06-30 15:06 ` Zi Yan
0 siblings, 2 replies; 7+ messages in thread
From: David Hildenbrand (Arm) @ 2026-06-30 13:39 UTC (permalink / raw)
To: Vlastimil Babka (SUSE), Zi Yan, Andrew Morton, Suren Baghdasaryan,
Michal Hocko, Brendan Jackman, Johannes Weiner, Lorenzo Stoakes,
Liam R. Howlett, Mike Rapoport, Yu Zhao
Cc: linux-mm, linux-kernel, stable
On 6/30/26 09:44, Vlastimil Babka (SUSE) wrote:
> On 6/30/26 03:35, Zi Yan wrote:
>> When using __GFP_COMP in alloc_contig_frozen_range(), if the allocated
>> range does not match the requested one, the code errors out with EINVAL
>> without freeing the allocated PFNs and causes free page leaks. Fix it by
>> calling release_free_list() in the error path.
>>
>> The issue is reported by Sashiko[1].
>
> So this?
> Reported-by: Sashiko <sashiko-bot@kernel.org>
>
>> Fixes: e98337d11bbd ("mm/contig_alloc: support __GFP_COMP")
>> Link: https://sashiko.dev/#/patchset/20260628-keep-subpage-private-zero-at-free-v1-0-f4ce3930d10f@nvidia.com [1]
>> Signed-off-by: Zi Yan <ziy@nvidia.com>
>> Cc: stable@vger.kernel.org
>
> Hm well, it's a path that warns, can only happen due to a development error?
> Not sure we care about stable then. Anyway.
>
If someone would run into the WARN we would already be in Fixes: territory.
it's a path that should never be executed. If it does, the real issue must be fixed.
So (a) I don't think this is stable material (b) I am skeptical that this is
even a Fixes and (c) I am wondering whether we should touch this *at all*.
:)
--
Cheers,
David
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH] mm/page_alloc: free allocated PFNs if the range does not match
2026-06-30 13:39 ` David Hildenbrand (Arm)
@ 2026-06-30 14:47 ` Lance Yang
2026-06-30 15:06 ` Zi Yan
1 sibling, 0 replies; 7+ messages in thread
From: Lance Yang @ 2026-06-30 14:47 UTC (permalink / raw)
To: david
Cc: vbabka, ziy, akpm, surenb, mhocko, jackmanb, hannes, ljs, liam,
rppt, yuzhao, linux-mm, linux-kernel, stable, Lance Yang
On Tue, Jun 30, 2026 at 03:39:56PM +0200, David Hildenbrand (Arm) wrote:
>On 6/30/26 09:44, Vlastimil Babka (SUSE) wrote:
>> On 6/30/26 03:35, Zi Yan wrote:
>>> When using __GFP_COMP in alloc_contig_frozen_range(), if the allocated
>>> range does not match the requested one, the code errors out with EINVAL
>>> without freeing the allocated PFNs and causes free page leaks. Fix it by
>>> calling release_free_list() in the error path.
>>>
>>> The issue is reported by Sashiko[1].
>>
>> So this?
>> Reported-by: Sashiko <sashiko-bot@kernel.org>
>>
>>> Fixes: e98337d11bbd ("mm/contig_alloc: support __GFP_COMP")
>>> Link: https://sashiko.dev/#/patchset/20260628-keep-subpage-private-zero-at-free-v1-0-f4ce3930d10f@nvidia.com [1]
>>> Signed-off-by: Zi Yan <ziy@nvidia.com>
>>> Cc: stable@vger.kernel.org
>>
>> Hm well, it's a path that warns, can only happen due to a development error?
>> Not sure we care about stable then. Anyway.
>>
>
>If someone would run into the WARN we would already be in Fixes: territory.
>
>it's a path that should never be executed. If it does, the real issue must be fixed.
>
>So (a) I don't think this is stable material (b) I am skeptical that this is
>even a Fixes and (c) I am wondering whether we should touch this *at all*.
FWIW, this patch looks fine defensively, but probably not a stable
material unless we know a real caller can hit it :)
Cheers, Lance
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH] mm/page_alloc: free allocated PFNs if the range does not match
2026-06-30 13:39 ` David Hildenbrand (Arm)
2026-06-30 14:47 ` Lance Yang
@ 2026-06-30 15:06 ` Zi Yan
1 sibling, 0 replies; 7+ messages in thread
From: Zi Yan @ 2026-06-30 15:06 UTC (permalink / raw)
To: David Hildenbrand (Arm), Vlastimil Babka (SUSE), Andrew Morton,
Suren Baghdasaryan, Michal Hocko, Brendan Jackman,
Johannes Weiner, Lorenzo Stoakes, Liam R. Howlett, Mike Rapoport,
Yu Zhao
Cc: linux-mm, linux-kernel, stable
On Tue Jun 30, 2026 at 9:39 AM EDT, David Hildenbrand (Arm) wrote:
> On 6/30/26 09:44, Vlastimil Babka (SUSE) wrote:
>> On 6/30/26 03:35, Zi Yan wrote:
>>> When using __GFP_COMP in alloc_contig_frozen_range(), if the allocated
>>> range does not match the requested one, the code errors out with EINVAL
>>> without freeing the allocated PFNs and causes free page leaks. Fix it by
>>> calling release_free_list() in the error path.
>>>
>>> The issue is reported by Sashiko[1].
>>
>> So this?
>> Reported-by: Sashiko <sashiko-bot@kernel.org>
>>
>>> Fixes: e98337d11bbd ("mm/contig_alloc: support __GFP_COMP")
>>> Link: https://sashiko.dev/#/patchset/20260628-keep-subpage-private-zero-at-free-v1-0-f4ce3930d10f@nvidia.com [1]
>>> Signed-off-by: Zi Yan <ziy@nvidia.com>
>>> Cc: stable@vger.kernel.org
>>
>> Hm well, it's a path that warns, can only happen due to a development error?
>> Not sure we care about stable then. Anyway.
>>
>
> If someone would run into the WARN we would already be in Fixes: territory.
>
> it's a path that should never be executed. If it does, the real issue must be fixed.
>
> So (a) I don't think this is stable material (b) I am skeptical that this is
> even a Fixes and (c) I am wondering whether we should touch this *at all*.
>
> :)
I looked at the code again and agree with you that the code is not
reachable and the fix should not be in the WARN path. Theoretically, if
order = ilog2(end - start) is smaller than MAX_PAGE_ORDER,
find_large_buddy() can return an outer_start smaller than start, leading
to this WARN path. But currently alloc_contig_frozen_range() with
__GFP_COMP is used by gigantic hugetlb, thus that is not possible.
How about
1. making sure order is bigger or equal to MAX_PAGE_ORDER,
2. adding a comment in the WARN path to prevent someone else trying to
fix WARN path if Sashiko reports this again
like the patch below?
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index ee902a468c2f..e87d3fced9d4 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -7130,8 +7130,13 @@ int alloc_contig_frozen_range_noprof(unsigned long start, unsigned long end,
* In contrast to the buddy, we allow for orders here that exceed
* MAX_PAGE_ORDER, so we must manually make sure that we are not
* exceeding the maximum folio order.
+ *
+ * The order cannot be smaller than MAX_PAGE_ORDER either to prevent a
+ * potential mismatch between the requested range and the allocated
+ * range that leads to an allocation failure.
*/
- if (WARN_ON_ONCE((gfp_mask & __GFP_COMP) && order > MAX_FOLIO_ORDER))
+ if (WARN_ON_ONCE((gfp_mask & __GFP_COMP) &&
+ (order > MAX_FOLIO_ORDER || order < MAX_PAGE_ORDER))
return -EINVAL;
gfp_mask = current_gfp_context(gfp_mask);
@@ -7235,6 +7240,7 @@ int alloc_contig_frozen_range_noprof(unsigned long start, unsigned long end,
check_new_pages(head, order);
prep_new_page(head, order, gfp_mask, 0);
} else {
+ /* Fix the caller if this is reachable */
ret = -EINVAL;
WARN(true, "PFN range: requested [%lu, %lu), allocated [%lu, %lu)\n",
start, end, outer_start, outer_end);
--
Best Regards,
Yan, Zi
^ permalink raw reply related [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-06-30 15:07 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-30 1:35 [PATCH] mm/page_alloc: free allocated PFNs if the range does not match Zi Yan
2026-06-30 2:06 ` Andrew Morton
2026-06-30 2:23 ` Zi Yan
2026-06-30 7:44 ` Vlastimil Babka (SUSE)
2026-06-30 13:39 ` David Hildenbrand (Arm)
2026-06-30 14:47 ` Lance Yang
2026-06-30 15:06 ` Zi Yan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox