[PATCH RFC 32/39] xen/balloon: xen_shim_domain() support

From: Joao Martins
Date: Wed Feb 20 2019 - 15:20:08 EST


Xen ballooning uses hollow struct pages (with the underlying PFNs being
populated/unpopulated via hypercalls) which are used by the grant logic
to map grants from other domains.

For purposes of a KVM based xen-shim, this model is not useful --
mapping is unnecessary since all guest memory is already mapped in the
KVM host. The simplest option is to just translate grant references to
GPAs (essentially a get_page() on the appropriate GPA.)

This patch provides an alternate balloon allocation mechanism where in
the allocation path we just provide a constant struct page
(corresponding to page 0.) This allows the calling code -- which does a
page_to_pfn() on the returned struct page -- to remain unchanged before
doing the grant operation (which in this case would fill in the real
struct page.)

Co-developed-by: Ankur Arora <ankur.a.arora@xxxxxxxxxx>
Signed-off-by: Joao Martins <joao.m.martins@xxxxxxxxxx>
Signed-off-by: Ankur Arora <ankur.a.arora@xxxxxxxxxx>
---
arch/x86/kvm/xen-shim.c | 31 +++++++++++++++++++++++++++++++
drivers/xen/balloon.c | 15 ++++++++++++++-
include/xen/balloon.h | 7 +++++++
3 files changed, 52 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kvm/xen-shim.c b/arch/x86/kvm/xen-shim.c
index 61fdceb63ec2..4086d92a4bfb 100644
--- a/arch/x86/kvm/xen-shim.c
+++ b/arch/x86/kvm/xen-shim.c
@@ -13,11 +13,40 @@
#include <xen/xen-ops.h>
#include <xen/events.h>
#include <xen/xenbus.h>
+#include <xen/balloon.h>

#define BITS_PER_EVTCHN_WORD (sizeof(xen_ulong_t)*8)

static struct kvm_xen shim = { .domid = XEN_SHIM_DOMID };

+static int shim_alloc_pages(int nr_pages, struct page **pages)
+{
+ int i;
+
+ /*
+ * We provide page 0 instead of NULL because we'll effectively
+ * do the inverse operation while deriving the pfn to pass to
+ * xen for mapping.
+ */
+ for (i = 0; i < nr_pages; i++)
+ pages[i] = pfn_to_page(0);
+
+ return 0;
+}
+
+static void shim_free_pages(int nr_pages, struct page **pages)
+{
+ int i;
+
+ for (i = 0; i < nr_pages; i++)
+ pages[i] = NULL;
+}
+
+static struct xen_balloon_ops shim_balloon_ops = {
+ .alloc_pages = shim_alloc_pages,
+ .free_pages = shim_free_pages,
+};
+
static void shim_evtchn_setup(struct shared_info *s)
{
int cpu;
@@ -65,6 +94,7 @@ static int __init shim_register(void)
mutex_init(&shim.xen_lock);

kvm_xen_register_lcall(&shim);
+ xen_balloon_ops = &shim_balloon_ops;

/* We can handle hypercalls after this point */
xen_shim_domain = 1;
@@ -94,6 +124,7 @@ static void __exit shim_exit(void)
xen_shim_domain = 0;

kvm_xen_unregister_lcall();
+ xen_balloon_ops = NULL;
HYPERVISOR_shared_info = NULL;
free_page((unsigned long) shim.shinfo);
shim.shinfo = NULL;
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index ceb5048de9a7..00375fa6c122 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -138,7 +138,7 @@ enum bp_state {

static DEFINE_MUTEX(balloon_mutex);

-struct balloon_stats balloon_stats;
+struct balloon_stats balloon_stats __read_mostly;
EXPORT_SYMBOL_GPL(balloon_stats);

/* We increase/decrease in batches which fit in a page */
@@ -158,6 +158,9 @@ static DECLARE_DELAYED_WORK(balloon_worker, balloon_process);
#define GFP_BALLOON \
(GFP_HIGHUSER | __GFP_NOWARN | __GFP_NORETRY | __GFP_NOMEMALLOC)

+struct xen_balloon_ops *xen_balloon_ops;
+EXPORT_SYMBOL(xen_balloon_ops);
+
/* balloon_append: add the given page to the balloon. */
static void __balloon_append(struct page *page)
{
@@ -589,6 +592,11 @@ int alloc_xenballooned_pages(int nr_pages, struct page **pages)
struct page *page;
int ret;

+ if (xen_shim_domain() && xen_balloon_ops)
+ return xen_balloon_ops->alloc_pages(nr_pages, pages);
+
+ WARN_ON_ONCE(xen_shim_domain());
+
mutex_lock(&balloon_mutex);

balloon_stats.target_unpopulated += nr_pages;
@@ -634,6 +642,11 @@ void free_xenballooned_pages(int nr_pages, struct page **pages)
{
int i;

+ if (xen_shim_domain() && xen_balloon_ops)
+ return xen_balloon_ops->free_pages(nr_pages, pages);
+
+ WARN_ON_ONCE(xen_shim_domain());
+
mutex_lock(&balloon_mutex);

for (i = 0; i < nr_pages; i++) {
diff --git a/include/xen/balloon.h b/include/xen/balloon.h
index 4914b93a23f2..9ba6a7e91d5e 100644
--- a/include/xen/balloon.h
+++ b/include/xen/balloon.h
@@ -22,6 +22,13 @@ struct balloon_stats {

extern struct balloon_stats balloon_stats;

+struct xen_balloon_ops {
+ int (*alloc_pages)(int nr_pages, struct page **pages);
+ void (*free_pages)(int nr_pages, struct page **pages);
+};
+
+extern struct xen_balloon_ops *xen_balloon_ops;
+
void balloon_set_new_target(unsigned long target);

int alloc_xenballooned_pages(int nr_pages, struct page **pages);
--
2.11.0