patches.xen/xen-x86-dcr-fallback
authorAlex Bligh <alex@alex.org.uk>
Thu, 17 May 2012 19:15:31 +0000 (20:15 +0100)
committerAlex Bligh <alex@alex.org.uk>
Thu, 17 May 2012 19:15:31 +0000 (20:15 +0100)
arch/x86/mm/hypervisor.c
drivers/xen/balloon/balloon.c
include/xen/balloon.h

index 8053b36..f030eb2 100644 (file)
@@ -779,6 +779,83 @@ void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order)
                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<<order); i++) {
+                       struct page *page = alloc_page(__GFP_HIGHMEM|__GFP_COLD);
+                       unsigned long pfn;
+                       mmu_update_t mmu;
+                       unsigned int j = 0;
+
+                       if (!page) {
+                               pr_warn("Xen and kernel out of memory"
+                                       " while trying to release an order"
+                                       " %u contiguous region\n", order);
+                               break;
+                       }
+                       pfn = page_to_pfn(page);
+
+                       balloon_lock(flags);
+
+                       if (!PageHighMem(page)) {
+                               void *v = __va(pfn << PAGE_SHIFT);
+
+                               scrub_pages(v, 1);
+                               MULTI_update_va_mapping(cr_mcl + j, (unsigned long)v,
+                                                       __pte_ma(0), UVMF_INVLPG|UVMF_ALL);
+                               ++j;
+                       }
+#ifdef CONFIG_XEN_SCRUB_PAGES
+                       else {
+                               scrub_pages(kmap(page), 1);
+                               kunmap(page);
+                               kmap_flush_unused();
+                       }
+#endif
+
+                       frame = pfn_to_mfn(pfn);
+                       set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
+
+                       MULTI_update_va_mapping(cr_mcl + j, vstart,
+                                               pfn_pte_ma(frame, PAGE_KERNEL),
+                                               UVMF_INVLPG|UVMF_ALL);
+                       ++j;
+
+                       pfn = __pa(vstart) >> 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 86e0865..915c6f4 100644 (file)
@@ -769,28 +769,45 @@ struct page **alloc_empty_pages_and_pagevec(int nr_pages)
 }
 EXPORT_SYMBOL_GPL(alloc_empty_pages_and_pagevec);
 
-void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages)
+#endif /* CONFIG_XEN_BACKEND */
+
+#ifdef CONFIG_XEN
+static void _free_empty_pages(struct page **pagevec, int nr_pages,
+                             bool account)
 {
        unsigned long flags;
        int i;
 
-       if (pagevec == NULL)
-               return;
-
        balloon_lock(flags);
        for (i = 0; i < nr_pages; i++) {
                BUG_ON(page_count(pagevec[i]) != 1);
-               balloon_append(pagevec[i], 0);
+               balloon_append(pagevec[i], account);
+       }
+       if (account) {
+               bs.current_pages -= nr_pages;
+               totalram_pages = bs.current_pages - totalram_bias;
        }
        balloon_unlock(flags);
 
-       kfree(pagevec);
-
        schedule_work(&balloon_worker);
 }
-EXPORT_SYMBOL_GPL(free_empty_pages_and_pagevec);
 
-#endif /* CONFIG_XEN_BACKEND */
+void free_empty_pages(struct page **pagevec, int nr_pages)
+{
+       _free_empty_pages(pagevec, nr_pages, true);
+}
+#endif
+
+#if defined(CONFIG_XEN_BACKEND) || defined(CONFIG_XEN_BACKEND_MODULE)
+void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages)
+{
+       if (pagevec) {
+               _free_empty_pages(pagevec, nr_pages, false);
+               kfree(pagevec);
+       }
+}
+EXPORT_SYMBOL_GPL(free_empty_pages_and_pagevec);
+#endif
 
 void balloon_release_driver_page(struct page *page)
 {
index 8edde20..9c27f97 100644 (file)
@@ -47,6 +47,10 @@ void balloon_update_driver_allowance(long delta);
 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);
 
 /*