[PATCH v1 13/29] mm/balloon_compaction: stop using __ClearPageMovable()

David Hildenbrand posted 29 patches 3 months, 1 week ago
There is a newer version of this series
[PATCH v1 13/29] mm/balloon_compaction: stop using __ClearPageMovable()
Posted by David Hildenbrand 3 months, 1 week ago
We can just look at the balloon device (stored in page->private), to see
if the page is still part of the balloon.

As isolated balloon pages cannot get released (they are taken off the
balloon list while isolated), we don't have to worry about this case in
the putback and migration callback. Add a WARN_ON_ONCE for now.

Signed-off-by: David Hildenbrand <david@redhat.com>
---
 include/linux/balloon_compaction.h |  4 +---
 mm/balloon_compaction.c            | 11 +++++++++++
 2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/include/linux/balloon_compaction.h b/include/linux/balloon_compaction.h
index bfc6e50bd004b..9bce8e9f5018c 100644
--- a/include/linux/balloon_compaction.h
+++ b/include/linux/balloon_compaction.h
@@ -136,10 +136,8 @@ static inline gfp_t balloon_mapping_gfp_mask(void)
  */
 static inline void balloon_page_finalize(struct page *page)
 {
-	if (IS_ENABLED(CONFIG_BALLOON_COMPACTION)) {
-		__ClearPageMovable(page);
+	if (IS_ENABLED(CONFIG_BALLOON_COMPACTION))
 		set_page_private(page, 0);
-	}
 	/* PageOffline is sticky until the page is freed to the buddy. */
 }
 
diff --git a/mm/balloon_compaction.c b/mm/balloon_compaction.c
index ec176bdb8a78b..e4f1a122d786b 100644
--- a/mm/balloon_compaction.c
+++ b/mm/balloon_compaction.c
@@ -206,6 +206,9 @@ static bool balloon_page_isolate(struct page *page, isolate_mode_t mode)
 	struct balloon_dev_info *b_dev_info = balloon_page_device(page);
 	unsigned long flags;
 
+	if (!b_dev_info)
+		return false;
+
 	spin_lock_irqsave(&b_dev_info->pages_lock, flags);
 	list_del(&page->lru);
 	b_dev_info->isolated_pages++;
@@ -219,6 +222,10 @@ static void balloon_page_putback(struct page *page)
 	struct balloon_dev_info *b_dev_info = balloon_page_device(page);
 	unsigned long flags;
 
+	/* Isolated balloon pages cannot get deflated. */
+	if (WARN_ON_ONCE(!b_dev_info))
+		return;
+
 	spin_lock_irqsave(&b_dev_info->pages_lock, flags);
 	list_add(&page->lru, &b_dev_info->pages);
 	b_dev_info->isolated_pages--;
@@ -234,6 +241,10 @@ static int balloon_page_migrate(struct page *newpage, struct page *page,
 	VM_BUG_ON_PAGE(!PageLocked(page), page);
 	VM_BUG_ON_PAGE(!PageLocked(newpage), newpage);
 
+	/* Isolated balloon pages cannot get deflated. */
+	if (WARN_ON_ONCE(!balloon))
+		return -EAGAIN;
+
 	return balloon->migratepage(balloon, newpage, page, mode);
 }
 
-- 
2.49.0
Re: [PATCH v1 13/29] mm/balloon_compaction: stop using __ClearPageMovable()
Posted by Lorenzo Stoakes 3 months, 1 week ago
On Mon, Jun 30, 2025 at 02:59:54PM +0200, David Hildenbrand wrote:
> We can just look at the balloon device (stored in page->private), to see
> if the page is still part of the balloon.
>
> As isolated balloon pages cannot get released (they are taken off the
> balloon list while isolated), we don't have to worry about this case in
> the putback and migration callback. Add a WARN_ON_ONCE for now.
>
> Signed-off-by: David Hildenbrand <david@redhat.com>

Seems reasonable, one comment below re: comment.

Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>

