2019-05-19 15:08:55 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2012-12-12 04:02:38 +04:00
/*
* mm / balloon_compaction . c
*
* Common interface for making balloon pages movable by compaction .
*
* Copyright ( C ) 2012 , Red Hat , Inc . Rafael Aquini < aquini @ redhat . com >
*/
# include <linux/mm.h>
# include <linux/slab.h>
# include <linux/export.h>
# include <linux/balloon_compaction.h>
2019-04-25 14:54:42 +03:00
static void balloon_page_enqueue_one ( struct balloon_dev_info * b_dev_info ,
struct page * page )
{
/*
* Block others from accessing the ' page ' when we get around to
* establishing additional references . We should be the only one
* holding a reference to the ' page ' at this point . If we are not , then
* memory corruption is possible and we should stop execution .
*/
BUG_ON ( ! trylock_page ( page ) ) ;
balloon_page_insert ( b_dev_info , page ) ;
unlock_page ( page ) ;
__count_vm_event ( BALLOON_INFLATE ) ;
}
/**
* balloon_page_list_enqueue ( ) - inserts a list of pages into the balloon page
* list .
* @ b_dev_info : balloon device descriptor where we will insert a new page to
* @ pages : pages to enqueue - allocated using balloon_page_alloc .
*
2019-07-18 15:19:24 +03:00
* Driver must call this function to properly enqueue balloon pages before
* definitively removing them from the guest system .
2019-04-25 14:54:42 +03:00
*
* Return : number of pages that were enqueued .
*/
size_t balloon_page_list_enqueue ( struct balloon_dev_info * b_dev_info ,
struct list_head * pages )
{
struct page * page , * tmp ;
unsigned long flags ;
size_t n_pages = 0 ;
spin_lock_irqsave ( & b_dev_info - > pages_lock , flags ) ;
list_for_each_entry_safe ( page , tmp , pages , lru ) {
2019-07-18 12:27:20 +03:00
list_del ( & page - > lru ) ;
2019-04-25 14:54:42 +03:00
balloon_page_enqueue_one ( b_dev_info , page ) ;
n_pages + + ;
}
spin_unlock_irqrestore ( & b_dev_info - > pages_lock , flags ) ;
return n_pages ;
}
EXPORT_SYMBOL_GPL ( balloon_page_list_enqueue ) ;
/**
* balloon_page_list_dequeue ( ) - removes pages from balloon ' s page list and
* returns a list of the pages .
2021-05-07 04:06:47 +03:00
* @ b_dev_info : balloon device descriptor where we will grab a page from .
2019-04-25 14:54:42 +03:00
* @ pages : pointer to the list of pages that would be returned to the caller .
* @ n_req_pages : number of requested pages .
*
* Driver must call this function to properly de - allocate a previous enlisted
2019-07-18 15:19:24 +03:00
* balloon pages before definitively releasing it back to the guest system .
2019-04-25 14:54:42 +03:00
* This function tries to remove @ n_req_pages from the ballooned pages and
* return them to the caller in the @ pages list .
*
2019-07-18 15:19:24 +03:00
* Note that this function may fail to dequeue some pages even if the balloon
* isn ' t empty - since the page list can be temporarily empty due to compaction
* of isolated pages .
2019-04-25 14:54:42 +03:00
*
* Return : number of pages that were added to the @ pages list .
*/
size_t balloon_page_list_dequeue ( struct balloon_dev_info * b_dev_info ,
struct list_head * pages , size_t n_req_pages )
{
struct page * page , * tmp ;
unsigned long flags ;
size_t n_pages = 0 ;
spin_lock_irqsave ( & b_dev_info - > pages_lock , flags ) ;
list_for_each_entry_safe ( page , tmp , & b_dev_info - > pages , lru ) {
if ( n_pages = = n_req_pages )
break ;
/*
* Block others from accessing the ' page ' while we get around to
* establishing additional references and preparing the ' page '
* to be released by the balloon driver .
*/
if ( ! trylock_page ( page ) )
continue ;
if ( IS_ENABLED ( CONFIG_BALLOON_COMPACTION ) & &
PageIsolated ( page ) ) {
/* raced with isolation */
unlock_page ( page ) ;
continue ;
}
balloon_page_delete ( page ) ;
__count_vm_event ( BALLOON_DEFLATE ) ;
list_add ( & page - > lru , pages ) ;
unlock_page ( page ) ;
n_pages + + ;
}
spin_unlock_irqrestore ( & b_dev_info - > pages_lock , flags ) ;
return n_pages ;
}
EXPORT_SYMBOL_GPL ( balloon_page_list_dequeue ) ;
2017-10-13 16:11:48 +03:00
/*
* balloon_page_alloc - allocates a new page for insertion into the balloon
2019-07-18 15:19:24 +03:00
* page list .
2017-10-13 16:11:48 +03:00
*
2019-07-18 15:19:24 +03:00
* Driver must call this function to properly allocate a new balloon page .
* Driver must call balloon_page_enqueue before definitively removing the page
* from the guest system .
*
* Return : struct page for the allocated page or NULL on allocation failure .
2017-10-13 16:11:48 +03:00
*/
struct page * balloon_page_alloc ( void )
{
struct page * page = alloc_page ( balloon_mapping_gfp_mask ( ) |
2019-08-20 12:16:46 +03:00
__GFP_NOMEMALLOC | __GFP_NORETRY |
__GFP_NOWARN ) ;
2017-10-13 16:11:48 +03:00
return page ;
}
EXPORT_SYMBOL_GPL ( balloon_page_alloc ) ;
2012-12-12 04:02:38 +04:00
/*
2019-07-18 12:27:20 +03:00
* balloon_page_enqueue - inserts a new page into the balloon page list .
*
2019-07-18 15:19:24 +03:00
* @ b_dev_info : balloon device descriptor where we will insert a new page
2017-10-13 16:11:48 +03:00
* @ page : new page to enqueue - allocated using balloon_page_alloc .
2012-12-12 04:02:38 +04:00
*
2019-07-18 15:19:24 +03:00
* Drivers must call this function to properly enqueue a new allocated balloon
* page before definitively removing the page from the guest system .
2019-07-18 12:27:20 +03:00
*
2019-07-18 15:19:24 +03:00
* Drivers must not call balloon_page_enqueue on pages that have been pushed to
* a list with balloon_page_push before removing them with balloon_page_pop . To
* enqueue a list of pages , use balloon_page_list_enqueue instead .
2012-12-12 04:02:38 +04:00
*/
2017-10-13 16:11:48 +03:00
void balloon_page_enqueue ( struct balloon_dev_info * b_dev_info ,
struct page * page )
2012-12-12 04:02:38 +04:00
{
unsigned long flags ;
spin_lock_irqsave ( & b_dev_info - > pages_lock , flags ) ;
2019-04-25 14:54:42 +03:00
balloon_page_enqueue_one ( b_dev_info , page ) ;
2012-12-12 04:02:38 +04:00
spin_unlock_irqrestore ( & b_dev_info - > pages_lock , flags ) ;
}
EXPORT_SYMBOL_GPL ( balloon_page_enqueue ) ;
/*
* balloon_page_dequeue - removes a page from balloon ' s page list and returns
2019-07-18 15:19:24 +03:00
* its address to allow the driver to release the page .
2021-05-07 04:06:47 +03:00
* @ b_dev_info : balloon device descriptor where we will grab a page from .
2012-12-12 04:02:38 +04:00
*
2019-07-18 15:19:24 +03:00
* Driver must call this function to properly dequeue a previously enqueued page
* before definitively releasing it back to the guest system .
*
* Caller must perform its own accounting to ensure that this
* function is called only if some pages are actually enqueued .
*
* Note that this function may fail to dequeue some pages even if there are
* some enqueued pages - since the page list can be temporarily empty due to
* the compaction of isolated pages .
*
* TODO : remove the caller accounting requirements , and allow caller to wait
* until all pages can be dequeued .
*
* Return : struct page for the dequeued page , or NULL if no page was dequeued .
2012-12-12 04:02:38 +04:00
*/
struct page * balloon_page_dequeue ( struct balloon_dev_info * b_dev_info )
{
unsigned long flags ;
2019-04-25 14:54:42 +03:00
LIST_HEAD ( pages ) ;
int n_pages ;
2012-12-12 04:02:38 +04:00
2019-04-25 14:54:42 +03:00
n_pages = balloon_page_list_dequeue ( b_dev_info , & pages , 1 ) ;
2012-12-12 04:02:38 +04:00
2019-04-25 14:54:42 +03:00
if ( n_pages ! = 1 ) {
2012-12-12 04:02:38 +04:00
/*
* If we are unable to dequeue a balloon page because the page
2019-07-18 15:19:24 +03:00
* list is empty and there are no isolated pages , then something
2012-12-12 04:02:38 +04:00
* went out of track and some balloon pages are lost .
2019-07-18 15:19:24 +03:00
* BUG ( ) here , otherwise the balloon driver may get stuck in
2012-12-12 04:02:38 +04:00
* an infinite loop while attempting to release all its pages .
*/
spin_lock_irqsave ( & b_dev_info - > pages_lock , flags ) ;
if ( unlikely ( list_empty ( & b_dev_info - > pages ) & &
! b_dev_info - > isolated_pages ) )
BUG ( ) ;
spin_unlock_irqrestore ( & b_dev_info - > pages_lock , flags ) ;
2019-04-25 14:54:42 +03:00
return NULL ;
2012-12-12 04:02:38 +04:00
}
2019-04-25 14:54:42 +03:00
return list_first_entry ( & pages , struct page , lru ) ;
2012-12-12 04:02:38 +04:00
}
EXPORT_SYMBOL_GPL ( balloon_page_dequeue ) ;
# ifdef CONFIG_BALLOON_COMPACTION
2022-01-25 16:22:21 +03:00
static bool balloon_page_isolate ( struct page * page , isolate_mode_t mode )
2016-07-27 01:23:09 +03:00
2012-12-12 04:02:38 +04:00
{
2014-10-10 02:29:29 +04:00
struct balloon_dev_info * b_dev_info = balloon_page_device ( page ) ;
2012-12-12 04:02:38 +04:00
unsigned long flags ;
2014-10-10 02:29:27 +04:00
2012-12-12 04:02:38 +04:00
spin_lock_irqsave ( & b_dev_info - > pages_lock , flags ) ;
list_del ( & page - > lru ) ;
b_dev_info - > isolated_pages + + ;
spin_unlock_irqrestore ( & b_dev_info - > pages_lock , flags ) ;
2016-07-27 01:23:09 +03:00
return true ;
2012-12-12 04:02:38 +04:00
}
2022-01-25 16:22:21 +03:00
static void balloon_page_putback ( struct page * page )
2012-12-12 04:02:38 +04:00
{
2014-10-10 02:29:29 +04:00
struct balloon_dev_info * b_dev_info = balloon_page_device ( page ) ;
2012-12-12 04:02:38 +04:00
unsigned long flags ;
2014-10-10 02:29:27 +04:00
2012-12-12 04:02:38 +04:00
spin_lock_irqsave ( & b_dev_info - > pages_lock , flags ) ;
list_add ( & page - > lru , & b_dev_info - > pages ) ;
b_dev_info - > isolated_pages - - ;
spin_unlock_irqrestore ( & b_dev_info - > pages_lock , flags ) ;
}
/* move_to_new_page() counterpart for a ballooned page */
2022-06-07 22:38:48 +03:00
static int balloon_page_migrate ( struct page * newpage , struct page * page ,
2016-07-27 01:23:09 +03:00
enum migrate_mode mode )
2012-12-12 04:02:38 +04:00
{
2014-10-10 02:29:29 +04:00
struct balloon_dev_info * balloon = balloon_page_device ( page ) ;
2012-12-12 04:02:38 +04:00
2017-09-09 02:12:06 +03:00
/*
* We can not easily support the no copy case here so ignore it as it
2019-07-18 15:19:24 +03:00
* is unlikely to be used with balloon pages . See include / linux / hmm . h
* for a user of the MIGRATE_SYNC_NO_COPY mode .
2017-09-09 02:12:06 +03:00
*/
if ( mode = = MIGRATE_SYNC_NO_COPY )
return - EINVAL ;
2015-11-06 05:49:49 +03:00
VM_BUG_ON_PAGE ( ! PageLocked ( page ) , page ) ;
VM_BUG_ON_PAGE ( ! PageLocked ( newpage ) , newpage ) ;
2012-12-12 04:02:38 +04:00
2016-07-27 01:23:09 +03:00
return balloon - > migratepage ( balloon , newpage , page , mode ) ;
}
2012-12-12 04:02:38 +04:00
2022-06-07 22:38:48 +03:00
const struct movable_operations balloon_mops = {
. migrate_page = balloon_page_migrate ,
2016-07-27 01:23:09 +03:00
. isolate_page = balloon_page_isolate ,
. putback_page = balloon_page_putback ,
} ;
2022-06-07 22:38:48 +03:00
EXPORT_SYMBOL_GPL ( balloon_mops ) ;
2012-12-12 04:02:38 +04:00
# endif /* CONFIG_BALLOON_COMPACTION */