]> Pileus Git - ~andy/linux/blobdiff - drivers/xen/balloon.c
xen/balloon: flush persistent kmaps in correct position
[~andy/linux] / drivers / xen / balloon.c
index 4c02e2b9410377d9e6b77fe1bc2b50d929774551..61a6ac8fa8fc7ab00dcc7c33cea47981f2509d4b 100644 (file)
@@ -157,13 +157,6 @@ static struct page *balloon_retrieve(bool prefer_highmem)
        return page;
 }
 
-static struct page *balloon_first_page(void)
-{
-       if (list_empty(&ballooned_pages))
-               return NULL;
-       return list_entry(ballooned_pages.next, struct page, lru);
-}
-
 static struct page *balloon_next_page(struct page *page)
 {
        struct list_head *next = page->lru.next;
@@ -328,7 +321,7 @@ static enum bp_state increase_reservation(unsigned long nr_pages)
        if (nr_pages > ARRAY_SIZE(frame_list))
                nr_pages = ARRAY_SIZE(frame_list);
 
-       page = balloon_first_page();
+       page = list_first_entry_or_null(&ballooned_pages, struct page, lru);
        for (i = 0; i < nr_pages; i++) {
                if (!page) {
                        nr_pages = i;
@@ -406,11 +399,25 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
                        state = BP_EAGAIN;
                        break;
                }
+               scrub_page(page);
 
-               pfn = page_to_pfn(page);
-               frame_list[i] = pfn_to_mfn(pfn);
+               frame_list[i] = page_to_pfn(page);
+       }
 
-               scrub_page(page);
+       /*
+        * Ensure that ballooned highmem pages don't have kmaps.
+        *
+        * Do this before changing the p2m as kmap_flush_unused()
+        * reads PTEs to obtain pages (and hence needs the original
+        * p2m entry).
+        */
+       kmap_flush_unused();
+
+       /* Update direct mapping, invalidate P2M, and add to balloon. */
+       for (i = 0; i < nr_pages; i++) {
+               pfn = frame_list[i];
+               frame_list[i] = pfn_to_mfn(pfn);
+               page = pfn_to_page(pfn);
 
 #ifdef CONFIG_XEN_HAVE_PVMMU
                /*
@@ -436,11 +443,9 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
                }
 #endif
 
-               balloon_append(pfn_to_page(pfn));
+               balloon_append(page);
        }
 
-       /* Ensure that ballooned highmem pages don't have kmaps. */
-       kmap_flush_unused();
        flush_tlb_all();
 
        set_xen_guest_handle(reservation.extent_start, frame_list);