> ---
>  include/linux/balloon_compaction.h |  4 +---
>  mm/balloon_compaction.c            | 11 +++++++++++
>  2 files changed, 12 insertions(+), 3 deletions(-)
>
> diff --git a/include/linux/balloon_compaction.h b/include/linux/balloon_compaction.h
> index bfc6e50bd004b..9bce8e9f5018c 100644
> --- a/include/linux/balloon_compaction.h
> +++ b/include/linux/balloon_compaction.h
> @@ -136,10 +136,8 @@ static inline gfp_t balloon_mapping_gfp_mask(void)
>   */
>  static inline void balloon_page_finalize(struct page *page)
>  {
> -	if (IS_ENABLED(CONFIG_BALLOON_COMPACTION)) {
> -		__ClearPageMovable(page);
> +	if (IS_ENABLED(CONFIG_BALLOON_COMPACTION))
>  		set_page_private(page, 0);
> -	}
>  	/* PageOffline is sticky until the page is freed to the buddy. */
>  }
>
> diff --git a/mm/balloon_compaction.c b/mm/balloon_compaction.c
> index ec176bdb8a78b..e4f1a122d786b 100644
> --- a/mm/balloon_compaction.c
> +++ b/mm/balloon_compaction.c
> @@ -206,6 +206,9 @@ static bool balloon_page_isolate(struct page *page, isolate_mode_t mode)
>  	struct balloon_dev_info *b_dev_info = balloon_page_device(page);
>  	unsigned long flags;
>
> +	if (!b_dev_info)
> +		return false;
> +
>  	spin_lock_irqsave(&b_dev_info->pages_lock, flags);
>  	list_del(&page->lru);
>  	b_dev_info->isolated_pages++;
> @@ -219,6 +222,10 @@ static void balloon_page_putback(struct page *page)
>  	struct balloon_dev_info *b_dev_info = balloon_page_device(page);
>  	unsigned long flags;
>
> +	/* Isolated balloon pages cannot get deflated. */
> +	if (WARN_ON_ONCE(!b_dev_info))
> +		return;
> +
>  	spin_lock_irqsave(&b_dev_info->pages_lock, flags);
>  	list_add(&page->lru, &b_dev_info->pages);
>  	b_dev_info->isolated_pages--;
> @@ -234,6 +241,10 @@ static int balloon_page_migrate(struct page *newpage, struct page *page,
>  	VM_BUG_ON_PAGE(!PageLocked(page), page);
>  	VM_BUG_ON_PAGE(!PageLocked(newpage), newpage);
>
> +	/* Isolated balloon pages cannot get deflated. */

Hm do you mean migrated?

> +	if (WARN_ON_ONCE(!balloon))
> +		return -EAGAIN;
> +
>  	return balloon->migratepage(balloon, newpage, page, mode);
>  }
>
> --
> 2.49.0
>
Re: [PATCH v1 13/29] mm/balloon_compaction: stop using __ClearPageMovable()
Posted by David Hildenbrand 3 months, 1 week ago
On 01.07.25 12:03, Lorenzo Stoakes wrote:
> On Mon, Jun 30, 2025 at 02:59:54PM +0200, David Hildenbrand wrote:
>> We can just look at the balloon device (stored in page->private), to see
>> if the page is still part of the balloon.
>>
>> As isolated balloon pages cannot get released (they are taken off the
>> balloon list while isolated), we don't have to worry about this case in
>> the putback and migration callback. Add a WARN_ON_ONCE for now.
>>
>> Signed-off-by: David Hildenbrand <david@redhat.com>
> 
> Seems reasonable, one comment below re: comment.
> 
> Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
> 
>> ---
>>   include/linux/balloon_compaction.h |  4 +---
>>   mm/balloon_compaction.c            | 11 +++++++++++
>>   2 files changed, 12 insertions(+), 3 deletions(-)
>>
>> diff --git a/include/linux/balloon_compaction.h b/include/linux/balloon_compaction.h
>> index bfc6e50bd004b..9bce8e9f5018c 100644
>> --- a/include/linux/balloon_compaction.h
>> +++ b/include/linux/balloon_compaction.h
>> @@ -136,10 +136,8 @@ static inline gfp_t balloon_mapping_gfp_mask(void)
>>    */
>>   static inline void balloon_page_finalize(struct page *page)
>>   {
>> -	if (IS_ENABLED(CONFIG_BALLOON_COMPACTION)) {
>> -		__ClearPageMovable(page);
>> +	if (IS_ENABLED(CONFIG_BALLOON_COMPACTION))
>>   		set_page_private(page, 0);
>> -	}
>>   	/* PageOffline is sticky until the page is freed to the buddy. */
>>   }
>>
>> diff --git a/mm/balloon_compaction.c b/mm/balloon_compaction.c
>> index ec176bdb8a78b..e4f1a122d786b 100644
>> --- a/mm/balloon_compaction.c
>> +++ b/mm/balloon_compaction.c
>> @@ -206,6 +206,9 @@ static bool balloon_page_isolate(struct page *page, isolate_mode_t mode)
>>   	struct balloon_dev_info *b_dev_info = balloon_page_device(page);
>>   	unsigned long flags;
>>
>> +	if (!b_dev_info)
>> +		return false;
>> +
>>   	spin_lock_irqsave(&b_dev_info->pages_lock, flags);
>>   	list_del(&page->lru);
>>   	b_dev_info->isolated_pages++;
>> @@ -219,6 +222,10 @@ static void balloon_page_putback(struct page *page)
>>   	struct balloon_dev_info *b_dev_info = balloon_page_device(page);
>>   	unsigned long flags;
>>
>> +	/* Isolated balloon pages cannot get deflated. */
>> +	if (WARN_ON_ONCE(!b_dev_info))
>> +		return;
>> +
>>   	spin_lock_irqsave(&b_dev_info->pages_lock, flags);
>>   	list_add(&page->lru, &b_dev_info->pages);
>>   	b_dev_info->isolated_pages--;
>> @@ -234,6 +241,10 @@ static int balloon_page_migrate(struct page *newpage, struct page *page,
>>   	VM_BUG_ON_PAGE(!PageLocked(page), page);
>>   	VM_BUG_ON_PAGE(!PageLocked(newpage), newpage);
>>
>> +	/* Isolated balloon pages cannot get deflated. */
> 
> Hm do you mean migrated?

Well, they can get migrated, obviously :)

Deflation would be the other code path where we would remove a balloon 
page from the balloon, and invalidate page->private, suddenly seeing 
!b_dev_info here.

But that cannot happen, as isolation takes them off the balloon list. So 
deflating the balloon cannot find them until un-isolated.

-- 
Cheers,

David / dhildenb
Re: [PATCH v1 13/29] mm/balloon_compaction: stop using __ClearPageMovable()
Posted by Lorenzo Stoakes 3 months, 1 week ago
On Tue, Jul 01, 2025 at 12:19:47PM +0200, David Hildenbrand wrote:
> On 01.07.25 12:03, Lorenzo Stoakes wrote:
> > On Mon, Jun 30, 2025 at 02:59:54PM +0200, David Hildenbrand wrote:
> > > We can just look at the balloon device (stored in page->private), to see
> > > if the page is still part of the balloon.
> > >
> > > As isolated balloon pages cannot get released (they are taken off the
> > > balloon list while isolated), we don't have to worry about this case in
> > > the putback and migration callback. Add a WARN_ON_ONCE for now.
> > >
> > > Signed-off-by: David Hildenbrand <david@redhat.com>
> >
> > Seems reasonable, one comment below re: comment.
> >
> > Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
> >
> > > ---
> > >   include/linux/balloon_compaction.h |  4 +---
> > >   mm/balloon_compaction.c            | 11 +++++++++++
> > >   2 files changed, 12 insertions(+), 3 deletions(-)
> > >
> > > diff --git a/include/linux/balloon_compaction.h b/include/linux/balloon_compaction.h
> > > index bfc6e50bd004b..9bce8e9f5018c 100644
> > > --- a/include/linux/balloon_compaction.h
> > > +++ b/include/linux/balloon_compaction.h
> > > @@ -136,10 +136,8 @@ static inline gfp_t balloon_mapping_gfp_mask(void)
> > >    */
> > >   static inline void balloon_page_finalize(struct page *page)
> > >   {
> > > -	if (IS_ENABLED(CONFIG_BALLOON_COMPACTION)) {
> > > -		__ClearPageMovable(page);
> > > +	if (IS_ENABLED(CONFIG_BALLOON_COMPACTION))
> > >   		set_page_private(page, 0);
> > > -	}
> > >   	/* PageOffline is sticky until the page is freed to the buddy. */
> > >   }
> > >
> > > diff --git a/mm/balloon_compaction.c b/mm/balloon_compaction.c
> > > index ec176bdb8a78b..e4f1a122d786b 100644
> > > --- a/mm/balloon_compaction.c
> > > +++ b/mm/balloon_compaction.c
> > > @@ -206,6 +206,9 @@ static bool balloon_page_isolate(struct page *page, isolate_mode_t mode)
> > >   	struct balloon_dev_info *b_dev_info = balloon_page_device(page);
> > >   	unsigned long flags;
> > >
> > > +	if (!b_dev_info)
> > > +		return false;
> > > +
> > >   	spin_lock_irqsave(&b_dev_info->pages_lock, flags);
> > >   	list_del(&page->lru);
> > >   	b_dev_info->isolated_pages++;
> > > @@ -219,6 +222,10 @@ static void balloon_page_putback(struct page *page)
> > >   	struct balloon_dev_info *b_dev_info = balloon_page_device(page);
> > >   	unsigned long flags;
> > >
> > > +	/* Isolated balloon pages cannot get deflated. */
> > > +	if (WARN_ON_ONCE(!b_dev_info))
> > > +		return;
> > > +
> > >   	spin_lock_irqsave(&b_dev_info->pages_lock, flags);
> > >   	list_add(&page->lru, &b_dev_info->pages);
> > >   	b_dev_info->isolated_pages--;
> > > @@ -234,6 +241,10 @@ static int balloon_page_migrate(struct page *newpage, struct page *page,
> > >   	VM_BUG_ON_PAGE(!PageLocked(page), page);
> > >   	VM_BUG_ON_PAGE(!PageLocked(newpage), newpage);
> > >
> > > +	/* Isolated balloon pages cannot get deflated. */
> >
> > Hm do you mean migrated?
>
> Well, they can get migrated, obviously :)

Right yeah we isolate to migrate :P

I guess I was confused by the 'get' deflated, wrongly thinking putback was doing
this (I got confused about terminology), but I see in balloon_page_dequeue() we
balloon_page_finalize() which sets page->private = NULL which is what
balloon_page_device() returns.

OK I guess this is fine... :)

An aside, unrelated tot his series: it'd be nice to use 'deflate' consistently
in this code. We do __count_vm_event(BALLOON_DEFLATE) in
balloon_page_list_dequeue() but say 'deflate' nowhere else... well before this
patch :)

>
> Deflation would be the other code path where we would remove a balloon page
> from the balloon, and invalidate page->private, suddenly seeing !b_dev_info
> here.

ACtually it's 'balloon' not b_dev_info. Kind of out of scope for this patch but
would be good to rename.

>
> But that cannot happen, as isolation takes them off the balloon list. So
> deflating the balloon cannot find them until un-isolated.

Ack.

>
> --
> Cheers,
>
> David / dhildenb
>
Re: [PATCH v1 13/29] mm/balloon_compaction: stop using __ClearPageMovable()
Posted by David Hildenbrand 3 months, 1 week ago
> OK I guess this is fine... :)
> 
> An aside, unrelated tot his series: it'd be nice to use 'deflate' consistently
> in this code. We do __count_vm_event(BALLOON_DEFLATE) in
> balloon_page_list_dequeue() but say 'deflate' nowhere else... well before this
> patch :)

Right, dequeue is actually deflate, because one couldn't use that 
function for anything else as it stands.

TODO list ... :)

-- 
Cheers,

David / dhildenb