xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
From: Juergen Gross <jgross@suse.com>
To: xen-devel@lists.xenproject.org, linux-kernel@vger.kernel.org
Cc: "Juergen Gross" <jgross@suse.com>,
	"Boris Ostrovsky" <boris.ostrovsky@oracle.com>,
	"Stefano Stabellini" <sstabellini@kernel.org>,
	stable@vger.kernel.org,
	"Marek Marczykowski-Górecki" <marmarek@invisiblethingslab.com>
Subject: [PATCH] xen/balloon: fix page onlining when populating new zone
Date: Wed,  6 Apr 2022 15:32:29 +0200	[thread overview]
Message-ID: <20220406133229.15979-1-jgross@suse.com> (raw)

When onlining a new memory page in a guest the Xen balloon driver is
adding it to the ballooned pages instead making it available to be
used immediately. This is meant to enable to add a new upper memory
limit to a guest via hotplugging memory, without having to assign the
new memory in one go.

In case the upper memory limit will be raised above 4G, the new memory
will populate the ZONE_NORMAL memory zone, which wasn't populated
before. The newly populated zone won't be added to the list of zones
looked at by the page allocator though, as only zones with available
memory are being added, and the memory isn't yet available as it is
ballooned out.

This will result in the new memory being assigned to the guest, but
without the allocator being able to use it.

When running as a PV guest the situation is even worse: when having
been started with less memory than allowed, and the upper limit being
lower than 4G, ballooning up will have the same effect as hotplugging
new memory. This is due to the usage of the zone device functionality
since commit 9e2369c06c8a ("xen: add helpers to allocate unpopulated
memory") for creating mappings of other guest's pages, which as a side
effect is being used for PV guest ballooning, too.

Fix this by checking in xen_online_page() whether the new memory page
will be the first in a new zone. If this is the case, add another page
to the balloon and use the first memory page of the new chunk as a
replacement for this now ballooned out page. This will result in the
newly populated zone containing one page being available for the page
allocator, which in turn will lead to the zone being added to the
allocator.

Cc: stable@vger.kernel.org
Fixes: 9e2369c06c8a ("xen: add helpers to allocate unpopulated memory")
Reported-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
Signed-off-by: Juergen Gross <jgross@suse.com>
---
 drivers/xen/balloon.c | 72 ++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 65 insertions(+), 7 deletions(-)

diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index dfe26fa17e95..f895c54c4c65 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -355,14 +355,77 @@ static enum bp_state reserve_additional_memory(void)
 	return BP_ECANCELED;
 }
 
+static struct page *alloc_page_for_balloon(gfp_t gfp)
+{
+	struct page *page;
+
+	page = alloc_page(gfp);
+	if (page == NULL)
+		return NULL;
+
+	adjust_managed_page_count(page, -1);
+	xenmem_reservation_scrub_page(page);
+
+	return page;
+}
+
+static void add_page_to_balloon(struct page *page)
+{
+	xenmem_reservation_va_mapping_reset(1, &page);
+	balloon_append(page);
+}
+
 static void xen_online_page(struct page *page, unsigned int order)
 {
 	unsigned long i, size = (1 << order);
 	unsigned long start_pfn = page_to_pfn(page);
 	struct page *p;
+	struct zone *zone;
 
 	pr_debug("Online %lu pages starting at pfn 0x%lx\n", size, start_pfn);
 	mutex_lock(&balloon_mutex);
+	zone = page_zone(pfn_to_page(start_pfn));
+
+	/*
+	 * In case a new memory zone is going to be populated, we need to
+	 * ensure at least one page is made available for the memory allocator.
+	 * As the number of pages per zone is updated only after a batch of
+	 * pages having been added, use the number of managed pages as an
+	 * additional indicator for a new zone.
+	 * Otherwise this zone won't be added to the zonelist resulting in the
+	 * zone's memory not usable by the kernel.
+	 * Add an already valid page to the balloon and replace it with the
+	 * first page of the to be added new memory chunk.
+	 */
+	if (!populated_zone(zone) && !managed_zone(zone)) {
+		xen_pfn_t frame;
+
+		pr_info("Populating new zone\n");
+
+		p = alloc_page_for_balloon(GFP_ATOMIC);
+		if (!p) {
+			pr_err("Failed to allocate replacement balloon page!\n");
+			pr_err("New onlined memory might not be usable.\n");
+		} else {
+			kmap_flush_unused();
+			add_page_to_balloon(p);
+			flush_tlb_all();
+			frame = xen_page_to_gfn(p);
+			xenmem_reservation_decrease(1, &frame);
+			balloon_stats.current_pages--;
+		}
+
+		p = pfn_to_page(start_pfn);
+		frame = page_to_xen_pfn(p);
+		if (xenmem_reservation_increase(1, &frame) > 0) {
+			xenmem_reservation_va_mapping_update(1, &p, &frame);
+			free_reserved_page(p);
+			balloon_stats.current_pages++;
+
+			start_pfn++;
+			size--;
+		}
+	}
 	for (i = 0; i < size; i++) {
 		p = pfn_to_page(start_pfn + i);
 		balloon_append(p);
@@ -452,14 +515,12 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
 		nr_pages = ARRAY_SIZE(frame_list);
 
 	for (i = 0; i < nr_pages; i++) {
-		page = alloc_page(gfp);
+		page = alloc_page_for_balloon(gfp);
 		if (page == NULL) {
 			nr_pages = i;
 			state = BP_EAGAIN;
 			break;
 		}
-		adjust_managed_page_count(page, -1);
-		xenmem_reservation_scrub_page(page);
 		list_add(&page->lru, &pages);
 	}
 
@@ -480,11 +541,8 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
 	list_for_each_entry_safe(page, tmp, &pages, lru) {
 		frame_list[i++] = xen_page_to_gfn(page);
 
-		xenmem_reservation_va_mapping_reset(1, &page);
-
 		list_del(&page->lru);
-
-		balloon_append(page);
+		add_page_to_balloon(page);
 	}
 
 	flush_tlb_all();
-- 
2.34.1



             reply	other threads:[~2022-04-06 13:32 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-04-06 13:32 Juergen Gross [this message]
2022-04-06 23:31 ` [PATCH] xen/balloon: fix page onlining when populating new zone kernel test robot
2022-04-07  2:06 ` kernel test robot
2022-04-07  5:09 ` kernel test robot
2022-04-07  8:23 ` David Hildenbrand
2022-04-07  8:50   ` Juergen Gross
2022-04-07  9:00     ` David Hildenbrand
2022-04-08 23:16       ` Wei Yang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220406133229.15979-1-jgross@suse.com \
    --to=jgross@suse.com \
    --cc=boris.ostrovsky@oracle.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=marmarek@invisiblethingslab.com \
    --cc=sstabellini@kernel.org \
    --cc=stable@vger.kernel.org \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).