From: kfraser@dhcp93.uk.xensource.com Date: Fri, 16 Jun 2006 13:45:01 +0000 (+0100) Subject: [LINUX] Use new XENMEM_exchange hypercall (where possible) X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~15921^2~56^2~2 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=a2ee238fcf52491bc2bf5b17d57491b488ec491e;p=xen.git [LINUX] Use new XENMEM_exchange hypercall (where possible) to provide watertight implementations that should never crash in ENOMEM situations. Signed-off-by: Keir Fraser --- diff --git a/linux-2.6-xen-sparse/arch/i386/mm/hypervisor.c b/linux-2.6-xen-sparse/arch/i386/mm/hypervisor.c index f9615358d1..a358373c89 100644 --- a/linux-2.6-xen-sparse/arch/i386/mm/hypervisor.c +++ b/linux-2.6-xen-sparse/arch/i386/mm/hypervisor.c @@ -263,6 +263,10 @@ static void contiguous_bitmap_clear( } } +/* Protected by balloon_lock. */ +#define MAX_CONTIG_ORDER 7 +static unsigned long discontig_frames[1< MAX_CONTIG_ORDER) + return -ENOMEM; + + set_xen_guest_handle(exchange.in.extent_start, in_frames); + set_xen_guest_handle(exchange.out.extent_start, &out_frame); + scrub_pages(vstart, 1 << order); balloon_lock(flags); - /* 1. Zap current PTEs, giving away the underlying pages. */ - for (i = 0; i < (1<>PAGE_SHIFT)+i, INVALID_P2M_ENTRY); - BUG_ON(HYPERVISOR_memory_op( - XENMEM_decrease_reservation, &reservation) != 1); } /* 2. Get a new contiguous memory extent. */ - reservation.extent_order = order; - reservation.address_bits = address_bits; - frame = __pa(vstart) >> PAGE_SHIFT; - if (HYPERVISOR_memory_op(XENMEM_populate_physmap, - &reservation) != 1) - goto fail; - - /* 3. Map the new extent in place of old pages. */ - for (i = 0; i < (1<>PAGE_SHIFT)+i, frame+i); + out_frame = __pa(vstart) >> PAGE_SHIFT; + rc = HYPERVISOR_memory_op(XENMEM_exchange, &exchange); + success = (exchange.nr_exchanged == (1UL << order)); + BUG_ON(!success && ((exchange.nr_exchanged != 0) || (rc == 0))); + BUG_ON(success && (rc != 0)); + if (unlikely(rc == -ENOSYS)) { + /* Compatibility when XENMEM_exchange is unsupported. */ + if (HYPERVISOR_memory_op(XENMEM_decrease_reservation, + &exchange.in) != (1UL << order)) + BUG(); + success = (HYPERVISOR_memory_op(XENMEM_populate_physmap, + &exchange.out) == 1); + if (!success) { + /* Couldn't get special memory: fall back to normal. */ + for (i = 0; i < (1UL<>PAGE_SHIFT) + i; + if (HYPERVISOR_memory_op(XENMEM_populate_physmap, + &exchange.in) != (1UL<> PAGE_SHIFT, 1UL << order); - - balloon_unlock(flags); - - return 0; - - fail: - reservation.extent_order = 0; - reservation.address_bits = 0; - - for (i = 0; i < (1<> PAGE_SHIFT) + i; - BUG_ON(HYPERVISOR_memory_op( - XENMEM_populate_physmap, &reservation) != 1); - BUG_ON(HYPERVISOR_update_va_mapping( - vstart + (i*PAGE_SIZE), - pfn_pte_ma(frame, PAGE_KERNEL), 0)); + /* 3. Map the new extent in place of old pages. */ + for (i = 0; i < (1UL<>PAGE_SHIFT)+i, frame); } flush_tlb_all(); + if (success) + contiguous_bitmap_set(__pa(vstart) >> PAGE_SHIFT, + 1UL << order); + balloon_unlock(flags); - return -ENOMEM; + return success ? 0 : -ENOMEM; } void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order) @@ -357,47 +376,79 @@ void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order) pud_t *pud; pmd_t *pmd; pte_t *pte; + unsigned long *out_frames = discontig_frames, in_frame; unsigned long frame, i, flags; - struct xen_memory_reservation reservation = { - .nr_extents = 1, - .extent_order = 0, - .domid = DOMID_SELF + long rc; + int success; + struct xen_memory_exchange exchange = { + .in = { + .nr_extents = 1, + .extent_order = order, + .domid = DOMID_SELF + }, + .out = { + .nr_extents = 1UL << order, + .extent_order = 0, + .domid = DOMID_SELF + } }; - set_xen_guest_handle(reservation.extent_start, &frame); if (xen_feature(XENFEAT_auto_translated_physmap) || !test_bit(__pa(vstart) >> PAGE_SHIFT, contiguous_bitmap)) return; + if (order > MAX_CONTIG_ORDER) + return; + + set_xen_guest_handle(exchange.in.extent_start, &in_frame); + set_xen_guest_handle(exchange.out.extent_start, out_frames); + scrub_pages(vstart, 1 << order); balloon_lock(flags); contiguous_bitmap_clear(__pa(vstart) >> PAGE_SHIFT, 1UL << order); - /* 1. Zap current PTEs, giving away the underlying pages. */ - for (i = 0; i < (1<>PAGE_SHIFT)+i, INVALID_P2M_ENTRY); - BUG_ON(HYPERVISOR_memory_op( - XENMEM_decrease_reservation, &reservation) != 1); + out_frames[i] = (__pa(vstart) >> PAGE_SHIFT) + i; + } + + /* 3. Do the exchange for non-contiguous MFNs. */ + rc = HYPERVISOR_memory_op(XENMEM_exchange, &exchange); + success = (exchange.nr_exchanged == 1); + BUG_ON(!success && ((exchange.nr_exchanged != 0) || (rc == 0))); + BUG_ON(success && (rc != 0)); + if (rc == -ENOSYS) { + /* Compatibility when XENMEM_exchange is unsupported. */ + if (HYPERVISOR_memory_op(XENMEM_decrease_reservation, + &exchange.in) != 1) + BUG(); + if (HYPERVISOR_memory_op(XENMEM_populate_physmap, + &exchange.out) != (1UL << order)) + BUG(); + success = 1; } - /* 2. Map new pages in place of old pages. */ - for (i = 0; i < (1<> PAGE_SHIFT) + i; - BUG_ON(HYPERVISOR_memory_op( - XENMEM_populate_physmap, &reservation) != 1); - BUG_ON(HYPERVISOR_update_va_mapping( - vstart + (i*PAGE_SIZE), - pfn_pte_ma(frame, PAGE_KERNEL), 0)); + /* 4. Map new pages in place of old pages. */ + for (i = 0; i < (1UL<>PAGE_SHIFT)+i, frame); }