When a reported free page is split via expand() to satisfy a
smaller allocation, the sub-pages placed back on the free lists
lose the PageReported flag.  This means they will be unnecessarily
re-reported to the hypervisor in the next reporting cycle, wasting
work.

Propagate the PageReported flag to sub-pages during expand() so
that they are recognized as already-reported.

Signed-off-by: Michael S. Tsirkin <[email protected]>
Assisted-by: Claude:claude-opus-4-6
---
 mm/page_alloc.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 7791bc1eeefa..ca4f9c0948af 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1730,7 +1730,7 @@ struct page *__pageblock_pfn_to_page(unsigned long 
start_pfn,
  * -- nyc
  */
 static inline unsigned int expand(struct zone *zone, struct page *page, int 
low,
-                                 int high, int migratetype)
+                                 int high, int migratetype, bool reported)
 {
        unsigned int size = 1 << high;
        unsigned int nr_added = 0;
@@ -1752,6 +1752,15 @@ static inline unsigned int expand(struct zone *zone, 
struct page *page, int low,
                __add_to_free_list(&page[size], zone, high, migratetype, false);
                set_buddy_order(&page[size], high);
                nr_added += size;
+
+               /*
+                * The parent page has been reported to the host.  The
+                * sub-pages are part of the same reported block, so mark
+                * them reported too.  This avoids re-reporting pages that
+                * the host already knows about.
+                */
+               if (reported)
+                       __SetPageReported(&page[size]);
        }
 
        return nr_added;
@@ -1762,9 +1771,10 @@ static __always_inline void page_del_and_expand(struct 
zone *zone,
                                                int high, int migratetype)
 {
        int nr_pages = 1 << high;
+       bool was_reported = page_reported(page);
 
        __del_page_from_free_list(page, zone, high, migratetype);
-       nr_pages -= expand(zone, page, low, high, migratetype);
+       nr_pages -= expand(zone, page, low, high, migratetype, was_reported);
        account_freepages(zone, -nr_pages, migratetype);
 }
 
@@ -2334,7 +2344,8 @@ try_to_claim_block(struct zone *zone, struct page *page,
 
                del_page_from_free_list(page, zone, current_order, block_type);
                change_pageblock_range(page, current_order, start_type);
-               nr_added = expand(zone, page, order, current_order, start_type);
+               nr_added = expand(zone, page, order, current_order, start_type,
+                                 false);
                account_freepages(zone, nr_added, start_type);
                return page;
        }
-- 
MST


Reply via email to