|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v2 1/2] xen/mm: Fix off-by-one preventing tail merge in reserve_offlined_page()
On 03.06.2026 16:27, Bernhard Kaindl wrote:
> 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>
Oleksii, same question again here.
Jan
> ---
> v2:
> - Bugfix isolated from the test case for backporting.
> - Removed stray blank from the line that I touch.
> - Title: Replaced stopping with preventing.
> - Title: Added parentheses after reserve_offlined_page().
> ---
> 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 2767376a710b..e01ac3e99c72 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. */
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |