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. Index: head-2008-11-20/arch/x86/mm/hypervisor.c =================================================================== --- head-2008-11-20.orig/arch/x86/mm/hypervisor.c 2008-11-21 15:51:34.000000000 +0100 +++ head-2008-11-20/arch/x86/mm/hypervisor.c 2008-11-17 12:12:39.000000000 +0100 @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -668,6 +669,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); Index: head-2008-11-20/drivers/xen/balloon/balloon.c =================================================================== --- head-2008-11-20.orig/drivers/xen/balloon/balloon.c 2008-11-21 15:56:56.000000000 +0100 +++ head-2008-11-20/drivers/xen/balloon/balloon.c 2008-11-21 16:00:18.000000000 +0100 @@ -687,7 +687,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; @@ -702,11 +702,24 @@ void free_empty_pages_and_pagevec(struct } balloon_unlock(flags); - kfree(pagevec); + if (free_vec) + kfree(pagevec); + else + totalram_pages = bs.current_pages -= nr_pages; 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; Index: head-2008-11-20/include/xen/balloon.h =================================================================== --- head-2008-11-20.orig/include/xen/balloon.h 2008-11-21 15:51:34.000000000 +0100 +++ head-2008-11-20/include/xen/balloon.h 2008-11-21 09:39:34.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); /*