[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[xen master] xen/mm: Fix off-by-one preventing tail merge in reserve_offlined_page()



commit 5cb7ff13eec6cc332c671f70d6055022863ca222
Author:     Bernhard Kaindl <bernhard.kaindl@xxxxxxxxxx>
AuthorDate: Fri Jun 5 10:08:42 2026 +0200
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Fri Jun 5 10:08:42 2026 +0200

    xen/mm: Fix off-by-one preventing tail merge in reserve_offlined_page()
    
    reserve_offlined_page() reserves pages marked for offlining and
    returns free buddies from the remaining healthy tail pages back
    to the free list.
    
    Consider an order-2 buddy (4 pages) with the following layout:
    +---------------+---------------+---------------+---------------+
    | head page       tail page 1,    tail page 2     tail page 3   |
    | PFN_ORDER(pg)   marked as to                                  |
    | == 2            be offlined                                   |
    +---------------+---------------+---------------+---------------+
    
    The expected result after removing tail page 1 and returning the
    remaining healthy pages to the free list would be:
    
    +---------------+               +---------------+---------------+
    | single page   | offlined page | head page       tail page     |
    | PFN_ORDER(pg) | not returned  | PFN_ORDER(pg)                 |
    | == 0          | to the heap   | == 1                          |
    +---------------+               +---------------+---------------+
    
    A trivial off-by-one error in the growth loop stops the growth loop
    early before the tail end of the original buddy and we end up with:
    
    +---------------+               +---------------+---------------+
    | single page   | offlined page | single page   | single page   |
    | PFN_ORDER(pg) | not returned  | PFN_ORDER(pg) | PFN_ORDER(pg) |
    | == 0          | to the heap   | == 0          | == 0          |
    +---------------+               +---------------+---------------+
    
    If the offlined page was in a much larger buddy, this would lead
    to much more memory not available for higher order allocations
    requiring the full tail end of the original buddy for allocation.
    
    Fix the growth loop to correctly grow the buddy to the tail end
    to make the full allocation unit available for future allocation.
    
    Fixes: e4865c2315 ('Page offline support in Xen side')
    Signed-off-by: Bernhard Kaindl <bernhard.kaindl@xxxxxxxxxx>
    Reviewed-by: Jan Beulich <jbeulich@xxxxxxxx>
    Release-Acked-by: Oleksii Kurochko <oleksii.kurochko@xxxxxxxxx>
---
 xen/common/page_alloc.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c
index 2767376a71..e01ac3e99c 100644
--- a/xen/common/page_alloc.c
+++ b/xen/common/page_alloc.c
@@ -1195,11 +1195,13 @@ static int reserve_offlined_page(struct page_info *head)
 
         next_order = cur_order = 0;
 
+        /* Attempt to grow the order (size) of the buddy as much as possible. 
*/
         while ( cur_order < head_order )
         {
             next_order = cur_order + 1;
 
-            if ( (cur_head + (1 << next_order)) >= (head + ( 1 << head_order)) 
)
+            /* Do not grow to next_order if it would go beyond the buddy. */
+            if ( (cur_head + (1 << next_order)) > (head + (1 << head_order)) )
                 goto merge;
 
             /* Do not grow to next_order if cur_head is not aligned to it. */
--
generated by git-patchbot for /home/xen/git/xen.git#master



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.