xref: /linux/mm/balloon.c (revision 4cff5c05e076d2ee4e34122aa956b84a2eaac587)
125b48b4cSDavid Hildenbrand (Red Hat) // SPDX-License-Identifier: GPL-2.0-only
225b48b4cSDavid Hildenbrand (Red Hat) /*
325b48b4cSDavid Hildenbrand (Red Hat)  * Common interface for implementing a memory balloon, including support
425b48b4cSDavid Hildenbrand (Red Hat)  * for migration of pages inflated in a memory balloon.
525b48b4cSDavid Hildenbrand (Red Hat)  *
625b48b4cSDavid Hildenbrand (Red Hat)  * Copyright (C) 2012, Red Hat, Inc.  Rafael Aquini <aquini@redhat.com>
725b48b4cSDavid Hildenbrand (Red Hat)  */
825b48b4cSDavid Hildenbrand (Red Hat) #include <linux/mm.h>
925b48b4cSDavid Hildenbrand (Red Hat) #include <linux/slab.h>
1025b48b4cSDavid Hildenbrand (Red Hat) #include <linux/export.h>
1125b48b4cSDavid Hildenbrand (Red Hat) #include <linux/balloon.h>
1225b48b4cSDavid Hildenbrand (Red Hat) 
1325b48b4cSDavid Hildenbrand (Red Hat) /*
1425b48b4cSDavid Hildenbrand (Red Hat)  * Lock protecting the balloon_dev_info of all devices. We don't really
1525b48b4cSDavid Hildenbrand (Red Hat)  * expect more than one device.
1625b48b4cSDavid Hildenbrand (Red Hat)  */
1725b48b4cSDavid Hildenbrand (Red Hat) static DEFINE_SPINLOCK(balloon_pages_lock);
1825b48b4cSDavid Hildenbrand (Red Hat) 
1925b48b4cSDavid Hildenbrand (Red Hat) /**
2025b48b4cSDavid Hildenbrand (Red Hat)  * balloon_page_insert - insert a page into the balloon's page list and make
2125b48b4cSDavid Hildenbrand (Red Hat)  *			 the page->private assignment accordingly.
2225b48b4cSDavid Hildenbrand (Red Hat)  * @balloon : pointer to balloon device
2325b48b4cSDavid Hildenbrand (Red Hat)  * @page    : page to be assigned as a 'balloon page'
2425b48b4cSDavid Hildenbrand (Red Hat)  *
2525b48b4cSDavid Hildenbrand (Red Hat)  * Caller must ensure the balloon_pages_lock is held.
2625b48b4cSDavid Hildenbrand (Red Hat)  */
2725b48b4cSDavid Hildenbrand (Red Hat) static void balloon_page_insert(struct balloon_dev_info *balloon,
2825b48b4cSDavid Hildenbrand (Red Hat) 				       struct page *page)
2925b48b4cSDavid Hildenbrand (Red Hat) {
3025b48b4cSDavid Hildenbrand (Red Hat) 	lockdep_assert_held(&balloon_pages_lock);
3125b48b4cSDavid Hildenbrand (Red Hat) 	__SetPageOffline(page);
32*cd8e95d8SDavid Hildenbrand (Red Hat) 	if (IS_ENABLED(CONFIG_BALLOON_MIGRATION)) {
3325b48b4cSDavid Hildenbrand (Red Hat) 		SetPageMovableOps(page);
3425b48b4cSDavid Hildenbrand (Red Hat) 		set_page_private(page, (unsigned long)balloon);
3525b48b4cSDavid Hildenbrand (Red Hat) 	}
3625b48b4cSDavid Hildenbrand (Red Hat) 	list_add(&page->lru, &balloon->pages);
3725b48b4cSDavid Hildenbrand (Red Hat) }
3825b48b4cSDavid Hildenbrand (Red Hat) 
3925b48b4cSDavid Hildenbrand (Red Hat) /**
4025b48b4cSDavid Hildenbrand (Red Hat)  * balloon_page_finalize - prepare a balloon page that was removed from the
4125b48b4cSDavid Hildenbrand (Red Hat)  *			   balloon list for release to the page allocator
4225b48b4cSDavid Hildenbrand (Red Hat)  * @page: page to be released to the page allocator
4325b48b4cSDavid Hildenbrand (Red Hat)  *
4425b48b4cSDavid Hildenbrand (Red Hat)  * Caller must ensure the balloon_pages_lock is held.
4525b48b4cSDavid Hildenbrand (Red Hat)  */
4625b48b4cSDavid Hildenbrand (Red Hat) static void balloon_page_finalize(struct page *page)
4725b48b4cSDavid Hildenbrand (Red Hat) {
4825b48b4cSDavid Hildenbrand (Red Hat) 	lockdep_assert_held(&balloon_pages_lock);
49*cd8e95d8SDavid Hildenbrand (Red Hat) 	if (IS_ENABLED(CONFIG_BALLOON_MIGRATION))
5025b48b4cSDavid Hildenbrand (Red Hat) 		set_page_private(page, 0);
5125b48b4cSDavid Hildenbrand (Red Hat) 	/* PageOffline is sticky until the page is freed to the buddy. */
5225b48b4cSDavid Hildenbrand (Red Hat) }
5325b48b4cSDavid Hildenbrand (Red Hat) 
5425b48b4cSDavid Hildenbrand (Red Hat) static void balloon_page_enqueue_one(struct balloon_dev_info *b_dev_info,
5525b48b4cSDavid Hildenbrand (Red Hat) 				     struct page *page)
5625b48b4cSDavid Hildenbrand (Red Hat) {
5725b48b4cSDavid Hildenbrand (Red Hat) 	balloon_page_insert(b_dev_info, page);
5825b48b4cSDavid Hildenbrand (Red Hat) 	if (b_dev_info->adjust_managed_page_count)
5925b48b4cSDavid Hildenbrand (Red Hat) 		adjust_managed_page_count(page, -1);
6025b48b4cSDavid Hildenbrand (Red Hat) 	__count_vm_event(BALLOON_INFLATE);
6125b48b4cSDavid Hildenbrand (Red Hat) 	inc_node_page_state(page, NR_BALLOON_PAGES);
6225b48b4cSDavid Hildenbrand (Red Hat) }
6325b48b4cSDavid Hildenbrand (Red Hat) 
6425b48b4cSDavid Hildenbrand (Red Hat) /**
6525b48b4cSDavid Hildenbrand (Red Hat)  * balloon_page_list_enqueue() - inserts a list of pages into the balloon page
6625b48b4cSDavid Hildenbrand (Red Hat)  *				 list.
6725b48b4cSDavid Hildenbrand (Red Hat)  * @b_dev_info: balloon device descriptor where we will insert a new page to
6825b48b4cSDavid Hildenbrand (Red Hat)  * @pages: pages to enqueue - allocated using balloon_page_alloc.
6925b48b4cSDavid Hildenbrand (Red Hat)  *
7025b48b4cSDavid Hildenbrand (Red Hat)  * Driver must call this function to properly enqueue balloon pages before
7125b48b4cSDavid Hildenbrand (Red Hat)  * definitively removing them from the guest system.
7225b48b4cSDavid Hildenbrand (Red Hat)  *
7325b48b4cSDavid Hildenbrand (Red Hat)  * Return: number of pages that were enqueued.
7425b48b4cSDavid Hildenbrand (Red Hat)  */
7525b48b4cSDavid Hildenbrand (Red Hat) size_t balloon_page_list_enqueue(struct balloon_dev_info *b_dev_info,
7625b48b4cSDavid Hildenbrand (Red Hat) 				 struct list_head *pages)
7725b48b4cSDavid Hildenbrand (Red Hat) {
7825b48b4cSDavid Hildenbrand (Red Hat) 	struct page *page, *tmp;
7925b48b4cSDavid Hildenbrand (Red Hat) 	unsigned long flags;
8025b48b4cSDavid Hildenbrand (Red Hat) 	size_t n_pages = 0;
8125b48b4cSDavid Hildenbrand (Red Hat) 
8225b48b4cSDavid Hildenbrand (Red Hat) 	spin_lock_irqsave(&balloon_pages_lock, flags);
8325b48b4cSDavid Hildenbrand (Red Hat) 	list_for_each_entry_safe(page, tmp, pages, lru) {
8425b48b4cSDavid Hildenbrand (Red Hat) 		list_del(&page->lru);
8525b48b4cSDavid Hildenbrand (Red Hat) 		balloon_page_enqueue_one(b_dev_info, page);
8625b48b4cSDavid Hildenbrand (Red Hat) 		n_pages++;
8725b48b4cSDavid Hildenbrand (Red Hat) 	}
8825b48b4cSDavid Hildenbrand (Red Hat) 	spin_unlock_irqrestore(&balloon_pages_lock, flags);
8925b48b4cSDavid Hildenbrand (Red Hat) 	return n_pages;
9025b48b4cSDavid Hildenbrand (Red Hat) }
9125b48b4cSDavid Hildenbrand (Red Hat) EXPORT_SYMBOL_GPL(balloon_page_list_enqueue);
9225b48b4cSDavid Hildenbrand (Red Hat) 
9325b48b4cSDavid Hildenbrand (Red Hat) /**
9425b48b4cSDavid Hildenbrand (Red Hat)  * balloon_page_list_dequeue() - removes pages from balloon's page list and
9525b48b4cSDavid Hildenbrand (Red Hat)  *				 returns a list of the pages.
9625b48b4cSDavid Hildenbrand (Red Hat)  * @b_dev_info: balloon device descriptor where we will grab a page from.
9725b48b4cSDavid Hildenbrand (Red Hat)  * @pages: pointer to the list of pages that would be returned to the caller.
9825b48b4cSDavid Hildenbrand (Red Hat)  * @n_req_pages: number of requested pages.
9925b48b4cSDavid Hildenbrand (Red Hat)  *
10025b48b4cSDavid Hildenbrand (Red Hat)  * Driver must call this function to properly de-allocate a previous enlisted
10125b48b4cSDavid Hildenbrand (Red Hat)  * balloon pages before definitively releasing it back to the guest system.
10225b48b4cSDavid Hildenbrand (Red Hat)  * This function tries to remove @n_req_pages from the ballooned pages and
10325b48b4cSDavid Hildenbrand (Red Hat)  * return them to the caller in the @pages list.
10425b48b4cSDavid Hildenbrand (Red Hat)  *
10525b48b4cSDavid Hildenbrand (Red Hat)  * Note that this function may fail to dequeue some pages even if the balloon
10625b48b4cSDavid Hildenbrand (Red Hat)  * isn't empty - since the page list can be temporarily empty due to compaction
10725b48b4cSDavid Hildenbrand (Red Hat)  * of isolated pages.
10825b48b4cSDavid Hildenbrand (Red Hat)  *
10925b48b4cSDavid Hildenbrand (Red Hat)  * Return: number of pages that were added to the @pages list.
11025b48b4cSDavid Hildenbrand (Red Hat)  */
11125b48b4cSDavid Hildenbrand (Red Hat) size_t balloon_page_list_dequeue(struct balloon_dev_info *b_dev_info,
11225b48b4cSDavid Hildenbrand (Red Hat) 				 struct list_head *pages, size_t n_req_pages)
11325b48b4cSDavid Hildenbrand (Red Hat) {
11425b48b4cSDavid Hildenbrand (Red Hat) 	struct page *page, *tmp;
11525b48b4cSDavid Hildenbrand (Red Hat) 	unsigned long flags;
11625b48b4cSDavid Hildenbrand (Red Hat) 	size_t n_pages = 0;
11725b48b4cSDavid Hildenbrand (Red Hat) 
11825b48b4cSDavid Hildenbrand (Red Hat) 	spin_lock_irqsave(&balloon_pages_lock, flags);
11925b48b4cSDavid Hildenbrand (Red Hat) 	list_for_each_entry_safe(page, tmp, &b_dev_info->pages, lru) {
12025b48b4cSDavid Hildenbrand (Red Hat) 		if (n_pages == n_req_pages)
12125b48b4cSDavid Hildenbrand (Red Hat) 			break;
12225b48b4cSDavid Hildenbrand (Red Hat) 		list_del(&page->lru);
12325b48b4cSDavid Hildenbrand (Red Hat) 		if (b_dev_info->adjust_managed_page_count)
12425b48b4cSDavid Hildenbrand (Red Hat) 			adjust_managed_page_count(page, 1);
12525b48b4cSDavid Hildenbrand (Red Hat) 		balloon_page_finalize(page);
12625b48b4cSDavid Hildenbrand (Red Hat) 		__count_vm_event(BALLOON_DEFLATE);
12725b48b4cSDavid Hildenbrand (Red Hat) 		list_add(&page->lru, pages);
12825b48b4cSDavid Hildenbrand (Red Hat) 		dec_node_page_state(page, NR_BALLOON_PAGES);
12925b48b4cSDavid Hildenbrand (Red Hat) 		n_pages++;
13025b48b4cSDavid Hildenbrand (Red Hat) 	}
13125b48b4cSDavid Hildenbrand (Red Hat) 	spin_unlock_irqrestore(&balloon_pages_lock, flags);
13225b48b4cSDavid Hildenbrand (Red Hat) 
13325b48b4cSDavid Hildenbrand (Red Hat) 	return n_pages;
13425b48b4cSDavid Hildenbrand (Red Hat) }
13525b48b4cSDavid Hildenbrand (Red Hat) EXPORT_SYMBOL_GPL(balloon_page_list_dequeue);
13625b48b4cSDavid Hildenbrand (Red Hat) 
13725b48b4cSDavid Hildenbrand (Red Hat) /**
13825b48b4cSDavid Hildenbrand (Red Hat)  * balloon_page_alloc - allocates a new page for insertion into the balloon
13925b48b4cSDavid Hildenbrand (Red Hat)  *			page list.
14025b48b4cSDavid Hildenbrand (Red Hat)  *
14125b48b4cSDavid Hildenbrand (Red Hat)  * Driver must call this function to properly allocate a new balloon page.
14225b48b4cSDavid Hildenbrand (Red Hat)  * Driver must call balloon_page_enqueue before definitively removing the page
14325b48b4cSDavid Hildenbrand (Red Hat)  * from the guest system.
14425b48b4cSDavid Hildenbrand (Red Hat)  *
14525b48b4cSDavid Hildenbrand (Red Hat)  * Return: struct page for the allocated page or NULL on allocation failure.
14625b48b4cSDavid Hildenbrand (Red Hat)  */
14725b48b4cSDavid Hildenbrand (Red Hat) struct page *balloon_page_alloc(void)
14825b48b4cSDavid Hildenbrand (Red Hat) {
14925b48b4cSDavid Hildenbrand (Red Hat) 	gfp_t gfp_flags = __GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN;
15025b48b4cSDavid Hildenbrand (Red Hat) 
151*cd8e95d8SDavid Hildenbrand (Red Hat) 	if (IS_ENABLED(CONFIG_BALLOON_MIGRATION))
15225b48b4cSDavid Hildenbrand (Red Hat) 		gfp_flags |= GFP_HIGHUSER_MOVABLE;
15325b48b4cSDavid Hildenbrand (Red Hat) 	else
15425b48b4cSDavid Hildenbrand (Red Hat) 		gfp_flags |= GFP_HIGHUSER;
15525b48b4cSDavid Hildenbrand (Red Hat) 
15625b48b4cSDavid Hildenbrand (Red Hat) 	return alloc_page(gfp_flags);
15725b48b4cSDavid Hildenbrand (Red Hat) }
15825b48b4cSDavid Hildenbrand (Red Hat) EXPORT_SYMBOL_GPL(balloon_page_alloc);
15925b48b4cSDavid Hildenbrand (Red Hat) 
16025b48b4cSDavid Hildenbrand (Red Hat) /**
16125b48b4cSDavid Hildenbrand (Red Hat)  * balloon_page_enqueue - inserts a new page into the balloon page list.
16225b48b4cSDavid Hildenbrand (Red Hat)  *
16325b48b4cSDavid Hildenbrand (Red Hat)  * @b_dev_info: balloon device descriptor where we will insert a new page
16425b48b4cSDavid Hildenbrand (Red Hat)  * @page: new page to enqueue - allocated using balloon_page_alloc.
16525b48b4cSDavid Hildenbrand (Red Hat)  *
16625b48b4cSDavid Hildenbrand (Red Hat)  * Drivers must call this function to properly enqueue a new allocated balloon
16725b48b4cSDavid Hildenbrand (Red Hat)  * page before definitively removing the page from the guest system.
16825b48b4cSDavid Hildenbrand (Red Hat)  *
16925b48b4cSDavid Hildenbrand (Red Hat)  * Drivers must not enqueue pages while page->lru is still in
17025b48b4cSDavid Hildenbrand (Red Hat)  * use, and must not use page->lru until a page was unqueued again.
17125b48b4cSDavid Hildenbrand (Red Hat)  */
17225b48b4cSDavid Hildenbrand (Red Hat) void balloon_page_enqueue(struct balloon_dev_info *b_dev_info,
17325b48b4cSDavid Hildenbrand (Red Hat) 			  struct page *page)
17425b48b4cSDavid Hildenbrand (Red Hat) {
17525b48b4cSDavid Hildenbrand (Red Hat) 	unsigned long flags;
17625b48b4cSDavid Hildenbrand (Red Hat) 
17725b48b4cSDavid Hildenbrand (Red Hat) 	spin_lock_irqsave(&balloon_pages_lock, flags);
17825b48b4cSDavid Hildenbrand (Red Hat) 	balloon_page_enqueue_one(b_dev_info, page);
17925b48b4cSDavid Hildenbrand (Red Hat) 	spin_unlock_irqrestore(&balloon_pages_lock, flags);
18025b48b4cSDavid Hildenbrand (Red Hat) }
18125b48b4cSDavid Hildenbrand (Red Hat) EXPORT_SYMBOL_GPL(balloon_page_enqueue);
18225b48b4cSDavid Hildenbrand (Red Hat) 
18325b48b4cSDavid Hildenbrand (Red Hat) /**
18425b48b4cSDavid Hildenbrand (Red Hat)  * balloon_page_dequeue - removes a page from balloon's page list and returns
18525b48b4cSDavid Hildenbrand (Red Hat)  *			  its address to allow the driver to release the page.
18625b48b4cSDavid Hildenbrand (Red Hat)  * @b_dev_info: balloon device descriptor where we will grab a page from.
18725b48b4cSDavid Hildenbrand (Red Hat)  *
18825b48b4cSDavid Hildenbrand (Red Hat)  * Driver must call this function to properly dequeue a previously enqueued page
18925b48b4cSDavid Hildenbrand (Red Hat)  * before definitively releasing it back to the guest system.
19025b48b4cSDavid Hildenbrand (Red Hat)  *
19125b48b4cSDavid Hildenbrand (Red Hat)  * Caller must perform its own accounting to ensure that this
19225b48b4cSDavid Hildenbrand (Red Hat)  * function is called only if some pages are actually enqueued.
19325b48b4cSDavid Hildenbrand (Red Hat)  *
19425b48b4cSDavid Hildenbrand (Red Hat)  * Note that this function may fail to dequeue some pages even if there are
19525b48b4cSDavid Hildenbrand (Red Hat)  * some enqueued pages - since the page list can be temporarily empty due to
19625b48b4cSDavid Hildenbrand (Red Hat)  * the compaction of isolated pages.
19725b48b4cSDavid Hildenbrand (Red Hat)  *
19825b48b4cSDavid Hildenbrand (Red Hat)  * TODO: remove the caller accounting requirements, and allow caller to wait
19925b48b4cSDavid Hildenbrand (Red Hat)  * until all pages can be dequeued.
20025b48b4cSDavid Hildenbrand (Red Hat)  *
20125b48b4cSDavid Hildenbrand (Red Hat)  * Return: struct page for the dequeued page, or NULL if no page was dequeued.
20225b48b4cSDavid Hildenbrand (Red Hat)  */
20325b48b4cSDavid Hildenbrand (Red Hat) struct page *balloon_page_dequeue(struct balloon_dev_info *b_dev_info)
20425b48b4cSDavid Hildenbrand (Red Hat) {
20525b48b4cSDavid Hildenbrand (Red Hat) 	unsigned long flags;
20625b48b4cSDavid Hildenbrand (Red Hat) 	LIST_HEAD(pages);
20725b48b4cSDavid Hildenbrand (Red Hat) 	int n_pages;
20825b48b4cSDavid Hildenbrand (Red Hat) 
20925b48b4cSDavid Hildenbrand (Red Hat) 	n_pages = balloon_page_list_dequeue(b_dev_info, &pages, 1);
21025b48b4cSDavid Hildenbrand (Red Hat) 
21125b48b4cSDavid Hildenbrand (Red Hat) 	if (n_pages != 1) {
21225b48b4cSDavid Hildenbrand (Red Hat) 		/*
21325b48b4cSDavid Hildenbrand (Red Hat) 		 * If we are unable to dequeue a balloon page because the page
21425b48b4cSDavid Hildenbrand (Red Hat) 		 * list is empty and there are no isolated pages, then something
21525b48b4cSDavid Hildenbrand (Red Hat) 		 * went out of track and some balloon pages are lost.
21625b48b4cSDavid Hildenbrand (Red Hat) 		 * BUG() here, otherwise the balloon driver may get stuck in
21725b48b4cSDavid Hildenbrand (Red Hat) 		 * an infinite loop while attempting to release all its pages.
21825b48b4cSDavid Hildenbrand (Red Hat) 		 */
21925b48b4cSDavid Hildenbrand (Red Hat) 		spin_lock_irqsave(&balloon_pages_lock, flags);
22025b48b4cSDavid Hildenbrand (Red Hat) 		if (unlikely(list_empty(&b_dev_info->pages) &&
22125b48b4cSDavid Hildenbrand (Red Hat) 			     !b_dev_info->isolated_pages))
22225b48b4cSDavid Hildenbrand (Red Hat) 			BUG();
22325b48b4cSDavid Hildenbrand (Red Hat) 		spin_unlock_irqrestore(&balloon_pages_lock, flags);
22425b48b4cSDavid Hildenbrand (Red Hat) 		return NULL;
22525b48b4cSDavid Hildenbrand (Red Hat) 	}
22625b48b4cSDavid Hildenbrand (Red Hat) 	return list_first_entry(&pages, struct page, lru);
22725b48b4cSDavid Hildenbrand (Red Hat) }
22825b48b4cSDavid Hildenbrand (Red Hat) EXPORT_SYMBOL_GPL(balloon_page_dequeue);
22925b48b4cSDavid Hildenbrand (Red Hat) 
230*cd8e95d8SDavid Hildenbrand (Red Hat) #ifdef CONFIG_BALLOON_MIGRATION
23125b48b4cSDavid Hildenbrand (Red Hat) static struct balloon_dev_info *balloon_page_device(struct page *page)
23225b48b4cSDavid Hildenbrand (Red Hat) {
23325b48b4cSDavid Hildenbrand (Red Hat) 	return (struct balloon_dev_info *)page_private(page);
23425b48b4cSDavid Hildenbrand (Red Hat) }
23525b48b4cSDavid Hildenbrand (Red Hat) 
23625b48b4cSDavid Hildenbrand (Red Hat) static bool balloon_page_isolate(struct page *page, isolate_mode_t mode)
23725b48b4cSDavid Hildenbrand (Red Hat) 
23825b48b4cSDavid Hildenbrand (Red Hat) {
23925b48b4cSDavid Hildenbrand (Red Hat) 	struct balloon_dev_info *b_dev_info;
24025b48b4cSDavid Hildenbrand (Red Hat) 	unsigned long flags;
24125b48b4cSDavid Hildenbrand (Red Hat) 
24225b48b4cSDavid Hildenbrand (Red Hat) 	spin_lock_irqsave(&balloon_pages_lock, flags);
24325b48b4cSDavid Hildenbrand (Red Hat) 	b_dev_info = balloon_page_device(page);
24425b48b4cSDavid Hildenbrand (Red Hat) 	if (!b_dev_info) {
24525b48b4cSDavid Hildenbrand (Red Hat) 		/*
24625b48b4cSDavid Hildenbrand (Red Hat) 		 * The page already got deflated and removed from the
24725b48b4cSDavid Hildenbrand (Red Hat) 		 * balloon list.
24825b48b4cSDavid Hildenbrand (Red Hat) 		 */
24925b48b4cSDavid Hildenbrand (Red Hat) 		spin_unlock_irqrestore(&balloon_pages_lock, flags);
25025b48b4cSDavid Hildenbrand (Red Hat) 		return false;
25125b48b4cSDavid Hildenbrand (Red Hat) 	}
25225b48b4cSDavid Hildenbrand (Red Hat) 	list_del(&page->lru);
25325b48b4cSDavid Hildenbrand (Red Hat) 	b_dev_info->isolated_pages++;
25425b48b4cSDavid Hildenbrand (Red Hat) 	spin_unlock_irqrestore(&balloon_pages_lock, flags);
25525b48b4cSDavid Hildenbrand (Red Hat) 
25625b48b4cSDavid Hildenbrand (Red Hat) 	return true;
25725b48b4cSDavid Hildenbrand (Red Hat) }
25825b48b4cSDavid Hildenbrand (Red Hat) 
25925b48b4cSDavid Hildenbrand (Red Hat) static void balloon_page_putback(struct page *page)
26025b48b4cSDavid Hildenbrand (Red Hat) {
26125b48b4cSDavid Hildenbrand (Red Hat) 	struct balloon_dev_info *b_dev_info = balloon_page_device(page);
26225b48b4cSDavid Hildenbrand (Red Hat) 	unsigned long flags;
26325b48b4cSDavid Hildenbrand (Red Hat) 
26425b48b4cSDavid Hildenbrand (Red Hat) 	/*
26525b48b4cSDavid Hildenbrand (Red Hat) 	 * When we isolated the page, the page was still inflated in a balloon
26625b48b4cSDavid Hildenbrand (Red Hat) 	 * device. As isolated balloon pages cannot get deflated, we still have
26725b48b4cSDavid Hildenbrand (Red Hat) 	 * a balloon device here.
26825b48b4cSDavid Hildenbrand (Red Hat) 	 */
26925b48b4cSDavid Hildenbrand (Red Hat) 	if (WARN_ON_ONCE(!b_dev_info))
27025b48b4cSDavid Hildenbrand (Red Hat) 		return;
27125b48b4cSDavid Hildenbrand (Red Hat) 
27225b48b4cSDavid Hildenbrand (Red Hat) 	spin_lock_irqsave(&balloon_pages_lock, flags);
27325b48b4cSDavid Hildenbrand (Red Hat) 	list_add(&page->lru, &b_dev_info->pages);
27425b48b4cSDavid Hildenbrand (Red Hat) 	b_dev_info->isolated_pages--;
27525b48b4cSDavid Hildenbrand (Red Hat) 	spin_unlock_irqrestore(&balloon_pages_lock, flags);
27625b48b4cSDavid Hildenbrand (Red Hat) }
27725b48b4cSDavid Hildenbrand (Red Hat) 
27825b48b4cSDavid Hildenbrand (Red Hat) static int balloon_page_migrate(struct page *newpage, struct page *page,
27925b48b4cSDavid Hildenbrand (Red Hat) 		enum migrate_mode mode)
28025b48b4cSDavid Hildenbrand (Red Hat) {
28125b48b4cSDavid Hildenbrand (Red Hat) 	struct balloon_dev_info *b_dev_info = balloon_page_device(page);
28225b48b4cSDavid Hildenbrand (Red Hat) 	unsigned long flags;
28325b48b4cSDavid Hildenbrand (Red Hat) 	int rc;
28425b48b4cSDavid Hildenbrand (Red Hat) 
28525b48b4cSDavid Hildenbrand (Red Hat) 	/*
28625b48b4cSDavid Hildenbrand (Red Hat) 	 * When we isolated the page, the page was still inflated in a balloon
28725b48b4cSDavid Hildenbrand (Red Hat) 	 * device. As isolated balloon pages cannot get deflated, we still have
28825b48b4cSDavid Hildenbrand (Red Hat) 	 * a balloon device here.
28925b48b4cSDavid Hildenbrand (Red Hat) 	 */
29025b48b4cSDavid Hildenbrand (Red Hat) 	if (WARN_ON_ONCE(!b_dev_info))
29125b48b4cSDavid Hildenbrand (Red Hat) 		return -EAGAIN;
29225b48b4cSDavid Hildenbrand (Red Hat) 
29325b48b4cSDavid Hildenbrand (Red Hat) 	rc = b_dev_info->migratepage(b_dev_info, newpage, page, mode);
29425b48b4cSDavid Hildenbrand (Red Hat) 	if (rc < 0 && rc != -ENOENT)
29525b48b4cSDavid Hildenbrand (Red Hat) 		return rc;
29625b48b4cSDavid Hildenbrand (Red Hat) 
29725b48b4cSDavid Hildenbrand (Red Hat) 	spin_lock_irqsave(&balloon_pages_lock, flags);
29825b48b4cSDavid Hildenbrand (Red Hat) 	if (!rc) {
29925b48b4cSDavid Hildenbrand (Red Hat) 		/* Insert the new page into the balloon list. */
30025b48b4cSDavid Hildenbrand (Red Hat) 		get_page(newpage);
30125b48b4cSDavid Hildenbrand (Red Hat) 		balloon_page_insert(b_dev_info, newpage);
30225b48b4cSDavid Hildenbrand (Red Hat) 		__count_vm_event(BALLOON_MIGRATE);
30325b48b4cSDavid Hildenbrand (Red Hat) 
30425b48b4cSDavid Hildenbrand (Red Hat) 		if (b_dev_info->adjust_managed_page_count &&
30525b48b4cSDavid Hildenbrand (Red Hat) 		    page_zone(page) != page_zone(newpage)) {
30625b48b4cSDavid Hildenbrand (Red Hat) 			/*
30725b48b4cSDavid Hildenbrand (Red Hat) 			 * When we migrate a page to a different zone we
30825b48b4cSDavid Hildenbrand (Red Hat) 			 * have to fixup the count of both involved zones.
30925b48b4cSDavid Hildenbrand (Red Hat) 			 */
31025b48b4cSDavid Hildenbrand (Red Hat) 			adjust_managed_page_count(page, 1);
31125b48b4cSDavid Hildenbrand (Red Hat) 			adjust_managed_page_count(newpage, -1);
31225b48b4cSDavid Hildenbrand (Red Hat) 		}
31325b48b4cSDavid Hildenbrand (Red Hat) 	} else {
31425b48b4cSDavid Hildenbrand (Red Hat) 		/* Old page was deflated but new page not inflated. */
31525b48b4cSDavid Hildenbrand (Red Hat) 		__count_vm_event(BALLOON_DEFLATE);
31625b48b4cSDavid Hildenbrand (Red Hat) 
31725b48b4cSDavid Hildenbrand (Red Hat) 		if (b_dev_info->adjust_managed_page_count)
31825b48b4cSDavid Hildenbrand (Red Hat) 			adjust_managed_page_count(page, 1);
31925b48b4cSDavid Hildenbrand (Red Hat) 	}
32025b48b4cSDavid Hildenbrand (Red Hat) 
32125b48b4cSDavid Hildenbrand (Red Hat) 	b_dev_info->isolated_pages--;
32225b48b4cSDavid Hildenbrand (Red Hat) 
32325b48b4cSDavid Hildenbrand (Red Hat) 	/* Free the now-deflated page we isolated in balloon_page_isolate(). */
32425b48b4cSDavid Hildenbrand (Red Hat) 	balloon_page_finalize(page);
32525b48b4cSDavid Hildenbrand (Red Hat) 	spin_unlock_irqrestore(&balloon_pages_lock, flags);
32625b48b4cSDavid Hildenbrand (Red Hat) 
32725b48b4cSDavid Hildenbrand (Red Hat) 	put_page(page);
32825b48b4cSDavid Hildenbrand (Red Hat) 
32925b48b4cSDavid Hildenbrand (Red Hat) 	return 0;
33025b48b4cSDavid Hildenbrand (Red Hat) }
33125b48b4cSDavid Hildenbrand (Red Hat) 
33225b48b4cSDavid Hildenbrand (Red Hat) static const struct movable_operations balloon_mops = {
33325b48b4cSDavid Hildenbrand (Red Hat) 	.migrate_page = balloon_page_migrate,
33425b48b4cSDavid Hildenbrand (Red Hat) 	.isolate_page = balloon_page_isolate,
33525b48b4cSDavid Hildenbrand (Red Hat) 	.putback_page = balloon_page_putback,
33625b48b4cSDavid Hildenbrand (Red Hat) };
33725b48b4cSDavid Hildenbrand (Red Hat) 
33825b48b4cSDavid Hildenbrand (Red Hat) static int __init balloon_init(void)
33925b48b4cSDavid Hildenbrand (Red Hat) {
34025b48b4cSDavid Hildenbrand (Red Hat) 	return set_movable_ops(&balloon_mops, PGTY_offline);
34125b48b4cSDavid Hildenbrand (Red Hat) }
34225b48b4cSDavid Hildenbrand (Red Hat) core_initcall(balloon_init);
34325b48b4cSDavid Hildenbrand (Red Hat) 
344*cd8e95d8SDavid Hildenbrand (Red Hat) #endif /* CONFIG_BALLOON_MIGRATION */
345