Subject: Add fallback when XENMEM_exchange fails to replace contiguous region From: jbeulich@novell.com Patch-mainline: obsolete References: 181869 This avoids losing precious special memory in places where any memory can be used. --- sle11-2009-06-29.orig/arch/x86/mm/hypervisor.c 2009-03-16 16:17:45.000000000 +0100 +++ sle11-2009-06-29/arch/x86/mm/hypervisor.c 2009-03-30 12:18:24.000000000 +0200 @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -712,6 +713,83 @@ void xen_destroy_contiguous_region(unsig BUG(); balloon_unlock(flags); + + if (unlikely(!success)) { + /* Try hard to get the special memory back to Xen. */ + exchange.in.extent_order = 0; + set_xen_guest_handle(exchange.in.extent_start, &in_frame); + + for (i = 0; i < (1U<> PAGE_SHIFT; + set_phys_to_machine(pfn, frame); + if (!xen_feature(XENFEAT_auto_translated_physmap)) { + mmu.ptr = ((uint64_t)frame << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE; + mmu.val = pfn; + cr_mcl[j].op = __HYPERVISOR_mmu_update; + cr_mcl[j].args[0] = (unsigned long)&mmu; + cr_mcl[j].args[1] = 1; + cr_mcl[j].args[2] = 0; + cr_mcl[j].args[3] = DOMID_SELF; + ++j; + } + + cr_mcl[j].op = __HYPERVISOR_memory_op; + cr_mcl[j].args[0] = XENMEM_decrease_reservation; + cr_mcl[j].args[1] = (unsigned long)&exchange.in; + + if (HYPERVISOR_multicall(cr_mcl, j + 1)) + BUG(); + BUG_ON(cr_mcl[j].result != 1); + while (j--) + BUG_ON(cr_mcl[j].result != 0); + + balloon_unlock(flags); + + free_empty_pages(&page, 1); + + in_frame++; + vstart += PAGE_SIZE; + } + } } EXPORT_SYMBOL_GPL(xen_destroy_contiguous_region); --- sle11-2009-06-29.orig/drivers/xen/balloon/balloon.c 2009-06-29 15:44:49.000000000 +0200 +++ sle11-2009-06-29/drivers/xen/balloon/balloon.c 2009-06-29 15:46:09.000000000 +0200 @@ -665,7 +665,7 @@ struct page **alloc_empty_pages_and_page goto out; } -void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages) +static void _free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages, int free_vec) { unsigned long flags; int i; @@ -678,13 +678,26 @@ void free_empty_pages_and_pagevec(struct BUG_ON(page_count(pagevec[i]) != 1); balloon_append(pagevec[i]); } + if (!free_vec) + totalram_pages = bs.current_pages -= nr_pages; balloon_unlock(flags); - kfree(pagevec); + if (free_vec) + kfree(pagevec); schedule_work(&balloon_worker); } +void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages) +{ + _free_empty_pages_and_pagevec(pagevec, nr_pages, 1); +} + +void free_empty_pages(struct page **pagevec, int nr_pages) +{ + _free_empty_pages_and_pagevec(pagevec, nr_pages, 0); +} + void balloon_release_driver_page(struct page *page) { unsigned long flags; --- sle11-2009-06-29.orig/include/xen/balloon.h 2009-03-16 16:38:05.000000000 +0100 +++ sle11-2009-06-29/include/xen/balloon.h 2009-03-16 16:40:33.000000000 +0100 @@ -47,6 +47,10 @@ void balloon_update_driver_allowance(lon struct page **alloc_empty_pages_and_pagevec(int nr_pages); void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages); +/* Free an empty page range (not allocated through + alloc_empty_pages_and_pagevec), adding to the balloon. */ +void free_empty_pages(struct page **pagevec, int nr_pages); + void balloon_release_driver_page(struct page *page); /*