# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID ec2ac5a5f0a31d3fbab26b738af814e7c3428105
# Parent 532979a7807111ff387df950e314ed97dd411e6f
[XEN] New memory_op XENMEM_exchange. Allows atomic
exchange of one memory reservation for another of the
same size, but with different properties.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
xen-unstable changeset: 10360:ee3d108289370351347f46284024f3347897d2bb
xen-unstable date: Fri Jun 16 14:43:54 2006 +0100
---
xen/arch/x86/domain_build.c | 2
xen/arch/x86/mm.c | 7
xen/arch/x86/shadow.c | 4
xen/arch/x86/shadow_public.c | 4
xen/common/grant_table.c | 2
xen/common/memory.c | 274 ++++++++++++++++++++++++++++++++++----
xen/common/page_alloc.c | 86 +++++++----
xen/include/asm-x86/grant_table.h | 3
xen/include/asm-x86/mm.h | 3
xen/include/public/memory.h | 47 ++++++
xen/include/xen/mm.h | 14 +
11 files changed, 374 insertions(+), 72 deletions(-)
diff -r 532979a78071 -r ec2ac5a5f0a3 xen/arch/x86/domain_build.c
--- a/xen/arch/x86/domain_build.c Sat Jun 17 12:31:40 2006 +0100
+++ b/xen/arch/x86/domain_build.c Sat Jun 17 12:48:07 2006 +0100
@@ -368,7 +368,7 @@ int construct_dom0(struct domain *d,
panic("Domain 0 allocation is too small for kernel image.\n");
/* Allocate from DMA pool: PAE L3 table must be below 4GB boundary. */
- if ( (page = alloc_domheap_pages(d, order, ALLOC_DOM_DMA)) == NULL )
+ if ( (page = alloc_domheap_pages(d, order, MEMF_dma)) == NULL )
panic("Not enough RAM for domain 0 allocation.\n");
alloc_spfn = page_to_mfn(page);
alloc_epfn = alloc_spfn + d->tot_pages;
diff -r 532979a78071 -r ec2ac5a5f0a3 xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c Sat Jun 17 12:31:40 2006 +0100
+++ b/xen/arch/x86/mm.c Sat Jun 17 12:48:07 2006 +0100
@@ -2482,8 +2482,8 @@ int destroy_grant_host_mapping(
return destroy_grant_va_mapping(addr, frame);
}
-int steal_page_for_grant_transfer(
- struct domain *d, struct page_info *page)
+int steal_page(
+ struct domain *d, struct page_info *page, unsigned int memflags)
{
u32 _d, _nd, x, y;
@@ -2520,7 +2520,8 @@ int steal_page_for_grant_transfer(
* Unlink from 'd'. At least one reference remains (now anonymous), so
* noone else is spinning to try to delete this page from 'd'.
*/
- d->tot_pages--;
+ if ( !(memflags & MEMF_no_refcount) )
+ d->tot_pages--;
list_del(&page->list);
spin_unlock(&d->page_alloc_lock);
diff -r 532979a78071 -r ec2ac5a5f0a3 xen/arch/x86/shadow.c
--- a/xen/arch/x86/shadow.c Sat Jun 17 12:31:40 2006 +0100
+++ b/xen/arch/x86/shadow.c Sat Jun 17 12:48:07 2006 +0100
@@ -292,10 +292,10 @@ alloc_shadow_page(struct domain *d,
#elif CONFIG_PAGING_LEVELS >= 3
if ( d->arch.ops->guest_paging_levels == PAGING_L2 &&
psh_type == PGT_l4_shadow ) /* allocated for PAE PDP page */
- page = alloc_domheap_pages(NULL, 0, ALLOC_DOM_DMA);
+ page = alloc_domheap_pages(NULL, 0, MEMF_dma);
else if ( d->arch.ops->guest_paging_levels == PAGING_L3 &&
(psh_type == PGT_l3_shadow || psh_type == PGT_l4_shadow) )
- page = alloc_domheap_pages(NULL, 0, ALLOC_DOM_DMA); /* allocated
for PAE PDP page */
+ page = alloc_domheap_pages(NULL, 0, MEMF_dma); /* allocated for
PAE PDP page */
else
page = alloc_domheap_page(NULL);
#endif
diff -r 532979a78071 -r ec2ac5a5f0a3 xen/arch/x86/shadow_public.c
--- a/xen/arch/x86/shadow_public.c Sat Jun 17 12:31:40 2006 +0100
+++ b/xen/arch/x86/shadow_public.c Sat Jun 17 12:48:07 2006 +0100
@@ -43,7 +43,7 @@ int shadow_direct_map_init(struct domain
struct page_info *page;
l3_pgentry_t *root;
- if ( !(page = alloc_domheap_pages(NULL, 0, ALLOC_DOM_DMA)) )
+ if ( !(page = alloc_domheap_pages(NULL, 0, MEMF_dma)) )
return 0;
root = map_domain_page(page_to_mfn(page));
@@ -381,7 +381,7 @@ static void alloc_monitor_pagetable(stru
ASSERT(!pagetable_get_paddr(v->arch.monitor_table)); /* we should only get
called once */
- m3mfn_info = alloc_domheap_pages(NULL, 0, ALLOC_DOM_DMA);
+ m3mfn_info = alloc_domheap_pages(NULL, 0, MEMF_dma);
ASSERT( m3mfn_info );
m3mfn = page_to_mfn(m3mfn_info);
diff -r 532979a78071 -r ec2ac5a5f0a3 xen/common/grant_table.c
--- a/xen/common/grant_table.c Sat Jun 17 12:31:40 2006 +0100
+++ b/xen/common/grant_table.c Sat Jun 17 12:48:07 2006 +0100
@@ -637,7 +637,7 @@ gnttab_transfer(
goto copyback;
}
- if ( steal_page_for_grant_transfer(d, page) < 0 )
+ if ( steal_page(d, page, 0) < 0 )
{
gop.status = GNTST_bad_page;
goto copyback;
diff -r 532979a78071 -r ec2ac5a5f0a3 xen/common/memory.c
--- a/xen/common/memory.c Sat Jun 17 12:31:40 2006 +0100
+++ b/xen/common/memory.c Sat Jun 17 12:48:07 2006 +0100
@@ -34,7 +34,7 @@ increase_reservation(
GUEST_HANDLE(ulong) extent_list,
unsigned int nr_extents,
unsigned int extent_order,
- unsigned int flags,
+ unsigned int memflags,
int *preempted)
{
struct page_info *page;
@@ -57,11 +57,11 @@ increase_reservation(
}
if ( unlikely((page = alloc_domheap_pages(
- d, extent_order, flags)) == NULL) )
+ d, extent_order, memflags)) == NULL) )
{
DPRINTK("Could not allocate order=%d extent: "
- "id=%d flags=%x (%ld of %d)\n",
- extent_order, d->domain_id, flags, i, nr_extents);
+ "id=%d memflags=%x (%ld of %d)\n",
+ extent_order, d->domain_id, memflags, i, nr_extents);
return i;
}
@@ -83,7 +83,7 @@ populate_physmap(
GUEST_HANDLE(ulong) extent_list,
unsigned int nr_extents,
unsigned int extent_order,
- unsigned int flags,
+ unsigned int memflags,
int *preempted)
{
struct page_info *page;
@@ -108,11 +108,11 @@ populate_physmap(
goto out;
if ( unlikely((page = alloc_domheap_pages(
- d, extent_order, flags)) == NULL) )
+ d, extent_order, memflags)) == NULL) )
{
DPRINTK("Could not allocate order=%d extent: "
- "id=%d flags=%x (%ld of %d)\n",
- extent_order, d->domain_id, flags, i, nr_extents);
+ "id=%d memflags=%x (%ld of %d)\n",
+ extent_order, d->domain_id, memflags, i, nr_extents);
goto out;
}
@@ -180,7 +180,6 @@ decrease_reservation(
GUEST_HANDLE(ulong) extent_list,
unsigned int nr_extents,
unsigned int extent_order,
- unsigned int flags,
int *preempted)
{
unsigned long i, j, gmfn;
@@ -270,10 +269,234 @@ translate_gpfn_list(
return 0;
}
+static long
+memory_exchange(GUEST_HANDLE(xen_memory_exchange_t) arg)
+{
+ struct xen_memory_exchange exch;
+ LIST_HEAD(in_chunk_list);
+ LIST_HEAD(out_chunk_list);
+ unsigned long in_chunk_order, out_chunk_order;
+ unsigned long gpfn, gmfn, mfn;
+ unsigned long i, j, k;
+ unsigned int memflags = 0;
+ long rc = 0;
+ struct domain *d;
+ struct page_info *page;
+
+ if ( copy_from_guest(&exch, arg, 1) )
+ return -EFAULT;
+
+ /* Various sanity checks. */
+ if ( (exch.nr_exchanged > exch.in.nr_extents) ||
+ /* Input and output domain identifiers match? */
+ (exch.in.domid != exch.out.domid) ||
+ /* Sizes of input and output lists do not overflow a long? */
+ ((~0UL >> exch.in.extent_order) < exch.in.nr_extents) ||
+ ((~0UL >> exch.out.extent_order) < exch.out.nr_extents) ||
+ /* Sizes of input and output lists match? */
+ ((exch.in.nr_extents << exch.in.extent_order) !=
+ (exch.out.nr_extents << exch.out.extent_order)) )
+ {
+ rc = -EINVAL;
+ goto fail_early;
+ }
+
+ /* Only privileged guests can allocate multi-page contiguous extents. */
+ if ( ((exch.in.extent_order != 0) || (exch.out.extent_order != 0)) &&
+ !multipage_allocation_permitted(current->domain) )
+ {
+ rc = -EPERM;
+ goto fail_early;
+ }
+
+ if ( (exch.out.address_bits != 0) &&
+ (exch.out.address_bits <
+ (get_order_from_pages(max_page) + PAGE_SHIFT)) )
+ {
+ if ( exch.out.address_bits < 31 )
+ {
+ rc = -ENOMEM;
+ goto fail_early;
+ }
+ memflags = MEMF_dma;
+ }
+
+ guest_handle_add_offset(exch.in.extent_start, exch.nr_exchanged);
+ exch.in.nr_extents -= exch.nr_exchanged;
+
+ if ( exch.in.extent_order <= exch.out.extent_order )
+ {
+ in_chunk_order = exch.out.extent_order - exch.in.extent_order;
+ out_chunk_order = 0;
+ guest_handle_add_offset(
+ exch.out.extent_start, exch.nr_exchanged >> in_chunk_order);
+ exch.out.nr_extents -= exch.nr_exchanged >> in_chunk_order;
+ }
+ else
+ {
+ in_chunk_order = 0;
+ out_chunk_order = exch.in.extent_order - exch.out.extent_order;
+ guest_handle_add_offset(
+ exch.out.extent_start, exch.nr_exchanged << out_chunk_order);
+ exch.out.nr_extents -= exch.nr_exchanged << out_chunk_order;
+ }
+
+ /*
+ * Only support exchange on calling domain right now. Otherwise there are
+ * tricky corner cases to consider (e.g., DOMF_dying domain).
+ */
+ if ( unlikely(exch.in.domid != DOMID_SELF) )
+ {
+ rc = IS_PRIV(current->domain) ? -EINVAL : -EPERM;
+ goto fail_early;
+ }
+ d = current->domain;
+
+ for ( i = 0; i < (exch.in.nr_extents >> in_chunk_order); i++ )
+ {
+ if ( hypercall_preempt_check() )
+ {
+ exch.nr_exchanged += i << in_chunk_order;
+ if ( copy_field_to_guest(arg, &exch, nr_exchanged) )
+ return -EFAULT;
+ return hypercall_create_continuation(
+ __HYPERVISOR_memory_op, "lh", XENMEM_exchange, arg);
+ }
+
+ /* Steal a chunk's worth of input pages from the domain. */
+ for ( j = 0; j < (1UL << in_chunk_order); j++ )
+ {
+ if ( unlikely(__copy_from_guest_offset(
+ &gmfn, exch.in.extent_start, (i<<in_chunk_order)+j, 1)) )
+ {
+ rc = -EFAULT;
+ goto fail;
+ }
+
+ for ( k = 0; k < (1UL << exch.in.extent_order); k++ )
+ {
+ mfn = gmfn_to_mfn(d, gmfn + k);
+ if ( unlikely(!mfn_valid(mfn)) )
+ {
+ rc = -EINVAL;
+ goto fail;
+ }
+
+ page = mfn_to_page(mfn);
+
+ if ( unlikely(steal_page(d, page, MEMF_no_refcount)) )
+ {
+ rc = -EINVAL;
+ goto fail;
+ }
+
+ list_add(&page->list, &in_chunk_list);
+ }
+ }
+
+ /* Allocate a chunk's worth of anonymous output pages. */
+ for ( j = 0; j < (1UL << out_chunk_order); j++ )
+ {
+ page = alloc_domheap_pages(
+ NULL, exch.out.extent_order, memflags);
+ if ( unlikely(page == NULL) )
+ {
+ rc = -ENOMEM;
+ goto fail;
+ }
+
+ list_add(&page->list, &out_chunk_list);
+ }
+
+ /*
+ * Success! Beyond this point we cannot fail for this chunk.
+ */
+
+ /* Destroy final reference to each input page. */
+ while ( !list_empty(&in_chunk_list) )
+ {
+ page = list_entry(in_chunk_list.next, struct page_info, list);
+ list_del(&page->list);
+ if ( !test_and_clear_bit(_PGC_allocated, &page->count_info) )
+ BUG();
+ mfn = page_to_mfn(page);
+ guest_physmap_remove_page(d, mfn_to_gmfn(d, mfn), mfn);
+ put_page(page);
+ }
+
+ /* Assign each output page to the domain. */
+ j = 0;
+ while ( !list_empty(&out_chunk_list) )
+ {
+ page = list_entry(out_chunk_list.next, struct page_info, list);
+ list_del(&page->list);
+ if ( assign_pages(d, page, exch.out.extent_order,
+ MEMF_no_refcount) )
+ BUG();
+
+ /* Note that we ignore errors accessing the output extent list. */
+ (void)__copy_from_guest_offset(
+ &gpfn, exch.out.extent_start, (i<<out_chunk_order)+j, 1);
+
+ mfn = page_to_mfn(page);
+ if ( unlikely(shadow_mode_translate(d)) )
+ {
+ for ( k = 0; k < (1UL << exch.out.extent_order); k++ )
+ guest_physmap_add_page(d, gpfn + k, mfn + k);
+ }
+ else
+ {
+ for ( k = 0; k < (1UL << exch.out.extent_order); k++ )
+ set_gpfn_from_mfn(mfn + k, gpfn + k);
+ (void)__copy_to_guest_offset(
+ exch.out.extent_start, (i<<out_chunk_order)+j, &mfn, 1);
+ }
+
+ j++;
+ }
+ BUG_ON(j != (1UL << out_chunk_order));
+ }
+
+ exch.nr_exchanged += exch.in.nr_extents;
+ if ( copy_field_to_guest(arg, &exch, nr_exchanged) )
+ rc = -EFAULT;
+ return rc;
+
+ /*
+ * Failed a chunk! Free any partial chunk work. Tell caller how many
+ * chunks succeeded.
+ */
+ fail:
+ /* Reassign any input pages we managed to steal. */
+ while ( !list_empty(&in_chunk_list) )
+ {
+ page = list_entry(in_chunk_list.next, struct page_info, list);
+ list_del(&page->list);
+ if ( assign_pages(d, page, 0, MEMF_no_refcount) )
+ BUG();
+ }
+
+ /* Free any output pages we managed to allocate. */
+ while ( !list_empty(&out_chunk_list) )
+ {
+ page = list_entry(out_chunk_list.next, struct page_info, list);
+ list_del(&page->list);
+ free_domheap_pages(page, exch.out.extent_order);
+ }
+
+ exch.nr_exchanged += i << in_chunk_order;
+
+ fail_early:
+ if ( copy_field_to_guest(arg, &exch, nr_exchanged) )
+ rc = -EFAULT;
+ return rc;
+}
+
long do_memory_op(unsigned long cmd, GUEST_HANDLE(void) arg)
{
struct domain *d;
- int rc, op, flags = 0, preempted = 0;
+ int rc, op, preempted = 0;
+ unsigned int memflags = 0;
unsigned long start_extent, progress;
struct xen_memory_reservation reservation;
domid_t domid;
@@ -285,16 +508,17 @@ long do_memory_op(unsigned long cmd, GUE
case XENMEM_increase_reservation:
case XENMEM_decrease_reservation:
case XENMEM_populate_physmap:
+ start_extent = cmd >> START_EXTENT_SHIFT;
+
if ( copy_from_guest(&reservation, arg, 1) )
- return -EFAULT;
+ return start_extent;
/* Is size too large for us to encode a continuation? */
if ( reservation.nr_extents > (ULONG_MAX >> START_EXTENT_SHIFT) )
- return -EINVAL;
-
- start_extent = cmd >> START_EXTENT_SHIFT;
+ return start_extent;
+
if ( unlikely(start_extent > reservation.nr_extents) )
- return -EINVAL;
+ return start_extent;
if ( !guest_handle_is_null(reservation.extent_start) )
guest_handle_add_offset(reservation.extent_start, start_extent);
@@ -305,16 +529,15 @@ long do_memory_op(unsigned long cmd, GUE
(get_order_from_pages(max_page) + PAGE_SHIFT)) )
{
if ( reservation.address_bits < 31 )
- return -ENOMEM;
- flags = ALLOC_DOM_DMA;
+ return start_extent;
+ memflags = MEMF_dma;
}
if ( likely(reservation.domid == DOMID_SELF) )
d = current->domain;
- else if ( !IS_PRIV(current->domain) )
- return -EPERM;
- else if ( (d = find_domain_by_id(reservation.domid)) == NULL )
- return -ESRCH;
+ else if ( !IS_PRIV(current->domain) ||
+ ((d = find_domain_by_id(reservation.domid)) == NULL) )
+ return start_extent;
switch ( op )
{
@@ -324,7 +547,7 @@ long do_memory_op(unsigned long cmd, GUE
reservation.extent_start,
reservation.nr_extents,
reservation.extent_order,
- flags,
+ memflags,
&preempted);
break;
case XENMEM_decrease_reservation:
@@ -333,7 +556,6 @@ long do_memory_op(unsigned long cmd, GUE
reservation.extent_start,
reservation.nr_extents,
reservation.extent_order,
- flags,
&preempted);
break;
case XENMEM_populate_physmap:
@@ -343,7 +565,7 @@ long do_memory_op(unsigned long cmd, GUE
reservation.extent_start,
reservation.nr_extents,
reservation.extent_order,
- flags,
+ memflags,
&preempted);
break;
}
@@ -358,6 +580,10 @@ long do_memory_op(unsigned long cmd, GUE
__HYPERVISOR_memory_op, "lh",
op | (rc << START_EXTENT_SHIFT), arg);
+ break;
+
+ case XENMEM_exchange:
+ rc = memory_exchange(guest_handle_cast(arg, xen_memory_exchange_t));
break;
case XENMEM_maximum_ram_page:
diff -r 532979a78071 -r ec2ac5a5f0a3 xen/common/page_alloc.c
--- a/xen/common/page_alloc.c Sat Jun 17 12:31:40 2006 +0100
+++ b/xen/common/page_alloc.c Sat Jun 17 12:48:07 2006 +0100
@@ -531,16 +531,66 @@ void init_domheap_pages(paddr_t ps, padd
}
+int assign_pages(
+ struct domain *d,
+ struct page_info *pg,
+ unsigned int order,
+ unsigned int memflags)
+{
+ unsigned long i;
+
+ spin_lock(&d->page_alloc_lock);
+
+ if ( unlikely(test_bit(_DOMF_dying, &d->domain_flags)) )
+ {
+ DPRINTK("Cannot assign page to domain%d -- dying.\n", d->domain_id);
+ goto fail;
+ }
+
+ if ( !(memflags & MEMF_no_refcount) )
+ {
+ if ( unlikely((d->tot_pages + (1 << order)) > d->max_pages) )
+ {
+ DPRINTK("Over-allocation for domain %u: %u > %u\n",
+ d->domain_id, d->tot_pages + (1 << order), d->max_pages);
+ goto fail;
+ }
+
+ if ( unlikely(d->tot_pages == 0) )
+ get_knownalive_domain(d);
+
+ d->tot_pages += 1 << order;
+ }
+
+ for ( i = 0; i < (1 << order); i++ )
+ {
+ ASSERT(page_get_owner(&pg[i]) == NULL);
+ ASSERT((pg[i].count_info & ~(PGC_allocated | 1)) == 0);
+ page_set_owner(&pg[i], d);
+ wmb(); /* Domain pointer must be visible before updating refcnt. */
+ pg[i].count_info = PGC_allocated | 1;
+ list_add_tail(&pg[i].list, &d->page_list);
+ }
+
+ spin_unlock(&d->page_alloc_lock);
+ return 0;
+
+ fail:
+ spin_unlock(&d->page_alloc_lock);
+ return -1;
+}
+
+
struct page_info *alloc_domheap_pages(
- struct domain *d, unsigned int order, unsigned int flags)
+ struct domain *d, unsigned int order, unsigned int memflags)
{
struct page_info *pg = NULL;
cpumask_t mask;
- int i;
+ unsigned long i;
ASSERT(!in_irq());
- if ( !(flags & ALLOC_DOM_DMA) )
+ if ( !(memflags & MEMF_dma) )
{
pg = alloc_heap_pages(MEMZONE_DOM, order);
/* Failure? Then check if we can fall back to the DMA pool. */
@@ -582,37 +632,11 @@ struct page_info *alloc_domheap_pages(
flush_tlb_mask(mask);
}
- if ( d == NULL )
- return pg;
-
- spin_lock(&d->page_alloc_lock);
-
- if ( unlikely(test_bit(_DOMF_dying, &d->domain_flags)) ||
- unlikely((d->tot_pages + (1 << order)) > d->max_pages) )
- {
- DPRINTK("Over-allocation for domain %u: %u > %u\n",
- d->domain_id, d->tot_pages + (1 << order), d->max_pages);
- DPRINTK("...or the domain is dying (%d)\n",
- !!test_bit(_DOMF_dying, &d->domain_flags));
- spin_unlock(&d->page_alloc_lock);
+ if ( (d != NULL) && assign_pages(d, pg, order, memflags) )
+ {
free_heap_pages(pfn_dom_zone_type(page_to_mfn(pg)), pg, order);
return NULL;
}
-
- if ( unlikely(d->tot_pages == 0) )
- get_knownalive_domain(d);
-
- d->tot_pages += 1 << order;
-
- for ( i = 0; i < (1 << order); i++ )
- {
- page_set_owner(&pg[i], d);
- wmb(); /* Domain pointer must be visible before updating refcnt. */
- pg[i].count_info |= PGC_allocated | 1;
- list_add_tail(&pg[i].list, &d->page_list);
- }
-
- spin_unlock(&d->page_alloc_lock);
return pg;
}
diff -r 532979a78071 -r ec2ac5a5f0a3 xen/include/asm-x86/grant_table.h
--- a/xen/include/asm-x86/grant_table.h Sat Jun 17 12:31:40 2006 +0100
+++ b/xen/include/asm-x86/grant_table.h Sat Jun 17 12:48:07 2006 +0100
@@ -18,9 +18,6 @@ int destroy_grant_host_mapping(
int destroy_grant_host_mapping(
unsigned long addr, unsigned long frame, unsigned int flags);
-int steal_page_for_grant_transfer(
- struct domain *d, struct page_info *page);
-
#define gnttab_create_shared_page(d, t, i) \
do { \
share_xen_page_with_guest( \
diff -r 532979a78071 -r ec2ac5a5f0a3 xen/include/asm-x86/mm.h
--- a/xen/include/asm-x86/mm.h Sat Jun 17 12:31:40 2006 +0100
+++ b/xen/include/asm-x86/mm.h Sat Jun 17 12:48:07 2006 +0100
@@ -387,4 +387,7 @@ long arch_memory_op(int op, GUEST_HANDLE
long arch_memory_op(int op, GUEST_HANDLE(void) arg);
long subarch_memory_op(int op, GUEST_HANDLE(void) arg);
+int steal_page(
+ struct domain *d, struct page_info *page, unsigned int memflags);
+
#endif /* __ASM_X86_MM_H__ */
diff -r 532979a78071 -r ec2ac5a5f0a3 xen/include/public/memory.h
--- a/xen/include/public/memory.h Sat Jun 17 12:31:40 2006 +0100
+++ b/xen/include/public/memory.h Sat Jun 17 12:48:07 2006 +0100
@@ -10,8 +10,8 @@
#define __XEN_PUBLIC_MEMORY_H__
/*
- * Increase or decrease the specified domain's memory reservation. Returns a
- * -ve errcode on failure, or the # extents successfully allocated or freed.
+ * Increase or decrease the specified domain's memory reservation. Returns the
+ * number of extents successfully allocated or freed.
* arg == addr of struct xen_memory_reservation.
*/
#define XENMEM_increase_reservation 0
@@ -48,9 +48,50 @@ typedef struct xen_memory_reservation {
* Unprivileged domains can specify only DOMID_SELF.
*/
domid_t domid;
-
} xen_memory_reservation_t;
DEFINE_GUEST_HANDLE(xen_memory_reservation_t);
+
+/*
+ * An atomic exchange of memory pages. If return code is zero then
+ * @out.extent_list provides GMFNs of the newly-allocated memory.
+ * Returns zero on complete success, otherwise a negative error code.
+ * On complete success then always @nr_exchanged == @in.nr_extents.
+ * On partial success @nr_exchanged indicates how much work was done.
+ */
+#define XENMEM_exchange 11
+typedef struct xen_memory_exchange {
+ /*
+ * [IN] Details of memory extents to be exchanged (GMFN bases).
+ * Note that @in.address_bits is ignored and unused.
+ */
+ struct xen_memory_reservation in;
+
+ /*
+ * [IN/OUT] Details of new memory extents.
+ * We require that:
+ * 1. @in.domid == @out.domid
+ * 2. @in.nr_extents << @in.extent_order ==
+ * @out.nr_extents << @out.extent_order
+ * 3. @in.extent_start and @out.extent_start lists must not overlap
+ * 4. @out.extent_start lists GPFN bases to be populated
+ * 5. @out.extent_start is overwritten with allocated GMFN bases
+ */
+ struct xen_memory_reservation out;
+
+ /*
+ * [OUT] Number of input extents that were successfully exchanged:
+ * 1. The first @nr_exchanged input extents were successfully
+ * deallocated.
+ * 2. The corresponding first entries in the output extent list correctly
+ * indicate the GMFNs that were successfully exchanged.
+ * 3. All other input and output extents are untouched.
+ * 4. If not all input exents are exchanged then the return code of this
+ * command will be non-zero.
+ * 5. THIS FIELD MUST BE INITIALISED TO ZERO BY THE CALLER!
+ */
+ unsigned long nr_exchanged;
+} xen_memory_exchange_t;
+DEFINE_GUEST_HANDLE(xen_memory_exchange_t);
/*
* Returns the maximum machine frame number of mapped RAM in this system.
diff -r 532979a78071 -r ec2ac5a5f0a3 xen/include/xen/mm.h
--- a/xen/include/xen/mm.h Sat Jun 17 12:31:40 2006 +0100
+++ b/xen/include/xen/mm.h Sat Jun 17 12:48:07 2006 +0100
@@ -60,13 +60,23 @@ void free_xenheap_pages(void *v, unsigne
/* Domain suballocator. These functions are *not* interrupt-safe.*/
void init_domheap_pages(paddr_t ps, paddr_t pe);
struct page_info *alloc_domheap_pages(
- struct domain *d, unsigned int order, unsigned int flags);
+ struct domain *d, unsigned int order, unsigned int memflags);
void free_domheap_pages(struct page_info *pg, unsigned int order);
unsigned long avail_domheap_pages(void);
#define alloc_domheap_page(d) (alloc_domheap_pages(d,0,0))
#define free_domheap_page(p) (free_domheap_pages(p,0))
-#define ALLOC_DOM_DMA 1
+int assign_pages(
+ struct domain *d,
+ struct page_info *pg,
+ unsigned int order,
+ unsigned int memflags);
+
+/* memflags: */
+#define _MEMF_dma 0
+#define MEMF_dma (1U<<_MEMF_dma)
+#define _MEMF_no_refcount 1
+#define MEMF_no_refcount (1U<<_MEMF_no_refcount)
/* Up to 2^20 pages can be allocated at once. */
#define MAX_ORDER 20
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|