|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v2 54/62] xen/pvshim: memory hotplug
From: Roger Pau Monne <roger.pau@xxxxxxxxxx>
Signed-off-by: Roger Pau Monné <roger.pau@xxxxxxxxxx>
---
Changes since v1:
- Add an order parameter to batch_memory_op.
- Add a TODO item regarding high order memory chunks to
pv_shim_online_memory.
- Use page_list_splice.
- Make sure the shim handlers are not called multiple times when
the hypercall is preempted.
---
xen/arch/x86/pv/shim.c | 112 ++++++++++++++++++++++++++++++++++++++++++
xen/common/memory.c | 21 ++++++++
xen/include/asm-x86/pv/shim.h | 10 ++++
3 files changed, 143 insertions(+)
diff --git a/xen/arch/x86/pv/shim.c b/xen/arch/x86/pv/shim.c
index 68ec7bed8e..4120cc550e 100644
--- a/xen/arch/x86/pv/shim.c
+++ b/xen/arch/x86/pv/shim.c
@@ -48,6 +48,9 @@ static unsigned int nr_grant_list;
static unsigned long *grant_frames;
static DEFINE_SPINLOCK(grant_lock);
+static PAGE_LIST_HEAD(balloon);
+static DEFINE_SPINLOCK(balloon_lock);
+
static long pv_shim_event_channel_op(int cmd, XEN_GUEST_HANDLE_PARAM(void)
arg);
static long pv_shim_grant_table_op(unsigned int cmd,
XEN_GUEST_HANDLE_PARAM(void) uop,
@@ -814,6 +817,115 @@ long pv_shim_cpu_down(void *data)
return 0;
}
+static unsigned long batch_memory_op(unsigned int cmd, unsigned int order,
+ const struct page_list_head *list)
+{
+ struct xen_memory_reservation xmr = {
+ .domid = DOMID_SELF,
+ .extent_order = order,
+ };
+ unsigned long pfns[64];
+ const struct page_info *pg;
+ unsigned long done = 0;
+
+ set_xen_guest_handle(xmr.extent_start, pfns);
+ page_list_for_each ( pg, list )
+ {
+ pfns[xmr.nr_extents++] = page_to_mfn(pg);
+ if ( xmr.nr_extents == ARRAY_SIZE(pfns) || !page_list_next(pg, list) )
+ {
+ long nr = xen_hypercall_memory_op(cmd, &xmr);
+
+ done += nr > 0 ? nr : 0;
+ if ( nr != xmr.nr_extents )
+ break;
+ xmr.nr_extents = 0;
+ }
+ }
+
+ return done;
+}
+
+void pv_shim_online_memory(unsigned int nr, unsigned int order)
+{
+ struct page_info *page, *tmp;
+ PAGE_LIST_HEAD(list);
+
+ spin_lock(&balloon_lock);
+ page_list_for_each_safe ( page, tmp, &balloon )
+ {
+ /* TODO: add support for splitting high order memory chunks. */
+ if ( page->v.free.order != order )
+ continue;
+
+ page_list_del(page, &balloon);
+ page_list_add_tail(page, &list);
+ if ( !--nr )
+ break;
+ }
+ spin_unlock(&balloon_lock);
+
+ if ( nr )
+ gprintk(XENLOG_WARNING,
+ "failed to allocate %u extents of order %u for onlining\n",
+ nr, order);
+
+ nr = batch_memory_op(XENMEM_populate_physmap, order, &list);
+ while ( nr-- )
+ {
+ BUG_ON((page = page_list_remove_head(&list)) == NULL);
+ free_domheap_pages(page, order);
+ }
+
+ if ( !page_list_empty(&list) )
+ {
+ gprintk(XENLOG_WARNING,
+ "failed to online some of the memory regions\n");
+ spin_lock(&balloon_lock);
+ page_list_splice(&list, &balloon);
+ spin_unlock(&balloon_lock);
+ }
+}
+
+void pv_shim_offline_memory(unsigned int nr, unsigned int order)
+{
+ struct page_info *page;
+ PAGE_LIST_HEAD(list);
+
+ while ( nr-- )
+ {
+ page = alloc_domheap_pages(NULL, order, 0);
+ if ( !page )
+ break;
+
+ page_list_add_tail(page, &list);
+ page->v.free.order = order;
+ }
+
+ if ( nr + 1 )
+ gprintk(XENLOG_WARNING,
+ "failed to reserve %u extents of order %u for offlining\n",
+ nr + 1, order);
+
+
+ nr = batch_memory_op(XENMEM_decrease_reservation, order, &list);
+ spin_lock(&balloon_lock);
+ while ( nr-- )
+ {
+ BUG_ON((page = page_list_remove_head(&list)) == NULL);
+ page_list_add_tail(page, &balloon);
+ }
+ spin_unlock(&balloon_lock);
+
+ if ( !page_list_empty(&list) )
+ {
+ gprintk(XENLOG_WARNING,
+ "failed to offline some of the memory regions\n");
+ while ( (page = page_list_remove_head(&list)) != NULL )
+ free_domheap_pages(page, order);
+ }
+}
+
domid_t get_initial_domain_id(void)
{
uint32_t eax, ebx, ecx, edx;
diff --git a/xen/common/memory.c b/xen/common/memory.c
index 5a1508a292..71e19aa629 100644
--- a/xen/common/memory.c
+++ b/xen/common/memory.c
@@ -29,6 +29,10 @@
#include <public/memory.h>
#include <xsm/xsm.h>
+#ifdef CONFIG_X86
+#include <asm/guest.h>
+#endif
+
struct memop_args {
/* INPUT */
struct domain *domain; /* Domain to be affected. */
@@ -993,6 +997,12 @@ long do_memory_op(unsigned long cmd,
XEN_GUEST_HANDLE_PARAM(void) arg)
return start_extent;
}
+#ifdef CONFIG_X86
+ if ( pv_shim && op != XENMEM_decrease_reservation && !args.preempted )
+ /* Avoid calling pv_shim_online_memory when preempted. */
+ pv_shim_online_memory(args.nr_extents, args.extent_order);
+#endif
+
switch ( op )
{
case XENMEM_increase_reservation:
@@ -1015,6 +1025,17 @@ long do_memory_op(unsigned long cmd,
XEN_GUEST_HANDLE_PARAM(void) arg)
__HYPERVISOR_memory_op, "lh",
op | (rc << MEMOP_EXTENT_SHIFT), arg);
+#ifdef CONFIG_X86
+ if ( pv_shim && op == XENMEM_decrease_reservation )
+ /*
+ * Only call pv_shim_offline_memory when the hypercall has
+ * finished. Note that nr_done is used to cope in case the
+ * hypercall has failed and only part of the extents where
+ * processed.
+ */
+ pv_shim_offline_memory(args.nr_extents, args.nr_done);
+#endif
+
break;
case XENMEM_exchange:
diff --git a/xen/include/asm-x86/pv/shim.h b/xen/include/asm-x86/pv/shim.h
index eb59ddd38a..fb739772df 100644
--- a/xen/include/asm-x86/pv/shim.h
+++ b/xen/include/asm-x86/pv/shim.h
@@ -39,6 +39,8 @@ int pv_shim_shutdown(uint8_t reason);
void pv_shim_inject_evtchn(unsigned int port);
long pv_shim_cpu_up(void *data);
long pv_shim_cpu_down(void *data);
+void pv_shim_online_memory(unsigned int nr, unsigned int order);
+void pv_shim_offline_memory(unsigned int nr, unsigned int order);
domid_t get_initial_domain_id(void);
uint64_t pv_shim_mem(uint64_t avail);
@@ -72,6 +74,14 @@ static inline long pv_shim_cpu_down(void *data)
ASSERT_UNREACHABLE();
return 0;
}
+static inline void pv_shim_online_memory(unsigned int nr, unsigned int order)
+{
+ ASSERT_UNREACHABLE();
+}
+static inline void pv_shim_offline_memory(unsigned int nr, unsigned int order)
+{
+ ASSERT_UNREACHABLE();
+}
static inline domid_t get_initial_domain_id(void)
{
return 0;
--
2.11.0
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |