mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
xen/pvshim: memory hotplug
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
This commit is contained in:
1 parent
129e09b515
commit
b2245acc60
3 files changed
+143
No files matched your search
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||