Index: 2006-06-29/linux-2.6-xen-sparse/arch/i386/mm/hypervisor.c =================================================================== --- 2006-06-29.orig/linux-2.6-xen-sparse/arch/i386/mm/hypervisor.c 2006-06-29 15:29:06.000000000 +0200 +++ 2006-06-29/linux-2.6-xen-sparse/arch/i386/mm/hypervisor.c 2006-06-29 15:32:32.000000000 +0200 @@ -42,6 +42,7 @@ #include #include #include +#include #include #ifdef CONFIG_X86_64 @@ -419,7 +420,8 @@ void xen_destroy_contiguous_region(unsig /* 2. Zap current PTEs. */ for (i = 0; i < (1UL<>PAGE_SHIFT)+i, INVALID_P2M_ENTRY); out_frames[i] = (__pa(vstart) >> PAGE_SHIFT) + i; @@ -430,7 +432,7 @@ void xen_destroy_contiguous_region(unsig success = (exchange.nr_exchanged == 1); BUG_ON(!success && ((exchange.nr_exchanged != 0) || (rc == 0))); BUG_ON(success && (rc != 0)); - if (rc == -ENOSYS) { + if (unlikely(rc == -ENOSYS)) { /* Compatibility when XENMEM_exchange is unsupported. */ if (HYPERVISOR_memory_op(XENMEM_decrease_reservation, &exchange.in) != 1) @@ -455,6 +457,68 @@ void xen_destroy_contiguous_region(unsig flush_tlb_all(); 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 < (1UL<> PAGE_SHIFT; + set_phys_to_machine(pfn, frame); + xen_machphys_update(frame, pfn); + + if (HYPERVISOR_memory_op(XENMEM_decrease_reservation, + &exchange.in) != 1) + BUG(); + + balloon_unlock(flags); + + set_page_count(page, 1); + balloon_free_empty_page_range(page, 1); + + in_frame++; + vstart += PAGE_SIZE; + } + } } #ifdef __i386__ Index: 2006-06-29/linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c =================================================================== --- 2006-06-29.orig/linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c 2006-06-29 15:29:06.000000000 +0200 +++ 2006-06-29/linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c 2006-06-29 15:29:29.000000000 +0200 @@ -597,22 +597,37 @@ struct page *balloon_alloc_empty_page_ra return page; } -void balloon_dealloc_empty_page_range( - struct page *page, unsigned long nr_pages) +static void _balloon_free_empty_page_range( + struct page *page, unsigned long nr_pages, int account) { unsigned long i, flags; - unsigned int order = get_order(nr_pages * PAGE_SIZE); balloon_lock(flags); - for (i = 0; i < (1UL << order); i++) { + for (i = 0; i < nr_pages; i++) { BUG_ON(page_count(page + i) != 1); balloon_append(page + i); } + if (account) { + current_pages -= nr_pages; + totalram_pages = current_pages; + } balloon_unlock(flags); schedule_work(&balloon_worker); } +void balloon_dealloc_empty_page_range( + struct page *page, unsigned long nr_pages) +{ + _balloon_free_empty_page_range(page, 1UL << get_order(nr_pages * PAGE_SIZE), 0); +} + +void balloon_free_empty_page_range( + struct page *page, unsigned long nr_pages) +{ + _balloon_free_empty_page_range(page, nr_pages, 1); +} + EXPORT_SYMBOL_GPL(balloon_update_driver_allowance); EXPORT_SYMBOL_GPL(balloon_alloc_empty_page_range); EXPORT_SYMBOL_GPL(balloon_dealloc_empty_page_range); Index: 2006-06-29/linux-2.6-xen-sparse/include/xen/balloon.h =================================================================== --- 2006-06-29.orig/linux-2.6-xen-sparse/include/xen/balloon.h 2006-06-29 15:29:06.000000000 +0200 +++ 2006-06-29/linux-2.6-xen-sparse/include/xen/balloon.h 2006-06-29 15:29:29.000000000 +0200 @@ -52,6 +52,12 @@ extern void balloon_dealloc_empty_page_range( struct page *page, unsigned long nr_pages); +/* Free an empty page range (not allocated through + balloon_alloc_empty_page_range), adding to the balloon. */ +extern void +balloon_free_empty_page_range( + struct page *page, unsigned long nr_pages); + /* * Prevent the balloon driver from changing the memory reservation during * a driver critical region.