When two buddy pages merge in __free_one_page(), preserve
PG_zeroed on the merged page only if both buddies have the
flag set.  Otherwise clear it.

Without this, a zeroed page (freed via free_frozen_pages_zeroed
from balloon deflate) could merge with a non-zero buddy.  The merged
page would inherit PG_zeroed, and a later __GFP_ZERO allocation
would skip zeroing stale data in the non-zero half.

The page reporting path is not affected: it sets PG_zeroed during
allocation (page_del_and_expand), not on free list pages.

Signed-off-by: Michael S. Tsirkin <[email protected]>
Assisted-by: Claude:claude-opus-4-6
Assisted-by: cursor-agent:GPT-5.4-xhigh
---
 mm/page_alloc.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index eff01a819744..1183ef3e91c9 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -984,10 +984,14 @@ static inline void __free_one_page(struct page *page,
        unsigned long buddy_pfn = 0;
        unsigned long combined_pfn;
        struct page *buddy;
+       bool buddy_zeroed;
+       bool page_zeroed;
        bool to_tail;
 
        VM_BUG_ON(!zone_is_initialized(zone));
-       VM_BUG_ON_PAGE(page->flags.f & PAGE_FLAGS_CHECK_AT_PREP, page);
+       /* PG_zeroed (aliased to PG_private) is valid on free-list pages */
+       VM_BUG_ON_PAGE(page->flags.f &
+                      (PAGE_FLAGS_CHECK_AT_PREP & ~__PG_ZEROED), page);
 
        VM_BUG_ON(migratetype == -1);
        VM_BUG_ON_PAGE(pfn & ((1 << order) - 1), page);
@@ -1022,6 +1026,8 @@ static inline void __free_one_page(struct page *page,
                                goto done_merging;
                }
 
+               buddy_zeroed = PageZeroed(buddy);
+
                /*
                 * Our buddy is free or it is CONFIG_DEBUG_PAGEALLOC guard page,
                 * merge with it and move up one order.
@@ -1040,10 +1046,17 @@ static inline void __free_one_page(struct page *page,
                        change_pageblock_range(buddy, order, migratetype);
                }
 
+               page_zeroed = PageZeroed(page);
+               __ClearPageZeroed(page);
+               __ClearPageZeroed(buddy);
+
                combined_pfn = buddy_pfn & pfn;
                page = page + (combined_pfn - pfn);
                pfn = combined_pfn;
                order++;
+
+               if (page_zeroed && buddy_zeroed)
+                       __SetPageZeroed(page);
        }
 
 done_merging:
-- 
MST


Reply via email to