From 40a69f4cf35bb3f0ab6a55ce82edb92f0400aee6 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 10 Nov 2006 14:22:17 +0000 Subject: [PATCH] [XEN] memory_op hypercall does not use guest_handle_add_offset(). It was causing compatibility issues across architectures as on x86 the effect would not persist across a continuation. On x86/64 and powerpc (both of which use xencomm) the effect would persist. This patch sidesteps the whole issue. Signed-off-by: Keir Fraser --- xen/common/memory.c | 229 +++++++++++++++++++------------------------- 1 file changed, 101 insertions(+), 128 deletions(-) diff --git a/xen/common/memory.c b/xen/common/memory.c index a0e65e08e1..33ead8e259 100644 --- a/xen/common/memory.c +++ b/xen/common/memory.c @@ -29,98 +29,105 @@ */ #define START_EXTENT_SHIFT 4 /* cmd[:4] == start_extent */ -static long -increase_reservation( - struct domain *d, - XEN_GUEST_HANDLE(xen_pfn_t) extent_list, - unsigned int nr_extents, - unsigned int extent_order, - unsigned int memflags, - int *preempted) +struct memop_args { + /* INPUT */ + struct domain *domain; /* Domain to be affected. */ + XEN_GUEST_HANDLE(xen_pfn_t) extent_list; /* List of extent base addrs. */ + unsigned int nr_extents; /* Number of extents to allocate or free. */ + unsigned int extent_order; /* Size of each extent. */ + unsigned int memflags; /* Allocation flags. */ + + /* INPUT/OUTPUT */ + unsigned int nr_done; /* Number of extents processed so far. */ + int preempted; /* Was the hypercall preempted? */ +}; + +static unsigned int select_local_cpu(struct domain *d) +{ + struct vcpu *v = d->vcpu[0]; + return (v ? v->processor : 0); +} + +static void increase_reservation(struct memop_args *a) { struct page_info *page; unsigned long i; xen_pfn_t mfn; - /* use domain's first processor for locality parameter */ - unsigned int cpu = d->vcpu[0]->processor; + struct domain *d = a->domain; + unsigned int cpu = select_local_cpu(d); - if ( !guest_handle_is_null(extent_list) && - !guest_handle_okay(extent_list, nr_extents) ) - return 0; + if ( !guest_handle_is_null(a->extent_list) && + !guest_handle_okay(a->extent_list, a->nr_extents) ) + return; - if ( (extent_order != 0) && + if ( (a->extent_order != 0) && !multipage_allocation_permitted(current->domain) ) - return 0; + return; - for ( i = 0; i < nr_extents; i++ ) + for ( i = a->nr_done; i < a->nr_extents; i++ ) { if ( hypercall_preempt_check() ) { - *preempted = 1; - return i; + a->preempted = 1; + goto out; } - if ( unlikely((page = __alloc_domheap_pages( d, cpu, - extent_order, memflags )) == NULL) ) + page = __alloc_domheap_pages(d, cpu, a->extent_order, a->memflags); + if ( unlikely(page == NULL) ) { gdprintk(XENLOG_INFO, "Could not allocate order=%d extent: " "id=%d memflags=%x (%ld of %d)\n", - extent_order, d->domain_id, memflags, i, nr_extents); - return i; + a->extent_order, d->domain_id, a->memflags, + i, a->nr_extents); + goto out; } /* Inform the domain of the new page's machine address. */ - if ( !guest_handle_is_null(extent_list) ) + if ( !guest_handle_is_null(a->extent_list) ) { mfn = page_to_mfn(page); - if ( unlikely(__copy_to_guest_offset(extent_list, i, &mfn, 1)) ) - return i; + if ( unlikely(__copy_to_guest_offset(a->extent_list, i, &mfn, 1)) ) + goto out; } } - return nr_extents; + out: + a->nr_done = i; } -static long -populate_physmap( - struct domain *d, - XEN_GUEST_HANDLE(xen_pfn_t) extent_list, - unsigned int nr_extents, - unsigned int extent_order, - unsigned int memflags, - int *preempted) +static void populate_physmap(struct memop_args *a) { struct page_info *page; unsigned long i, j; - xen_pfn_t gpfn; - xen_pfn_t mfn; - /* use domain's first processor for locality parameter */ - unsigned int cpu = d->vcpu[0]->processor; + xen_pfn_t gpfn, mfn; + struct domain *d = a->domain; + unsigned int cpu = select_local_cpu(d); - if ( !guest_handle_okay(extent_list, nr_extents) ) - return 0; + if ( !guest_handle_okay(a->extent_list, a->nr_extents) ) + return; - if ( (extent_order != 0) && + if ( (a->extent_order != 0) && !multipage_allocation_permitted(current->domain) ) - return 0; + return; - for ( i = 0; i < nr_extents; i++ ) + for ( i = a->nr_done; i < a->nr_extents; i++ ) { if ( hypercall_preempt_check() ) { - *preempted = 1; + a->preempted = 1; goto out; } - if ( unlikely(__copy_from_guest_offset(&gpfn, extent_list, i, 1)) ) + if ( unlikely(__copy_from_guest_offset(&gpfn, a->extent_list, i, 1)) ) goto out; - if ( unlikely((page = __alloc_domheap_pages( d, cpu, - extent_order, memflags )) == NULL) ) + page = __alloc_domheap_pages(d, cpu, a->extent_order, a->memflags); + if ( unlikely(page == NULL) ) { gdprintk(XENLOG_INFO, "Could not allocate order=%d extent: " - "id=%d memflags=%x (%ld of %d)\n", - extent_order, d->domain_id, memflags, i, nr_extents); + "id=%d memflags=%x (%ld of %d)\n", + a->extent_order, d->domain_id, a->memflags, + i, a->nr_extents); goto out; } @@ -128,28 +135,25 @@ populate_physmap( if ( unlikely(shadow_mode_translate(d)) ) { - for ( j = 0; j < (1 << extent_order); j++ ) + for ( j = 0; j < (1 << a->extent_order); j++ ) guest_physmap_add_page(d, gpfn + j, mfn + j); } else { - for ( j = 0; j < (1 << extent_order); j++ ) + for ( j = 0; j < (1 << a->extent_order); j++ ) set_gpfn_from_mfn(mfn + j, gpfn + j); /* Inform the domain of the new page's machine address. */ - if ( unlikely(__copy_to_guest_offset(extent_list, i, &mfn, 1)) ) + if ( unlikely(__copy_to_guest_offset(a->extent_list, i, &mfn, 1)) ) goto out; } } out: - return i; + a->nr_done = i; } -int -guest_remove_page( - struct domain *d, - unsigned long gmfn) +int guest_remove_page(struct domain *d, unsigned long gmfn) { struct page_info *page; unsigned long mfn; @@ -191,43 +195,35 @@ guest_remove_page( return 1; } -static long -decrease_reservation( - struct domain *d, - XEN_GUEST_HANDLE(xen_pfn_t) extent_list, - unsigned int nr_extents, - unsigned int extent_order, - int *preempted) +static void decrease_reservation(struct memop_args *a) { unsigned long i, j; xen_pfn_t gmfn; - if ( !guest_handle_okay(extent_list, nr_extents) ) - return 0; + if ( !guest_handle_okay(a->extent_list, a->nr_extents) ) + return; - for ( i = 0; i < nr_extents; i++ ) + for ( i = a->nr_done; i < a->nr_extents; i++ ) { if ( hypercall_preempt_check() ) { - *preempted = 1; - return i; + a->preempted = 1; + goto out; } - if ( unlikely(__copy_from_guest_offset(&gmfn, extent_list, i, 1)) ) - return i; + if ( unlikely(__copy_from_guest_offset(&gmfn, a->extent_list, i, 1)) ) + goto out; - for ( j = 0; j < (1 << extent_order); j++ ) - { - if ( !guest_remove_page(d, gmfn + j) ) - return i; - } + for ( j = 0; j < (1 << a->extent_order); j++ ) + if ( !guest_remove_page(a->domain, gmfn + j) ) + goto out; } - return nr_extents; + out: + a->nr_done = i; } -static long -translate_gpfn_list( +static long translate_gpfn_list( XEN_GUEST_HANDLE(xen_translate_gpfn_list_t) uop, unsigned long *progress) { struct xen_translate_gpfn_list op; @@ -289,8 +285,7 @@ translate_gpfn_list( return 0; } -static long -memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg) +static long memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg) { struct xen_memory_exchange exch; LIST_HEAD(in_chunk_list); @@ -341,24 +336,15 @@ memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg) 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; } /* @@ -372,14 +358,15 @@ memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg) } d = current->domain; - /* use domain's first processor for locality parameter */ - cpu = d->vcpu[0]->processor; + cpu = select_local_cpu(d); - for ( i = 0; i < (exch.in.nr_extents >> in_chunk_order); i++ ) + for ( i = (exch.nr_exchanged >> in_chunk_order); + i < (exch.in.nr_extents >> in_chunk_order); + i++ ) { if ( hypercall_preempt_check() ) { - exch.nr_exchanged += i << in_chunk_order; + exch.nr_exchanged = i << in_chunk_order; if ( copy_field_to_guest(arg, &exch, nr_exchanged) ) return -EFAULT; return hypercall_create_continuation( @@ -420,8 +407,8 @@ memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg) /* Allocate a chunk's worth of anonymous output pages. */ for ( j = 0; j < (1UL << out_chunk_order); j++ ) { - page = __alloc_domheap_pages( NULL, cpu, - exch.out.extent_order, memflags); + page = __alloc_domheap_pages( + NULL, cpu, exch.out.extent_order, memflags); if ( unlikely(page == NULL) ) { rc = -ENOMEM; @@ -480,7 +467,7 @@ memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg) BUG_ON(j != (1UL << out_chunk_order)); } - exch.nr_exchanged += exch.in.nr_extents; + exch.nr_exchanged = exch.in.nr_extents; if ( copy_field_to_guest(arg, &exch, nr_exchanged) ) rc = -EFAULT; return rc; @@ -507,7 +494,7 @@ memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg) free_domheap_pages(page, exch.out.extent_order); } - exch.nr_exchanged += i << in_chunk_order; + exch.nr_exchanged = i << in_chunk_order; fail_early: if ( copy_field_to_guest(arg, &exch, nr_exchanged) ) @@ -518,10 +505,10 @@ memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg) long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE(void) arg) { struct domain *d; - int rc, op, preempted = 0; - unsigned int memflags = 0; + int rc, op; unsigned long start_extent, progress; struct xen_memory_reservation reservation; + struct memop_args args; domid_t domid; op = cmd & ((1 << START_EXTENT_SHIFT) - 1); @@ -543,9 +530,12 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE(void) arg) if ( unlikely(start_extent > reservation.nr_extents) ) return start_extent; - if ( !guest_handle_is_null(reservation.extent_start) ) - guest_handle_add_offset(reservation.extent_start, start_extent); - reservation.nr_extents -= start_extent; + args.extent_list = reservation.extent_start; + args.nr_extents = reservation.nr_extents; + args.extent_order = reservation.extent_order; + args.nr_done = start_extent; + args.preempted = 0; + args.memflags = 0; if ( (reservation.address_bits != 0) && (reservation.address_bits < @@ -553,7 +543,7 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE(void) arg) { if ( reservation.address_bits < 31 ) return start_extent; - memflags = MEMF_dma; + args.memflags = MEMF_dma; } if ( likely(reservation.domid == DOMID_SELF) ) @@ -561,44 +551,27 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE(void) arg) else if ( !IS_PRIV(current->domain) || ((d = find_domain_by_id(reservation.domid)) == NULL) ) return start_extent; + args.domain = d; switch ( op ) { case XENMEM_increase_reservation: - rc = increase_reservation( - d, - reservation.extent_start, - reservation.nr_extents, - reservation.extent_order, - memflags, - &preempted); + increase_reservation(&args); break; case XENMEM_decrease_reservation: - rc = decrease_reservation( - d, - reservation.extent_start, - reservation.nr_extents, - reservation.extent_order, - &preempted); + decrease_reservation(&args); break; - case XENMEM_populate_physmap: - default: - rc = populate_physmap( - d, - reservation.extent_start, - reservation.nr_extents, - reservation.extent_order, - memflags, - &preempted); + default: /* XENMEM_populate_physmap */ + populate_physmap(&args); break; } if ( unlikely(reservation.domid != DOMID_SELF) ) put_domain(d); - rc += start_extent; + rc = args.nr_done; - if ( preempted ) + if ( args.preempted ) return hypercall_create_continuation( __HYPERVISOR_memory_op, "lh", op | (rc << START_EXTENT_SHIFT), arg); -- 2.30.2